2013-04-05 4 views
15

Sto avendo semplice codice come segue:Qual è l'indirizzo stampato da printf() con un formato% p in c?

#include<stdio.h> 

int glob; 

int main(void) 
{ 
    int a; 
    printf("&a is : %p \n", &a); 
    printf("glob is : %p \n", &glob); 
    return 0; 
} 

uscita del programma di cui sopra è: Prima esecuzione:

&a is : 0x7fff70de91ec 
glob is : 0x6008f4 

Seconda manche:

&a is : 0x7fff38c4c7ac 
glob is : 0x6008f4 

sto studiando su virtuale & indirizzi fisici. Ho una domanda seguente:

  1. Qual è l'indirizzo stampato (fisico/virtuale) della variabile "a"?
  2. Se è virtuale, come cambia in ogni esecuzione dello stesso programma? Come ho capito il compilatore fornisce l'indirizzo virtuale alle variabili al momento della compilazione?
  3. Perché l'indirizzo della variabile globale è costante in ogni esecuzione del programma?

In eseguito questo programma su Linux: 2.6.18-308.el5 x86_64 GNU/Linux

compilato utilizzando: versione di gcc 4.1.2 20.080.704 (Red Hat 4.1.2-52)

+2

Il tuo programma richiama ** comportamento non definito **. A '% p' deve essere dato un ptr-to-void, quindi è necessario eseguire il cast a' (void *) 'in entrambi i printfs. – Jens

+0

@Jens L'argomento non dovrebbe essere gettato implicitamente in 'void *'? –

+3

@VilhelmGray le conversioni implicite avvengono quando è previsto un tipo, ma non ci sono tipi in una funzione variadica. – effeffe

risposta

6

Gli indirizzi visualizzati in un programma sono sempre virtuali e il comportamento descritto dall'OP è una contromisura di Linux per evitare buffer overflow attacks.

solo per provare, si può disattivare con

sysctl -w kernel.randomize_va_space=0 

quindi eseguire nuovamente il programma e guardare.

quello globale è in un altro spazio di memoria che non può essere dannoso in un punto di vista hackish-saggio. Questo perché non è casuale ogni volta.

15

Entrambi gli indirizzi sono virtuali.

sistemi moderni utilizza pila randomizzazione per evitare i cosiddetti attacchi di stack-smashing, motivo per cui la variabile locale può cambiare la sua posizione ogni corsa. Tuttavia, la variabile globale viene memorizzata nell'eseguibile e viene caricata sempre allo stesso offset.

+7

Vale la pena notare che alcuni altri sistemi operativi e alcune distribuzioni Linux più orientate alla sicurezza hanno PIE (posizione eseguibile indipendente) e su quelli cambierà anche l'indirizzo della variabile globale. – Art

+0

@Joachim, sì sono d'accordo che le variabili locali sono immagazzinate nello stack ma perché si dice che le variabili abbiano un indirizzo specifico in fase di compilazione da parte del compilatore? – BSalunke

+0

@BSalunke Le variabili locali vengono posizionate a un _offset_ specifico dal puntatore dello stack quando viene chiamata una funzione. Così mentre il compilatore non gli dà un indirizzo fisso, le variabili hanno ancora un indirizzo dato dal compilatore. –

3

il programma verrà sempre vedere l'indirizzo solo virtuale.

indirizzi reali sono disponibili solo di gestore della memoria virtuale in modalità kernel.

Globali ha stesso indirizzo (fino a quando si posiziona altre variabili prima di esso), perché è creato nel segmento di dati.

variabili locali sono sempre creati sulla pila.

+1

Le variabili locali possono essere 'statico', anche ... :) – unwind

+0

@unwind: sì, hai ragione. Descrivo solo il codice fornito da OP. – rkosegi

2

Tutti gli indirizzi visualizzati dal programma sono virtuali. Tuttavia, le variabili locali vengono messe in pila e globali nell'area speciale denominata Segmento dati. Anche se le variabili relative posizioni vengono decise in fase di compilazione, lo stack può variare a ogni esecuzione.