12

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

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

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

4

3 回答 3

11

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

于 2013-05-23T00:48:08.570 回答
2

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

于 2013-05-23T03:47:30.713 回答
1

正如 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;
}

为了得出结论,我们需要了解搬迁信息。如果您从未接触过,请考虑先阅读这篇文章

编译它:

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将增加的值移回内存
  • 13移动ieax返回值。这显然是不必要的,因为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
  • A: Added:-4
  • P: 加载时字节 6 的地址

-P需要,因为 GCC 使用RIP相对寻址,所以我们必须打折.text

-4之所以需要,是因为RIP在 byte 处指向下面的指令0xA但是P是 byte 0x6,所以我们需要折扣 4。

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

于 2015-05-28T19:53:45.483 回答