static int arr [10] l'indirizzo di memoria termina sempre con 060


17

Ho un programma CA che assomiglia a questo

main.c

#include <stdio.h>
#define SOME_VAR 10

static int heap[SOME_VAR];


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

e lo emette quando eseguo il programma compilato alcune volte

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

Perché finisce sempre con 060? E l'array è archiviato nell'heap?

Modifica: sono su Linux e ho ASLR attivo. Ho compilato il programma usando gcc


2
Quale sistema operativo? Quale compilatore?
Andrew Henle,

2
La variabile non è nell'heap, è nella sezione data o bss dello spazio degli indirizzi del programma, vedi en.wikipedia.org/wiki/Static_variable . La mia ipotesi è che il programma verrà sempre posizionato a un indirizzo di memoria a un certo limite, ad esempio divisibile per 0x1000, e la variabile viene posizionata dal compilatore a un offset fisso nello spazio degli indirizzi del programma.
Bodo

Risposte:


15

Gli indirizzi differiscono a causa dell'ASLR (ramdomizzazione del layout dello spazio degli indirizzi). Usando questo, il binario può essere mappato in diverse posizioni nello spazio degli indirizzi virtuali.

La variabile heapè - in contrasto con il suo nome - non si trova sull'heap, ma su bss. L'offset nello spazio degli indirizzi è quindi costante.

Le pagine sono mappate alla granularità della pagina, che è 4096 byte (esadecimale: 0x1000) su molte piattaforme. Questo è il motivo per cui le ultime tre cifre esadecimali dell'indirizzo sono le stesse.

Quando hai fatto lo stesso con una variabile dello stack , l'indirizzo potrebbe persino variare nelle ultime cifre su alcune piattaforme (vale a dire Linux con kernel recenti), perché lo stack non è mappato solo da qualche altra parte ma riceve anche un offset casuale all'avvio.


ASLR randomizza la base di caricamento come ricordo. Gli indirizzi di sezione si basano su quell'indirizzo.
Afshin

Sto usando un libro sulla programmazione orientata agli oggetti ANSI-C di Axel-Thobias Schreiner. Il libro è stato scritto in qualcosa come il 1993. Sai se il layout della memoria era diverso allora? In caso contrario, perché avrebbe potuto nominare la variabile heapquando non è in heap?
linuxlmao,

4096 si traduce in 060 in qualche modo o 0x1000 si traduce in 060 altrimenti non capisco cosa intendi per essere la ragione del finale? Ho pensato che potrebbe avere a che fare con la dimensione dell'array essere qualcosa che si traduce in 060 in esadecimale da, ad esempio decimale
linuxlmao

2
@linuxlmao L'offset è ad esempio 14060, quindi quando si aggiunge un multiplo di dimensioni pagina (0x1000), rimangono le ultime tre cifre 060.
Ctx,

4

Se si utilizza Windows, il motivo è la struttura PE .

La heapvariabile è memorizzata nella .datasezione del file e il suo indirizzo viene calcolato in base all'inizio di questa sezione. Ogni sezione viene caricata in un indirizzo in modo indipendente, ma il suo indirizzo iniziale è multiplo della dimensione della pagina. Poiché non hai altre variabili, il suo indirizzo è probabilmente l'inizio della .datasezione, quindi il suo indirizzo sarà multiplo della dimensione del blocco.

Ad esempio, questa è la tabella della versione compilata di Windows del tuo codice: sezioni la .textsezione è dove è il tuo codice compilato e .datacontiene la tua heapvariabile. Quando PE viene caricato in memoria, le sezioni vengono caricate in un indirizzo diverso e che viene restituito VirtualAlloc()e sarà multiplo delle dimensioni della pagina. Ma l'indirizzo di ogni variabile è relativo all'inizio della sezione che ora è una dimensione di pagina. Quindi vedrai sempre un numero fisso su cifre inferiori. Poiché l'indirizzo relativo di heapdall'inizio della sezione si basa sul compilatore, sulle opzioni di compilazione, ecc., Vedrai un numero diverso dallo stesso codice ma diversi compilatori, ma ogni volta che ciò che verrà stampato è fisso.

Quando compilo il codice, ho notato che heapviene inserito nei 0x8B0byte dopo l'inizio della .datasezione. Quindi ogni volta che eseguo questo codice, il mio indirizzo finisce 0x8B0.


Sto usando un libro sulla programmazione orientata agli oggetti ANSI-C di Axel-Thobias Schreiner. Il libro è stato scritto in qualcosa come il 1993. Sai se il layout della memoria era diverso allora? In caso contrario, perché avrebbe potuto nominare la variabile heapquando non è in heap?
linuxlmao,

2
@linuxlmao Potrebbe anche essere stato diverso. Nel 1993, Windows era un sistema operativo a 16 bit, con segmentazione della memoria e ogni sorta di cose confuse. Era non a 32 bit, l'architettura flat-memoria, come è ora. Ma questi tipi di cose sono il motivo per cui non è utile porre / rispondere a domande generali sul layout di un programma binario in memoria. Comprendi cosa ti garantisce lo standard del linguaggio C in generale e questo è tutto ciò che devi sapere. Ti preoccupi solo del layout reale se stai eseguendo il debug di un problema specifico, quindi utilizza un debugger
Cody Grey

no, la variabile non deve essere creata su heap nemmeno su sistemi più vecchi perché non è stata allocata con malloc e ha una durata di archiviazione statica
phuclv,

@Afshin Sto affrontando il commento dell'OP sopra
phuclv,

@phuclv mi dispiace, perché non sei stato menzionato, pensavo che mi stessi rivolgendo a me. :)
Afshin,

4

Il compilatore ha messo heapin offset 0x60 byte in un segmento di dati che ha, probabilmente perché il compilatore ha qualche altra roba nei primi 0x60 byte, come i dati utilizzati dal codice che avvia la mainroutine. Questo è il motivo per cui vedi "060"; è proprio dove è successo e non ha un grande significato.

La randomizzazione del layout dello spazio degli indirizzi modifica gli indirizzi di base utilizzati per varie parti della memoria del programma, ma lo fa sempre in unità di 0x1000 byte (poiché ciò evita di causare problemi di allineamento e altri problemi). Quindi vedi gli indirizzi fluttuare di multipli di 0x1000, ma le ultime tre cifre non cambiano.

La definizione static int heap[SOME_VAR];definisce heapcon durata di archiviazione statica. Le tipiche implementazioni C lo archiviano in una sezione di dati generali, non nell'heap. L'heap è un termine improprio per la memoria utilizzato per l'allocazione dinamica. (È un termine improprio perché le mallocimplementazioni possono utilizzare una varietà di strutture di dati e algoritmi, non limitati a heap. Possono persino utilizzare più metodi in un'unica implementazione.)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.