web-dev-qa-db-fra.com

VA (adresse virtuelle) & RVA (adresse virtuelle relative)

Un fichier donné en entrée à l'éditeur de liens est appelé Fichier objet . L'éditeur de liens produit un fichier image , qui à son tour est utilisé comme entrée par le chargeur.

Un texte de présentation de " Microsoft Portable Executable et Common Object File Format Specification "

RVA (adresse virtuelle relative) . Dans un fichier image, l'adresse d'un élément après son chargement en mémoire, avec l'adresse de base du fichier image soustraite. La RVA d'un élément diffère presque toujours de sa position dans le fichier sur le disque (pointeur de fichier).

Dans un fichier objet, un RVA est moins significatif car les emplacements de mémoire ne sont pas affectés. Dans ce cas, une RVA serait une adresse dans une section (décrite plus loin dans ce tableau), à laquelle une relocalisation est appliquée ultérieurement lors de la liaison. Par souci de simplicité, un compilateur doit simplement mettre le premier RVA de chaque section à zéro.

VA (adresse virtuelle) . Identique à RVA, sauf que l'adresse de base du fichier image n'est pas soustraite. L'adresse est appelée "VA" car Windows crée un espace VA distinct pour chaque processus, indépendamment de la mémoire physique. Pour presque tous les usages, un VA devrait être considéré comme une simple adresse. A VA n'est pas aussi prévisible qu'un RVA car le chargeur peut ne pas charger l'image à son emplacement préféré.

Même après avoir lu ceci, je ne comprends toujours pas. J'ai beaucoup de questions. Quelqu'un peut-il l'expliquer de manière pratique. Veuillez respecter la terminologie de Object File & Image File comme indiqué.

Tout ce que je sais des adresses, c'est que

  • Ni dans le fichier objet ni dans le fichier image, nous ne connaissons pas les emplacements de mémoire exacts donc,
  • L'assembleur lors de la génération du fichier objet calcule les adresses par rapport aux sections .data & .text (pour les noms de fonction).
  • L'éditeur de liens prenant plusieurs fichiers objet en entrée génère un fichier image. Lors de la génération, il fusionne d'abord toutes les sections de chaque fichier objet et lors de la fusion, il recalcule à nouveau les décalages d'adresse par rapport à chaque section. Et, il n'y a rien de tel que des compensations globales.

S'il y a quelque chose qui ne va pas dans ce que je sais, veuillez me corriger.

MODIFIER:

Après avoir lu la réponse donnée à Francis, je sais clairement quelle est l'adresse physique, VA & RVA et quelle est la relation entre eux.

Les RVA de toutes les variables et méthodes doivent être calculées par l'éditeur de liens lors de la relocalisation. Donc, (la valeur de RVA d'une méthode/variable) == (son décalage par rapport au début du fichier) ? doit être vrai. Mais étonnamment, ce n'est pas le cas. Pourquoi

J'ai vérifié cela en utilisant PEView on c:\WINDOWS\system32\kernel32.dll et a constaté que:

  1. RVA et FileOffset sont les mêmes jusqu'au début des sections. (.text est la première section de cette dll).
  2. Depuis le début de .text par .data, .rsrc jusqu'au dernier octet de la dernière section (.reloc) RVA et FileOffset sont différents. & aussi le RVA du premier octet de la première section est "toujours" affiché comme 0x1000
  3. Une chose intéressante est que les octets de chaque section sont continus dans FileOffset. Je veux dire qu'une autre section commence à l'octet suivant du dernier octet d'une section. Mais si je vois la même chose dans RVA, il s'agit d'un énorme écart entre les RVA du dernier octet d'une section et le premier octet de la section suivante.

My Guess:

  1. Tous, les octets de données qui étaient avant le premier (.text ici) les sections ne sont "pas" réellement chargées dans VA espace du processus, ces octets de données sont juste utilisés pour localiser et décrire ces sections. Ils peuvent être appelés "données de méta-section ".

    Puisqu'ils ne sont pas chargés dans VA espace de processus. L'utilisation du terme RVA est également dénuée de sens c'est la raison pour laquelle RVA == FileOffset pour ces octets.

  2. Puisque,

    • Le terme RVA n'est valide que pour les octets qui seront réellement chargés dans l'espace VA.
    • les octets de .text, .data, .rsrc, .reloc sont de tels octets.
    • Au lieu de partir de RVA 0x00000 Le logiciel PEView démarre à partir de 0x1000.
  3. Je ne comprends pas pourquoi la 3ème observation. Je ne peux pas expliquer.

47
claws

La plupart des processus Windows (* .exe) sont chargés dans l'adresse mémoire (mode utilisateur) 0x00400000, c'est ce que nous appelons l '"adresse virtuelle" (VA) - car ils ne sont visibles que pour chaque processus et seront convertis en différentes adresses physiques par l'OS (visible par la couche noyau/pilote).

Par exemple, une adresse mémoire physique possible (visible par le CPU):

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

Et le système d'exploitation peut avoir une table de mappage:

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

Ensuite, lorsque vous essayez de lire 0x004000000 dans le processus A, vous obtiendrez le contenu qui se trouve sur 0x00300000 de mémoire physique.

En ce qui concerne RVA, il est simplement conçu pour faciliter la relocalisation. Lors du chargement de modules déplaçables (par exemple, DLL), le système essaie de le faire glisser dans l'espace mémoire du processus. Ainsi, dans la disposition des fichiers, il met une adresse "relative" pour aider au calcul.

