2010-08-25 5 views
9

Je peux obtenir l'adresse de la fin du tas avec sbrk(0), mais est-il possible d'obtenir par programme l'adresse du début du tas, autrement qu'en analysant le contenu de /proc/self/maps?Comment obtenir par programme l'adresse du tas sur Linux

+0

Cela me rend confus ... si je reçois un tas avec p = (int *) malloc (sizeof (int)); , alors pourquoi je ne peux pas obtenir l'adresse de départ du tas par p? – bazysong

Répondre

12

Je pense que l'analyse /proc/self/maps est le seul moyen fiable sur le Linux pour trouver le segment de tas. Et n'oubliez pas que certains allocateurs (dont un dans mon SLES) utilisent pour les gros blocs mmap() donc la mémoire ne fait plus partie du tas et peut être à n'importe quel emplacement aléatoire.

Sinon, normalement ld ajoute un symbole qui marque la fin de tous les segments dans elf et le symbole est appelé _end. .: par exemple

extern void *_end; 
printf("%p\n", &_end); 

Il correspond à la fin de la .bss, traditionnellement le dernier segment d'Elf. Après l'adresse, avec un peu d'alignement, suit normalement le tas. Stack (s) et mmap() s (y compris les bibliothèques partagées) se trouvent aux adresses les plus élevées de l'espace adresse. Je ne suis pas sûr de la façon dont il est portable, mais apparemment, il fonctionne de la même manière sur Solaris 10. Sur HP-UX 11, la carte semble différente et le tas semble être fusionné avec le segment de données, mais les allocations _end. Sur AIX, procmap n'affiche pas du segment tas/données, mais les allocations obtiennent également les adresses après le symbole _end. Donc, il semble être en ce moment assez portable.

Cependant, tous considérés, je ne suis pas sûr de l'utilité de cela.

post-scriptum Le programme de test:

#include <stdio.h> 
#include <stdlib.h> 

char *ppp1 = "hello world"; 
char ppp0[] = "hello world"; 
extern void *_end; /* any type would do, only its address is important */ 

int main() 
{ 
    void *p = calloc(10000,1); 
    printf("end:%p heap:%p rodata:%p data:%p\n", &_end, p, ppp1, ppp0); 
    sleep(10000); /* sleep to give chance to look at the process memory map */ 
    return 0; 
} 
+0

Eh bien, s'il n'y a aucun moyen de trouver l'adresse de début du tas, comment est implémenté malloc, qui essaie de scinder le tas en plus petits morceaux de mémoire? – Jun

+0

Notez que cela peut échouer dans un système avec des décalages aléatoires. Il peut être activé, mais par défaut les fuzz linux où le tas "démarre", il est donc plus difficile de le trouver depuis l'extérieur de la machine (empêchant les attaques de débordement de buffer). – jwarner112

+0

@Jun, libc appelle 'sbrk (0)' pour trouver l'adresse du début du tas. Mais cela ne marche que pour la libc: elle est appelée très tôt lors du démarrage de l'application, avant le main(), et donc la fin du tas est la même que le début du tas. Dans le 'principal()' que ce n'est plus vrai. – Dummy00001

Questions connexes