2013-04-05 17 views
15

Ich habe einfachen Code wie folgt:Welche Adresse druckt printf() mit einem% p-Format 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; 
} 

Ausgabe des obigen Programms ist: Erster Lauf:

&a is : 0x7fff70de91ec 
glob is : 0x6008f4 

Zweiter Lauf:

&a is : 0x7fff38c4c7ac 
glob is : 0x6008f4 

Ich studiere über virtuelle & physikalische Adressen. Ich habe folgende Frage:

  1. der die gedruckte Adresse (physische/virtuelle) der Variablen „a“ ist?
  2. Wenn es dann virtuell ist, wie ändert es sich bei jedem Lauf desselben Programms? Wie ich verstanden, Compiler bietet virtuelle Adresse zu Variablen bei der Kompilierung?
  3. Warum ist die Adresse der globalen Variablen in jedem Programmlauf konstant?

In diesem Programm unter Linux ausgeführt: 2.6.18-308.el5 x86_64 GNU/Linux

mit Zusammengestellt: gcc Version 4.1.2 20.080.704 (Red Hat 4.1.2-52)

+2

Ihr Programm ruft ** undefiniertes Verhalten ** auf. Ein '% p' muss ein ptr-to-void haben, also müssen Sie in beiden printfs auf' (void *) 'umwandeln. – Jens

+0

@Jens Wird das Argument nicht implizit auf "void *" übertragen? –

+3

@VilhelmGray Implizite Konvertierungen finden statt, wenn ein Typ erwartet wird, aber es gibt keine Typen in Variadic-Funktionen. – effeffe

Antwort

6

Adressen, die in einem Programm gesehen werden, sind immer virtuell und das vom OP beschriebene Verhalten ist eine Linux-Gegenmaßnahme, um buffer overflow attacks zu vermeiden.

nur zu versuchen, können Sie es mit

sysctl -w kernel.randomize_va_space=0 

dann erneut aus Ihrem Programm und beobachten deaktivieren.

Die globale ist in einem anderen Raum der Erinnerung, der in einer hackish-weise Sichtweise nicht schädlich sein kann. Das liegt daran, dass es nicht jedes Mal randomisiert wird.

15

Beide Adressen sind virtuell.

Moderne Systeme verwenden Stack-Randomisierung, um sogenannte Stack-Smashing-Angriffe zu verhindern, weshalb die lokale Variable ihre Position bei jedem Lauf ändern kann. Die globale Variable wird jedoch in der ausführbaren Datei gespeichert und jedes Mal mit demselben Offset geladen.

+7

Es ist erwähnenswert, dass bestimmte andere Betriebssysteme und einige sicherheitsbewusste Linux-Distributionen PIE (positionsunabhängige ausführbare Dateien) haben und auf denen sich auch die Adresse der globalen Variablen ändert. – Art

+0

@Joachim, ja, ich stimme zu, dass lokale Variablen im Stack gespeichert werden, aber warum wird gesagt, dass Variablen eine bestimmte Adresse zur Kompilierzeit von Compiler gegeben? – BSalunke

+0

@BSalunke Lokale Variablen werden beim Aufruf einer Funktion vom Stapelzeiger auf einen bestimmten _offset_ gesetzt. Während der Compiler ihm keine feste Adresse gibt, hat die Variable immer noch eine vom Compiler angegebene Adresse. –

3

Ihr Programm wird immer nur virtuelle Adresse sehen.

Echte Adressen sind nur für den virtuellen Speichermanager im Kernelmodus verfügbar.

Globals hat dieselbe Adresse (bis Sie andere Variablen davor platzieren), da sie im Datensegment erstellt wird.

Lokale Variablen werden immer im Stapel erstellt.

+1

Lokale Variablen können 'static' sein, auch ... :) – unwind

+0

@unwind: Ja, Sie sind richtig. Ich beschreibe nur Code, den OP bieten. – rkosegi

2

Alle vom Programm angezeigten Adressen sind virtuell. Lokale Variablen werden jedoch im speziellen Bereich namens Datensegment auf Stapel und global verschoben. Obwohl die relativen Positionen der Variablen bei der Kompilierung festgelegt werden, kann der Stapel bei jedem Lauf variieren.