Привет из свободно от libc мира (Часть 2)

13
Привет из свободного от libc мира (Часть 2) В предыдущем посте мы справились с компиляцией, написав маленькую программу, которая может быть собрана без использования libc. Понимание объектного кода и деталей структуры ELF исполняемых файлов — следующий шаг в нашем приключении. Мы остановились на следующем коде: jesstess@kid-charlemagne:~$ cat stubstart.S .globl _start _start: call main movl $1, %eax xorl %ebx, %ebx int $0x80 jesstess@kid-charlemagne:~$ cat hello.c int main() { char *str = "Hello World"; return 0; } jesstess@kid-charlemagne:~/c$ gcc -nostdlib stubstart.S hello.c -o hello И что мы получили, проделав всю эту работу? 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. Шаг 1: Сосредоточились – что же такое «секция»? Если мы стряхнем пыль с нашей любимой копии Tool Interface Standard ELF Specification и заглянем в нее, то она скажет нам: У исполняемого файла, как результата нашей компиляции, есть два представления: он содержит program header, описывающий сегменты, которые содержат информацию, используемую во время выполнения, и section header, описывающий секции, которые содержат информацию для линковки и перемещения . Мы можем получить информацию о сегментах или секциях с помощью readelf -l или readelf -S соответственно (вывод см. в приложении). Результат работы этих двух команд для нашей программы сведен в рисунок 1.

Upload: dmitriy

Post on 27-Jul-2015

336 views

Category:

Documents


22 download

TRANSCRIPT

Page 1: Привет из свободно от libc мира (Часть 2)

Привет из свободного от libc мира (Часть 2)

В предыдущем посте мы справились с компиляцией, написав маленькую программу, которая может быть собрана без использования libc. Понимание объектного кода и деталей структуры ELF исполняемых файлов — следующий шаг в нашем приключении.

Мы остановились на следующем коде:

jesstess@kid-charlemagne:~$ cat stubstart.S.globl _start_start: call main movl $1, %eax xorl %ebx, %ebx int $0x80jesstess@kid-charlemagne:~$ cat hello.cint main(){ char *str = "Hello World"; return 0;}jesstess@kid-charlemagne:~/c$ gcc -nostdlib stubstart.S hello.c -o hello

И что мы получили, проделав всю эту работу?

jesstess@kid-charlemagne:~/c$ wc -c hello1373 hellojesstess@kid-charlemagne:~$ objdump -D hello | wc -l93

Теперь наш исполняемый файл занимает немногим более 1300 байт и менее 100 линий, это довольно разумное количество для анализа. Маленькая часть ассемблерного кода (assembly) не может испугать нас к этому моменту, давайте теперь взглянем на него с использованием objdump -D, который покажет содержимое всех секций (вывод см. в приложении). Если вывод кажется пугающим, то быстро пробегите по нему, я обещаю вам, что к концу этого поста от страха ничего не останется.

Итак, мы имеем 5 секций: .text, которая содержит знакомые символы _start и main, .rodata, .eh_frame_hdr, .eh_frame и .comment.

Шаг 1: Сосредоточились – что же такое «секция»?

Если мы стряхнем пыль с нашей любимой копии Tool Interface Standard ELF Specification и заглянем в нее, то она скажет нам:

У исполняемого файла, как результата нашей компиляции, есть два представления: он содержит program header, описывающий сегменты, которые содержат информацию, используемую во время выполнения, и section header, описывающий секции, которые содержат информацию для линковки и перемещения. Мы можем получить информацию о сегментах или секциях с помощью readelf -l или readelf -S соответственно (вывод см. в приложении). Результат работы этих двух команд для нашей программы сведен в рисунок 1.

Page 2: Привет из свободно от libc мира (Часть 2)

Рис.1. Сегменты и секции нашего ELF

Шаг 2: Что происходит в нашей секции?

Спецификация также сообщает нам, что и в каком порядке располагается в нашем исполняемом файле:

.text — содержит исполняемые инструкции программы (попросту код программы);

.rodata — содержит константные значения, это сегмент «только для чтения»;

.eh_frame — информация, необходимая для frame-unwinding во время обработки исключений;

.eh_frame_hdr — цитата из Linux Standard Base Specification: “Эта секция содержит указатель на секцию .eh_frame, которая доступна для «runtime support code» С++ приложения. Эта секция также может содержать двоичную таблицу поиска, которая может быть использована «runtime support code» для более эффективного доступа к записям секции .eh_frame”.

Мы не должны волноваться об исключениях в нашем примере, поэтому .eh_frame и .eh_frame_hdr не должны нас беспокоить и компилирование с флагом -fno-asynchronous-unwind-tables подавит создание этих двух секций;

