在哪个区段?BSS, .DATA,其他)的可执行文件的静态变量存储,以便他们没有名称冲突?
例如:
foo.c: bar.c:
static int foo = 1; static int foo = 10;
void fooTest() { void barTest() {
static int bar = 2; static int bar = 20;
foo++; foo++;
bar++; bar++;
printf("%d,%d", foo, bar); printf("%d, %d", foo, bar);
} }
如果我编译这两个文件并将其链接到重复调用fooTest()和barTest的主程序,printf语句将独立递增。这是有意义的,因为foo和bar变量是翻译单元的局部变量。
但是存储分配在哪里呢?
需要明确的是,假设您有一个工具链,该工具链将以ELF格式输出文件。因此,我认为在可执行文件中必须为那些静态变量保留一些空间。
为了便于讨论,让我们假设我们使用GCC工具链。
如何用objdump -Sr自己找到它
要真正理解发生了什么,您必须理解连接器重定位。如果你从未接触过,考虑先阅读这篇文章。
让我们来分析一个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 -Sr main.o
-S混合原始源代码反编译代码
-r显示重定位信息
在f的反编译中,我们看到:
static int i = 1;
i++;
4: 8b 05 00 00 00 00 mov 0x0(%rip),%eax # a <f+0xa>
6: R_X86_64_PC32 .data-0x4
而.data-0x4表示它将到。data段的第一个字节。
-0x4的存在是因为我们正在使用RIP相对寻址,因此指令中的% RIP和R_X86_64_PC32。
它是必需的,因为RIP指向下面的指令,它在00 00 00 00 00之后4个字节开始,00 00 00 00将被重新定位。我已经在https://stackoverflow.com/a/30515926/895245上详细解释了这一点
然后,如果我们将源修改为i = 1,并进行同样的分析,我们得出:
静态int I = 0是。bss
静态int I = 1在。data上
事实上,变量是元组(存储,范围,类型,地址,值):
storage : where is it stored, for example data, stack, heap...
scope : who can see us, for example global, local...
type : what is our type, for example int, int*...
address : where are we located
value : what is our value
局部作用域可以是翻译单元(源文件)、函数或块的局部作用域,这取决于它的定义位置。要使变量对多个函数可见,它肯定必须在DATA或BSS区域(取决于它是否分别显式初始化)。然后,它的范围相应地是源文件中的所有函数或函数。