Страницы

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

пятница, 10 января 2020 г.

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

#c #оптимизация #gcc


При следующем значении 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».
    


Ответы

Ответ 1



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

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

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