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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Кодогенерация и адреса подпрограмм 
:(
    Опции темы
ТарасАтавин
Дата 7.9.2013, 07:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 370
Регистрация: 26.8.2013

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



Переменные, предположим, можно все разместить до подпрограмм и к этапу кодогенерации уже иметь готовые адреса. А как быть с подпрограммами? Если текущая подпрограмма должна вызвать следующую, то откуда может быть известно, по какому адресу её вызывать? Упорядочивать на основе того, какая подпрограмма какую вызывает, не получится из-за конструкций вида 
Код
void f1(...)
{
 ...
 f2(...);
 ...
}
void f2(...)
{
 ...
 f1(...);
 ...
}
, 
Код
procedure p (...)
...
begin
     ...
     ...:=f(...);
    ....
end;
function f(...):...
....
begin
     ...
     p(....);
     ...
end;
 и тому подобных перекрёстных вызовов. Как это обычно решается?


--------------------
Не так всё плохо, как оно есть на самом деле.
PM MAIL   Вверх
feodorv
Дата 7.9.2013, 11:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 11
Всего: 45



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

Есть же декларация функции. Более того, в современных C/C++ она обязательна. 
Код

void f2(...);

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


Но даже в C в стиле K&R компилятор отнюдь не запутывался. Применяются специальные техники увязывания реального адреса функции и места её вызова.

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

Добавлено через 5 минут и 54 секунды
Цитата(ТарасАтавин @  7.9.2013,  08:59 Найти цитируемый пост)
Переменные, предположим, можно все разместить до подпрограмм и к этапу кодогенерации уже иметь готовые адреса.

Вот такой код в отдельном модуле:
Код

extern int g_Count;

void GlobalReinit( void )
{
  g_Count = 0; 
}

Полагаете, что компилятор уже знает адрес переменной g_Count? 

Но вот линковщик уже должен знать этот адрес. При чём здесь "до подпрограмм"? Вы, случаем, не ассемблерщик?


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
ТарасАтавин
Дата 7.9.2013, 12:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 370
Регистрация: 26.8.2013

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



Цитата(feodorv @  7.9.2013,  11:13 Найти цитируемый пост)
Более того, в современных C/C++ она обязательна. 
Она и обязательна Но как это связано с размером текущей функции и стартовым адресом следующей? Или предварительная генерация асма обязательна для счёта размера?

Добавлено @ 12:12
Цитата(feodorv @  7.9.2013,  11:13 Найти цитируемый пост)
Полагаете, что компилятор уже знает адрес переменной g_Count? 
Речь шла о внутримодульных адресах и прямой адресации. С межмодульных потом разберусь. Скорей всего с помощью неявного превращения в ссылку, реализованную на указателе. Но для внутримодульных адресов это не подходит.

Это сообщение отредактировал(а) ТарасАтавин - 7.9.2013, 12:15


--------------------
Не так всё плохо, как оно есть на самом деле.
PM MAIL   Вверх
feodorv
Дата 7.9.2013, 12:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 11
Всего: 45



Цитата(ТарасАтавин @  7.9.2013,  13:09 Найти цитируемый пост)
Но как это связано с размером текущей функции и стартовым адресом следующей?

Никак. А как связан порядок следования функций в исходниках с их адресами? Компилятор не обязан располагать коды функций в порядке их следования в исходниках. Он может руководствоваться какими-то своими резонами.

Цитата(ТарасАтавин @  7.9.2013,  13:09 Найти цитируемый пост)
Или предварительная генерация асма обязательна для счёта размера?

Не обязательна.


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
ТарасАтавин
Дата 7.9.2013, 12:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 370
Регистрация: 26.8.2013

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



Цитата(feodorv @  7.9.2013,  12:27 Найти цитируемый пост)
Компилятор не обязан располагать коды функций в порядке их следования в исходниках. 
Вот именно. Поэтому нефиг придумывать, что речь об исходнике, а не о порядке кодогенерации.

Добавлено через 1 минуту и 33 секунды
Цитата(feodorv @  7.9.2013,  12:27 Найти цитируемый пост)
Не обязательна. 
Тогда как?



--------------------
Не так всё плохо, как оно есть на самом деле.
PM MAIL   Вверх
bems
Дата 7.9.2013, 12:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

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



как насчет отложить часть символов на потом?
а вообще конечно нужно читать. например это


--------------------
Обижено школьников: 8
PM MAIL   Вверх
ТарасАтавин
Дата 7.9.2013, 13:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 370
Регистрация: 26.8.2013

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



Цитата(bems @  7.9.2013,  12:59 Найти цитируемый пост)
как насчет отложить часть символов на потом?
То есть? Вот отложил я часть тела функции, перешёл к следующей, сколько места займёт предыдущая не знаю. По какому адресу начинать следующую?



--------------------
Не так всё плохо, как оно есть на самом деле.
PM MAIL   Вверх
bems
Дата 7.9.2013, 13:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

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



не часть тела, а те символы, определить адрес которых в файле ты пока не можешь. адрес занимает фиксированный размер (пока для простоты не думай про оптимизацию размера адреса), поэтому ты можешь сгенерить переход на символ адрес которого пока неизвестен, а потом вернуться к этому месту и записать туда реальный адрес


--------------------
Обижено школьников: 8
PM MAIL   Вверх
feodorv
Дата 7.9.2013, 13:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 11
Всего: 45



Цитата(ТарасАтавин @  7.9.2013,  13:40 Найти цитируемый пост)
Поэтому нефиг придумывать

Я ничего не придумывал  smile Это Ваши фантазии.

Цитата(bems @  7.9.2013,  14:05 Найти цитируемый пост)
потом вернуться к этому месту и записать туда реальный адрес 

Вот именно. 
Цитата(feodorv @  7.9.2013,  12:13 Найти цитируемый пост)
Применяются специальные техники увязывания реального адреса функции и места её вызова.




--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
ТарасАтавин
Дата 7.9.2013, 16:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 370
Регистрация: 26.8.2013

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



Цитата(feodorv @  7.9.2013,  11:13 Найти цитируемый пост)
Ситуация, на самом деле, ещё хуже, подумайте о динамических библиотеках.
Внешние вызовы как раз достаточно косвенны, чтоб не вызывать проблемы. 
Цитата(feodorv @  7.9.2013,  11:13 Найти цитируемый пост)
 Подумайте и о том, что исполняемый код файла в создаваемом процессе может быть загружен не по тому адресу, на который рассчитывал компилятор.
А это забота системы. Пусть как хочет, так и перебазирует, хоть анализирует код в поисках адресов внутримодульных переходов и исправляет. Или виртуализирует адреса каждого модуля. Меня это не касается.

Добавлено через 2 минуты и 32 секунды
Цитата(bems @  7.9.2013,  13:05 Найти цитируемый пост)
адрес занимает фиксированный размер (пока для простоты не думай про оптимизацию размера адреса)
Это как раз понятно. 
Цитата(bems @  7.9.2013,  13:05 Найти цитируемый пост)
поэтому ты можешь сгенерить переход на символ адрес которого пока неизвестен, а потом вернуться к этому месту и записать туда реальный адрес 
А где его искать потом, чтоб вставить? Кстати, к go to вперёд это тоже относится.


--------------------
Не так всё плохо, как оно есть на самом деле.
PM MAIL   Вверх
bems
Дата 7.9.2013, 16:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

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



Цитата(ТарасАтавин @  7.9.2013,  16:48 Найти цитируемый пост)
 Пусть как хочет, так и перебазирует, хоть анализирует код в поисках адресов внутримодульных переходов и исправляет. Или виртуализирует адреса каждого модуля. Меня это не касается.
касается, потому что ты должен дать системе таблицу релоков



--------------------
Обижено школьников: 8
PM MAIL   Вверх
ТарасАтавин
Дата 7.9.2013, 16:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 370
Регистрация: 26.8.2013

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



что то новенькое. Вроде в формате были предусмотрены таблицы импорта и экспорта, а теперь ещё и реаллоков добавляется.

Это сообщение отредактировал(а) ТарасАтавин - 7.9.2013, 16:53


--------------------
Не так всё плохо, как оно есть на самом деле.
PM MAIL   Вверх
bems
Дата 7.9.2013, 16:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

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



секция .reloc

Добавлено через 9 минут и 19 секунд
Цитата(ТарасАтавин @  7.9.2013,  16:48 Найти цитируемый пост)
А где его искать потом, чтоб вставить? Кстати, к go to вперёд это тоже относится. 
добавлять в рабочие данные компилера список таких мест для каждого символа, адрес которого не известен, а потом при выяснении адреса проходить по этому списку?



--------------------
Обижено школьников: 8
PM MAIL   Вверх
ТарасАтавин
Дата 7.9.2013, 17:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 370
Регистрация: 26.8.2013

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



Цитата(bems @  7.9.2013,  16:58 Найти цитируемый пост)
секция .reloc
Что это?

Это сообщение отредактировал(а) ТарасАтавин - 7.9.2013, 17:12


--------------------
Не так всё плохо, как оно есть на самом деле.
PM MAIL   Вверх
bems
Дата 7.9.2013, 17:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

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



Цитата(ТарасАтавин @  7.9.2013,  17:11 Найти цитируемый пост)
Что это? 
что именно? "секция .reloc"? ну так часто называется секция РЕ-файла, содержащая таблицу релоков. "Часто" потому что насколько я помню загрузчик не использует имена секций для поиска нужной инфы, а пользуется массивом DataDirectory опционального заголовка. Релоки это это элемент массива за индексом IMAGE_DIRECTORY_ENTRY_BASERELOC



--------------------
Обижено школьников: 8
PM MAIL   Вверх
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   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
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.0617 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


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

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