静态局部变量存储在内存中的哪个位置?局部变量只能在声明它们的函数内部访问。
全局静态变量进入.data段。
如果静态全局变量和静态局部变量的名称相同,编译器如何区分它们?
答案 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
将递增的值移回内存13
将i
移至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 05
是mov
部分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
指向字节0xA
处的以下指令,但P
是字节0x6
,因此我们需要折扣4. < / p>
结论:链接后,它将指向.data
段的第一个字节。