Форум программистов, компьютерный форум CyberForum.ru

Процесс компиляции - C++

Восстановить пароль Регистрация
Другие темы раздела
C++ Почему С++ хороший для gamedeva? http://www.cyberforum.ru/cpp/thread607453.html
На всех сайтах, форумах пишут, что игры нужно писать на С/С++, но почему? Нигде не видел объяснения этому, может кто здесь объяснит?
C++ Нажатие ЛКМ в экранных координатах Программа должна создавать точку в центре экрана(пусть не в центре(по указанным пикселям) эта точка должна присутствовать все время на экране,пока не будет выключена программа,при том при запущенных посторонних программах) и должна автоматически нажимать ЛКМ при появлении в квадрате(точки также должны указываться в пикселях). Это реально?Простите за корявое оформление и если не так тему... http://www.cyberforum.ru/cpp/thread606849.html
C++ Перемножение матриц 6000Х6000
Нужно перемножить матрицы размером в 6000 на одном ядре(один поток). Рассчитать теоретическое время. Кто-нибудь, подскажите пожалуйста: почему препод говорит, что время выполнения операции с плавающей точкой при частоте 2.5 GHz 10^10(процессоры вычисляют 4 операции с плавающей точкой одновременно, то есть 2.5*4*10^9) и почему он говорит, что в эту величину внесено время выборки из ОП. В...
Где найти ответы к самоконтролю в книге Шилдта "С++ руководство для начинающих" C++
В книге сказано,что ответы есть на сайте осборне ком, но он перенаправляет на другой сайт,на котором ничего нет кроме продажи книг,по крайней мере мне так показалось.
C++ Автоматическое объявление объекта произвольного типа http://www.cyberforum.ru/cpp/thread603519.html
Помогите найти информацию по "Автоматическому объявлению объекта произвольного типа". Что это такое, как работает и т.д.
C++ Как интегрировать Notepad++ с MinGW компилятором? Уважаемые форумчане, подскажите как можно грамотно интегрировать Notepad++ (или аналогичный редактор с подcветкой разных синтаксисов) с MinGW компилятором (или опять же аналогичным по windows). подробнее

Показать сообщение отдельно
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16935 / 5340 / 328
Регистрация: 30.03.2009
Сообщений: 14,354
Записей в блоге: 26
19.06.2012, 13:24  [ТС]     Процесс компиляции
Процесс компиляции состоит из нескольких стадий. Ко всему, что я буду объяснять, следует подходить условно и воспринимать как самое общее приблизительное пояснение. Просто в реальной жизни есть очень много тонкостей, которые начинающему понять будет сложно и такие объяснения будут лишь загромождением. Просто попытаюсь вкратце пояснить на пальцах суть происходящего.

Рассмотрим на простеньком примере

C
#include <stdio.h>
 
int main (void)
{
  printf ("Hello world\n");
  return 0;
}
Конкретные действия буду объяснять на примере компилятора gcc. Просто потому, что с ним я умею работать из консоли. Наверняка все эти действия можно выполнять и из-под IDE, но я с ними не работаю, а потому не знаю, как это делается

*** UPDATE ***
Пока писал, понял, что пример выбрал неудачно и методику изложения следует немного поменять. Но для этого нужно в очередной раз найти время и уже в законченном виде с нормальными пояснениями выложить в блог, где можно спокойно редактировать и исправлять

1 этап. Препроцессирование

На данном этапе работа идёт только с текстовыми файлами. Здесь препроцессор объединит наш исходник и все include-файлы в один большой текстовый файл. Для нашего случая это будет что-то типа:

C
/* Здесь идут потроха, подцепившиеся из stdio.h и прочих .h файлов,
 * которые могут подключаться внутри stdio.h. Касаемо функций или переменных
 * тут будут только описания, но никаких определений */
 
...
 
extern int printf (const char*, ...);
 
...
 
 
/* Текст из stdio.h закончился, далее идёт текст нашей программы */
 
