statique int arr [10] l'adresse mémoire se termine toujours par 060

17

J'ai un programme ca qui ressemble à ça

principal c

#include <stdio.h>
#define SOME_VAR 10

static int heap[SOME_VAR];


int main(void) {
    printf("%p", heap);
    return 0;
}

et sort cela lorsque j'exécute le programme compilé plusieurs fois

0x58aa7c49060
0x56555644060
0x2f8d1f8e060
0x92f58280060
0x59551c53060
0xd474ed6e060
0x767c4561060
0xf515aeda060
0xbe62367e060

Pourquoi ça finit toujours en 060? Et le tableau est-il stocké en tas?

Edit: je suis sur Linux et j'ai ASLR sur. J'ai compilé le programme en utilisant gcc

linuxlmao
la source
2
Quel système d'exploitation? Quel compilateur?
Andrew Henle
2
La variable n'est pas dans le tas, elle se trouve dans la section data ou bss de l'espace d'adressage du programme, voir en.wikipedia.org/wiki/Static_variable . Je suppose que le programme sera toujours placé à une adresse mémoire à une certaine limite, par exemple divisible par 0x1000, et la variable est placée par le compilateur à un décalage fixe dans l'espace d'adressage du programme.
Bodo

Réponses:

15

Les adresses diffèrent en raison de l'ASLR (ramdomisation de la disposition de l'espace d'adressage). En utilisant cela, le binaire peut être mappé à différents emplacements dans l'espace d'adressage virtuel.

heapContrairement à son nom, la variable n'est pas située sur le tas, mais sur le bss. Le décalage dans l'espace d'adressage est donc constant.

Les pages sont mappées avec une granularité de page, qui est de 4096 octets (hex: 0x1000) sur de nombreuses plates-formes. C'est la raison pour laquelle les trois derniers chiffres hexadécimaux de l'adresse sont les mêmes.

Lorsque vous avez fait de même avec une variable de pile , l'adresse peut même varier dans les derniers chiffres sur certaines plates-formes (à savoir Linux avec des noyaux récents), car la pile n'est pas seulement mappée ailleurs, mais reçoit également un décalage aléatoire au démarrage.

Ctx
la source
ASLR randomise la base de chargement si je me souviens bien. L'adresse de la section est basée sur cette adresse.
Afshin
J'utilise un livre sur la programmation ANSI-C orientée objet par Axel-Thobias Schreiner. Le livre est écrit dans quelque chose comme 1993. Savez-vous si la disposition de la mémoire était différente à l'époque? Si ce n'était pas le cas, pourquoi aurait-il pu nommer la variable heapalors qu'elle n'est pas en tas?
linuxlmao
Est-ce que 4096 se traduit en 060 d'une certaine manière ou 0x1000 se traduit-il en 060 sinon je ne comprends pas ce que vous entendez par cela étant la raison de la fin? Je pensais que cela pourrait avoir à voir avec la taille du tableau étant quelque chose qui est traduit en 060 en hexadécimal, par exemple décimal
linuxlmao
2
@linuxlmao Le décalage est par exemple 14060, donc lorsque vous ajoutez un multiple d'une taille de page (0x1000), les trois derniers chiffres restent 060.
Ctx
4

Si vous utilisez Windows, la raison en est la structure PE .

Votre heapvariable est stockée dans une .datasection de fichier et son adresse est calculée en fonction du début de cette section. Chaque section est chargée dans une adresse indépendamment, mais son adresse de départ est multiple de la taille de la page. Parce que vous n'avez pas d'autres variables, son adresse est probablement le début de la .datasection, donc son adresse sera multiple de la taille du bloc.

Par exemple, voici le tableau de la version Windows compilée de votre code: sections La .textsection est où se trouve votre code compilé et .datacontient votre heapvariable. Lorsque votre PE est chargé en mémoire, les sections sont chargées à des adresses différentes et retournées par VirtualAlloc()et seront multiples de taille de page. Mais l'adresse de chaque variable est relative au début de la section qui est maintenant une taille de page. Ainsi, vous verrez toujours un nombre fixe sur les chiffres inférieurs. Étant donné que l'adresse relative heapdu début de la section est basée sur le compilateur, les options de compilation, etc., vous verrez un nombre différent du même code mais des compilateurs différents, mais à chaque fois ce qui sera imprimé est fixe.

Lorsque je compile du code, j'ai remarqué qu'il heapest placé sur des 0x8B0octets après le début de la .datasection. Donc, chaque fois que j'exécute ce code, mon adresse se termine 0x8B0.

Afshin
la source
J'utilise un livre sur la programmation ANSI-C orientée objet par Axel-Thobias Schreiner. Le livre est écrit dans quelque chose comme 1993. Savez-vous si la disposition de la mémoire était différente à l'époque? Si ce n'était pas le cas, pourquoi aurait-il pu nommer la variable heapalors qu'elle n'est pas en tas?
linuxlmao
2
@linuxlmao C'était peut-être différent. En 1993, Windows était un système d'exploitation 16 bits, avec une segmentation de la mémoire et toutes sortes de choses déroutantes. Ce n'était pas une architecture 32 bits à mémoire plate comme c'est le cas actuellement. Mais ce genre de choses explique pourquoi poser / répondre à des questions générales sur la disposition d'un programme binaire en mémoire n'est pas utile. Comprenez ce que le standard du langage C vous garantit en général , et c'est tout ce que vous devez savoir. Ne vous inquiétez de la mise en page réelle que si vous déboguez un problème spécifique, puis utilisez un débogueur
Cody Gray
non, la variable ne doit pas être créée sur le tas, même sur les anciens systèmes, car elle n'a pas été allouée avec malloc et a une durée de stockage statique
phuclv
@Afshin J'adresse le commentaire du PO ci
phuclv
@phuclv désolé, parce que vous ne l'avez pas mentionné, je pensais que vous vous adressiez à moi. :)
Afshin
4

Le compilateur est arrivé à mettre heapà l'offset 0x60 octets dans un segment de données qu'il possède, probablement parce que le compilateur a d'autres éléments dans les premiers octets 0x60, tels que les données utilisées par le code qui démarre la mainroutine. C'est pourquoi vous voyez «060»; c'est exactement là où cela s'est passé, et cela n'a pas beaucoup d'importance.

La randomisation de la configuration de l'espace d'adressage modifie la ou les adresses de base utilisées pour diverses parties de la mémoire du programme, mais elle le fait toujours en unités de 0x1000 octets (car cela évite de causer des problèmes d'alignement et d'autres problèmes). Vous voyez donc que les adresses fluctuent par multiples de 0x1000, mais les trois derniers chiffres ne changent pas.

La définition static int heap[SOME_VAR];définit heapavec la durée de stockage statique. Les implémentations C typiques le stockent dans une section de données générales, pas dans le tas. Le «tas» est un terme impropre pour la mémoire qui est utilisée pour l'allocation dynamique. (Il s'agit d'un terme impropre car les mallocimplémentations peuvent utiliser une variété de structures de données et d'algorithmes, non limités aux tas. Ils peuvent même utiliser plusieurs méthodes dans une seule implémentation.)

Eric Postpischil
la source