.comment — информация о версии компилятора.Говоря о избавлении от секций: для нас, приверженцев минимализма, strip(1)

хороший друг. Мы можем воспользоваться --remove-section по несущественным разделам, таким как .comment, чтобы полностью от них избавиться; file(1) сообщит нам, если исполняемая программа была разделена (stripped).

Мы не видим другие секции в нашем примере (они не были включены в исполняемый файл), потому что они были пустыми:

.data — в этой секции инициализируются глобальные и локальные переменные;

.bss — секция неинициализированных глобальных и локальных переменных, то есть заполненных нулями.

Page 3: Привет из свободно от libc мира (Часть 2)

На этом все о секциях. Теперь мы знаем, что символы, такие как _start и main, находятся в этих секциях, но есть ли в программе еще символы?

Шаг 3: Понимание символов и почему они расположены там, где расположены.

Мы можем получить информацию о символах нашего исполняемого файла с помощью objdump -t:

jesstess@kid-charlemagne:~/c$ objdump -t hello

hello: file format elf64-x86-64

SYMBOL TABLE:00000000004000e8 l d .text 0000000000000000 .text0000000000400107 l d .rodata 0000000000000000 .rodata0000000000400114 l d .eh_frame_hdr 0000000000000000 .eh_frame_hdr0000000000400128 l d .eh_frame 0000000000000000 .eh_frame0000000000000000 l d .comment 0000000000000000 .comment0000000000000000 l df *ABS* 0000000000000000 hello.c00000000004000e8 g .text 0000000000000000 _start0000000000600fe8 g *ABS* 0000000000000000 __bss_start00000000004000f4 g F .text 0000000000000013 main0000000000600fe8 g *ABS* 0000000000000000 _edata0000000000600fe8 g *ABS* 0000000000000000 _end

Таблица символов для нашего исполняемого файла имеет 11 записей. Странным образом только редкие версии документации (man pages) по objdump, как эта, объясняет таблицу символов столбец за столбцом. Таблица поделена следующим образом:

Столбец 1: значение/адрес символа.Столбец 2: набор символов и пробелов представляющих флаговые биты, установленные для символа. Есть 7 групп, три из которых представлены в этой таблице символов. Значение из первой группы может быть — l, g, <пробел> или !, если символ локальный, глобальный, ни то ни другое или оба сразу, соответственно. Значение из шестой группы может быть — d, D или <пробел> для debugging, dynamic или normal соответственно. Значение из седьмой может быть — F, f, O или <пробел> для функции, файла, объекта или нормального символа, соответственно. Описание оставшихся 4 групп может быть найдено в unusally comprehensive objdump manpage.Столбец 3: в какой секции расположен символ. *ABS* (абсолютный) означает символ, не связанный с определенной секцией.Столбец 4: размер/выравнивание символа.Столбец 5: имя символа.

Все наши 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, наша инициализированная локальная переменная, не представлена в таблице символов. Почему? Потому что она размещается в стеке

Page 4: Привет из свободно от libc мира (Часть 2)

(возможно в регистре) во время выполнения. Однако, что-то связанное с str находиться в секции .rodata, несмотря на то, что мы не видим это в таблице символов...

Теперь о char *str = «Hello World»; на самом деле мы создаем два различных объекта. Первый это строковый литерал «Hello World», который представляет собой просто массив символов и имеет некоторый адрес, но явного имени не имеет. Это массив «только для чтения» и расположен в секции .rodata. Второй — локальная переменная str, которая имеет тип «pointer to char». Она и располагается в стеке, а ее начальное значение — адрес строкового литерала, который был создан.

Мы можем доказать это и получить некоторую другую полезную информацию, смотря на содержимое наших секций, используя декодирование строк:

jesstess@kid-charlemagne:~$ objdump -s hello

hello: file format elf64-x86-64

Contents of section .text: 4000e8 e80b0000 00b80100 000031db cd809090 ..........1..... 4000f8 554889e5 48c745f8 0b014000 b8000000 UH..H.E...@..... 400108 00c9c3 ...Contents of section .rodata: 40010b 48656c6c 6f20576f 726c6400 Hello World.Contents of section .eh_frame_hdr: 400118 011b033b 14000000 01000000 e0ffffff ...;............ 400128 30000000 0...Contents of section .eh_frame: 400130 14000000 00000000 017a5200 01781001 .........zR..x.. 400140 030c0708 90010000 1c000000 1c000000 ................ 400150 f8004000 13000000 00410e10 8602430d [email protected]. 400160 06000000 00000000 ........Contents of section .comment: 0000 00474343 3a202855 62756e74 7520342e .GCC: (Ubuntu 4. 0010 332e332d 35756275 6e747534 2920342e 3.3-5ubuntu4) 4. 0020 332e3300 3.3.

