не ясный с заданием компоновщика

Я использую язык C на окнах. Этим вопросом была ранее часть того, Что происходит с идентификаторами в программе?. Я повредил его для сокращения нет. из вопросов. Это - автономный запрос (не зависит от предыдущего вопроса),

Если нет ничего для соединения (т.е. я не пользуюсь никакими библиотеками. Я знаю это привычка иметь любое применение.) компоновщик изменит вывод объектного кода ассемблера? Раз так, что это изменяет?

Я слышал, что КОМПОНОВЩИК также делает операцию некоторого размещения в ОЗУ. Я не понимаю как. Программа не работает, ее только в стадии производства. Как компоновщик мог отобразиться на память? Как это было бы похоже? Что все - функции КОМПОНОВЩИКА?

Когда люди обращаются к "перемещению", "привязке по адресу". Я действительно не получаю то, что они имеют в виду. Что это и какова его цель?

Некоторые отладчики показывают информацию как: стек вызовов: 0xfffef32, 0xf3234fe и т.д. В праве времени выполнения? или адреса памяти так называемого "размещения в ОЗУ" компоновщика?

когда люди обращаются к чему-то как symbols или symbol table. Они имеют в виду идентификаторы (имена переменной, постоянные имена, имена функций)?

Я искал информацию в Интернете, но ничто не мог найти полезным. Может быть я не уверен, что искать. Я не хочу читать большие книги по этому. Но если существуют какие-либо статьи, учебные руководства, которые очищают понятия. Это также было бы полезно.

Я - программист новичка. Так, было бы замечательно, что можно объяснить в простых но технических терминах.

6
задан Community 23 May 2017 в 12:30
поделиться

4 ответа

При компиляции исходного файла компилятор/ассемблер обычно разделяет его на несколько секций. В качестве гипотетического примера представьте, что используются следующие секции:

  • .text - содержит весь исполняемый код
  • .const - содержит константные данные
  • .data - содержит инициализированные данные для чтения/записи
  • . bss - содержит читать/записывать неинициализированные данные

В одном исходном файле компилятор/ассемблер выделяет соответствующие секции и присваивает символы, которые используются в секции, начиная с нуля.

Например:

int i;
const j = 3;
int k = 4;
int l;
int main()
{
return 1;
}

Это может привести к следующей таблице символов:

Symbol Section Offset
i      .bss    0
j      .const  0
k      .data   0
l      .bss    4
main   .text   0

В объектном файле, помимо таблицы символов, могут быть сохранены данные в каждой секции. В этом примере, .текстовая секция содержала бы объектный код для "return 1", секция const - 3, секция данных - 4. .bss секция не обязательно должна была бы находиться в объектном файле, так как переменные не были инициализированы.

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

Теперь мы переходим к тому, что называется "перемещение" или "привязка по адресу". Допустим, в гипотетической системе исполняемый код начинается с адреса 0x1000. Допустим также, что секции данных программы хотят начинаться на четной границе страницы после исполняемого кода. Линкер назначит 0x1000 в качестве базы конкатенированных .текстовых секций и скорректирует все символы. Затем база .const, .data и .bss секций аналогично размещала бы их в соответствующих местах в памяти.

Иногда в секции встречаются символические ссылки. Эти ссылки должны быть обновлены компоновщиком, чтобы отразить окончательное положение символа, на который они ссылаются. Объектный файл может содержать "записи перемещения", которые выглядят как

section offset symbol
.text   0x1234 foo

Линкер перейдет к каждому смещению в каждой секции и обновит там значение, чтобы отразить окончательное значение символа.

После всего этого, полученный "абсолютный" объектный файл можно загрузить в память (в нужное место, конечно!) и выполнить.

.
4
ответ дан 17 December 2019 в 00:10
поделиться

Я буду работать с Си для этого обсуждения.

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

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

Даже если вы не ссылаетесь ни на какие внешние модули, ссылка, вероятно, должна будет преобразовать некоторые относительные ссылки в вашем коде в абсолютные; т.е. как только она "знает", где в файле будет находиться ваш код, она может присвоить вещам правильные конечные адреса.

.
1
ответ дан 17 December 2019 в 00:10
поделиться

Если нечего компоновать (т.е. я не использую никаких библиотек, я знаю, что это не принесет никакой пользы.) изменит ли компоновщик объектный код, выводимый ассемблером? Если да, то что он изменит?

Он всегда связывает какой-нибудь код инициализации. Вы можете попробовать это, написать пустую программу и связать ее, а затем использовать objdump -d для ее разбора.

Я слышал, что LINKER также делает операцию отображения некоторой памяти. Я не понимаю как. Программа не запущена, она просто на стадии производства. Как компоновщик может компоновать карту памяти? Как бы это выглядело? Каковы все функции LINKER?

Каждая система имеет схему памяти, которой должны следовать исполняемые программы для работы. Она определяет, куда идут различные части программы (как минимум код, инициализированные данные, данные, инициализированные до нуля). Линкер должен производить исполняемый файл в соответствии с этими правилами, которые варьируются в зависимости от системы, например, Windows и Linux. На встраиваемых системах это становится ещё интереснее, там программа обычно находится в памяти только для чтения (Flash), а данные - в оперативной памяти, и существуют фиксированные диапазоны адресов для различных типов памяти в зависимости от типа микроконтроллера.

Когда говорят о "перемещении" , "привязке по адресу". Я не совсем понимаю, что они означают. Что это и какова его цель?

Привязка в общем случае означает присвоение значения имени, в данном случае адреса символу функции или глобальной переменной.

Что касается "перемещения", то обычно вы связываете более одного объектного файла, и каждый объектный файл указывает свои адреса как смещения относительно его начала. При их объединении каждый из них получает свой собственный диапазон адресов, а компоновщик вычисляет адрес для символа, отображая смещение в диапазон адресов. Это называется смещением.

Некоторые отладчики показывают информацию типа : call stack: 0xfffef32 , 0xf3234fe и т.д... Это во время выполнения, или адреса памяти так называемого "отображения памяти" компоновщика?

Что 0xfffef32 будет типичным адресом на стеке, так как стек обычно располагается в верхней части памяти и растёт вниз. Стек используется для адресов возврата, локальных переменных и фактических параметров функции. Они являются локальными и хранятся по адресам относительно указателя стека, поэтому обычно компилятор их не обрабатывает, скорее компилятор уже знает, какие смещения использовать, и помещает их в код ассемблера.

когда люди ссылаются на что-то вроде символов или таблицы символов. Имеют ли они в виду идентификаторы (имена переменных, констант, имен функций)?

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

В компоновщике имеется возможность --печатать карту, чтобы распечатать таблицу символов. Вы можете использовать -Wl,--print-map, если вы используете gcc для компоновки.

Если вам нравится такой низкоуровневый технический материал, то вам следует обратить внимание на встроенное программирование, т.е. программирование микроконтроллеров, которые используются в различных электрических устройствах. Для настольных систем, таких как Windows, вам обычно не нужно смотреть на такие детали.

1
ответ дан 17 December 2019 в 00:10
поделиться

Не ответ, а просто предложение: купите "Линкеры и погрузчики" , прочитайте его несколько раз. Это удивительно полезно.

1
ответ дан 17 December 2019 в 00:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: