GeekOS之旅-Project1 (Parse an ELF executable Files) 與 ELF 檔案格式的淺析

來源:互聯網
上載者:User

想知道這個Project的Assignment之前,我們首先需要把這個Project編譯過並把bochs啟動起來. 編譯和前一個Project一樣很快通過.但是bochs啟動遇到一個錯誤

00000000000p[     ] >>PANIC<< .bochsrc:10: directive 'diskc' not understood

看了下 .boshrc 中有這樣一句:    10 diskc: file=diskc.img, cyl=40, heads=8, spt=64 

看了下剛才編譯過的project1裡面有個disk.img ,這個diskc.img是什麼呢? 其實diskc.img是個硬碟映像,我們之所以要載入這個是因為我們下面肯定會用到. 所謂映像是原始裝置的對應位元組.  所以需要在.bochrc中配置 disk.img.

再.boshrc添加如下

ata0-master:type=disk, mode=flat, path=./diskc.img, cylinders=40, heads=8, spt=64

這句話就是制定硬碟參數,type為(disk,cdrom) mode(flat<一個檔案布局>, concat<多檔案布局>, external, dll ....), path就是路徑了, cylinders為柱面大小, heads為頭部大小,spt為每磁軌扇區數 

這麼一解釋,也就清楚多了. 好加上去,並把 第10行注釋掉. 然後啟動.

啟動成功! 可以看到這個Project的Assigment:  Parse an ELF executable image.  

仔細閱讀附帶的手冊Project2 的 Required Reading  和 Synopsis . 主要任務是實現  src/geekos/elf.c 的 Parse_ELF_Executable()  這個函數. 函數的功能是讀取ELF檔案中的offset, length, user address for the executable's text and data segments . 然後fill in the Exe_Format中!  

所以我們首先要進行瞭解ELF格式的檔案. 分析的樣本用 project1 user下提供的a.exe , 這個源碼在 src/user下a.c . 

可以從google中搜尋 Elf  format file來進行瞭解.這裡 可以我們也可以探討下ELF 檔案:

-> ELF是Linux預設的可執行檔格式, ELF包含三種類型:可重定位的檔案(比如.o 目標檔案), 共用檔案 , 可執行檔. ELF檔案包含 ELF Header, Sections ,String Table , Symbol Table, Relocation(Relocation Types)  這幾個重要的部分. 讓我們大概來看下ELF檔案的組織圖.

上面第一個為串連視圖, 第二個為執行視圖, ELF header(ELF 頭部) , Program header table(程式頭表), Section header table(節頭表) 

