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

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

реклама от "Microsoft Portable исполняемый и общий формат объектного файла спецификация"

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

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

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

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

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

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

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

EDIT:

после прочтения ответ, данный Фрэнсисом, мне ясно, что такое физический адрес, VA & RVA и каковы отношения между ними.

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

я проверил это с помощью PEView on c:WINDOWSsystem32kernel32.dll и нашли что:

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

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

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

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

  2. С,

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

2 ответов


большинство процессов 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, он просто предназначен для облегчения перемещения. При загрузке relocable модулями (например, библиотеки 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. физический адрес памяти-это то, что видит CPU
  2. Virtual Addreess (VA) относительно физического адреса, на процесс (управляемый ОС)
  3. RVA относительно VA (базы файлов или базы разделов), на файл (управляется компоновщиком и загрузчиком)

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

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

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

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

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

  2. как я уже сказал, RVA просто "относительно некоторого VA", независимо от того, что это VA (хотя, когда речь идет о PE, VA обычно относится к базовому адресу нагрузки). Когда вы читаете спецификацию формата PE, вы может найти некоторый "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, размер=1000", который принудительно .текст для начала на RVA 1000. Разделы должны быть непрерывными при загрузке в память (т. е. VA), поэтому их RVA является непрерывным. Однако, поскольку память выделяется страницами, она будет кратна размеру страницы (4096=0x1000 байт). Вот почему раздел #2 начинается с 1000 + C5000 = C6000 (C5000 происходит от C44C1).

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

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

    OK, это связано с весь материал загрузки PE поэтому может быть немного трудно понять...

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

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

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