Страницы

Поиск по вопросам

среда, 20 февраля 2019 г.

Как избежать удаления функции _start при межмодульной оптимизации?

При следующем значении CFLAGS
-Wall -Werror -Wextra -pedantic -std=c99 -O3 -nostartfiles -nodefaultlibs
моя точка входа __start (обратите внимание на -nostartfiles) успешно компилируется и помещается в исполняемый файл.
Однако при добавлении флага -flto и сама точка входа, и все вызываемые только ей функции выкидываются оптимизатором. Более того, дальнейшая компоновка производится без ошибок и предупреждений, но с некорректной (случайной) точкой входа.
Вопрос: как предотвратить удаление функции __start? Также интересно узнать, почему компоновщик во время оптимизации «забывает» о наличие зависимости от моей точки входа при отсутствии встроенной.
Версия GCC: gcc (i686-posix-dwarf-rev1, Built by MinGW-W64 project) 4.9.2
Исходный код (исправлено с учётом замечания об особенностях Windows ABI [в оригинале это был комментарий, но здесь я добавил его в ответ — прим. пер.]):
#include
void _start() { MessageBox(NULL, TEXT("Hello world."), TEXT(""), MB_OK); ExitProcess(0); }
Ассемблерный код, выдаваемый компоновщиком (-S):
Вариант без -flto
Disassembly of section .text:
00401000 <__start>: 401000: 83 ec 1c sub $0x1c,%esp 401003: c7 44 24 0c 00 00 00 movl $0x0,0xc(%esp) 40100a: 00 40100b: c7 44 24 08 00 20 40 movl $0x402000,0x8(%esp) 401012: 00 401013: c7 44 24 04 0d 20 40 movl $0x40200d,0x4(%esp) 40101a: 00 40101b: c7 04 24 00 00 00 00 movl $0x0,(%esp) 401022: ff 15 54 40 40 00 call *0x404054 401028: 83 ec 10 sub $0x10,%esp 40102b: c7 04 24 00 00 00 00 movl $0x0,(%esp) 401032: ff 15 4c 40 40 00 call *0x40404c 401038: 90 nop 401039: 90 nop 40103a: 90 nop 40103b: 90 nop 40103c: 90 nop 40103d: 90 nop 40103e: 90 nop 40103f: 90 nop
00401040 <__CTOR_LIST__>: 401040: ff (bad) 401041: ff (bad) 401042: ff (bad) 401043: ff 00 incl (%eax) 401045: 00 00 add %al,(%eax) ...
00401048 <__DTOR_LIST__>: 401048: ff (bad) 401049: ff (bad) 40104a: ff (bad) 40104b: ff 00 incl (%eax) 40104d: 00 00 add %al,(%eax) Вариант с -flto (обратите внимание на отсутствие _start, но наличие переходников для API-функций):
Disassembly of section .text:
00401000 <_ExitProcess@4>: 401000: ff 25 4c 30 40 00 jmp *0x40304c 401006: 90 nop 401007: 90 nop
00401008 <_MessageBoxA@16>: 401008: ff 25 54 30 40 00 jmp *0x403054 40100e: 90 nop 40100f: 90 nop
00401010 <__CTOR_LIST__>: 401010: ff (bad) 401011: ff (bad) 401012: ff (bad) 401013: ff 00 incl (%eax) 401015: 00 00 add %al,(%eax) ...
00401018 <__DTOR_LIST__>: 401018: ff (bad) 401019: ff (bad) 40101a: ff (bad) 40101b: ff 00 incl (%eax) 40101d: 00 00 add %al,(%eax)

Данный вопрос является переводом «Prevent __start entry point from being optimized out».


Ответ

Необходимо удостовериться, что данный символ воспринимается как точка входа и не выбрасывается при оптимизации на уровне компоновщика.
Чтобы указать точку входа, необходимо передать компоновщику следующий ключ:
-Wl,-e__start
либо написать spec-файл с объявлением данного символа. Однако способ с ключом проще.
И ещё. При использовании Windows ABI компилятор неявно добавляет дополнительное подчёркивание перед именем Си-функций. Как результат, void __start() превращается в ___start, и компоновщик его не видит.

Данный ответ является переводом ответа участника Jean-François Fabre и комментария участника fuz

Комментариев нет:

Отправить комментарий