Вуаля! Наша строка «Hello World» расположена в .rodata и наша секция .comment объяснена: она просто содержит строку с версией gcc, используемой для компиляции программы.

Шаг 4: Исключим лишнее и соединим все вместе

Исполняемый файл содержит 5 секций: .text, .rodata, .eh_frame_hdr, .eh_frame и .comment. В действительности только одна из них (.text) содержит код, определяющий, что делает эта маленькая программа. В этом можно убедиться, используя objdump -d (дизассемблирует только те секции, которые должны содержать инструкции) вместо objdump -D (дизассемблирует содержимое всех секций, не только содержащих инструкции), использованного в начале поста, отмечая, что выведено только содержимое .text (используя objudump -d).

.rodata в действительности содержит только строку «Hello World», а .comment содержит только версию gcc. «Инструкции» для этих секций, показанные в выводе objdump -D получаются в следствии ошибочного представления objdump ASCII символов как инструкций и попытке дизассемблировать их. Мы можем конвертировать первую пару чисел из секции .comment в ASCII символы, чтобы доказать это. На Python:

>>>"".join(chr(int(x, 16)) for x in "47 43 43 3a 20 28 55 62 75 6e 74 75".split())'GCC: (Ubuntu'

В секции .text, _start вызывает main, и в main в стек вталкивается указатель

Page 5: Привет из свободно от libc мира (Часть 2)

на адрес в памяти, где хранится «Hello World», 0x40010b (где начинается секция .rodata, как видно из вывода objdump -D). Затем мы возвращаемся из main в _start, который заботится о выходе из программы, как описано в Части 1.

И это все! Все секции и символы учтены. Никакого волшебства (я имею ввиду волшебство в хорошем смысле Я-бы-прошел-это-испытание, а не в смысле прости-Jimmy-Santa-не-настоящий). Вот так. Whew.

Первая часть - http://blog.ksplice.com/2010/03/libc-free-world/Перевод первой части - http://habrahabr.ru/blogs/nix_coding/88101/Оригинал второй части - http://blog.ksplice.com/2010/04/libc-free-world-2/

Page 6: Привет из свободно от libc мира (Часть 2)

Вывод objdump -D

jesstess@kid-charlemagne:~$ objdump -D hellohello: file format elf64-x86-64

Disassembly of section .text:

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

Disassembly of section .rodata:

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 ...

Disassembly of section .eh_frame_hdr:

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) ...

Disassembly of section .eh_frame:

0000000000400130 <.eh_frame>: 400130: 14 00 adc $0x0,%al 400132: 00 00 add %al,(%rax)

Page 7: Привет из свободно от libc мира (Часть 2)

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) ...

Disassembly of section .comment:

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

Page 8: Привет из свободно от libc мира (Часть 2)

Вывод readelf -l и readelf -S

jesstess@kid-charlemagne:~$ readelf -l hello

Elf file type is EXEC (Executable file)Entry point 0x4000e8There are 3 program headers, starting at offset 64

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 to Segment mapping: Segment Sections... 00 .text .rodata .eh_frame_hdr .eh_frame 01 .eh_frame_hdr 02 jesstess@kid-charlemagne:~$ readelf -S helloThere are 9 section headers, starting at offset 0x1d8:

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 1Key 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)

Page 9: Привет из свободно от libc мира (Часть 2)

Вывод ld --verbose

jesstess@kid-charlemagne:~$ ld --verbose

GNU ld (GNU Binutils for Ubuntu) 2.19.1 Supported emulations: elf_x86_64 elf_i386 i386linuxusing internal linker script:==================================================/* Script for -z combreloc: combine and sort reloc sections */OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")OUTPUT_ARCH(i386:x86-64)ENTRY(_start)SEARCH_DIR("/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("/usr/local/lib64"); SEARCH_DIR("/lib64"); SEARCH_DIR("/usr/lib64"); SEARCH_DIR("/usr/x86_64-linux-gnu/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib");SECTIONS{ /* Read-only sections, merged into text segment: */ PROVIDE (__executable_start = 0x400000); . = 0x400000 + SIZEOF_HEADERS; .interp : { *(.interp) } .note.gnu.build-id : { *(.note.gnu.build-id) } .hash : { *(.hash) } .gnu.hash : { *(.gnu.hash) } .dynsym : { *(.dynsym) } .dynstr : { *(.dynstr) } .gnu.version : { *(.gnu.version) } .gnu.version_d : { *(.gnu.version_d) } .gnu.version_r : { *(.gnu.version_r) } .rel.dyn : { *(.rel.init) *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) *(.rel.fini) *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) *(.rel.ctors) *(.rel.dtors) *(.rel.got) *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) *(.rel.ldata .rel.ldata.* .rel.gnu.linkonce.l.*) *(.rel.lbss .rel.lbss.* .rel.gnu.linkonce.lb.*) *(.rel.lrodata .rel.lrodata.* .rel.gnu.linkonce.lr.*) } .rela.dyn : { *(.rela.init) *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) *(.rela.fini) *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)