Par exemple, un DLL C peut avoir cette adresse:

 RVA 0x00001000 DLL C's main entry

Lors du chargement dans le processus A à l'adresse de base 0x10000000, l'entrée principale de C devient

 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).

Lorsqu'elle est chargée dans le processus B à l'adresse de base 0x32000000, l'entrée principale de C devient

 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).

Habituellement, le RVA dans les fichiers image est relatif à l'adresse de base du processus lors du chargement en mémoire, mais certains RVA peuvent être relatifs à l'adresse de début de "section" dans les fichiers image ou objet (vous devez vérifier les spécifications de format PE pour plus de détails). Quoi qu'il en soit, le RVA est relatif à "certains" VA de base.

Résumer,

  1. L'adresse de mémoire physique est ce que le CPU voit
  2. L'adresse virtuelle (VA) est relative à l'adresse physique, par processus (géré par le système d'exploitation)
  3. RVA est relatif à VA (base de fichiers ou base de sections), par fichier (géré par l'éditeur de liens et le chargeur)

(modifier) ​​concernant la nouvelle question de griffe:

La valeur de RVA d'une méthode/variable n'est PAS toujours son décalage depuis le début du fichier. Ils sont généralement relatifs à certains VA, qui peuvent être une adresse de base de chargement par défaut ou une base de section VA - c'est pourquoi je dis que vous devez vérifier le spécification de format PE pour plus de détails .

Votre outil, PEView essaie d'afficher le RVA de chaque octet pour charger l'adresse de base. Étant donné que les sections commencent à une base différente, la RVA peut devenir différente lors du franchissement des sections.

Concernant vos suppositions, elles sont très proches des bonnes réponses:

  1. Habituellement, nous ne discuterons pas du "RVA" avant les sections, mais l'en-tête PE sera toujours chargé jusqu'à la fin des en-têtes de section. L'écart entre l'en-tête de section et le corps de section (le cas échéant) ne sera pas chargé. Vous pouvez l'examiner par les débogueurs. De plus, quand il y a un écart entre les sections, elles peuvent ne pas être chargées.

  2. Comme je l'ai dit, RVA est simplement "par rapport à certains VA", peu importe ce que VA c'est (bien qu'en parlant de PE, le VA fait généralement référence à l'adresse de base de charge). Lorsque vous lisez la spécification de format PE, vous pouvez trouver un "RVA" qui est relatif à une adresse spéciale comme l'adresse de démarrage de la ressource. La liste PEView RVA de 0x1000 est parce que cette section commence à 0x1000. Pourquoi 0x1000? Parce que l'éditeur de liens a laissé 0x1000 octets pour l'en-tête PE, donc le RVA commence à 0x1000.

  3. Ce que vous avez manqué, c'est le concept de "section" dans l'étape de chargement PE. Le PE peut contenir plusieurs "sections", chaque section est mappée vers une nouvelle adresse de démarrage VA. Par exemple, elle est transférée de 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
    

    Il y a un "0 en-tête RVA = 0000, SIZE = 1000" invisible qui a forcé .text à démarrer à RVA 1000. Les sections doivent être continues lorsqu'elles sont chargées en mémoire (c'est-à-dire, VA) afin que leur RVA soit continu. Cependant, puisque la mémoire est allouée par pages, elle sera multiple de la taille de la page (4096 = 0x1000 octets). C'est pourquoi la section # 2 commence à 1000 + C5000 = C6000 (C5000 vient de C44C1).

    Afin de fournir le mappage de la mémoire, ces sections doivent toujours être alignées par une certaine taille (taille d'alignement du fichier - décider par l'éditeur de liens. Dans mon exemple ci-dessus, c'est 0x200 = 512 octets), qui contrôle le champ PhysSize. Décalage signifie "décalage au début du fichier PE physique".

    Ainsi, les en-têtes occupent 0x800 octets de fichier (et 0x1000 lorsqu'ils sont mappés en mémoire), ce qui est le décalage de la section # 1. Ensuite, en alignant ses données (octets c44c1), nous obtenons la taille physique C4600. C4600 + 800 = C4E00, qui est exactement le décalage de la deuxième section.

    OK, cela est lié à tout le chargement de PE, donc cela peut être un peu difficile à comprendre ...

(modifier) ​​permettez-moi de faire à nouveau un nouveau résumé simple.

  1. Les "RVA" dans les fichiers DLL/EXE (format PE) sont généralement relatifs à "l'adresse de base de chargement en mémoire" (mais pas toujours - vous devez lire la spécification)
  2. Le format PE contient une structure de mappage "section" pour mapper le contenu du fichier physique en mémoire. La RVA n'est donc pas vraiment relative à l'offset du fichier.
  3. Pour calculer un RVA d'un octet, vous devez trouver son décalage dans la section et ajouter la base de la section.
62
Francis

Une adresse virtuelle relative est un décalage par rapport à l'adresse à laquelle le fichier est chargé. La façon la plus simple d'obtenir l'idée est probablement avec un exemple. Supposons que vous ayez un fichier (par exemple, une DLL) chargé à l'adresse 1000h. Dans ce fichier, vous avez une variable à RVA 200h. Dans ce cas, le VA de cette variable (après le DLL est mappé en mémoire)) est de 1200h (c'est-à-dire l'adresse de base de 1000h du DLL plus le RVA 200h (offset) à la variable.

11
Jerry Coffin