MyTetra Share
Делитесь знаниями!
Основы работы компиляторов GCC и Clang
Время создания: 13.05.2021 11:13
Текстовые метки: компилятор, gcc, clang
Раздел: Компьютер - Программирование - Теория программирования - Теория компиляции
Запись: xintrea/mytetra_syncro/master/base/1620893635850roas114/text.html на raw.github.com

Есть всего три популярных, высококачественных, широко принятых в индустрии компиляторов C/C++:

  • GCC (Gnu Compiler Collections и GNU C Compiler), кроссплатформенный и Open-Source, используется в Linux как основной, на Windows известен как MinGW
  • MSVC (Microsoft Visual C/C++), низкая кроссплатформенность и закрытый код, используется в Windows как основной
  • LLVM/Clang, кроссплатформенный и Open-Source, используется в Mac OSX как основной, на Windows умеет быть совместимым и с MinGW, и с MSVC, доступен в Visual Studio 2015 и выше в модификации Clang/C2

Принципы работы GCC и Clang можно детально исследовать благодаря открытому исходному коду и отладочным средствам.

GCC (компиляция и вывод ассемблера)

Разберёмся, как использовать GCC из командной строки. На UNIX-платформах GCC доступен по команде gcc, а для Windows есть порт GCC — MinGW. Воспользуемся примером кода, складывающего два числа:

#include <stdio.h>


float sum(float a, float b)

{

return a + b;

}


int main()

{

float a = 0;

float b = 0;

scanf("%f %f", &a, &b);

float ab = sum(a, b);

printf("a + b = %f\n", ab);

}


Компиляция файла из командной строки с опциями по умолчанию (отладочная сборка без оптимизаций):

# после флага -o задан выходной путь

# все параметры вне флагов считаются входными путями

gcc a+b.c -o a+b


Вывод программы после запуска:

10 29

a + b = 39.000000


Получение ассемблерного кода для отладочного режима без оптимизаций возможно с опцией -S. По умолчанию создаваемый ассемблер использует синтаксис AT&T, который заметно отличается от синтаксиса Intel.

# -oa+b_debug.s необязательная опция, указывает явно имя выходного файла

# -S указывает генерировать ассемблер вместо исполяемого кода

gcc -S a+b.c -oa+b_debug.s

# -masm=intel указывает на смену синтаксиса выходного ассемблера

gcc -S a+b.c -oa+b_debug.s -masm=intel


Можно получить ассемблерный код в режиме с оптимизациями, используя флаг -O2, где “O” в верхнем регистре. Если сравнить отладочный и оптимизированный код с помощью утилиты diff, будут видны сильные отличия в цепочках инструкций.

# -oa+b_debug.s необязательная опция, указывает явно имя выходного файла

# -S указывает генерировать ассемблер вместо исполяемого кода

# -O2 указывает второй уровень оптимизаций, аналогичный Release-сборкам

gcc -O2 -S a+b.c -oa+b_debug.s


Вы можете скомпилировать ассемблер с помощью того же gcc, который сам передаст нужные параметры утилите “gas” (GNU Assembler).

gcc a+b_debug.s


Clang (компиляция, вывод ассемблера и LLVM-IR)

Clang разрабатывался как прозрачная замена компилятору GCC для Linux и Mac OSX. Поэтому большая часть опций, касающихся компиляции C/C++, у этих двух компиляторов совпадает. Компиляция примера на языке C выглядит точно так же:

# после флага -o задан выходной путь

# все параметры вне флагов считаются входными путями

clang a+b.c -o a+b


Генерация ассемблера с синтаксисом Intel:

clang -S -mllvm --x86-asm-syntax=intel a+b.c


Бекенды GCC и Clang

GCC и Clang оба используют гибкие фреймворки для построения бекендов компилятора. В GNU Compiler Collections используется собственный промежуточный язык и бекенд GIMPLE, который сильно упрощает написание компиляторов для новых языков в составе GNU Compiler Collections, но плохо подходит для изучения новичком. Проект LLVM гораздо дружественнее к новичкам и студентам, и именно его использует компилятор Clang.

Вы можете изучать промежуточный код проекта LLVM, называемый LLVM-IR, с помощью clang, исследуя преобразование кода из C в LLVM-IR:

# Выходной файл: a+b.ll

clang -S -emit-llvm a+b.c


# Компиляция с оптимизациями (O2)

# Выходной файл: a+b.ll

clang -O2 -S -emit-llvm a+b.c


Упражнения

  • Напишите 3-4 простейших программы в 10-20 строк на C (сложение двух чисел, вывод текущего времени с начала эпохи UNIX, вывод версии операционной системы, переворачивание строки т.п.). Сгенерируйте из этих программ листинги в машинном ассемблере либо в LLVM-IR, и сравните листинги от разных программ с помощью diff. Попробуйте собрать минимальный шаблон ассемблерного кода, который можно было бы разворачивать в полноценную программу путём подстановки цепочки инструкций вместо переменной {CODE}.
Так же в этом разделе:
 
MyTetra Share v.0.59
Яндекс индекс цитирования