目標:讀取 64位/32位 elf文件,打印section,segments,sectiom to segments mapping
一,elf文件解析
這部分內容請參考互聯網,已經有很多博客說的很清楚了。
二,代碼佈局
代碼非常簡單,一個頭文件用於聲明操作的類,一個cpp文件,用於實現該類,下面先介紹一下頭文件的相關聲明和組成。
/************************************************************************/
/* AUTHOR : FangJianYang
/* VERSION : 01
/* TIME : 2019-02-17
/* DESC : Some function to read a elf file
/* Email : [email protected]
/************************************************************************/
#include <elf.h>
#include <iostream>
#include <string.h>
#include <vector>
#include <map>
#include <string>
using namespace std;
#define SUCCESS 0
#define WRONG_ARGMENTS -1
#define FILE_OPEN_ERR -2
#define NOT_A_ELF_FILE -3
#define READ_FILE_FAILED -4
#define FILE_SEEK_ERROR -5
#define GET_SEC_NAME_ERR -6
#define CALC_MAPPING_ERROR -7
上面幾行代碼,主要關注這麼幾行:
1. elf.h 頭文件可能不是所有Linux發行版都提供,因此需要按照對應的系統做調整。可以直接使用whereis 命令去查找,比如在Ubuntu上是這個結果:
xxx@ubuntu:~xxx$ whereis elf
elf: /usr/include/elf.h /usr/share/man/man5/elf.5.gz
2. 我定義了幾個宏,用於表示程序的錯誤碼,其中:
WRONG_ARGMENTS 表示:用戶輸入了錯誤的參數(本例程並不支持所有參數)
GET_SEC_NAME_ERR 表示:獲取section名字失敗(關於section的名字,可以搜索elf格式來獲取更多詳情)
CALC_MAPPING_ERROR 表示:計算section到segments的映射錯誤(同上,搜索elf格式獲取更多詳情)
typedef struct
{
string sh_strname;
Elf64_Shdr elf64sehd;
}myElf64_Shdr;
typedef struct
{
string sh_strname;
Elf32_Shdr elf32sehd;
}myElf32_Shdr;
typedef struct sec2SegMapping
{
int index;
string secNameVec;
public:
sec2SegMapping(int id,string arg):index(id),secNameVec(arg){}
}sec2SegMapping;
上面的代碼我定義了幾個結構體,其中myElf64_Shdr和myElf32_Shdr是爲了兼容64/32位系統的elf文件。然後sec2SegMapping是用於保存單個的section序號和名字,後面會看到具體用法。
class CReadElf
{
private:
int osType ;
vector<string> secName;
FILE * pFile;
string filename;
vector<sec2SegMapping> mapping;
上面是具體工作類的部分描述,其中
- osType:表示獲取的elf文件是32還是64位的
- secName:用於保存沒一部分的section名字
- pFile:用於操作ELF文件的句柄
- filename:具體的elf文件名字
- mapping:保存section和segment對應的映射(現在看來,這裏直接用map類型可能更好一點,但是我不想改了)
private:
vector<myElf64_Shdr> sections;
vector<Elf64_Phdr> segments;
Elf64_Ehdr elfHead64;
private:
vector<myElf32_Shdr> sections32;
vector<Elf32_Phdr> segments32;
Elf32_Ehdr elfHead32;
上面兩段代碼是完全一模一樣的,只是爲了兼容32/64位操作系統,可以優化(你看出來了,我不怎麼想優化)。
- sections:用於保存讀取到的section header相關信息(關於這個結構體——最底層的Elf64_Shdr/Elf32_Shdr,請查看elf.h)
- segments:同上
- Elf32/64_Ehdr:查看elf.h 文件,我只是需要在解析出來後,保存他們,將來直接拿來用
public:
CReadElf(char *argc);
virtual ~CReadElf();
int getfd();
public:
int readFile();
int readSection();
int readSegment();
int getSectionName();
int caclSec2Segments();
void showHead();
void showSection();
void showSegments();
void showSec2SegMapping();
};
上面代碼聲明瞭一些函數,函數功能可以直接從函數名字上大致獲得,不做解析。
下面簡要講解一下cpp代碼實現
/***********************************************************************/
/* AUTHOR : FangJianYang
/* VERSION : 01
/* TIME : 2019-02-17
/* DESC : Some function to read a elf file
/* Email : [email protected]
/************************************************************************/
#include "readelf.h"
#include <stdio.h>
#include <stdlib.h>
這段代碼是cpp文件的一些準備工作,比如用到了stdio.h庫文件,主要是需要用到他的輸入和輸出。stdlib.h頭文件,主要是用到了他的一些字符串操作函數。
CReadElf::CReadElf(char *argc):osType(0),filename(""),pFile(NULL)
{
if (argc!=NULL && strlen(argc) != 0)
{
filename= argc;
}
}
CReadElf::~CReadElf()
{
if(pFile != NULL)
fclose(pFile);
}
構造函數和析構函數的實現。在構造函數內我們檢查了一下參數是否正確(是否將要解析的elf文件傳遞了過來),在析構函數內,簡單判斷了一下是否需要關閉文件句柄(說句柄可能不太準確,因爲Linux沒這個概念,但是我沒想出來那個正確的叫法)。
int CReadElf::readFile()
{
long lSize;
size_t result;
// obtain file size:
fseek (pFile , 0 , SEEK_END);
lSize = ftell (pFile);
rewind (pFile);
if(lSize < sizeof(Elf32_Ehdr) || lSize < sizeof(Elf64_Ehdr) )
{
printf("not a elf file!\n");
return NOT_A_ELF_FILE;
}
char headbuf[EI_NIDENT] = {0};
result = fread(headbuf,1,EI_NIDENT,pFile);
//judge if this is a elf file
if(
headbuf[0] != 0x7f && headbuf[1] != 0x45 &&
headbuf[2] != 0x4c && headbuf[3] != 0x46
)
{
printf("not a elf file!\n");
return NOT_A_ELF_FILE;
}
rewind(pFile);
if(headbuf[4] == 0x02)
{
fread (&elfHead64,1,sizeof(Elf64_Ehdr),pFile);
osType = 64;
}
else
{
fread (&elfHead32,1,sizeof(Elf32_Ehdr),pFile);
osType = 32;
}
rewind(pFile);
return SUCCESS;
}
上述代碼,主要作用是讀取用戶指定的文件,然後判斷是否是一個elf文件,假如是的話,看他對用的是32位的還是64爲的elf文件。
- 第一個if判斷他的長度是否超過了elf section header的長度,假如不足,那麼肯定不是正確的elf
- 第二個判斷,看headbuf 中是否有elf文件特有的標記(7f 45 4c 46是ELF頭裏面特有的,稱之爲magic,中文叫魔數,實際上不止這幾個,詳情可搜索readelf -h 命令)
- 第三個判斷,用於判斷當前的elf是作用域32還是64位系統上的
int CReadElf::readSection()
{
size_t result;
if(osType == 64)
{
size_t secNum = elfHead64.e_shnum;
int secindex = elfHead64.e_shoff;
if(getSectionName()!= secNum)
{
printf("get section head failed!\n");
return GET_SEC_NAME_ERR;
}
//go to the entry of section
fseek(pFile,secindex,SEEK_SET);
Elf64_Shdr elf64Sec;
for(int i = 0;i < secNum;i++)
{
result = fread(&elf64Sec,1,sizeof(Elf64_Shdr),pFile);
if(result != sizeof(Elf64_Shdr))
{
printf("read file failed\n");
return READ_FILE_FAILED;
}
myElf64_Shdr tmpsec;
tmpsec.sh_strname = secName[i];
tmpsec.elf64sehd = elf64Sec;
sections.push_back(tmpsec);
}
}
else
{
size_t secNum = elfHead32.e_shnum;
int secindex = elfHead32.e_shoff;
if(getSectionName()!= secNum)
{
printf("get section head failed\n");
return GET_SEC_NAME_ERR;
}
//go to the entry of section
fseek(pFile,secindex,SEEK_SET);
Elf32_Shdr elf32Sec;
for(int i = 0;i < secNum;i++)
{
result = fread(&elf32Sec,1,sizeof(Elf32_Shdr),pFile);
if(result != sizeof(Elf32_Shdr))
{
printf("read file failed\n");
return READ_FILE_FAILED;
}
myElf32_Shdr tmpsec;
tmpsec.sh_strname = secName[i];
tmpsec.elf32sehd = elf32Sec;
sections32.push_back(tmpsec);
}
}
rewind(pFile);
return SUCCESS;
}
這個函數,關注任意一個分支即可(要麼處理64位ELF要麼處理32位,邏輯都一樣)。
- secNum 可以直接從ELF頭結構體中獲得,getSectionName()用於獲取每一個section的名字,該函數在後面介紹,返回獲取的名字數量,假如兩者對不上,說明出問題。
- secindex 保存頭結構體中的e_shoff,該成員表示“Section header table file offset”,既,section相對於ELF文件的偏移,程序隨後seek了這個偏移量(fseek(pFile,secindex,SEEK_SET);)此時pFIle所讀取的位置就是實際的Setion存儲的位置了。
- 程序接下來用一個for循環,每次讀取一個elf32/64_shdr的大小,將讀取出來的內容保存起來(保存整個結構體對象:tmpsec.elf64sehd = elf64Sec);以及他對應的名字(tmpsec.sh_strname = secName[i];)後面會用到。
int CReadElf::getfd()
{
pFile = fopen (filename.c_str() , "rb" );
if (pFile==NULL)
{
printf("File error\n");
return FILE_OPEN_ERR;
}
return SUCCESS;
}
這個函數就沒有很多要解釋的了。可能函數名改動一下會更合適。
int CReadElf::getSectionName()
{
if (osType == 64)
{
Elf64_Shdr *shdr = new Elf64_Shdr[sizeof(Elf64_Shdr) * elfHead64.e_shnum];
int sz = fseek(pFile, elfHead64.e_shoff, SEEK_SET);
if (sz != 0)
{
printf("file fseek ERROR\n");
delete[] shdr;
return FILE_SEEK_ERROR;
}
sz = fread(shdr, sizeof(Elf64_Shdr) * elfHead64.e_shnum, 1, pFile);
if (sz == 0)
{
printf("file read ERROR \n");
delete[] shdr;
return READ_FILE_FAILED;
}
rewind(pFile);
sz = fseek(pFile, shdr[elfHead64.e_shstrndx].sh_offset, SEEK_SET);
if (sz != 0)
{
printf("file fseek ERROR\n");
delete[] shdr;
return FILE_SEEK_ERROR;
}
char shstrtab[shdr[elfHead64.e_shstrndx].sh_size];
char *temp = NULL;
sz = fread(shstrtab, shdr[elfHead64.e_shstrndx].sh_size, 1, pFile);
if (sz == 0)
{
printf("file fread ERROR\n");
delete[] shdr;
return FILE_SEEK_ERROR;
}
for (int shnum = 0; shnum < elfHead64.e_shnum; shnum++)
{
temp = shstrtab;
temp = temp + shdr[shnum].sh_name;
secName.push_back(string(temp));
}
delete[] shdr;
}
else
{
Elf32_Shdr *shdr = new Elf32_Shdr[sizeof(Elf32_Shdr) * elfHead32.e_shnum];
int sz = fseek(pFile, elfHead32.e_shoff, SEEK_SET);
if (sz != 0)
{
printf("file fseek ERROR\n");
delete[] shdr;
return FILE_SEEK_ERROR;
}
sz = fread(shdr, sizeof(Elf32_Shdr) * elfHead32.e_shnum, 1, pFile);
if (sz == 0)
{
printf("file read ERROR \n");
delete[] shdr;
return READ_FILE_FAILED;
}
rewind(pFile);
sz = fseek(pFile, shdr[elfHead32.e_shstrndx].sh_offset, SEEK_SET);
if (sz != 0)
{
printf("file fseek ERROR\n");
delete[] shdr;
return FILE_SEEK_ERROR;
}
char shstrtab[shdr[elfHead32.e_shstrndx].sh_size];
char *temp = NULL;
sz = fread(shstrtab, shdr[elfHead32.e_shstrndx].sh_size, 1, pFile);
if (sz == 0)
{
printf("file fread ERROR\n");
delete[] shdr;
return FILE_SEEK_ERROR;
}
for (int shnum = 0; shnum < elfHead32.e_shnum; shnum++)
{
temp = shstrtab;
temp = temp + shdr[shnum].sh_name;
secName.push_back(string(temp));
}
delete[] shdr;
}
rewind(pFile);
return secName.size();
}
上面代碼依然有兩個大的分支,我們關注一個即可(關注os64分支吧)。在該函數中
- 首先seek了一份偏移量,然後將所有的section結構體全部讀取出來了(sz = fread(shdr, sizeof(Elf64_Shdr) * elfHead64.e_shnum, 1, pFile); 這裏和readSection套路一樣,當時做的時候,參考了一些網上的代碼,可以進行優化,畢竟此處畫蛇添足了);
- 然後我們用shdr的每個元素對應的(shdr[elfHead32.e_shstrndx].sh_offset),其中e_shstrndx 表示Section header string tableindex ,通俗點“從0開始,包含節名稱的字符串是第tableindex個節”,sh_offset表示shdr當前元素(即Elf64/32_Shdr)對應的頭部表的文件偏移,這樣seek到一個正確的位置
- 最後,獲取了從上述位置,讀取正確的section的大小,用一個for循環讀取正確的section名字。
注意,這個函數,我解釋的不是非常清晰,可以參考elf.h上的解釋,當時做的時候,這個函數我參考了其他人的博客。特此說明!
int CReadElf::readSegment()
{
if (osType == 64)
{
int phoffset = elfHead64.e_phoff;
int phnum = elfHead64.e_phnum;
int phentsize = elfHead64.e_phentsize;
fseek(pFile, phoffset, SEEK_SET);
for (int i = 0; i < phnum; i++)
{
Elf64_Phdr Pro_header;
if (fread(&Pro_header, 1, phentsize, pFile) != phentsize)
{
printf("read segments err!");
return READ_FILE_FAILED;
}
segments.push_back(Pro_header);
}
}
else
{
int phoffset = elfHead32.e_phoff;
int phnum = elfHead32.e_phnum;
int phentsize = elfHead32.e_phentsize;
fseek(pFile, phoffset, SEEK_SET);
for (int i = 0; i < phnum; i++)
{
Elf32_Phdr Pro_header;
if (fread(&Pro_header, 1, phentsize, pFile) != phentsize)
{
printf("read segments err!");
return READ_FILE_FAILED;
}
segments32.push_back(Pro_header);
}
}
return SUCCESS;
}
這段代碼我認爲沒啥解釋的,參考elf.h中關於Elf64_Ehdr/Elf32_Ehdr的解釋
- phoffset = elfHead64.e_phoff; /* program header table offset */即,segments相對於文件的偏移量,所有程序中有一個seek的過程。
- phnum = elfHead64.e_phnum; /* number of program header entries */ 即,segments的數量,所以程序中用for循環依次拿出所有segments。
- phentsize = elfHead64.e_phentsize; /* section header entry size */ 即,每個segments的大小,所以程序中每次read才能正確。
/**********************************section to Segment mapping 計算方法:***************************
首先,查看program Headers中的各個字段的地址 virtAddr (或 physAddr 一般這兩個字段的值是一樣的).
表示這個*segment的開始地址,然後看MenSiz(注意,不是FileSize).表示這個segment可以組裝的section的大小.
我們對上面兩個值相加,獲得這個segment的開始地址和結束地址.比如LOADsegment:
開始地址爲: 0x0000000000400000,結束地址爲 0x00000000004007dc.
然後明確: elf會將地址連續的section分配到同一個segment,前提是這些section的地址在某個segment的範圍內.
比如說:Section Headers 字段中,分佈在地址 0x0000000000400000 - 0x00000000004007dc
剛好是 "interp .note.ABI-tag .note.gnu.build*id .gnu.hash .dynsym
.dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt
.text .fini .rodata .eh_frame_hdr .eh_frame"
其中過最後一個section的開始地址爲 4006e8 大小爲 f4 相加後剛好爲:4007DC.
***********************************************************************************************/
int CReadElf::caclSec2Segments()
{
if (osType == 64)
{
if (sections.size() == 0 || segments.size() == 0)
{
printf( "can not cal sectiong to segments mapping\n") ;
return CALC_MAPPING_ERROR;
}
for (vector<Elf64_Phdr>::iterator pit = segments.begin(); pit != segments.end(); pit++)
{
string belongSec("");
Elf64_Addr startAddr = pit->p_paddr;
Elf64_Addr endAddr = pit->p_paddr + pit->p_memsz;
for (vector<myElf64_Shdr>::iterator sit = sections.begin(); sit != sections.end(); sit++)
{
Elf64_Addr secBeginAddr = sit->elf64sehd.sh_addr;
Elf64_Addr secEndAddr = sit->elf64sehd.sh_addr + sit->elf64sehd.sh_size;
if (secBeginAddr >= startAddr && secEndAddr <= endAddr)
{
belongSec.append(sit->sh_strname);
belongSec.append(" ");
}
}
sec2SegMapping tmpmap(mapping.size(), belongSec);
mapping.push_back(tmpmap);
}
}
else
{
if (sections32.size() == 0 || segments32.size() == 0)
{
printf("can not cal sectiong to segments mapping\n");
return CALC_MAPPING_ERROR;
}
for (vector<Elf32_Phdr>::iterator pit = segments32.begin(); pit != segments32.end(); pit++)
{
string belongSec("");
Elf32_Addr startAddr = pit->p_paddr;
Elf32_Addr endAddr = pit->p_paddr + pit->p_memsz;
for (vector<myElf32_Shdr>::iterator sit = sections32.begin(); sit != sections32.end(); sit++)
{
Elf32_Addr secBeginAddr = sit->elf32sehd.sh_addr;
Elf32_Addr secEndAddr = sit->elf32sehd.sh_addr + sit->elf32sehd.sh_size;
if (secBeginAddr >= startAddr && secEndAddr <= endAddr)
{
belongSec.append(sit->sh_strname);
belongSec.append(" ");
}
}
sec2SegMapping tmpmap(mapping.size(), belongSec);
mapping.push_back(tmpmap);
}
}
return SUCCESS;
}
這段代碼是用於整理segments和section的映射的,關鍵在於代碼中的註釋說明,他說明了他們的關係是如何組織的。關於他的驗證可以手動readelf一個文件後,動手算一算。該函數不在解釋,原理懂了就特別簡單。
特別說明:註釋中舉得例子,只是我電腦運行的結構,相關的地址位置,需要結合實際去驗證。
void CReadElf::showHead()
{
if (osType == 64)
{
printf("e_type : %x \n", elfHead64.e_type);
printf("e_machine : %x \n", elfHead64.e_machine);
printf("e_version : %x \n", elfHead64.e_version);
printf("e_entry : %x \n", elfHead64.e_entry);
printf("e_phoff : %x \n", elfHead64.e_phoff);
printf("e_shoff : %x \n", elfHead64.e_shoff);
printf("e_flags : %x \n", elfHead64.e_flags);
printf("e_ehsize : %x \n", elfHead64.e_ehsize);
printf("e_phentsize : %x \n", elfHead64.e_phentsize);
printf("e_phnum : %x \n", elfHead64.e_phnum);
printf("e_shentsize : %x \n", elfHead64.e_shentsize);
printf("e_shnum : %x \n", elfHead64.e_shnum);
printf("e_shstrndx : %x \n", elfHead64.e_shstrndx);
}
else
{
printf("e_type : %x \n", elfHead32.e_type);
printf("e_machine : %x \n", elfHead32.e_machine);
printf("e_version : %x \n", elfHead32.e_version);
printf("e_entry : %x \n", elfHead32.e_entry);
printf("e_phoff : %x \n", elfHead32.e_phoff);
printf("e_shoff : %x \n", elfHead32.e_shoff);
printf("e_flags : %x \n", elfHead32.e_flags);
printf("e_ehsize : %x \n", elfHead32.e_ehsize);
printf("e_phentsize : %x \n", elfHead32.e_phentsize);
printf("e_phnum : %x \n", elfHead32.e_phnum);
printf("e_shentsize : %x \n", elfHead32.e_shentsize);
printf("e_shnum : %x \n", elfHead32.e_shnum);
printf("e_shstrndx : %x \n", elfHead32.e_shstrndx);
}
printf("\n\n");
}
void CReadElf::showSection()
{
if (osType == 64)
{
if (sections.size() == 0)
{
printf("empty section map!\n");
return;
}
printf("%-20s %-8s %-16s %-8s %-16s %-16s %-8s %-8s %-8s %-8s\n",
"Name", "Type", "Address", "Offset", "Size", "EntSize", "Flags", "Link", "Info", "Align");
for (vector<myElf64_Shdr>::iterator pit = sections.begin(); pit != sections.end(); pit++)
{
printf("%-20s %-8x %016x %08x %016x %016x %-8x %-8x %-8x %-8x\n",
pit->sh_strname.c_str(),
pit->elf64sehd.sh_type,
pit->elf64sehd.sh_addr,
pit->elf64sehd.sh_offset,
pit->elf64sehd.sh_size,
pit->elf64sehd.sh_entsize,
pit->elf64sehd.sh_flags,
pit->elf64sehd.sh_link,
pit->elf64sehd.sh_info,
pit->elf64sehd.sh_addralign
);
}
}
else
{
if (sections32.size() == 0)
{
printf("empty section map!\n");
return;
}
printf("%-20s %-8s %-16s %-8s %-16s %-16s %-8s %-8s %-8s %-8s\n",
"Name", "Type", "Address", "Offset", "Size", "EntSize", "Flags", "Link", "Info", "Align");
for (vector<myElf32_Shdr>::iterator pit = sections32.begin(); pit != sections32.end(); pit++)
{
printf("%-20s %-8x %016x %08x %016x %016x %-8x %-8x %-8x %-8x\n",
pit->sh_strname.c_str(),
pit->elf32sehd.sh_type,
pit->elf32sehd.sh_addr,
pit->elf32sehd.sh_offset,
pit->elf32sehd.sh_size,
pit->elf32sehd.sh_entsize,
pit->elf32sehd.sh_flags,
pit->elf32sehd.sh_link,
pit->elf32sehd.sh_info,
pit->elf32sehd.sh_addralign
);
}
}
printf("\n\n");
}
void CReadElf::showSegments()
{
if (osType == 64)
{
if (segments.size() == 0)
{
printf("segments reads err!\n");
return;
}
printf("%-12s %-18s %-18s %-18s %-18s %-18s %-8s %-8s\n",
"Type", "Offset", "VirtAddr", "PhysAddr", "FileSiz", "MemSiz", "Flags", "Align");
for (vector<Elf64_Phdr>::iterator pit = segments.begin(); pit != segments.end(); pit++)
{
printf("%-12x 0x%016x 0x%016x 0x%016x 0x%016x 0x%016x %-8x %-8x\n",
pit->p_type,
pit->p_offset,
pit->p_vaddr,
pit->p_paddr,
pit->p_filesz,
pit->p_memsz,
pit->p_flags,
pit->p_align
);
}
}
else
{
if (segments32.size() == 0)
{
printf("segments reads err!\n");
return;
}
printf("%-12s %-18s %-18s %-18s %-18s %-18s %-8s %-8s\n",
"Type", "Offset", "VirtAddr", "PhysAddr", "FileSiz", "MemSiz", "Flags", "Align");
for (vector<Elf32_Phdr>::iterator pit = segments32.begin(); pit != segments32.end(); pit++)
{
printf("%-12x 0x%016x 0x%016x 0x%016x 0x%016x 0x%016x %-8x %-8x\n",
pit->p_type,
pit->p_offset,
pit->p_vaddr,
pit->p_paddr,
pit->p_filesz,
pit->p_memsz,
pit->p_flags,
pit->p_align
);
}
}
printf("\n\n");
}
void CReadElf::showSec2SegMapping()
{
if(mapping.size() == 0)
{
printf("mapping error!\n");
return;
}
for(vector<sec2SegMapping>::iterator pit = mapping.begin();pit != mapping.end();pit++)
{
printf("%d\t%s\n",pit->index,pit->secNameVec.c_str());
}
printf("\n");
}
上述函數,用於輸出結果,不贅述。
下面附加一個測試程序:
/************************************************************************/
/* AUTHOR : FangJianYang
/* VERSION : 01
/* TIME : 2019-02-17
/* DESC : Some function to read a elf file
/* Email : [email protected]
/************************************************************************/
#include "readelf.h"
int main(int argc,char** argv)
{
if(argc != 2)
{
cout<<"argments err : you should enter 2 argments!"<<endl;
return WRONG_ARGMENTS;
}
CReadElf obj(argv[1]);
int rt = obj.getfd();
if(rt != SUCCESS)
{
return rt;
}
rt = obj.readFile();
if(rt != SUCCESS)
{
return rt;
}
cout<<"ELF head infomation"<<endl;
obj.showHead();
cout<<"section infomation"<<endl;
rt = obj.readSection();
if(rt != SUCCESS)
{
return rt;
}
obj.showSection();
cout<<"segment infomation"<<endl;
rt = obj.readSegment();
if(rt != SUCCESS)
{
return rt;
}
obj.showSegments();
rt = obj.caclSec2Segments();
if(rt != SUCCESS)
{
return rt;
}
cout<<"section to segment mapping"<<endl;
obj.showSec2SegMapping();
return 0;
}
三 ,編譯和使用說明:
我手寫了一個makefile,各位可以直接運行他即可,也可以用vscode打開,有相應的工程文件。我將這段代碼和所有文件都上傳到了XXX鏈接處(還在審覈中,等通過了,我吧這段給補上)。