静态局部变量在哪里

时间:2013-05-23 00:45:07

标签: c static

静态局部变量存储在内存中的哪个位置?局部变量只能在声明它们的函数内部访问。

全局静态变量进入.data段。

如果静态全局变量和静态局部变量的名称相同,编译器如何区分它们?

3 个答案:

答案 0 :(得分:11)

静态变量与全局变量进入同一段。两者之间唯一不同的是编译器“隐藏”链接器中的所有静态变量:只暴露外部(全局)变量的名称。这就是编译器允许具有相同名称的静态变量存在于不同翻译单元中的方式。静态变量的名称在编译阶段仍然是已知的,但随后他们的数据将被匿名放入.data段。

答案 1 :(得分:2)

静态变量几乎与全局变量相似,因此未初始化的静态变量在BSS中,初始化的静态变量在数据段中。

答案 2 :(得分:0)

正如dasblinken所提到的,GCC 4.8将局部静态放在与全局相同的位置。

更确切地说:

  • static int i = 0继续.bss
  • static int i = 1继续.data

让我们自己分析一个Linux x86-64 ELF示例:

#include <stdio.h>

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

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

为了得出结论,我们需要了解搬迁信息。如果您从未接触过,请考虑reading this post first

编译:

gcc -ggdb -c main.c

使用以下代码反编译代码:

objdump -S main.o

f包含:

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   

3次访问i

  • 4移至eax以准备增量
  • d将递增的值移回内存
  • 13i移至eax以获取返回值。显然没有必要,因为eax已经包含它,-O3能够删除它。

所以让我们只关注4

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

让我们看一下重定位数据:

readelf -r main.o

说明了链接器在创建可执行文件时如何修改文本部分地址。

它包含:

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

我们会关注.rela.text而不是其他人,因为我们对.text的重新定位感兴趣。

Offset 6直接进入从字节4开始的指令:

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

根据我们对x86-64指令编码的了解:

  • 8b 05mov部分
  • 00 00 00 00是地址部分,从字节6
  • 开始

AMD64 System V ABI Update告诉我们R_X86_64_PC32对4个字节(00 00 00 00)起作用,并将地址计算为:

S + A - P

表示:

  • S:该段指向:.data
  • AAdded-4
  • P:加载时字节6的地址

-P是必需的,因为GCC使用RIP相对寻址,所以我们必须在.text

中打折。

-4是必需的,因为RIP指向字节0xA处的以下指令,但P是字节0x6,因此我们需要折扣4. < / p>

结论:链接后,它将指向.data段的第一个字节。