VA (виртуальный адрес) и RVA (относительный виртуальный адрес)

Файл, который вводится в качестве вставки в компоновщик, называется Object File . Компилятор создает файл изображения , который, в свою очередь, используется в качестве входа загрузчика.

Разметка из « Спецификация формата файлов Microsoft Executable и Common Object File Specification »

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

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

VA (виртуальный адрес) . То же, что и RVA, за исключением того, что базовый адрес файла изображения не вычитается. Адрес называется «VA», потому что Windows создает отдельное пространство VA для каждого процесса, независимо от физической памяти. Для почти всех целей VA следует рассматривать только как адрес. VA не так предсказуем, как RVA, потому что загрузчик может не загружать изображение в предпочтительном месте.

Даже после прочтения этого я все еще не понимаю. У меня много вопросов. Может ли кто-нибудь объяснить это практическим способом. Пожалуйста, придерживайтесь терминологии Object File & Image File как указано.

Все, что я знаю об адресах, это то, что

  • Ни в объектном файле, ни в файле изображений мы не знаем точных мест памяти, поэтому,
  • Ассемблер при создании Object File вычисляет адреса относительно разделов .data & .text (для имен функций).
  • Linker принимает несколько объектных файлов в качестве входных данных, генерирует один файл изображения. Во время генерации он сначала объединяет все разделы каждого объектного файла, и при слиянии он повторно пересчитывает смещения адреса по отношению к каждому разделу. И нет ничего подобного глобальным смещениям.

Если в том, что я знаю, что-то не так, пожалуйста, поправьте меня.

РЕДАКТИРОВАТЬ:

Прочитав ответ, данный Фрэнсис, я понимаю, что такое Physical Address, VA & RVA и какова связь между ними.

RVAs всех переменных и методов должны вычисляться компоновщиком во время перемещения. Итак, (значение RVA метода / переменной) == (его смещение от начала файла) ? должно быть правдой. Но удивительно, его нет. Почему так?

Я проверил это, используя PEView на c:\WINDOWS\system32\kernel32.dll и обнаружил, что:

  1. RVA & FileOffset одинаковы до начала разделов. ( .text – это первый раздел в этой DLL).
  2. С начала .text до .data , .rsrc до последнего байта последнего раздела ( .reloc ) RVA и FileOffset отличаются. & также RVA первого байта первой секции «всегда» отображается как 0x1000
  3. Интересно, что байты каждого раздела непрерывны в FileOffset. Я имею в виду, что другой раздел начинается с следующего байта последнего байта раздела. Но если я вижу то же самое в RVA, это огромный разрыв между RVAs последнего байта раздела и первого байта следующего раздела.

Мое предположение:

  1. Все байты данных, которые были до первого ( .text здесь) раздела, «не» фактически загружены в пространство VA процесса, эти байты данных просто используются для поиска и описания этих разделов. Их можно назвать «данными метаданных».

    Так как они не загружаются в VA-пространство процесса. использование термина RVA также бессмысленно, поэтому RVA == FileOffset для этих байтов.

  2. Поскольку,

    • Термин RVA действителен только для тех байтов, которые будут фактически загружены в пространство VA.
    • байты .text , .data , .rsrc , .reloc – это такие байты.
    • Вместо запуска с RVA 0x00000 программное обеспечение 0x00000 запускает его с 0x1000 .
  3. Я не могу понять, почему произошло третье наблюдение. Я не могу объяснить.

Большинство процессов Windows (* .exe) загружаются в (адрес пользователя) адрес памяти 0x00400000, это то, что мы называем «виртуальным адресом» (VA) – потому что они видны только для каждого процесса и будут преобразованы в разные физические адреса посредством ОС (видимо уровнем ядра / драйвера).

Например, возможный адрес физической памяти (видимый процессором):

 0x00300000 on physical memory has process A's main 0x00500000 on physical memory has process B's main 

И ОС может иметь таблицу сопоставления:

 process A's 0x00400000 (VA) = physical address 0x00300000 process B's 0x00400000 (VA) = physical address 0x00500000 

Затем, когда вы попытаетесь прочитать 0x004000000 в процессе A, вы получите контент, который находится на 0x00300000 физической памяти.

Что касается RVA, он просто предназначен для облегчения перемещения. При загрузке перегружаемых модhive (например, DLL) система попытается сместить ее через пространство памяти процесса. Поэтому в макете файла он помещает «относительный» адрес для расчета.

Например, DLL C может иметь этот адрес:

  RVA 0x00001000 DLL C's main entry 

При загрузке в процесс A по базовому адресу 0x10000000 основная запись C становится

  VA = 0x10000000 + 0x00001000 = 0x10001000 (if process A's VA 0x10000000 mapped to physical address was 0x30000000, then C's main entry will be 0x30001000 for physical address). 

При загрузке в процесс B по базовому адресу 0x32000000 основная запись C становится

  VA = 0x32000000 + 0x00001000 = 0x32001000 (if process B's VA 0x32000000 mapped to physical address was 0x50000000, then C's main entry will be 0x50001000 for physical address). 

Обычно RVA в файлах изображений относится к базовому адресу обработки при загрузке в память, но некоторые RVA могут относиться к начальному адресу «раздела» в файлах изображений или объектов (вам нужно проверить спецификацию формата PE для подробностей). Независимо от того, что RVA относится к «некоторой» базе VA.

Обобщить,

  1. Адрес физической памяти – это то, что видит процессор
  2. Virtual Addreess (VA) относится к физическому адресу, за каждый процесс (управляемый ОС)
  3. RVA относится к VA (база файлов или базовая база), для каждого файла (управляется компоновщиком и загрузчиком)

(править) о новом вопросе коготь:

Значение RVA метода / переменной НЕ всегда является его смещением от начала файла. Они обычно относятся к некоторому VA, который может быть базовым адресом загрузки по умолчанию или базовой базой VA – вот почему я говорю, что вы должны проверить спецификацию формата PE для деталей.

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

Что касается ваших догадок, они очень близки к правильным ответам:

  1. Обычно мы не будем обсуждать «RVA» перед разделами, но заголовок PE по-прежнему будет загружен до конца заголовков разделов. Разрыв между заголовком раздела и корпусом секции (если есть) не будет загружен. Вы можете проверить это с помощью отладчиков. Более того, когда есть какой-то промежуток между разделами, они могут быть не загружены.

  2. Как я уже сказал, RVA просто «относительно некоторого VA», независимо от того, что это VA (хотя, говоря о PE, VA обычно ссылается на адрес базы нагрузки). Когда вы читаете спецификацию формата TE, вы можете найти некоторые «RVA», которые относятся к некоторому специальному адресу, такому как начальный адрес ресурса. Список PEView RVA от 0x1000 состоит в том, что этот раздел начинается с 0x1000. Почему 0x1000? Поскольку компоновщик оставил 0x1000 байт для заголовка PE, значит, RVA начинается с 0x1000.

  3. То, что вы пропустили, – это понятие «секция» на этапе загрузки PE. PE может содержать несколько «разделов», каждый раздел соответствует новому стартовому адресу VA. Например, это сбрасывается из win7 kernel32.dll:

     # Name VirtSize RVA PhysSize Offset 1 .text 000C44C1 00001000 000C4600 00000800 2 .data 00000FEC 000C6000 00000E00 000C4E00 3 .rsrc 00000520 000C7000 00000600 000C5C00 4 .reloc 0000B098 000C8000 0000B200 000C6200 

    Существует невидимый «0-заголовок RVA = 0000, SIZE = 1000», который принудительно запускает .text для запуска в RVA 1000. Секции должны быть непрерывными при загрузке в память (то есть VA), поэтому их RVA является непрерывным. Однако, поскольку память выделяется страницами, она будет кратной размеру страницы (4096 = 0x1000 байтов). Вот почему секция №2 начинается с 1000 + C5000 = C6000 (C5000 поставляется с C44C1).

    Чтобы обеспечить сопоставление памяти, эти разделы все равно должны быть выровнены по определенному размеру (размер выравнивания файлов – решить по компоновщику. В моем примере выше это 0x200 = 512 байт), который контролирует поле PhysSize. Смещение означает «смещение к началу физического PE-файла».

    Таким образом, заголовки занимают 0x800 байт файла (и 0x1000 при сопоставлении с памятью), что является смещением раздела №1. Затем, выровняв свои данные (c44c1 bytes), мы получим физическое значение C4600. C4600 + 800 = C4E00, что является точно смещением второй секции.

    Хорошо, это связано с загрузкой всего ПО, поэтому немного сложно понять …

(edit) позвольте мне снова сделать новое простое резюме.

  1. Файлы RVA в файлах DLL / EXE (PE Format) обычно относятся к «базовому адресу нагрузки в памяти» (но не всегда – вы должны прочитать спецификацию)
  2. Формат PE содержит структуру отображения «раздела» для сопоставления физического содержимого файла в памяти. Таким образом, RVA на самом деле не относится к файловому смещению.
  3. Чтобы вычислить RVA некоторого байта, вы должны найти его смещение в разделе и добавить базу раздела.

Относительный виртуальный адрес – это смещение от адреса, на котором загружен файл. Вероятно, самый простой способ получить идею – пример. Предположим, у вас есть файл (например, DLL), загруженный по адресу 1000h. В этом файле у вас есть переменная в RVA 200h. В этом случае VA этой переменной (после того, как DLL отображается в память) составляет 1200h (то есть 1000h базовый адрес DLL плюс 200h RVA (смещение) к переменной.

  • Технические детали Android Garbage Collector
  • Правильное использование интерфейса IDisposable
  • Оператор блокировки vs Метод Monitor.Enter
  • Android-java- Как отсортировать список объектов по определенному значению внутри объекта
  • Ошибка java.lang.OutOfMemoryError: превышен верхний предел GC
  • Очистите ArrayList или просто создайте новый, и пусть старый будет собран мусором?
  • finalize (), вызванный для объекта с высокой степенью достижимости в Java 8
  • ASP MVC: Когда вызывается IController Dispose ()?
  • Interesting Posts

    xpath найти, если узел существует

    Разделить строку на подстроки равной длины в Java

    Объект или сложный тип ” не могут быть сконструированы в запросе LINQ to Entities

    Promise.all потребляет всю мою RAM

    Пропустить обновление W8 Pro до W10 и установить W10 и использовать ключ от W8 Pro?

    Использовать клавиатуру bluetooth для доступа / редактирования BIOS?

    Есть ли инструменты для выравнивания динамических дисков в Windows 7?

    Удалите белый фон с изображения и сделайте его прозрачным

    Получение «низкого уровня ошибок памяти» в Windows 7 64-бит с 8 ГБ ОЗУ

    Лучший способ автоматически переносить тесты с JUnit 3 на JUnit 4?

    Извлечь и загрузить DLL из JAR

    Windows Phone 8.1. Переключение видимости TextBlock в DataTemplate

    Если страница «забыл пароль?» Отправляет ваш старый пароль, является ли это окончательным доказательством того, что они сохранили его в виде обычного текста?

    Угловой разрыв JS ForEach

    Самый быстрый способ найти расстояние между двумя лат / длинными точками

    Давайте будем гением компьютера.