sam*_*249 0 c assembly static global-variables sections
根据定义存储在节中的变量是否是.data具有程序作用域的全局变量?换句话说,这两个词是否同义词,一个词暗示另一个词,或者,例如,是否可能有一个global未存储在该.data部分中的变量,或者一个不是全局的标签/变量?
举一个基本的例子:
// this is compiled as in the .data section with a .globl directive
char global_int = 11;
int main(int argc, char * argv[])
{
}
Run Code Online (Sandbox Code Playgroud)
会编译成类似的东西:
global_int:
.byte 11
main:
...
Run Code Online (Sandbox Code Playgroud)
但我正在查看这两个术语——全局和“在 .data 部分”是否是同一件事,或者是否有反例。
有两个不同的概念:变量进入哪个“部分”及其“可见性”
为了进行比较,我添加了一个.bss部分变量:
char global_int = 11;
char nondata_int;
int
main(int argc, char *argv[])
{
}
Run Code Online (Sandbox Code Playgroud)
编译产生cc -S:
.file "fix1.c"
.text
.globl global_int
.data
.type global_int, @object
.size global_int, 1
global_int:
.byte 11
.comm nondata_int,1,1
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl %edi, -4(%rbp)
movq %rsi, -16(%rbp)
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 8.3.1 20190223 (Red Hat 8.3.1-2)"
.section .note.GNU-stack,"",@progbits
Run Code Online (Sandbox Code Playgroud)
请注意.data将变量放在global_int数据部分中。并且,.comm放入nondata_int该.bss部分
另外,请注意.globl使变量具有全局可见性(即可以被其他.o文件看到)。
松散地说,.data和/或是变量放入的部分.bss。并且,全局 [ ] 是可见性。如果你这样做:.globl
static int foobar = 63;
Run Code Online (Sandbox Code Playgroud)
然后,foobar将进入该.data部分,但是本地的。在nm下面的输出中,D它不是 ,而是d指示本地/静态可见性。其他.o文件将无法看到此[或链接到它]。
nm该程序的一个.o结果是:
0000000000000000 D global_int
0000000000000000 T main
0000000000000001 C nondata_int
Run Code Online (Sandbox Code Playgroud)
并且,nm -g最终的可执行文件会生成:
000000000040401d B __bss_start
0000000000404018 D __data_start
0000000000404018 W data_start
0000000000401050 T _dl_relocate_static_pie
0000000000402008 R __dso_handle
000000000040401d D _edata
0000000000404020 B _end
0000000000401198 T _fini
000000000040401c D global_int
w __gmon_start__
0000000000401000 T _init
0000000000402000 R _IO_stdin_used
0000000000401190 T __libc_csu_fini
0000000000401120 T __libc_csu_init
U __libc_start_main@@GLIBC_2.2.5
0000000000401106 T main
000000000040401e B nondata_int
0000000000401020 T _start
0000000000404020 D __TMC_END__
Run Code Online (Sandbox Code Playgroud)
更新:
感谢您的回答。关于And,
.comm放入节nondata_int中.bss。您能解释一下吗?我没有看到任何对 .bss 的引用,那么这两者有什么关系呢?
当然。当你这样做时,可能有一个更严格但宽松的解释:
int nondata_int;
Run Code Online (Sandbox Code Playgroud)
您正在定义一个“common”节变量[历史起源来自Fortran的common]。
当链接[创建最终的可执行文件]时,如果没有其他.o[或.a]为其声明了值,它将.bss作为B节中。
但是,如果另一个 .o 已经定义了它(例如define_it.c):
int nondata_int = 43;
Run Code Online (Sandbox Code Playgroud)
在那里,define_it.o将其.data作为D符号
然后,当您链接两者时:
gcc -o executable fix1.o define_it.o
Run Code Online (Sandbox Code Playgroud)
然后,在 中executable,它将.data作为D部分。
因此,.o文件具有/使用.comm[汇编器指令]并且C公共部分。
可执行文件只有.data, 和.bss. 因此,给定文件,如果公共符号从未被初始化并且如果有的话.o,则该公共符号将进入[被提升为].bss.data .o。
宽松地说,.comm/C 是一个建议,.data并且.bss一个“承诺”
这是一种美好的感觉。从技术上讲,在 中fix1.c,如果我们事先知道我们将与 链接define_it.o,我们[可能]会想要这样做:
extern char nondata_int;
Run Code Online (Sandbox Code Playgroud)
然后,在 中fix1.o, 会被标记为“未定义”符号(即nm会显示U)。
但是,那么,如果fix1.o不是到任何定义该符号的东西,链接器就会抱怨未定义的符号。
通用符号允许我们拥有多个 .o文件,每个文件的作用如下:
int nondata_int;
Run Code Online (Sandbox Code Playgroud)
它们都产生C符号。链接器将所有内容组合起来生成一个。
所以,又常见了C符号又是:
我想要一个名为 X 的全局变量,并且希望它与任何其他文件中找到的 X 相同.o,但不要抱怨符号被多重定义。如果这些文件中的一个[并且只有一个]给它一个初始化的.o值,我希望从该值中受益。
历史上...
IIRC [我对此可能是错的],common 被添加到 [链接器] 以支持 FortranCOMMON声明/变量。
也就是说,所有的fortran.o文件都只是将一个符号声明为通用的[其全局概念],但 fortran 链接器应该将它们组合起来。
经典/旧的 fortran 只能将变量指定为COMMON(即在 C 中,相当于int val;),但 fortran没有全局初始值设定项(即它没有extern int val;或int val = 1;)
这个公共对 C 很有用,所以在某个时候它被添加了。
在过去的美好时光(tm),通用链接器类型不存在extern,除了一个文件和一个[且只有一个]声明它的文件外,所有链接器类型都必须有一个显式链接器类型.o。声明.o它可以使用值(例如)int val = 1;或不使用值(例如)来定义它int val;,但所有其他.o文件必须使用extern int val;