# ELF 檔解析 contributed by <`tina0405`> * 延續[學習實作小型作業系統筆記](https://hackmd.io/s/S1Ab0A9pX#ELF-%E8%A7%A3%E6%9E%90),本系統的在運行後,載入的應用程式的檔是excutable ELF 檔,而提供的新服務則是 relocatable ELF,先用以下的圖解釋一下 ELF 的結構([圖片來源](http://www.chuquan.me/2018/05/21/elf-introduce/))。 ![](https://i.imgur.com/g3D5aIM.png) * 針對一份測試應用程式來解析,先編譯成 relocatable ELF 的形式,如上圖介紹會包含: [紅] [ELF header](https://hackmd.io/s/H1G5-o83N#ELF-header) / [黃] 各個 section / [綠] section header table ~~~=c #include <stddef.h> #include <mutex.h> void * thread_run(void *arg); struct thread_mutex mutex; int count = 0; int main() { thread_t thread1; thread_mutex_lock(&mutex); thread_create(&thread1, NULL, thread_run, 0); thread_join(thread1, 0); return 0; } void * thread_run(void *arg) { int i; thread_mutex_unlock(&mutex); return 0; } ~~~ ### ELF header * `user.o` 的 file header 大小為 0x40, 因為結構裡64-bit 的 0x34 為 `e_ehsize`(此header的大小),參考 [ELF 格式](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format),因此只有前0x40 bit 是 file header。 ~~~ ---file header--- 0000000 457f 464c 0102 0001 0000 0000 0000 0000 0000010 0001 00b7 0001 0000 0000 0000 0000 0000 0000020 0000 0000 0000 0000 0430 0000 0000 0000 0000030 0000 0000 0040 0000 0000 0040 000a 0007 ---end of file header--- ~~~ * 經過 [ELF 格式](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format)的對照,其實 header 的 內容就如下,會從這裡知道 header section table 的起始是在 0x430(1072) * readelf -h user.o ~~~ ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: REL (Relocatable file) Machine: AArch64 Version: 0x1 Entry point address: 0x0 Start of program headers: 0 (bytes into file) Start of section headers: 1072 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 0 (bytes) Number of program headers: 0 Size of section headers: 64 (bytes) Number of section headers: 10 Section header string table index: 7 ~~~ * 從 0x430 往下找, section headers 共有 10個,然後每個 0x40, index 7 為 section header string table,對照[ELF 格式裡 section header 格式](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format),發現位在在 0x3e0,找到 section header string table(下方.shstrtab) 後可以對照每個 section header 的名字,下方已先標上。 ~~~ --- 0 0000430 0000 0000 0000 0000 0000 0000 0000 0000 * --- 1 .text section 0000470 0020 0000 0001 0000 0006 0000 0000 0000 0000480 0000 0000 0000 0000 0040 0000 0000 0000 0000490 006c 0000 0000 0000 0000 0000 0000 0000 00004a0 0004 0000 0000 0000 0000 0000 0000 0000 --- 2 .rela.text 00004b0 001b 0000 0004 0000 0040 0000 0000 0000 00004c0 0000 0000 0000 0000 02f0 0000 0000 0000 00004d0 00f0 0000 0000 0000 0008 0000 0001 0000 00004e0 0008 0000 0000 0000 0018 0000 0000 0000 --- 3 .data 00004f0 0026 0000 0001 0000 0003 0000 0000 0000 0000500 0000 0000 0000 0000 00ac 0000 0000 0000 0000510 0000 0000 0000 0000 0000 0000 0000 0000 0000520 0001 0000 0000 0000 0000 0000 0000 0000 --- 4 .bss 0000530 002c 0000 0008 0000 0003 0000 0000 0000 0000540 0000 0000 0000 0000 00ac 0000 0000 0000 0000550 0004 0000 0000 0000 0000 0000 0000 0000 * --- 5 .comment 0000570 0031 0000 0001 0000 0030 0000 0000 0000 0000580 0000 0000 0000 0000 00ac 0000 0000 0000 0000590 003c 0000 0000 0000 0000 0000 0000 0000 00005a0 0001 0000 0000 0000 0001 0000 0000 0000 --- 6 --- .note.GNU-stack 00005b0 003a 0000 0001 0000 0000 0000 0000 0000 00005c0 0000 0000 0000 0000 00e8 0000 0000 0000 00005d0 0000 0000 0000 0000 0000 0000 0000 0000 00005e0 0001 0000 0000 0000 0000 0000 0000 0000 --- 7 .shstrtab section 00005f0 0011 0000 0003 0000 0000 0000 0000 0000 0000600 0000 0000 0000 0000 03e0 0000 0000 0000 0000610 004a 0000 0000 0000 0000 0000 0000 0000 0000620 0001 0000 0000 0000 0000 0000 0000 0000 --- 8 .symtab = symbol table 0000630 0001 0000 0002 0000 0000 0000 0000 0000 0000640 0000 0000 0000 0000 00e8 0000 0000 0000 0000650 0198 0000 0000 0000 0009 0000 0009 0000 0000660 0008 0000 0000 0000 0018 0000 0000 0000 --- 9 .strtab 0000670 0009 0000 0003 0000 0000 0000 0000 0000 0000680 0000 0000 0000 0000 0280 0000 0000 0000 0000690 006a 0000 0000 0000 0000 0000 0000 0000 00006a0 0001 0000 0000 0000 0000 0000 0000 0000 ~~~ * 之後就可裡用 section header 裡的資訊(地址、大小等)找到 section 在哪,下面先標上 header 名稱。 ~~~ ---start of .text--- 0000040 7bfd a9be 03fd 9100 0000 9000 0000 9100 0000050 0000 9400 0000 9000 0001 9100 73a0 9100 0000060 0003 5280 03e2 aa01 0001 d280 0000 9400 0000070 1fa0 b940 0001 5280 0000 9400 0000 5280 0000080 7bfd a8c2 03c0 d65f 7bfd a9be 03fd 9100 0000090 0fa0 f900 0000 9000 0000 9100 0000 9400 00000a0 0000 d280 7bfd a8c2 03c0 d65f ---end of .text--- ---start of .comment--- 4700 4343 00000b0 203a 5528 7562 746e 2f75 694c 616e 6f72 00000c0 3520 342e 302e 362d 6275 6e75 7574 7e31 00000d0 3631 302e 2e34 2939 3520 342e 302e 3220 00000e0 3130 3036 3036 0039 ---end of .comment--- ---symbol table--- 0000 0000 0000 0000 00000f0 0000 0000 0000 0000 0000 0000 0000 0000 0000100 0001 0000 0004 fff1 0000 0000 0000 0000 0000110 0000 0000 0000 0000 0000 0000 0003 0001 0000120 0000 0000 0000 0000 0000 0000 0000 0000 0000130 0000 0000 0003 0003 0000 0000 0000 0000 0000140 0000 0000 0000 0000 0000 0000 0003 0004 0000150 0000 0000 0000 0000 0000 0000 0000 0000 0000160 0008 0000 0000 0004 0000 0000 0000 0000 0000170 0000 0000 0000 0000 000b 0000 0000 0001 0000180 0000 0000 0000 0000 0000 0000 0000 0000 0000190 0000 0000 0003 0006 0000 0000 0000 0000 00001a0 0000 0000 0000 0000 0000 0000 0003 0005 00001b0 0000 0000 0000 0000 0000 0000 0000 0000 00001c0 000e 0000 0011 fff2 0008 0000 0000 0000 00001d0 0020 0000 0000 0000 0014 0000 0011 0004 00001e0 0000 0000 0000 0000 0004 0000 0000 0000 00001f0 001a 0000 0012 0001 0000 0000 0000 0000 0000200 0048 0000 0000 0000 001f 0000 0010 0000 0000210 0000 0000 0000 0000 0000 0000 0000 0000 0000220 0031 0000 0012 0001 0048 0000 0000 0000 0000230 0024 0000 0000 0000 003c 0000 0010 0000 0000240 0000 0000 0000 0000 0000 0000 0000 0000 0000250 004a 0000 0010 0000 0000 0000 0000 0000 0000260 0000 0000 0000 0000 0056 0000 0010 0000 0000270 0000 0000 0000 0000 0000 0000 0000 0000 --- end of symbol table --- --- .strtab --- 0000280 7500 6573 2e72 0063 6424 2400 0078 756d .user.c.$d.$x.mu 0000290 6574 0078 6f63 6e75 0074 616d 6e69 7400 tex.count.main.t 00002a0 7268 6165 5f64 756d 6574 5f78 6f6c 6b63 hread_mutex_lock 00002b0 7400 7268 6165 5f64 7572 006e 6874 6572 .thread_run.thre 00002c0 6461 635f 6572 7461 0065 6874 6572 6461 ad_create.thread 00002d0 6a5f 696f 006e 6874 6572 6461 6d5f 7475 _join.thread_mut 00002e0 7865 755f 6c6e 636f 006b 0000 0000 0000 ex_unlock....... --- .rela.text --- 00002f0 0008 0000 0000 0000 0113 0000 0009 0000 0000300 0000 0000 0000 0000 000c 0000 0000 0000 0000310 0115 0000 0009 0000 0000 0000 0000 0000 0000320 0010 0000 0000 0000 011b 0000 000c 0000 0000330 0000 0000 0000 0000 0014 0000 0000 0000 0000340 0113 0000 000d 0000 0000 0000 0000 0000 0000350 0018 0000 0000 0000 0115 0000 000d 0000 0000360 0000 0000 0000 0000 002c 0000 0000 0000 0000370 011b 0000 000e 0000 0000 0000 0000 0000 0000380 0038 0000 0000 0000 011b 0000 000f 0000 0000390 0000 0000 0000 0000 0054 0000 0000 0000 00003a0 0113 0000 0009 0000 0000 0000 0000 0000 00003b0 0058 0000 0000 0000 0115 0000 0009 0000 00003c0 0000 0000 0000 0000 005c 0000 0000 0000 00003d0 011b 0000 0010 0000 0000 0000 0000 0000 --- .shstrtab section --- 00003e0 2e00 7973 746d 6261 2e00 7473 7472 6261 ..symtab..strtab 00003f0 2e00 6873 7473 7472 6261 2e00 6572 616c ..shstrtab..rela 0000400 742e 7865 0074 642e 7461 0061 622e 7373 .text..data..bss 0000410 2e00 6f63 6d6d 6e65 0074 6e2e 746f 2e65 ..comment..note. 0000420 4e47 2d55 7473 6361 006b 0000 0000 0000 GNU-stack....... ~~~ * ELF header table: * 雖然指令:`aarch64-linux-gnu-objdump -h user.o` 能觀察出各個 section 的位置和大小,但這部份 -h 不包含 `.symtab`, `.strtab`, `.shstrtab`, `.rela.text` 內部操作的 section, 但學習 kernel module 須用到。 ~~~ Idx Name Size VMA LMA File off Algn 0 .text 0000006c 0000000000000000 0000000000000000 00000040 2**2 CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE 1 .data 00000000 0000000000000000 0000000000000000 000000ac 2**0 CONTENTS, ALLOC, LOAD, DATA 2 .bss 00000004 0000000000000000 0000000000000000 000000ac 2**2 ALLOC 3 .comment 0000003c 0000000000000000 0000000000000000 000000ac 2**0 CONTENTS, READONLY 4 .note.GNU-stack 00000000 0000000000000000 0000000000000000 000000e8 2**0 CONTENTS, READONLY ~~~ ### ELF 中的 section - [x] .text * 我們會發現因為這個 ELF 還未經過連結,會發現裡面 0xc 的地方 `94000000 bl 0 <thread_mutex_lock>` 還不知道要 bl 的地址,所以先寫 0, add 的地方因為還沒放置變數,因此也先空著,這些會在之後 .rela.text 作介紹 ~~~ Disassembly of section .text: 0000000000000000 <main>: 0: a9be7bfd stp x29, x30, [sp,#-32]! 4: 910003fd mov x29, sp 8: 90000000 adrp x0, 20 <main+0x20> c: 91000000 add x0, x0, #0x0 10: 94000000 bl 0 <thread_mutex_lock> 14: 90000000 adrp x0, 48 <thread_run> 18: 91000001 add x1, x0, #0x0 1c: 910073a0 add x0, x29, #0x1c 20: 52800003 mov w3, #0x0 // #0 24: aa0103e2 mov x2, x1 28: d2800001 mov x1, #0x0 // #0 2c: 94000000 bl 0 <thread_create> 30: b9401fa0 ldr w0, [x29,#28] 34: 52800001 mov w1, #0x0 // #0 38: 94000000 bl 0 <thread_join> 3c: 52800000 mov w0, #0x0 // #0 40: a8c27bfd ldp x29, x30, [sp],#32 44: d65f03c0 ret 0000000000000048 <thread_run>: 48: a9be7bfd stp x29, x30, [sp,#-32]! 4c: 910003fd mov x29, sp 50: f9000fa0 str x0, [x29,#24] 54: 90000000 adrp x0, 20 <main+0x20> 58: 91000000 add x0, x0, #0x0 5c: 94000000 bl 0 <thread_mutex_unlock> 60: d2800000 mov x0, #0x0 // #0 64: a8c27bfd ldp x29, x30, [sp],#32 68: d65f03c0 ret ~~~ - [x] .comment: 這個部份帶的資訊用 ascii code 轉換放置旁邊 ~~~ Contents of section .comment: 0000 00474343 3a202855 62756e74 752f4c69 .GCC: (Ubuntu/Li 0010 6e61726f 20352e34 2e302d36 7562756e naro 5.4.0-6ubun 0020 7475317e 31362e30 342e3929 20352e34 tu1~16.04.9) 5.4 0030 2e302032 30313630 36303900 .0 20160609. ~~~ - [x] .symtab = symbol table * 64-bit 裡面的結構 symbol 的結構: 也就是一個 symbol 應該要帶有的資訊,一個 symbol 24 byte,至於各個名稱的解釋放置下面。 ~~~ typedef struct { Elf64_Word st_name; /* (4 bytes) Symbol name */ unsigned char st_info; /* (1 byte) Symbol type and binding */ unsigned char st_other; /* (1 byte) Symbol visibility */ Elf64_Section st_shndx; /* (2 bytes) Section index */ Elf64_Addr st_value; /* (8 bytes) Symbol value */ Elf64_Xword st_size; /* (8 bytes) Symbol size */ } Elf64_Sym; ~~~ * 以下是 symbol table 原始的 object code ~~~ ---symbol table--- 0000 0000 0000 0000 00000f0 0000 0000 0000 0000 0000 0000 0000 0000 - 0000100 0001 0000 0004 fff1 0000 0000 0000 0000 0000110 0000 0000 0000 0000 - 0000 0000 0003 0001 0000120 0000 0000 0000 0000 0000 0000 0000 0000 - 0000130 0000 0000 0003 0003 0000 0000 0000 0000 0000140 0000 0000 0000 0000 - 0000 0000 0003 0004 0000150 0000 0000 0000 0000 0000 0000 0000 0000 - 0000160 0008 0000 0000 0004 0000 0000 0000 0000 0000170 0000 0000 0000 0000 - 000b 0000 0000 0001 0000180 0000 0000 0000 0000 0000 0000 0000 0000 - 0000190 0000 0000 0003 0006 0000 0000 0000 0000 00001a0 0000 0000 0000 0000 - 0000 0000 0003 0005 00001b0 0000 0000 0000 0000 0000 0000 0000 0000 - mutex 00001c0 000e 0000 0011 fff2 0008 0000 0000 0000 00001d0 0020 0000 0000 0000 - count 0014 0000 0011 0004 00001e0 0000 0000 0000 0000 0004 0000 0000 0000 - main 00001f0 001a 0000 0012 0001 0000 0000 0000 0000 0000200 0048 0000 0000 0000 - 001f 0000 0010 0000 0000210 0000 0000 0000 0000 0000 0000 0000 0000 - 0000220 0031 0000 0012 0001 0048 0000 0000 0000 0000230 0024 0000 0000 0000 - 003c 0000 0010 0000 0000240 0000 0000 0000 0000 0000 0000 0000 0000 - 0000250 004a 0000 0010 0000 0000 0000 0000 0000 0000260 0000 0000 0000 0000 - 0056 0000 0010 0000 0000270 0000 0000 0000 0000 0000 0000 0000 0000 --- end of symbol table --- ~~~ * 以上的 byte 數剛好分成 17 組,如下表: ~~~ Symbol table '.symtab' contains 17 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS user.c 2: 0000000000000000 0 SECTION LOCAL DEFAULT 1 3: 0000000000000000 0 SECTION LOCAL DEFAULT 3 4: 0000000000000000 0 SECTION LOCAL DEFAULT 4 5: 0000000000000000 0 NOTYPE LOCAL DEFAULT 4 $d 6: 0000000000000000 0 NOTYPE LOCAL DEFAULT 1 $x 7: 0000000000000000 0 SECTION LOCAL DEFAULT 6 8: 0000000000000000 0 SECTION LOCAL DEFAULT 5 9: 0000000000000008 32 OBJECT GLOBAL DEFAULT COM mutex 10: 0000000000000000 4 OBJECT GLOBAL DEFAULT 4 count 11: 0000000000000000 72 FUNC GLOBAL DEFAULT 1 main 12: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND thread_mutex_lock 13: 0000000000000048 36 FUNC GLOBAL DEFAULT 1 thread_run 14: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND thread_create 15: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND thread_join 16: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND thread_mutex_unlock ~~~ * 拿第 13 組 thread_run 來作解釋(因為是 little endian 記得要倒過來): * st_name(4 byte): `0000 0031` * st_info(1 byte): `12` * 這部份帶有兩個訊息,參考 [File format](https://docs.oracle.com/cd/E19683-01/816-1386/6m7qcoblj/index.html#chapter7-27): ~~~c= #define ELF64_ST_BIND(info) ((info) >> 4) #define ELF64_ST_TYPE(info) ((info) & 0xf) #define ELF64_ST_INFO(bind, type) (((bind)<<4)+((type)&0xf)) ~~~ * 低位(symbol type):`1` GLOBAL * 高位(binding): `2` FUNCTION * st_other(1 byte): `00` ,參考 [File format](https://docs.oracle.com/cd/E19683-01/816-1386/6m7qcoblj/index.html#chapter7-27): ~~~ 00 - STV_DEFAULT The visibility of symbols with the STV_DEFAULT attribute is as specified by the symbol's binding type. That is, global and weak symbols are visible outside of their defining component, the executable file or shared object. Local symbols are hidden. Global and weak symbols can also be preempted, that is, they may by interposed by definitions of the same name in another component. ~~~ * st_shndx(2 bytes): `0001` * 00-SHT_NULL: 沒定義等待跟其他檔案連結 * 01-SHT_PROGBITS: 在這份檔案內 * st_value(8 bytes): `0000 0000 0000 0048` * 程式從 48 開始 * st_size(8 bytes):`0000 0000 0000 0024` * 程式的大小 24,6 行指令,1 行 4 bytes。 ~~~ 0000220 0031 0000 0012 0001 0048 0000 0000 0000 0000230 0024 0000 0000 0000 ~~~ - [ ] .strtab ~~~ --- .strtab --- 0000280 7500 6573 2e72 0063 6424 2400 0078 756d .user.c.$d.$x.mu 0000290 6574 0078 6f63 6e75 0074 616d 6e69 7400 tex.count.main.t 00002a0 7268 6165 5f64 756d 6574 5f78 6f6c 6b63 hread_mutex_lock 00002b0 7400 7268 6165 5f64 7572 006e 6874 6572 .thread_run.thre 00002c0 6461 635f 6572 7461 0065 6874 6572 6461 ad_create.thread 00002d0 6a5f 696f 006e 6874 6572 6461 6d5f 7475 _join.thread_mut 00002e0 7865 755f 6c6e 636f 006b 0000 0000 0000 ex_unlock....... ~~~ - [ ] .rela.text * 結構 ~~~c= typedef struct { Elf64_Addr r_offset; /*8 bytes*/ Elf64_Xword r_info; /*8 bytes*/ Elf64_Sxword r_addend; /*8 bytes*/ } Elf64_Rela; ~~~ * .rela.text ~~~ 00002f0 0008 0000 0000 0000 0113 0000 0009 0000 0000300 0000 0000 0000 0000 - 000c 0000 0000 0000 0000310 0115 0000 0009 0000 0000 0000 0000 0000 - 0000320 0010 0000 0000 0000 011b 0000 000c 0000 0000330 0000 0000 0000 0000 - 0014 0000 0000 0000 0000340 0113 0000 000d 0000 0000 0000 0000 0000 - 0000350 0018 0000 0000 0000 0115 0000 000d 0000 0000360 0000 0000 0000 0000 - 002c 0000 0000 0000 0000370 011b 0000 000e 0000 0000 0000 0000 0000 - 0000380 0038 0000 0000 0000 011b 0000 000f 0000 0000390 0000 0000 0000 0000 - 0054 0000 0000 0000 00003a0 0113 0000 0009 0000 0000 0000 0000 0000 - 00003b0 0058 0000 0000 0000 0115 0000 0009 0000 00003c0 0000 0000 0000 0000 - 005c 0000 0000 0000 00003d0 011b 0000 0010 0000 0000 0000 0000 0000 ~~~ * relocation text 資訊: offset 表示在原程式中的哪, info 裡包含了,在 symbol 中的 index 和 type ~~~ c= tina@tina-X550VB:~/Hw/raspberry-pi3-mini-os/9.ldaxr+cache_on/testcode/mutex_testina@tina-X550VB:~/Hw/raspberry-pi3-mini-os/9.ldaxr+cache_on/testcode/mutex_tesm$ readelf -r user.o Relocation section '.rela.text' at offset 0x2f0 contains 10 entries: Offset Info Type Sym. Value Sym. Name + Addend 000000000008 000900000113 R_AARCH64_ADR_PRE 0000000000000008 mutex + 0 00000000000c 000900000115 R_AARCH64_ADD_ABS 0000000000000008 mutex + 0 000000000010 000c0000011b R_AARCH64_CALL26 0000000000000000 thread_mutex_lock + 0 000000000014 000d00000113 R_AARCH64_ADR_PRE 0000000000000048 thread_run + 0 000000000018 000d00000115 R_AARCH64_ADD_ABS 0000000000000048 thread_run + 0 00000000002c 000e0000011b R_AARCH64_CALL26 0000000000000000 thread_create + 0 000000000038 000f0000011b R_AARCH64_CALL26 0000000000000000 thread_join + 0 000000000054 000900000113 R_AARCH64_ADR_PRE 0000000000000008 mutex + 0 000000000058 000900000115 R_AARCH64_ADD_ABS 0000000000000008 mutex + 0 00000000005c 00100000011b R_AARCH64_CALL26 0000000000000000 thread_mutex_unlock + 0 ~~~ - [x] .shstrtab: 提供給 section header table 去利用 offset 找尋名稱。 ~~~ --- .shstrtab section --- 00003e0 2e00 7973 746d 6261 2e00 7473 7472 6261 ..symtab..strtab 00003f0 2e00 6873 7473 7472 6261 2e00 6572 616c ..shstrtab..rela 0000400 742e 7865 0074 642e 7461 0061 622e 7373 .text..data..bss 0000410 2e00 6f63 6d6d 6e65 0074 6e2e 746f 2e65 ..comment..note. 0000420 4e47 2d55 7473 6361 006b 0000 0000 0000 GNU-stack....... ~~~ * 拿 section header table 中的 .text 舉例, `0x20` 為 offset, 對照上表 `0x00003e0 + 0x20 = 0x0000400`, 即為 `.text`: ~~~ --- 1 .text section 0000470 0020 0000 0001 0000 0006 0000 0000 0000 0000480 0000 0000 0000 0000 0040 0000 0000 0000 0000490 006c 0000 0000 0000 0000 0000 0000 0000 00004a0 0004 0000 0000 0000 0000 0000 0000 0000 ~~~ ### Linker to relocate * 我們從 relocation text 留給我們的資訊上發現, 有 10 筆資料樣填入,我會將第一筆和第二筆一起看,因為他們是有關係的: ~~~ Offset Info Type Sym. Value Sym. Name + Addend 000000000008 000900000113 R_AARCH64_ADR_PRE 0000000000000008 mutex + 0 00000000000c 000900000115 R_AARCH64_ADD_ABS 0000000000000008 mutex + 0 ~~~ * 比較未經過 relocation 的檔案, 0x8 和 0xc 目前都先未填 ~~~ 0: a9be7bfd stp x29, x30, [sp,#-32]! 4: 910003fd mov x29, sp 8: 90000000 adrp x0, 20 <main+0x20> c: 91000000 add x0, x0, #0x0 10: 94000000 bl 0 <thread_mutex_lock> 14: 90000000 adrp x0, 48 <thread_run> 18: 91000001 add x1, x0, #0x0 1c: 910073a0 add x0, x29, #0x1c .... ~~~ * 下方為 linker 後的 ELF 片段([完整的連結](https://hackmd.io/s/H1G5-o83N#linker-%E5%BE%8C%E7%9A%84%E5%AE%8C%E6%95%B4-ELF)), 因為 linker 知道 mutex這個 data 被放置 0x188, 因此 basic + offset 的方式,`x0` 先載入 `adrp x0, 0 <main>`, 再放置 `add x0, x0, #0x188` * 註: 0x188 = 392(十進位), 392*4 = 1568(十進位) = 0x620, 故機器碼為 `91062000` ~~~c= 0000000000000000 <main>: 0: a9be7bfd stp x29, x30, [sp,#-32]! 4: 910003fd mov x29, sp 8: 90000000 adrp x0, 0 <main> c: 91062000 add x0, x0, #0x188 10: 94000050 bl 150 <thread_mutex_lock> 14: 90000000 adrp x0, 0 <main> 18: 91012001 add x1, x0, #0x48 1c: 910073a0 add x0, x29, #0x1c ... ~~~ * `bl` 的對應,我們看未連結的機器碼 `10: 94000000 bl 0 <thread_mutex_lock>`, 因為 linker 把另一份有 thread_mutex_lock(.text)的 relocation elf, 一起重新配置, 已經知道放置 thread_mutex_lock 的 addr 是 0x150 * 註: 0x150 - 0x10(pc) = 0x140 = 320(十進位), 32/4(指令4-byte) = 80(十進位) = 0x50,故0x10 行重新填入 `10: 94000050` ### linker 後的完整 ELF ~~~c= 0000000000000000 <main>: 0: a9be7bfd stp x29, x30, [sp,#-32]! 4: 910003fd mov x29, sp 8: 90000000 adrp x0, 0 <main> c: 91062000 add x0, x0, #0x188 10: 94000050 bl 150 <thread_mutex_lock> 14: 90000000 adrp x0, 0 <main> 18: 91012001 add x1, x0, #0x48 1c: 910073a0 add x0, x29, #0x1c 20: 52800003 mov w3, #0x0 // #0 24: aa0103e2 mov x2, x1 28: d2800001 mov x1, #0x0 // #0 2c: 94000025 bl c0 <thread_create> 30: b9401fa0 ldr w0, [x29,#28] 34: 52800001 mov w1, #0x0 // #0 38: 94000028 bl d8 <thread_join> 3c: 52800000 mov w0, #0x0 // #0 40: a8c27bfd ldp x29, x30, [sp],#32 44: d65f03c0 ret 0000000000000048 <thread_run>: 48: a9be7bfd stp x29, x30, [sp,#-32]! 4c: 910003fd mov x29, sp 50: f9000fa0 str x0, [x29,#24] 54: 90000000 adrp x0, 0 <main> 58: 91062000 add x0, x0, #0x188 5c: 94000040 bl 15c <thread_mutex_unlock> 60: d2800000 mov x0, #0x0 // #0 64: a8c27bfd ldp x29, x30, [sp],#32 68: d65f03c0 ret 000000000000006c <user_delay>: 6c: f1000400 subs x0, x0, #0x1 70: 54ffffe1 b.ne 6c <user_delay> 74: d65f03c0 ret 0000000000000078 <call_sys_write>: 78: 52800008 mov w8, #0x0 // #0 7c: d4000001 svc #0x0 80: d65f03c0 ret 0000000000000084 <call_sys_write_int>: 84: 528000a8 mov w8, #0x5 // #5 88: d4000001 svc #0x0 8c: d65f03c0 ret 0000000000000090 <call_sys_exit>: 90: 52800048 mov w8, #0x2 // #2 94: d4000001 svc #0x0 98: d65f03c0 ret 000000000000009c <call_sys_fork>: 9c: 52800028 mov w8, #0x1 // #1 a0: d4000001 svc #0x0 a4: d65f03c0 ret 00000000000000a8 <call_sys_led>: a8: 52800068 mov w8, #0x3 // #3 ac: d4000001 svc #0x0 b0: d65f03c0 ret 00000000000000b4 <call_sys_read>: b4: 52800088 mov w8, #0x4 // #4 b8: d4000001 svc #0x0 bc: d65f03c0 ret 00000000000000c0 <thread_create>: c0: 528000c8 mov w8, #0x6 // #6 c4: d4000001 svc #0x0 c8: d65f03c0 ret 00000000000000cc <thread_self>: cc: 528000e8 mov w8, #0x7 // #7 d0: d4000001 svc #0x0 d4: d65f03c0 ret 00000000000000d8 <thread_join>: d8: 52800108 mov w8, #0x8 // #8 dc: d4000001 svc #0x0 e0: d65f03c0 ret 00000000000000e4 <thread_cond_signal>: e4: 52800148 mov w8, #0xa // #10 e8: d4000001 svc #0x0 ec: d65f03c0 ret 00000000000000f0 <call_sys_list>: f0: 52800168 mov w8, #0xb // #11 f4: d4000001 svc #0x0 f8: d65f03c0 ret 00000000000000fc <call_sys_cd>: fc: 52800188 mov w8, #0xc // #12 100: d4000001 svc #0x0 104: d65f03c0 ret 0000000000000108 <call_sys_dump>: 108: 528001a8 mov w8, #0xd // #13 10c: d4000001 svc #0x0 110: d65f03c0 ret 0000000000000114 <call_sys_root>: 114: 528001c8 mov w8, #0xe // #14 118: d4000001 svc #0x0 11c: d65f03c0 ret 0000000000000120 <call_sys_mod>: 120: 528001e8 mov w8, #0xf // #15 124: d4000001 svc #0x0 128: d65f03c0 ret 000000000000012c <call_sys_send>: 12c: 52800208 mov w8, #0x10 // #16 130: d4000001 svc #0x0 134: d65f03c0 ret 0000000000000138 <call_sys_recv>: 138: 52800228 mov w8, #0x11 // #17 13c: d4000001 svc #0x0 140: d65f03c0 ret 0000000000000144 <thread_mutex_trylock>: 144: 52800248 mov w8, #0x12 // #18 148: d4000001 svc #0x0 14c: d65f03c0 ret 0000000000000150 <thread_mutex_lock>: 150: 52800248 mov w8, #0x12 // #18 154: d4000001 svc #0x0 158: d65f03c0 ret 000000000000015c <thread_mutex_unlock>: 15c: 52800268 mov w8, #0x13 // #19 160: d4000001 svc #0x0 164: d65f03c0 ret 0000000000000168 <thread_equal>: 168: eb01001f cmp x0, x1 16c: 54000060 b.eq 178 <eq> 170: d2800000 mov x0, #0x0 // #0 174: 14000002 b 17c <neq> 0000000000000178 <eq>: 178: d2800020 mov x0, #0x1 // #1 000000000000017c <neq>: 17c: d65f03c0 ret Disassembly of section .bss: 0000000000000180 <count>: ... 0000000000000188 <mutex>: ... Disassembly of section .comment: 0000000000000000 <.comment>: 0: 3a434347 ccmn w26, w3, #0x7, mi 4: 62552820 .inst 0x62552820 ; undefined 8: 75746e75 .inst 0x75746e75 ; undefined c: 6e694c2f uqshl v15.8h, v1.8h, v9.8h 10: 206f7261 .inst 0x206f7261 ; undefined 14: 2e342e35 uqsub v21.8b, v17.8b, v20.8b 18: 75362d30 .inst 0x75362d30 ; undefined 1c: 746e7562 .inst 0x746e7562 ; undefined 20: 317e3175 adds w21, w11, #0xf8c, lsl #12 24: 34302e36 cbz w22, 605e8 <mutex+0x60460> 28: 2029392e .inst 0x2029392e ; undefined 2c: 2e342e35 uqsub v21.8b, v17.8b, v20.8b 30: 30322030 adr x16, 64435 <mutex+0x642ad> 34: 36303631 tbz w17, #6, 6f8 <mutex+0x570> 38: Address 0x0000000000000038 is out of bounds. ~~~ * 簡易的了解以下 3 點,終於要進入實做的部份[載入,連結與重配置](https://hackmd.io/wvADYU_3Sg2-VzHIibUSCg): * elf 如何配置 * 重填 rela.text 的 addr * 對照 symbol table 填 value ### Reference * [Implementing Loadable Kernel Modules for Linux](http://collaboration.cmc.ec.gc.ca/science/rpn/biblio/ddj/Website/articles/DDJ/1995/9505/9505a/9505a.htm) * https://myao0730.blogspot.com/2015/09/csapplinking.html * https://stac47.github.io/c/relocation/elf/tutorial/2018/03/01/understanding-relocation-elf.html * http://opass.logdown.com/posts/248172-linker-loader-library * http://www.cjwind.idv.tw/Static-Link/ * http://www.cjwind.idv.tw/Static-Link/