int main (void)
{
  printf ("Hello world\n");
  return 0;
}
Во время работы препроцессора идёт работа со всякими внешними файлами (include'ами) и путями (каталоги, в которых компилятор ищет include-файлы)

Результат работы препроцессора можно посмотреть так:

Bash
$ gcc t.c -E -o t.i
Итоговый препроцессированный текст будет в файле t.i

2 этап. Трансляция

Полученный после препроцессирования единый текстовый файл скармливается транслятору. В процессе работы транслятора уже нет никакой работы со внешними файлами, путями поиска и т.п. На вход транслятору подаётся один файл с исходником, на выходе транслятора получается один файл, содержащий ассемблерный текст. А сам транслятор занимается преобразованием исходника на языке программирования в ассемблерный текст, содержащий код целевой машины на языке ассемблера.

В нашем случае на выходе транслятора мы получим ассемблерный текст. Я привожу тот текст, который получен в результате работы компилятора gcc. Некоторые интересные места я отметил стрелочками и пронумеровал. О них пойдёт речь ниже.

Assembler
    .file   "t.c"
    .section    .rodata.str1.1,"aMS",@progbits,1
.LC0:                          <----- 1
    .string "Hello world\n"
    .text
    .p2align 4,,15
.globl main                    <----- 2
    .type   main, @function
main:                          <----- 3
    pushl   %ebp
    movl    %esp, %ebp
    andl    $-16, %esp
    subl    $16, %esp
    movl    $.LC0, 4(%esp)     <----- 4
    call    printf             <----- 5
    xorl    %eax, %eax
    leave
    ret
    .size   main, .-main
    .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
    .section    .note.GNU-stack,"",@progbits
Ассемблерный текст является не просто образом будущего кода, но ещё и образом будущего объектного файла, в котором будут символьные имена меток, которые в свою очередь будут использоваться при линковке.

В нашем случае мы видим, что в коде имеются две метки. Метка ".LC0" (стрелка 1), описывающая набор символов от строкового литерала и метка "main" (стрелка 3), описывающая начало функции main. У каждой метки есть так называемая область видимости: локальная или глобальная. Локальные метки видны только внутри данного модуля, глобальные метки видны из других модулей. Метка ".LC0" является локальной, т.к. строковой литерал - это внутренние данные нашего модуля. Метка main является глобальной, т.к. эта функция должна быть видна извне (в исходнике у main'а нет модификатора static), а потому этот факт подсвечивается специальной директивой (стрелка 2).

Помимо вхождения меток мы видим ещё и обращения к меткам: обращение к строковому литералу ".LC0" (стрелка 4) и обращение к внешней метке "printf" (стрелка 5).

Результат работы препроцессора можно посмотреть так:

Bash
$ gcc t.c -S -o t.s
Итоговый ассемблерный текст будет в файле t.s

3 этап. Ассемблирование

Полученный ассемблерный текст далее передаётся программе-ассемблеру, которая преобразует его в объектный файл. Объектный файл представляет собой бинарные коды целевой машины плюс дополнительная информация о метках и их использовании. Информация, содержащаяся в объектном файле принципиально ничем не отличается от информации, содержащейся в ассемблерном тексте. Только весь код вместо мнемоник, понятных человеку, содержит двоичный код, понятный машине. А вместо меток, расставленных по ассемблерному тексту, объектный файл содержит специальную таблицу символов (symbol table), описывающую все метки из нашего ассемблерного текста и таблицу перемещений (relocations table), описывающую точки, где метки использовались. Эти таблицы спроектированы таким образом, чтобы с ними было удобно работать линкеру и дизассемблеру.

Конкретно в нашем случае эти таблицы будут выглядеть примерно таким образом. В объектном файле определена локальная метка ".LC0", глобальная метка "main" и внешняя метка "printf", к которой в данном файле есть обращения (но определения метки нет). В объектном файле есть использование метки ".LC0" и использования метки "printf"

Важным моментом является то, что в объектном файле адреса ещё не настроены. Например, у нас в функции main есть обращение к метке ".LC0". но в том месте кода, где происходит это обращение, адрес метки ".LC0" ещё не проставлен, т.к. он будет известен только на этапе линковки

Объектный файл можно получить так:

Bash
$ gcc t.c -c -o t.o
В итоге создастся объектный файл с именем t.o. Просто так в него заглянуть уже не получится, т.к. это бинарный файл, но при помощи воспомогательных утилит можно выудить любую информацию.

Таблица символов (меток) - symbol table:

Bash
$ readelf --symbols t.o
 
Symbol table '.symtab' contains 10 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
...
     8: 00000000    41 FUNC    GLOBAL DEFAULT    1 main
     9: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND printf
Здесь удалил целую портянку служебных фиктивных символов, о которых на данном этапе можно и не вспоминать. Обратите внимание, что среди таблицы символов отсутствует метка ".LC0". Для процесса линковки метка как таковая не нужна (ибо она локальная внутри модуля), а все обращения к метке ассемблер заменил на смещения внутри объектного файла (см. далее). Это некая оптимизация. При желании можно попросить ассемблер эту метку сохранить (но это надо почитать документацию)

Таблица перемещений (использований) - relocation table:

Bash
$ readelf --relocs t.o
 
Relocation section '.rel.text' at offset 0x360 contains 2 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
00000015  00000501 R_386_32          00000000   .rodata.str1.1    <-----
00000021  00000902 R_386_PC32        00000000   printf
Место, помеченное стрелкой - это есть обращение к метке ".LC0", которое ассемблер заменил на обращение к секции данных с заданным смещением (правда для данного примера смещение оказалось нулевым)

4 этап. Линковка

Полученный объектный файл (а их может быть несколько) отдаётся линкеру. Линкер склеивает между собой все поданные ему файлы и формирует один большой исполняемый файл. Помимо объектных файлов компилятор подаёт в линкер ещё и библиотеки. Какие-то библиотеки компилятор подаёт невидимым для пользователя образом (т.е. пользователь непосредственно в этом процессе не участвует). Какие-то библиотеки пользователь сам просит компилятор передать линкеру. В первую группу, как правило, относятся библиотеки, отвечающие за run-time поддержку языка программирования и библиотеки, входящие в состав стандарта языка программирования или входящие в состав стандартной библиотечной поддержки на данной операционной системе. Библиотека, содержащая реализацию функции printf относится именно к этой группе. Ко второй группе относятся все пользовательские библиотеки (графические библиотеки, библиотеки для работы с криптографией и прочее)

В контексте данной статьи к библиотекам нужно относиться следующим образом. Где-то кто-то написал реализации всех стандартных функций, в том числе и printf. Далее все эти реализации откомпилированы до объектного файла. Дальше каким-то образом склеили эти объектные файлы в единый файл (или в небольшое количество раздельных файлов) и назвали эти файлы словом "библиотека". Т.е. библиотека - это набор уже откомпилированных кодов. Далее эту библиотеку и include-файлы к ним включили в состав компилятора или в состав операционной системы

Помимо склеивания файлов линкер ещё и занимается настройкой адресов. Поскольку весь набор кодов, требуемых для формирования программы-бинарника, уже имеется на руках у линкера, то линкер после склеивания уже однозначно может сказать, по какому адресу будет располагаться та или иная функция или переменная. Для каждого файла, поступившего на ликновку, линкер заглянет в таблицу перемещений (использований), из которой поймёт, в какое место кода какой адрес нужно прописать. Конкретно в нашем случае в объектном файле у нас две перемещения: для бывшей метки ".LC0" (которая превратилась в обращение к секции с данными) и для метки printf. В итоге в функцию main в те места, которые засвечены в таблице перемещений, будут воткнуты итоговые адреса в исполняемом файле, соответствующие местоположению метки ".LC0" и функции "printf"

================================================================

В общем, пояснение было несколько сумбурным, а потому лучше будет, если ты задашь конкретные вопросы по непонятным местам, чтобы было ясно, каким образом в дальнейшем аккуратно это дело переписать
 
Текущее время: 04:57. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru