Элегантный способ установить базовый адрес образа ELF с помощью Linux binutils?

Для личного проекта мне нужно написать исполняемый файл, который загружается не по адресу памяти по умолчанию. Из этого вопроса SO я знаю, что могу установить адрес входа для ELF и изменить адреса разделов вручную, чтобы исполняемый файл эффективно базировался на каком-то выбранном мной адресе. Однако ответ предполагает, что это работает только в том случае, если я не инициализирую glibc (что мне нужно для этого проекта), и установка адресов памяти разделов каждый раз при компиляции будет сложной (не говоря уже об утомительной).

Кажется, должен быть лучший способ установить базовый адрес для ELF при сборке, хотя я прибегну к этому вручную с помощью скрипта после сборки, если это необходимо. Этот вариант для ld был бы идеальным, если бы он не был специфичен для порта PE:

--image-base value
  Use value as the base address of your program or dll. This is the lowest 
  memory location that will be used when your program or dll is loaded. To 
  reduce the need to relocate and improve performance of your dlls, each should 
  have a unique base address and not overlap any other dlls. The default is 
  0x400000 for executables, and 0x10000000 for dlls. [This option is specific 
  to the i386 PE targeted port of the linker]

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


person emprice    schedule 08.03.2013    source источник
comment
Сбросить встроенный файл ответов компоновщика, изменить его и передать в качестве параметра компоновщика в gcc (и, следовательно, в ld)?   -  person Marco van de Voort    schedule 09.03.2013
comment
@MarcovandeVoort Быстрый поиск в Google ничего не дал по этому поводу для ld или gcc. Можете ли вы уточнить или направить меня к нужной документации?   -  person emprice    schedule 09.03.2013
comment
Зачем вам нужно загружать не по умолчанию адрес памяти? Может быть, вы могли бы достичь своей первоначальной цели по-другому....   -  person Basile Starynkevitch    schedule 09.03.2013
comment
Вы можете передать скрипт компоновщика в ld с ключом -T. Вы можете увидеть встроенный скрипт, сделав фиктивную ссылку с ld -verbose ‹любой файл ELF›   -  person Marco van de Voort    schedule 09.03.2013
comment
@MarcovandeVoort Спасибо! Теперь это работает, хотя кажется, что некоторые из адресов, которые я пробовал, работают (например, 0x200000 или 0x500000), но не другие (например, 0x100000); когда это не работает, программа убивается. Есть ли какое-то ограничение на то, какие адреса я могу использовать (помимо адресов ядра)?   -  person emprice    schedule 10.03.2013
comment
@BasileStarynkevitch Я не вижу другого способа сделать то, что мне нужно. Я знаю, что мне нужен адрес 0x400000 для отображения памяти, поэтому мне нужно, чтобы мой исполняемый файл загружался где-то в стороне.   -  person emprice    schedule 10.03.2013
comment
nosuchthingasstars: Я предполагаю, что это должно подпадать под определенный кодовый сегмент? Я не очень хорошо разбираюсь в Linux на этом уровне, я в основном использую FreeBSD, и я знаю эти детали точки входа в основном из-за того, что возился со встроенными (Microchip) целями. Я превратил комментарии в правильный ответ, так что вы можете принять его.   -  person Marco van de Voort    schedule 10.03.2013


Ответы (1)


Точка входа ELF может быть установлена ​​в файле ответов компоновщика, который можно передать в ld с помощью -T.

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

Обратите внимание, что могут быть дополнительные ограничения (например, точка входа, находящаяся в текстовом/кодовом сегменте).

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

person Marco van de Voort    schedule 10.03.2013
comment
-v просто распечатывает версию. Вместо этого используйте --verbose. (Это приводит к большому количеству вывода, поэтому вы можете передать его через less) - person dCSeven; 18.05.2019