Как адреса памяти в бинарных программах указывают на правильное место в памяти во время выполнения? - PullRequest
0 голосов
/ 21 марта 2020

Насколько я понимаю, когда вы компилируете программу (скажем, программу C), компилятор берет ваш код и выводит исполняемую программу в двоичном (т.е. машинный код для целевой арки) формате.

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

Учитывая, что эта программа будет загружена в память в произвольном месте, как программа узнает, что это за адреса памяти? Как они устанавливаются / рассчитываются, и кто должен это делать?

Например, имеет ли двоичный файл только заполнители для областей памяти, которые заменяются ОС при загрузке? в память в первый раз?

Если необходимо динамически загрузить разделяемую библиотеку, как получается, где для этого находится место в памяти?

Как «виртуальная память» вступает в игру с этим? (если вообще)

Ответы [ 2 ]

1 голос
/ 24 марта 2020

MMU позволяют ОС создавать одно и то же адресное пространство (например, адреса от нуля до N) для каждого приложения, так что каждое приложение может быть скомпилировано для известного адресного пространства. В этой ситуации нет особой необходимости переселения. Даже в дни DOS вы могли бы иметь фиксированное смещение относительно некоторого сегмента данных, чтобы приложения могли иметь предполагаемое адресное пространство.

Ядро bootstrap для linux - это место, где вы будете см. перемещение, но само ядро ​​не так сильно или, возможно, изменилось за последние столько лет.

Загружаемые модули и общие библиотеки - это то место, где может потребоваться перемещение. По крайней мере, для популярных процессоров, работающих под управлением популярных операционных систем (linux, windows, macos, arm, x86, mips), сам код может быть скомпонован так, чтобы его можно было перемещать без изменений, если он все относительно себя, что это то, что предполагается.

Данные относительно кода, хотя, если вы хотите переместить данные, тогда типична некоторая форма таблицы, где таблица фиксирована относительно кода (или некоторого другого связанного механизма), но она содержит информацию, чтобы сказать, где данные начинаются или задаются c элементов / маркеров в начале данных, так что другие ссылки на данные могут быть относительно этого.

1 голос
/ 24 марта 2020

как программа узнает, что это за адреса памяти?

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

  1. , где находится перемещенный адрес (его смещение в коде или сегменте данных)
  2. в каком сегменте он находится
  3. к какому сегменту или символу относится
  4. какой тип перемещения должен применяться к адресу

Рассмотрим следующий простой фрагмент или исходный код Windows Переносимая исполняемая программа:

[.text]
Main:NOP
     LEA ESI,[Mem]
     ; more instructions 
[.data]
     DB "Some data"
Mem: DB "Other data"

, которые будут преобразованы в машинные инструкции и данные памяти:

|[.text]                   |[.text]
|00000000:90               |Main:NOP
|00000001:8D35[09000000]   |     LEA ESI,[Mem]
|00000007:                 |     ; more instructions
|[.data]                   |[.data]
|00000000:536F6D6520646174~|     DB "Some data"
|00000009:4F74686572206461~|Mem: DB "Other data"

Компилятор не знает виртуальный адрес Mem, он знает только, что он расположен 0x00000009 байтов от начала .data сегмента, поэтому он вставит этот временный номер в код операции LEA ESI,[Mem] и создаст перемещение заполнителя (расположенного в сегменте .text со смещением 0x00000003) относительно сегмента .data.

Во время компоновки компоновщик решает, что сегмент .text будет загружен по виртуальному адресу 0x00401000 и сегмент .data по VA 0x00402000. Затем компоновщик читает запись о перемещении и изменяет местозаполнитель, добавляя 0x00402000. Тогда инструкция LEA ESI,[Mem] в связанном исполняемом файле будет 8D3509204000, что является окончательным фиксированным виртуальным адресом Mem. Мы сможем увидеть этот адрес в отладчике во время выполнения.

Перемещения присутствуют и в связанных исполняемых файлах (16-битный DOS MZ или Windows PE), в случае, если они не могут быть загружается по виртуальному адресу базы изображений, принятому во время соединения. Со связыванием библиотек SO в Linux это более сложно, см. Главу 2 Dynami c связывание в http://www.skyfree.org/linux/references/ELF_Format.pdf

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...