Стадии сборки программы¶
Сборка программы на C или C++ — это многошаговый процесс преобразования исходного текста в исполняемый файл. Компилятор
gcc/g++ выступает драйвером: он последовательно вызывает несколько специализированных инструментов, каждый из
которых отвечает за свою стадию.
Обзор стадий¶
| Стадия | Вход | Выход | Инструмент |
|---|---|---|---|
| Препроцессинг | .cpp / .c |
.i |
cc1plus, cpp |
| Компиляция | .i |
.s |
cc1plus |
| Ассемблирование | .s |
.o |
as |
| Линковка | .o, .a, .so |
бинарь / .so |
ld, collect2 |
main.cpp foo.cpp
│ │
│ g++ -E │ препроцессинг: раскрытие #include, #define
▼ ▼
main.i foo.i
│ │
│ cc1plus │ компиляция: синтаксический разбор, оптимизации, кодогенерация
▼ ▼
main.s foo.s
│ │
│ as │ ассемблирование: мнемоники → машинные байты
▼ ▼
main.o foo.o libc.a / libfoo.so
│ │ │
└──────────┴──────────┘
│
│ ld линковка: разрешение символов, релокации
▼
a.out (ELF ET_EXEC или ET_DYN)
Флаг -v заставляет g++ напечатать все порождаемые команды:
В выводе будет видно, что драйвер вызывает cc1plus, затем as, затем collect2/ld.
Препроцессинг¶
Препроцессор обрабатывает директивы, начинающиеся с #:
#include— вставляет содержимое заголовочных файлов;#define/#undef— определяет и отменяет макросы;#if,#ifdef,#ifndef,#elif,#else,#endif— условная компиляция;#pragma— платформенно-специфичные директивы.
Результат — обычный текстовый файл с расширением .i (или .ii для C++), в котором нет никаких директив: только
реальный код с уже подставленными заголовками и развёрнутыми макросами.
Остановиться после препроцессинга:
Компиляция¶
Компилятор читает препроцессированный файл и генерирует ассемблерный текст (.s). На этой стадии происходят:
- лексический и синтаксический разбор;
- семантический анализ и проверка типов;
- оптимизации (если включены флагами
-O1,-O2,-O3,-Osи т.д.); - генерация кода для целевой архитектуры.
Остановиться после компиляции (получить ассемблер):
Можно передать также -masm=intel, чтобы получить ассемблер в Intel-синтаксисе вместо AT&T.
Ассемблирование¶
Ассемблер (as) переводит текстовые мнемоники в машинные байты и упаковывает результат в объектный файл формата ELF
с типом REL (Relocatable).
Объектный файл содержит машинный код и данные, но часть символов остаётся неразрешённой — в таблице символов такие
записи помечаются как UND. Запустить объектный файл напрямую нельзя: нет точки входа _start, не завершены релокации.
Линковка¶
Линковщик (ld) объединяет один или несколько объектных файлов и нужные библиотеки, разрешает все внешние ссылки между
символами, выполняет релокации и формирует итоговый ELF-файл: исполняемый (EXEC или DYN/PIE) либо разделяемую
библиотеку (.so).
g++ main.cpp -o main # полный цикл: препроцессинг → линковка
g++ main.o other.o -o main # только линковка уже готовых .o
Объектный файл vs исполняемый файл¶
| Свойство | Объектный файл (.o) |
Исполняемый файл |
|---|---|---|
| Тип ELF | REL (Relocatable) | EXEC или DYN (PIE) |
| Неразрешённые символы | есть (UND) | нет (все разрешены или делегированы динамическому линковщику) |
Точка входа _start |
отсутствует | присутствует |
| Можно запустить | нет | да |
Подробнее о структуре ELF-файлов — в статье Формат ELF.
Флаги оптимизации и отладки¶
Флаг -g добавляет в бинарь отладочную информацию в формате DWARF: соответствие адресов строкам исходника, имена
переменных и типы. Он не влияет на логику программы, но увеличивает размер файла.
g++ -g -O0 main.cpp -o main_debug # отладочная сборка
g++ -O2 main.cpp -o main_release # релизная сборка
g++ -g -O2 main.cpp -o main # отладочная информация + оптимизации
Подробнее об использовании отладочной информации — в статье Отладка (GDB).
Дизассемблирование¶
Дизассемблировать готовый бинарь можно утилитой objdump:
objdump -d a.out # AT&T-синтаксис
objdump -d -M intel a.out # Intel-синтаксис
objdump -C -d a.out # с демангированием C++-имён
Либо через gdb:
Создание статической библиотеки¶
Статическая библиотека (.a) — это ar-архив объектных файлов:
Флаги ar: r — вставить/заменить, c — создать архив если не существует, s — обновить индекс символов (аналог
ranlib).
Подробнее о статической и динамической линковке — в статье Статическая и динамическая линковка.
Источники¶
man gcc— документация по флагам компилятораman as— документация ассемблера GNUman ld— документация линковщика GNUman ar— создание архивов статических библиотек- GCC Internals: Compilation Phases
info gcc— полная документация GCC