解碼.o檔

Assembly

這篇可以看到在vim中開啟main.o,而上圖充斥著1&0,看似截然不同的兩個東西。

main.o in vim

1
2
3
4
5
^?ELF^B^A^A^@^@^@^@^@^@^@^@^@^A^@>^@^A^@^@
^@^@^@^@^@^@^@^@^@^@X^B^@^@^@^@^@^@^@^@^@^
@@^@^@^@^@^@@^@^L^@^K^@ó^O^^úUHå¸^@^@^
@^@]Ã^@GCC: (Ubuntu 9.4.0-1ubuntu1~20.04.1)
9.4.0^@^@^@^@^@^@^D^@^......

理解兩者差異的原因,可以從兩個面向去釐清:

所有的檔案都是由0&1組成的

電腦中的檔案皆是藉由0&1組成的,包括source file, object file(.o), binary file等等,但vim會將所有的binary藉由ASCII轉換成為我們所看到的plain text,這裡以一main.cpp作為例子:

main.cpp in vim

1
2
3
4
#define N 81
int main(){
return 0;//this is the end
}

main.cpp, configured with :%! xxd -b

1
2
3
4
5
6
7
8
9
10
00000000: 00100011 01100100 01100101 01100110 01101001 01101110  #defin
00000006: 01100101 00100000 01001110 00100000 00111000 00110001 e N 81
0000000c: 00001010 01101001 01101110 01110100 00100000 01101101 .int m
00000012: 01100001 01101001 01101110 00101000 00101001 01111011 ain(){
00000018: 00001010 00001001 01110010 01100101 01110100 01110101 ..retu
0000001e: 01110010 01101110 00100000 00110000 00111011 00101111 rn 0;/
00000024: 00101111 01110100 01101000 01101001 01110011 00100000 /this
0000002a: 01101001 01110011 00100000 01110100 01101000 01100101 is the
00000030: 00100000 01100101 01101110 01100100 00001010 01111101 end.}
00000036: 00001010

而透過:%! xxd -b configure vim,則可以查看binary格式的原始資料,可以看到左側的binary與右側的plain text以ASCII CODE一對一的相對應(e.g, 00100011->#, 01100100->d)。
main.o 在透過vim開啟時,透過ASCII CODE decode並且呈現在vim中。而”^@”是在vim中則是對應到了00000000^@是vim用以表示null character的格式。

ELF 的 binary decoding

不同的檔案有不同的layout,不是所有的檔案都能經過ASCII CODE decode成plain text,如main.o ,可以看到vim中的main.o 無法被閱讀;順帶一提,也並非所有檔案形式都能被decode成plain text,e.g. binary file。.o 檔的檔案形式為ELF,這種檔案可以藉由objdump -dh main.o來decode成plain text。

main.o, configured with objdump -dh main.o

1
2
3
4
5
6
7
8
main.o:     file format elf64-x86-64

Sections:
Idx Name Size VMA LMA File off Algn
0 .text 0000000f 0000000000000000 0000000000000000 00000040 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000000 0000000000000000 0000000000000000 0000004f 2**0
......

Disassembly of section .text:

1
2
3
4
5
6
7
0000000000000000 :
0: f3 0f 1e fa endbr64
4: 55 push %rbp
5: 48 89 e5 mov %rsp,%rbp
8: b8 00 00 00 00 mov $0x0,%eax
d: 5d pop %rbp
e: c3 retq

ELF包含了很多資訊 ,而程式的邏輯放在 .text 裡面,如果回過頭去看main.s,會發現兩者的內容大同小異。

ELF是公定好,能夠被電腦所執行的資料格式。而因為電腦執行皆的資訊皆是0&1,所以上圖才藉由0&1去表達ELF檔,並非表面上純文字即0&1。此外,實際上被執行的machine code還包括排列記憶體等其餘的工作,assembly code所轉換的machine code並不是實際上被執行的machine code的全貌。