При следующем значении 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
Комментариев нет:
Отправить комментарий