TGViewer
.NET Kings .NET Kings @netskings · 7.38K subscribers
Post #731 552
👁‍🗨Hello world~

Компилятор: Путь от исходника до исполняемого файла. Обзор и практика на gcc

• В постах про AST, CFG и компоновщик мы разбирали отдельные части этого пути, сегодня соберём их в одну картину и пройдём её руками.

• Компилятором обычно называют всю цепочку, но на деле это несколько отдельных программ, а gcc лишь запускает их по очереди: cc1 (препроцессор и компилятор), as (ассемблер) и collect2 (обёртка над компоновщиком ld).

• Проверим это на простой программе hello.c, команды ниже для Linux с gcc (на Windows подойдёт WSL):

#include <stdio.h>
#define N 3

int main(void) {
int a = N * 2;
printf("%d\n", a);
return 0;
}


• Чтобы увидеть, кого вызывает gcc, запустите gcc -v hello.c и найдите в выводе строки с cc1, as и collect2. Теперь пройдём цепочку по шагам.

• Шаг 1. Препроцессор: gcc -E hello.c -o hello.i. Он раскрывает #include и #define: содержимое stdio.h подставляется в файл (получаются сотни строк), а в конце видно int a = 3 * 2;, то есть макрос N уже заменён на 3.

• Шаг 2. Компиляция в ассемблер: gcc -S -masm=intel hello.c -o hello.s. Внутри компилятор строит AST, проверяет типы, переводит код в промежуточное представление (IR), оптимизирует его (в том числе на основе CFG) и генерирует ассемблер. Вот что получилось (служебные директивы убраны, у вас вывод может слегка отличаться):

main:
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR -4[rbp], 6
...
call printf@PLT
...
ret


• Обратите внимание на 6: выражение 3 * 2 компилятор посчитал сам, до запуска программы.

• Шаг 3. Ассемблер: gcc -c hello.c -o hello.o. Получился объектный файл с символами, релокациями и секциями из цикла про компоновщик. Команда nm hello.o покажет символы:

0000000000000000 T main
U printf


• main определён в этом файле (T), а printf нет (U), его адреса компилятор не знает. Как же тогда собран вызов? Посмотрим objdump -dr -M intel hello.o:

27: e8 00 00 00 00   call 2c <main+0x2c>
28: R_X86_64_PLT32 printf-0x4


• Нули после e8 (код call) это заглушка, а строка под ней релокация: "подставь сюда смещение до printf с поправкой -4".

• Шаг 4. Компоновщик: gcc hello.o -o hello, затем ./hello выведет 6. Если снова вызвать objdump -d -M intel hello, на месте нулей окажется реальное смещение: call 1050 <printf@plt> (адрес у вас может отличаться). Компоновщик выполнил релокацию. Сам printf лежит в libc, поэтому nm hello покажет его всё ещё неопределённым, а адрес найдёт динамический компоновщик при запуске.

• Теперь оптимизации. Возьмём такой код (sq.c):

int square(int x) { return x * x; }

int main(void) {
return square(5);
}


• Сравните вывод gcc -S -masm=intel -O0 sq.c и -O2. На -O0 main честно вызывает square, а на -O2 остаётся только это:

main:
mov eax, 25
ret


• Компилятор встроил square в main (inlining) и посчитал 5 * 5 заранее (constant folding). Поэтому дизассемблированный оптимизированный код так сильно отличается от исходника.

• Промежуточное представление тоже можно увидеть: gcc -c -fdump-tree-gimple hello.c сохранит IR GCC в файл вида hello.c.006t.gimple, а clang -S -emit-llvm hello.c покажет LLVM IR.

• Вот небольшое задание, если хотите потренероваться: возьмите любую свою функцию с циклом и сравните её ассемблер на -O0 и -O2. Проще всего это делать в Compiler Explorer. Удачи!

#Компилятор

• Поддержать автора монеткой: @v_meshke
  • ❤ 10
  • 🔥 2
  • 👍 1
More from @netskings
  1. Oct 5, 2026Освой сети и командную строку с лучшими обучающими каналами 🤩 Network Admin - обучающий к…
  2. Oct 4, 2026👁‍🗨Hello world~ Когда проблема не в коде, а в замысле. OWASP A06: Insecure Design • Inse…
  3. Oct 3, 2026👁‍🗨Hello world~ Изучаем сеть: Как коммутатор запоминает устройства • Коммутатор передаёт…
  4. Oct 2, 2026👁‍🗨Hello world~ Парадокс дней рождения: почему коллизии хешей находить проще, чем кажетс…
  5. Oct 1, 2026👁‍🗨Hello world~ Как работает антивирус: Hell’s Gate • В прошлом посте мы разобрали Direc…
  6. Sep 30, 2026🖥 2 полезных канала для тех, кто увлечён ИБ и разведкой по открытым источникам: 😈 STEIN:…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →