Подтвердить что ты не робот

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

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

Сводка из " Спецификация формата файлов Microsoft Executable и Common Object

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

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

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

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

Все, что я знаю об адресах, заключается в том, что

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

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

EDIT:

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

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

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

  • RVA и FileOffset одинаковы до начала разделов. (.text - это первый раздел в этой DLL).
  • В начале .text через .data, .rsrc до последнего байта последнего раздела (.reloc) значения RVA и FileOffset различны. а также RVA первого байта первой секции "всегда" отображается как 0x1000
  • Интересно, что байты каждого раздела непрерывны в FileOffset. Я имею в виду, что другой раздел начинается с следующего байта последнего байта раздела. Но если я вижу то же самое в RVA, это огромный разрыв между RVAs последнего байта раздела и первого байта следующего раздела.

Мой угадай:

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

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

  • Так как,

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

4b9b3361

Ответ 1

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

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

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

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

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

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

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

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

 RVA 0x00001000 DLL C main entry

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

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

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

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

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

Подводя итог,

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

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

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

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

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

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

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

  • То, что вы пропустили, - это понятие "раздела" на этапе загрузки 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", который принудительно запускает текст в 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, что является точно смещением второй секции.

    ОК, это связано с загрузкой всего PE файла, поэтому может быть немного сложно понять...

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

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

Ответ 2

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