2013-05-23 5 views
11

Dove sono memorizzate le variabili locali statiche? Le variabili locali sono accessibili solo all'interno della funzione in cui sono dichiarate.Dove vanno le variabili locali statiche

Le variabili statiche globali vanno nel segmento .data.

Se il nome della variabile locale statica globale e statica è lo stesso, in che modo il compilatore li distingue?

+2

Perché pensi che il nome che il compilatore utilizza a livello di linker è lo stesso nome che dichiari? – bmargulies

+0

possibile duplicato di questo: [cosa “statica” significa in un programma C] [1] [1]: http: // StackOverflow.it/questions/572547/what-does-static-mean-in-ac-program – tejas

+1

possibile duplicato di [Dove sono memorizzate le variabili statiche (in C/C++)?] (http://stackoverflow.com/questions/93039/ dove-sono-static-variabili-memorizzate-in-cc) – jogojapan

risposta

11

Le variabili statiche vanno nello stesso segmento delle variabili globali. L'unica differenza tra i due è che il compilatore "nasconde" tutte le variabili statiche dal linker: vengono esposti solo i nomi delle variabili esterne (globali). È così che i compilatori consentono l'esistenza di variabili statiche con lo stesso nome in diverse unità di traduzione. I nomi delle variabili statiche rimangono noti durante la fase di compilazione, ma successivamente i loro dati vengono inseriti nel segmento .data in modo anonimo.

2

La variabile statica è quasi simile alla variabile globale e quindi la variabile statica non inizializzata è in BSS e la variabile statica inizializzata si trova nel segmento di dati.

0

Come accennato da dasblinken, GCC 4.8 mette le statistiche locali sullo stesso posto dei globali.

Più precisamente:

  • static int i = 0 va avanti .bss
  • static int i = 1 va avanti .data

Analizziamo esempio ELF uno Linux x86-64 per vedere noi stessi:

#include <stdio.h> 

int f() { 
    static int i = 1; 
    i++; 
    return i; 
} 

int main() { 
    printf("%d\n", f()); 
    printf("%d\n", f()); 
    return 0; 
} 

Per raggiungere conclusioni, dobbiamo capire le informazioni sulla ricollocazione. Se non l'hai mai toccato, considera reading this post first.

Compilarlo:

gcc -ggdb -c main.c 

decompilare il codice con:

objdump -S main.o 

f contiene:

int f() { 
    0: 55      push %rbp 
    1: 48 89 e5    mov %rsp,%rbp 
    static int i = 1; 
    i++; 
    4: 8b 05 00 00 00 00  mov 0x0(%rip),%eax  # a <f+0xa> 
    a: 83 c0 01    add $0x1,%eax 
    d: 89 05 00 00 00 00  mov %eax,0x0(%rip)  # 13 <f+0x13> 
    return i; 
    13: 8b 05 00 00 00 00  mov 0x0(%rip),%eax  # 19 <f+0x19> 
} 
    19: 5d      pop %rbp 
    1a: c3      retq 

che fa 3 accessi al i:

  • 4 sposta nella eax per preparare l'incremento
  • d sposta il valore incrementato alla memoria
  • 13 sposta i al eax per il valore restituito. Ovviamente non è necessario poiché lo contiene già eax e -O3 è in grado di rimuoverlo.

Quindi cerchiamo di concentrarsi solo sulla 4:

4: 8b 05 00 00 00 00  mov 0x0(%rip),%eax  # a <f+0xa> 

Guardiamo i dati trasferimento:

readelf -r main.o 

che dice come gli indirizzi sezione di testo saranno modificati dal linker quando è rendendo l'eseguibile.

Contiene:

Relocation section '.rela.text' at offset 0x660 contains 9 entries: 
    Offset   Info   Type   Sym. Value Sym. Name + Addend 
000000000006 000300000002 R_X86_64_PC32  0000000000000000 .data - 4 

guardiamo .rela.text e non gli altri perché siamo interessati a delocalizzazioni di .text.

Offset 6 cade a destra nella istruzione che inizia nel byte 4:

4: 8b 05 00 00 00 00  mov 0x0(%rip),%eax  # a <f+0xa> 
      ^^ 
      This is offset 6 

Dalla nostra conoscenza di codifica x86-64 istruzione:

  • 8b 05 è la parte mov
  • 00 00 00 00 è il indirizzo parte, che inizia al byte 6

AMD64 System V ABI Update ci dice che R_X86_64_PC32 agisce su 4 byte (00 00 00 00) e calcola l'indirizzo:

S + A - P 

che significa:

  • S: il segmento sottolineato: .data
  • A: il Added: -4
  • P: l'indirizzo del byte 6 quando caricato

-P è necessaria perché GCC utilizzato RIP indirizzamento relativo, quindi dobbiamo scontare la posizione in .text

-4 è necessario perché RIP punti al seguente istruzione a byte 0xA ma P è il byte 0x6, quindi è necessario lo sconto 4.

Conclusione: dopo il collegamento verrà indicato il primo byte del segmento .data.