Page 10: Привет из свободно от libc мира (Часть 2)

*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) *(.rela.ctors) *(.rela.dtors) *(.rela.got) *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*) *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*) *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*) } .rel.plt : { *(.rel.plt) } .rela.plt : { *(.rela.plt) } .init : { KEEP (*(.init)) } =0x90909090 .plt : { *(.plt) } .text : { *(.text .stub .text.* .gnu.linkonce.t.*) /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) } =0x90909090 .fini : { KEEP (*(.fini)) } =0x90909090 PROVIDE (__etext = .); PROVIDE (_etext = .); PROVIDE (etext = .); .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } .rodata1 : { *(.rodata1) } .eh_frame_hdr : { *(.eh_frame_hdr) } .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } /* Adjust the address for the data segment. We want to adjust up to the same address within the page on the next page up. */ . = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); /* Exception handling */ .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } /* Thread Local Storage sections */ .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } .preinit_array : { PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE_HIDDEN (__preinit_array_end = .); } .init_array : { PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array))

Page 11: Привет из свободно от libc мира (Часть 2)

PROVIDE_HIDDEN (__init_array_end = .); } .fini_array : { PROVIDE_HIDDEN (__fini_array_start = .); KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) PROVIDE_HIDDEN (__fini_array_end = .); } .ctors : { /* gcc uses crtbegin.o to find the start of the constructors, so we make sure it is first. Because this is a wildcard, it doesn't matter if the user does not actually link against crtbegin.o; the linker won't look for a file to match a wildcard. The wildcard also means that it doesn't matter which directory crtbegin.o is in. */ KEEP (*crtbegin.o(.ctors)) KEEP (*crtbegin?.o(.ctors)) /* We don't want to include the .ctor section from the crtend.o file until after the sorted ctors. The .ctor section from the crtend file contains the end of ctors marker and it must be last */ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) } .dtors : { KEEP (*crtbegin.o(.dtors)) KEEP (*crtbegin?.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) } .jcr : { KEEP (*(.jcr)) } .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } .dynamic : { *(.dynamic) } .got : { *(.got) } . = DATA_SEGMENT_RELRO_END (24, .); .got.plt : { *(.got.plt) } .data : { *(.data .data.* .gnu.linkonce.d.*) SORT(CONSTRUCTORS) } .data1 : { *(.data1) } _edata = .; PROVIDE (edata = .); __bss_start = .; .bss : { *(.dynbss) *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON)

Page 12: Привет из свободно от libc мира (Часть 2)

/* Align here to ensure that the .bss section occupies space up to _end. Align after .bss to ensure correct alignment even if the .bss section disappears because there are no input sections. FIXME: Why do we need it? When there is no .bss section, we don't pad the .data section. */ . = ALIGN(. != 0 ? 64 / 8 : 1); } .lbss : { *(.dynlbss) *(.lbss .lbss.* .gnu.linkonce.lb.*) *(LARGE_COMMON) } . = ALIGN(64 / 8); .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : { *(.lrodata .lrodata.* .gnu.linkonce.lr.*) } .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : { *(.ldata .ldata.* .gnu.linkonce.l.*) . = ALIGN(. != 0 ? 64 / 8 : 1); } . = ALIGN(64 / 8); _end = .; PROVIDE (end = .); . = DATA_SEGMENT_END (.); /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } .comment 0 : { *(.comment) } /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ /* DWARF 1 */ .debug 0 : { *(.debug) } .line 0 : { *(.line) } /* GNU DWARF 1 extensions */ .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 and DWARF 2 */ .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } /* SGI/MIPS DWARF 2 extensions */ .debug_weaknames 0 : { *(.debug_weaknames) } .debug_funcnames 0 : { *(.debug_funcnames) } .debug_typenames 0 : { *(.debug_typenames) }

Page 13: Привет из свободно от libc мира (Часть 2)

.debug_varnames 0 : { *(.debug_varnames) } /* DWARF 3 */ .debug_pubtypes 0 : { *(.debug_pubtypes) } .debug_ranges 0 : { *(.debug_ranges) } .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) }}

==================================================