Ответ 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 некоторого байта, вы должны найти его смещение в разделе и добавить базу раздела.