Пример сценария минимального запуска компоновщика
Техника упоминалась по адресу: https://stackoverflow.com/a/4081574/895245, но сейчас я приведу конкретный пример.
main.c
#include <stdio.h>
int __attribute__((section(".mySection"))) myvar = 0x9ABCDEF0;
int main(void) {
printf("adr %p\n", (void*)&myvar);
printf("val 0x%x\n", myvar);
myvar = 0;
printf("val 0x%x\n", myvar);
return 0;
}
link.ld
SECTIONS
{
.mySegment 0x12345678 : {KEEP(*(.mySection))}
}
GitHub upstream .
Скомпилируйте и запустите:
gcc -fno-pie -no-pie -o main.out -std=c99 -Wall -Wextra -pedantic link.ld main.c
./main.out
Выход:
adr 0x12345678
val 0x9abcdef0
val 0x0
Итак, мы видим, что он был помещен по желаемому адресу.
Я не могу найти, где это задокументировано в руководстве GCC, но следующий синтаксис:
gcc link.ld main.c
, кажется, добавляет данный скрипт компоновщика к скрипту по умолчанию, который будет использоваться.
-fno-pie -no-pie
требуется, потому что цепочка инструментов Ubuntu теперь настроена на генерацию исполняемых файлов PIE по умолчанию, что заставляет ядро Linux каждый раз размещать исполняемый файл по другому адресу, что мешает нашему эксперименту. См. Также: Что такое опция -fPIE для независимых от позиции исполняемых файлов в gcc и ld?
TODO: компиляция выдает предупреждение:
/usr/bin/x86_64-linux-gnu-ld: warning: link.ld contains output sections; did you forget -T?
Я что-то не так делаю? Как от этого избавиться? Смотрите также: Как убрать предупреждение: link.res содержит выходные разделы; ты забыл -T?
Проверено на Ubuntu 18.10, GCC 8.2.0.