我們從ELF頭部的資料結構開始看起, 開啟geekos/elf.c 看下面這個結構體

 14 /* 15  * ELF header at the beginning of the executable. 16  */ 17 typedef struct {  18     unsigned  char| ident[16]; //資訊 19     unsigned  short|type; // 檔案類型 20     unsigned  short|machine; //硬體體系 21     unsigned  int|  version;  22     unsigned  int|  entry; //程式進入點 23     unsigned  int|  phoff; //程式頭部位移量 24     unsigned  int|  sphoff; //節頭部位移量 25     unsigned  int|  flags;  //處理器特定標誌 26     unsigned  short|ehsize;  //ELF頭部長度 27     unsigned  short|phentsize;  //程式頭部一段的長度 28     unsigned  short|phnum;  //程式頭部段的個數 29     unsigned  short|shentsize; //section 頭部中一段的長度 30     unsigned  short|shnum; //section 段個數 31     unsigned  short|shstrndx; //section 頭部字元表索引 32 } elfHeader;

裡面的相關資訊 我已經注釋上去了. 我們接著用readelf -h工具查看下a.exe檔案 來對照著看下

ELF Header:  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00   Class:                             ELF32  Data:                              2's complement, little endian  Version:                           1 (current)  OS/ABI:                            UNIX - System V  ABI Version:                       0  Type:                              EXEC (Executable file)  Machine:                           Intel 80386  Version:                           0x1  Entry point address:               0x1000  Start of program headers:          52 (bytes into file)  Start of section headers:          4420 (bytes into file)  Flags:                             0x0  Size of this header:               52 (bytes)  Size of program headers:           32 (bytes)  Number of program headers:         3  Size of section headers:           40 (bytes)  Number of section headers:         7  Section header string table index: 4

可以對照的看下, 下面再研究 程式頭表,繼續看下它的結構體:

 34 /* 35  * An entry in the ELF program header table. 36  * This describes a single segment of the executable. 37  */ 38 typedef struct { 39     unsigned  int   type; //段類型 40     unsigned  int   offset; //段位置相對於檔案起始的offset 41     unsigned  int   vaddr; //段在記憶體中的地址 42     unsigned  int   paddr; //段的物理地址 43     unsigned  int   fileSize; //段在檔案中的長度 44     unsigned  int   memSize; //段在記憶體中的長度 45     unsigned  int   flags; //標記 46     unsigned  int   alignment; //對齊標記 47 } programHeader;

再用readelf -l 來看下a.exe的資訊.

Elf file type is EXEC (Executable file)Entry point 0x1000There are 3 program headers, starting at offset 52Program Headers:  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align  LOAD           0x001000 0x00001000 0x00001000 0x000a2 0x000a2 R E 0x1000  LOAD           0x0010c0 0x000020c0 0x000020c0 0x00028 0x00028 RW  0x1000  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x4 Section to Segment mapping:  Segment Sections...   00     .text    01     .data    02   

ELF深入可以看文檔 看資料. 等提到ELF問題時 我們再來深入一下.

來做第一步 研究下Parse_ELF_Executable的原型.

int Parse_ELF_Executable(char *exeFileData, ulong_t exeFileLength, struct Exe_Format *exeFormat);

exeFileData: 這個buffer包含了可執行檔檔案 也就是ELF檔案.

exeFileLength: 這個是執行檔案的長度

exeFormat: 這個結構體包含了檔案的段和入口地址

傳回值為int: ret返回0為成功 

解析了elfHeader 和 ProgramHeader這兩個結構體 剩下的就很輕鬆了, 分別用這兩個結構體解析exeFileData的內容

exeFileData頭部的指向肯定是從elfHeader開始的 因為之前我們已經分析過了,然後內建poff的屬性 這是程式頭部的位移量,首地址+poff就可以得出programHeader的首地址了.

33     elfHeader* header = exeFileData;34     programHeader* pHeader = (exeFileData+header->phoff);

再繼續看Exe_Format這個結構體.

 77 /* 78  * A struct concisely representing all information needed to 79  * load an execute an executable. 80  */ 81 struct Exe_Format { 82     struct Exe_Segment segmentList[EXE_MAX_SEGMENTS]; /* Definition of segments */ 83     int numSegments;|   |   /* Number of segments contained in the executable */ 84     ulong_t entryAddr;|  |  /* Code entry point address */ 85 };

segmentList是個段的數組.

numSegments是段的數目

entryAddr是入口地址. 

其中numSegments就是 elfHeader中的phnum, entryAddr是 elfHeader 的entry 

segmentList因為是個數組,但是裡面的每個元素是個結構體 我們先搞清這個結構體的內容:

 57 /* 58  * A segment of an executable. 59  * It specifies a region of the executable file to be loaded 60  * into memory. 61  */ 62 struct Exe_Segment { 63     ulong_t offsetInFile;|   /* Offset of segment in executable file */ 64     ulong_t lengthInFile;|   /* Length of segment data in executable file */ 65     ulong_t startAddress;|   /* Start address of segment in user memory */ 66     ulong_t sizeInMemory;|   /* Size of segment in memory */ 67     int protFlags;| |    /* VM protection flags; combination of VM_READ,VM_WRITE,VM_EXEC */ 68 };

稍微思考下, 這些不就是programHeader的offset, fileSize, vaddr, memSize, flags 嘛

ok一切準備就緒,就剩下苦力把程式寫上去了.

30 int Parse_ELF_Executable(char *exeFileData, ulong_t exeFileLength, 31     struct Exe_Format *exeFormat) 32 { 33     elfHeader* header = exeFileData; 34     programHeader* pHeader = (exeFileData+header->phoff); 35     exeFormat->numSegments = header->phnum; 36     exeFormat->entryAddr = header->entry; 37     int i = 0; 38     for (; i< header->phnum; i++) { 39         exeFormat->segmentList[i].offsetInFile = pHeader->offset; 40         exeFormat->segmentList[i].lengthInFile = pHeader->fileSize; 41         exeFormat->segmentList[i].startAddress = pHeader->vaddr; 42         exeFormat->segmentList[i].sizeInMemory = pHeader->memSize; 43         exeFormat->segmentList[i].protFlags = pHeader->flags; 44         pHeader++; 45     } 46      47     return 0; //!! 48  49     //TODO("Parse an ELF executable image"); 50 }

整個程式如上,需要注意的是 return 0; 別忘了放進去.測試結果如下:下面繼續 Project 2.!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.