Как лучше всего передать глобальную таблицу смещения (GOT) для моего языка на платформе x86?

Я пишу небольшой загрузчик программ для своего языка, потому что я разочаровался в понимании формата ELF (и, делая это, я, возможно, в конечном итоге пойму его лучше). Я mmap файлы на память и tux радуется чему угодно..

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

Проблема в том, как я могу пройти GOT для моей программы?

Первое, что приходит на ум, это указать его в аргументе регистра или стека. В регистре было бы здорово, но x86 отстает по количеству регистров. Это может означать, что я потеряю ebx, ebp или что-то в этом роде. В разумной архитектуре это был бы справедливый компромисс. В x86 он чувствует себя немного неудачно.

Разборка разделяемой библиотеки показывает мне, что gcc делает это как относительную IP-адресацию. Если бы я сделал это, это было бы:

    call 0
here:
    pop eax
    ; do something with [eax + (got - here) + index*4]

Хотя отчасти это кажется сложным. Мне не нравится это делать.

Есть еще идеи, кто-нибудь?

Редактировать: При работе с несколькими библиотеками я понял следующее: у меня будет несколько GOT для каждого приложения, и использование определенных GOT зависит от того, в каком фрагменте кода я нахожусь. Поэтому хранение GOT в отдельный регистр потребует некоторых дополнительных уловок, о которых я не знаю. Я хотел бы знать, как они решают эту проблему при сохранении GOT в реестрах.


person Cheery    schedule 26.02.2009    source источник


Ответы (1)


Вы можете использовать один из сегментных регистров (или их базу) в качестве основы вашего бинарного образа. Таким образом, вы бы ссылались на свои глобальные данные, например. как ФС:xxx.

Эти регистры являются остатками так называемой модели сегментированной памяти. По сути, сегменты представляют собой «окна» в линейное адресное пространство с заданной базой (и лимитом), и если вы используете их для адресации (например, если адрес равен 0010:00000001), результирующий адрес будет (база сегмента с селектором 0010). )+00000001. База (как и другие параметры) сегмента хранится в таблице дескрипторов (их больше), которая представляет собой специальную область в памяти. Их можно изменить только в режиме ядра, в Linux есть системные вызовы, которые делают это (modify_ldt, arch_prctl). В 64-битном режиме ситуация немного сложнее.

Для справки см. руководство по архитектуре AMD64., особенно Том 2: Системное программирование.

person jpalecek    schedule 26.02.2009
comment
Мне нужно прочитать об этих сегментных регистрах. До сих пор я игнорировал их как наследие. - person Cheery; 27.02.2009
comment
На самом деле, вы можете использовать GS и FS в 64-битном режиме. Они являются исключениями из режима плоской адресации. - person Nathan Fellman; 27.02.2009