Академический Документы
Профессиональный Документы
Культура Документы
jesstess@kid-charlemagne:~/c$ wc -c hello
1373 hello
jesstess@kid-charlemagne:~$ objdump -D hello | wc -l
93
Теперь наш исполняемый файл занимает немногим более 1300 байт и менее 100
линий, это довольно разумное количество для анализа. Маленькая часть ассемблерного
кода (assembly) не может испугать нас к этому моменту, давайте теперь взглянем на него
с использованием objdump -D, который покажет содержимое всех секций (вывод см. в
приложении). Если вывод кажется пугающим, то быстро пробегите по нему, я обещаю
вам, что к концу этого поста от страха ничего не останется.
Итак, мы имеем 5 секций: .text, которая содержит знакомые символы _start и
main, .rodata, .eh_frame_hdr, .eh_frame и .comment.
Если мы стряхнем пыль с нашей любимой копии Tool Interface Standard ELF
Specification и заглянем в нее, то она скажет нам:
SYMBOL TABLE:
00000000004000e8 l d .text 0000000000000000 .text
0000000000400107 l d .rodata 0000000000000000 .rodata
0000000000400114 l d .eh_frame_hdr 0000000000000000 .eh_frame_hdr
0000000000400128 l d .eh_frame 0000000000000000 .eh_frame
0000000000000000 l d .comment 0000000000000000 .comment
0000000000000000 l df *ABS* 0000000000000000 hello.c
00000000004000e8 g .text 0000000000000000 _start
0000000000600fe8 g *ABS* 0000000000000000 __bss_start
00000000004000f4 g F .text 0000000000000013 main
0000000000600fe8 g *ABS* 0000000000000000 _edata
0000000000600fe8 g *ABS* 0000000000000000 _end
Все наши 5 секций имеют связи с local (l), debugging (d) и symbols (s). main
действительно функция (F), hello.c действительно файл (f), и он не связан с какой-
либо секцией (*ABS*). _start и main — часть исполняемых инструкций для нашей
программы и, таким образом, расположены в секции .text, как мы и предполагали.
Единственной причудой здесь является __bss_start, _edata и _end, все *ABS*,
глобальные символы, которые мы не писали в нашей программе. Откуда они взялись?
Виновником на этот раз является скрипт компоновщика. gcc неявно вызывает ld,
как часть процесса компиляции. ld --verbose предоставит сценарий компоновщика,
который был использован и, глядя на него (вывод см. в приложении), мы видим, что
_edata определен как конец секции data, __bss_start и _end отмечают начало и конец
секции .bss. Эти символы могли быть использованы механизмом управления памятью
(например, если sbrk хочет знать, где начинается «куча») и сборщиком «мусора».
Следует отметить, что str, наша инициализированная локальная переменная, не
представлена в таблице символов. Почему? Потому что она размещается в стеке
(возможно в регистре) во время выполнения. Однако, что-то связанное с str
находиться в секции .rodata, несмотря на то, что мы не видим это в таблице
символов...
Теперь о char *str = «Hello World»; на самом деле мы создаем два различных
объекта. Первый это строковый литерал «Hello World», который представляет собой
просто массив символов и имеет некоторый адрес, но явного имени не имеет. Это
массив «только для чтения» и расположен в секции .rodata. Второй — локальная
переменная str, которая имеет тип «pointer to char». Она и располагается в стеке,
а ее начальное значение — адрес строкового литерала, который был создан.
Мы можем доказать это и получить некоторую другую полезную информацию,
смотря на содержимое наших секций, используя декодирование строк:
И это все! Все секции и символы учтены. Никакого волшебства (я имею ввиду
волшебство в хорошем смысле Я-бы-прошел-это-испытание, а не в смысле прости-Jimmy-
Santa-не-настоящий). Вот так. Whew.
00000000004000e8 <_start>:
4000e8: e8 0b 00 00 00 callq 4000f8 <main>
4000ed: b8 01 00 00 00 mov $0x1,%eax
4000f2: 31 db xor %ebx,%ebx
4000f4: cd 80 int $0x80
4000f6: 90 nop
4000f7: 90 nop
00000000004000f8 <main>:
4000f8: 55 push %rbp
4000f9: 48 89 e5 mov %rsp,%rbp
4000fc: 48 c7 45 f8 0b 01 40 movq $0x40010b,-0x8(%rbp)
400103: 00
400104: b8 00 00 00 00 mov $0x0,%eax
400109: c9 leaveq
40010a: c3 retq
000000000040010b <.rodata>:
40010b: 48 rex.W
40010c: 65 gs
40010d: 6c insb (%dx),%es:(%rdi)
40010e: 6c insb (%dx),%es:(%rdi)
40010f: 6f outsl %ds:(%rsi),(%dx)
400110: 20 57 6f and %dl,0x6f(%rdi)
400113: 72 6c jb 400181 <main+0x89>
400115: 64 fs
...
0000000000400118 <.eh_frame_hdr>:
400118: 01 1b add %ebx,(%rbx)
40011a: 03 3b add (%rbx),%edi
40011c: 14 00 adc $0x0,%al
40011e: 00 00 add %al,(%rax)
400120: 01 00 add %eax,(%rax)
400122: 00 00 add %al,(%rax)
400124: e0 ff loopne 400125 <main+0x2d>
400126: ff (bad)
400127: ff 30 pushq (%rax)
400129: 00 00 add %al,(%rax)
...
0000000000400130 <.eh_frame>:
400130: 14 00 adc $0x0,%al
400132: 00 00 add %al,(%rax)
400134: 00 00 add %al,(%rax)
400136: 00 00 add %al,(%rax)
400138: 01 7a 52 add %edi,0x52(%rdx)
40013b: 00 01 add %al,(%rcx)
40013d: 78 10 js 40014f <main+0x57>
40013f: 01 03 add %eax,(%rbx)
400141: 0c 07 or $0x7,%al
400143: 08 90 01 00 00 1c or %dl,0x1c000001(%rax)
400149: 00 00 add %al,(%rax)
40014b: 00 1c 00 add %bl,(%rax,%rax,1)
40014e: 00 00 add %al,(%rax)
400150: f8 clc
400151: 00 40 00 add %al,0x0(%rax)
400154: 13 00 adc (%rax),%eax
400156: 00 00 add %al,(%rax)
400158: 00 41 0e add %al,0xe(%rcx)
40015b: 10 86 02 43 0d 06 adc %al,0x60d4302(%rsi)
400161: 00 00 add %al,(%rax)
400163: 00 00 add %al,(%rax)
400165: 00 00 add %al,(%rax)
...
0000000000000000 <.comment>:
0: 00 47 43 add %al,0x43(%rdi)
3: 43 3a 20 rex.XB cmp (%r8),%spl
6: 28 55 62 sub %dl,0x62(%rbp)
9: 75 6e jne 79 <_start-0x40006f>
b: 74 75 je 82 <_start-0x400066>
d: 20 34 2e and %dh,(%rsi,%rbp,1)
10: 33 2e xor (%rsi),%ebp
12: 33 2d 35 75 62 75 xor 0x75627535(%rip),%ebp # 7562754d
<__bss_start+0x75026565>
18: 6e outsb %ds:(%rsi),(%dx)
19: 74 75 je 90 <_start-0x400058>
1b: 34 29 xor $0x29,%al
1d: 20 34 2e and %dh,(%rsi,%rbp,1)
20: 33 2e xor (%rsi),%ebp
22: 33 00 xor (%rax),%eax
Вывод readelf -l и readelf -S
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x0000000000000168 0x0000000000000168 R E 200000
GNU_EH_FRAME 0x0000000000000118 0x0000000000400118 0x0000000000400118
0x0000000000000014 0x0000000000000014 R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RWE 8
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .text PROGBITS 00000000004000e8 000000e8
0000000000000023 0000000000000000 AX 0 0 4
[ 2] .rodata PROGBITS 000000000040010b 0000010b
000000000000000c 0000000000000000 A 0 0 1
[ 3] .eh_frame_hdr PROGBITS 0000000000400118 00000118
0000000000000014 0000000000000000 A 0 0 4
[ 4] .eh_frame PROGBITS 0000000000400130 00000130
0000000000000038 0000000000000000 A 0 0 8
[ 5] .comment PROGBITS 0000000000000000 00000168
0000000000000024 0000000000000000 0 0 1
[ 6] .shstrtab STRTAB 0000000000000000 0000018c
000000000000004a 0000000000000000 0 0 1
[ 7] .symtab SYMTAB 0000000000000000 00000418
0000000000000120 0000000000000018 8 7 8
[ 8] .strtab STRTAB 0000000000000000 00000538
000000000000002d 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
Вывод ld --verbose
jesstess@kid-charlemagne:~$ ld --verbose
==================================================