Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Кодогенерация и адреса подпрограмм 
:(
    Опции темы
tzirechnoy
Дата 8.9.2013, 01:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1173
Регистрация: 30.1.2009

Репутация: 2
Всего: 16



Да всё примерно такжэ, как и для внешних функцый. Кодогенератор генерит код (call ..., jmp ... и т.д.), а вместо адресов пишэт нули (условно, на разных архитектурах там по-разному можэт быть реализовано). И записывает списки мест, куда поставить адрес (обычно в случае Си -- он всё это, и код и списки мест, пишэт в объектный файл. Расшырение .o. В винде, возможно, .obj). Затем линкер берёт этот объектный файл, плюс другие указанные ему библиотеки объектных файлов (в т.ч. т.н. "динамические"), выдирает из них списки адресов символов, строит дерево зависимостей, складывает весь код из объектных файлов (ну, на самом деле только из "статических" объектных файлов, т.е. не находящихся в динамических библиотеках)  в один большой объектный код (обычно -- у себя в памяти), ужэ в этом коде вычисляет получившыеся адреса всех переменных и функцый (кроме динамических, которых там нет), и затем проходит по списку мест, в которые он должэн записать эти адреса, и записывает их.
То есть никакой разницы -- в этом объектном файле, не в этом, сначала весь код, потом все адреса. Результат потом записывает в исполняемый файл (в винде -- .exe, так и буду его кстати дальшэ называть, для краткости).

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

Вторая деталь -- динамические библиотеки. Для них обычный линкер не выстраивает их код в одну линейку (поскольку при запуске это можэт быть совсем другой код), соотвественно, не записывает его в вывод (.exe ужэ). Когда линкер находит, что такие-то символы берутся из динамических библиотек -- он записывает в свой выходной файл список имён внешних функцый, на которые кто-то внутри ссылается. Ну, почти как в случае генерацыи .o-файла. А вот с адресами в основном файле (том самом .exe, который мы собираем) происходит интересная вещь: дело в том, что если просто оставить нули и понадеяться, что при запуске динамический линкер пропишэт вместо них правильные адреса -- то получится, что при одновременном запуске нескольких копий программы придётся держать в памяти столько копий кода, сколько их было запущено -- ведь код у разных экземпляров станет разным и держать его в одной readonly копии не получится.
Поэтому для динамических символов составляется отдельная таблица адресов перехода, которая собирается в одном известном месте (ну, в концэ) объектного кода. И непосредственно в код прописываются адреса ячеек этой таблицы. А ужэ при выполнении динамический линкер загружает эту таблицу в память и прописывает в неё правильные адреса функцый из внешних .dll -- благо эта таблица сильно меньшэ, чем весь выполняемые код данного .exe-шника. 
Более того, сейчас на самом деле там ещё веселее -- чтобы не перелопачивать при загрузке сразу всю таблицу, пытаясь найти в разных .dll-ах тысячи и десятки тысяч имён, которые, возможно, при этом запуске и не понадобятся -- в ячейки этой таблицы записывается адрес "трамплина", стандартной подпрограммки из пары команд, которая вызывается стандартную функцыю, которая по адресу вызванной функцыи определяет, что было вызвано и находит и записывает в соответствующую ячейку таблицы правильный адрес из .dll. Таким образом, ячейки таблицы заполняются правильными адресами когда они первый раз используются.

Как-то так. Но, в общем, со своими адресами никаких проблем нет: в первый проход остаются нули, ко второму проходу компиляторы их знают.
PM MAIL   Вверх
LeonidPr
Дата 9.9.2013, 08:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 220
Регистрация: 17.2.2012
Где: г. Чебоксары

Репутация: нет
Всего: 1



Цитата(ТарасАтавин @  7.9.2013,  07:59 Найти цитируемый пост)
Упорядочивать на основе того, какая подпрограмма какую вызывает, не получится из-за конструкций вида

Тут много уже понаписали, так что я скорее всего повторюсь. Просто недавно сам столкнулся с похожей проблемой (но в более простом виде). Писал элементарный ассемблер с некоего своего набота мнемоник в свой же байткод (его микроконтроллер потом исполняет). Необходима была поддержка меток в исходном коде (то же что и ваши подпрограммы). Все решилось стандартным (ну... почти стандартным) двухпроходным методом. За первый проход делается разбор строк исходного кода, счетчик инструкций соответственно обновляется после обработки каждой строки на нужное кол-во байт, равное размеру считанной инструкции + размер её операндом. Если встречается метка, то в некий std::map<string, uint32_t> заносится наименование метки и текущий счетчик инструкций, на втором проходе еще раз просматривается исходный код и уже ведется кодогенерация, если у считанной иснструкции операнд - метка, она берется из того map-а и её адрес подставляется в сгенерированный код. возможно вам для начала следует поступить аналогично. 

Цитата(ТарасАтавин @  7.9.2013,  07:59 Найти цитируемый пост)

Код

void f1(...)
{
 ...
 f2(...);
 ...
}
void f2(...)
{
 ...
 f1(...);
 ...
}

Сначала не заморачиваться, пройти по коду (уже распарсенному, в виде дерева вывода), вычислить адреса меток f1, f2, а потом на этапе кодогенерации подставлять их в аргументы соответствующих call-ов. Только вот как при этом работает оптимизатор - не знаю, мы в свое время в универе не дошли до него, а я как-то не интересовался.
--------------------
pkunzip.zip
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0409 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.