Как компоновщик узнает, где находится определение внешней функции?

Я прочитал несколько постов и пришел к выводу, что extern сообщает компилятору: «Эта функция существует, но код для нее где-то еще. Не паникуйте». Но как компоновщик узнает, где определена функция.

Мое дело:-
Я работаю над Keil Uvision 4. Существует заголовочный файл grlib.h, а основная функция находится в grlib_demo.c (он включает grlib.h). Теперь есть функция GrCircleDraw (), которая определена в Circle.c и вызвана в grlib_demo.c, также есть оператор

extern void GrCircleDraw (все аргументы);

в grlib.h. Мой запрос заключается в том, как компоновщик знает, где находится определение GrCircleDraw (), поскольку Circle.c не включен в grlib.h и grlib_demo.c

Примечание: — файлы grlib.h и Circle.c находятся в одной папке. Код выполняется успешно.

7

Решение

Простой ответ заключается в том, что «компилятору не нужно знать, но компоновщик должен его найти». Через несколько .o файлы, или через библиотеки, компоновщик должен быть в состоянии найти единственное определение GrCircleDraw функция.

9

Другие решения

Компилятор помещает только имя extern функция в .obj файл. Компилятору не нужно знать больше об этом.

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

Библиотеки по умолчанию обычно включаются неявно. Это усложняет вещи и создает иллюзии. Вы всегда можете указать, что вы не хотите никаких неявных библиотек и включать все явно. К сожалению, каждая система делает это по-своему.

4

Когда вы компилируете файл .o в Формат ELF, у вас есть много вещей на .o файл, такой как:

  • .text раздел, содержащий код;
  • .data, .rodata, .rss разделы, содержащие глобальные переменные;
  • .symtab содержащий список символов (функций, глобальных переменных и других) в .o (и их расположение в файле), а также символы, используемые .o файл;
  • такие разделы, как .rela.text Это список перемещений — это те изменения, которые редактор ссылок (и / или динамический компоновщик) должен будет сделать, чтобы связать различные части вашей программы вместе.

На стороне звонящего

Давайте скомпилируем простой C-файл:

extern void GrCircleDraw(int x);

int foo()
{
GrCircleDraw(42);
return 3;
}

int bla()
{
return 2;
}

с:

gcc -o test.o test.c -c

(Я использую встроенный компилятор моей системы, но он будет работать точно так же при кросс-компиляции в ARM).

Вы можете посмотреть содержимое вашего .o файла с помощью:

readelf -a test.o

В таблице символов вы найдете:

Таблица символов «.symtab» содержит 10 записей:
Num: Значение Размер Тип Bind Vis Ndx Имя
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
[...]
8: 0000000000000000 21 FUNC GLOBAL DEFAULT 1 foo
9: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND GrCircleDraw
10: 0000000000000015 11 FUNC GLOBAL DEFAULT 1 бла

Есть один символ для нашего foo функции и один для bla, Поле значения дает их местоположение в пределах .text раздел.

Существует один символ для используемого символа GrCircleDraw: это не определено, потому что эта функция не определена в этом .o файл, но остается найти в другом месте.

В таблице перемещения для .text раздел (.rela.text) ты находишь:

Раздел перемещения '.rela.text' со смещением 0x260 содержит 1 запись:
Информация о смещении Тип Sym. Значение Sym. Имя + Добавление
00000000000a 000900000002 R_X86_64_PC32 0000000000000000 GrCircleDraw - 4

Этот адрес находится в пределах foo: редактор ссылок пропустит инструкцию по этому адресу с адресом GrCircleDraw функция.

На стороне вызываемого

Теперь давайте скомпилируем реализацию GrCircleDraw:

void GrCircleDraw(int x)
{

}

Давайте посмотрим на его таблицу символов:

Таблица символов «.symtab» содержит 9 записей:
Num: Значение Размер Тип Bind Vis Ndx Имя
[...]
8: 0000000000000000 9 FUNC GLOBAL DEFAULT 1 GrCircleDraw

Имеется запись для GrCircleDraw определяя его местоположение в пределах его .text раздел.

Связывая их вместе

Поэтому, когда редактор ссылок объединяет оба файла, он становится известным:

  • какие функции определены в каком .o файл и их местоположение;
  • где в коде звонящего он должен обновиться с адресом звонящего.
4

Связывание обычно происходит следующим образом: командная строка повторяется, и каждый аргумент

  1. используется напрямую, если это объектный файл,
  2. используется в необходимом объеме (= для выполнения всех ссылок, которые до сих пор не разрешены).

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

0
По вопросам рекламы [email protected]