全局变量和 .data 部分 [英] Global variables and the .data section
问题描述
根据定义存储在 .data
部分的变量是否是具有程序作用域的全局变量?换句话说,这两个词是同义词,一个暗示另一个,或者,例如,可能有一个 global
变量没有存储在 .data
部分,或者不是全局的标签/变量?
Is a variable that is stored in the .data
section by definition a global variable that has program scope? In other words are these two words synonymous and one implies the other, or, for example would it be possible to have a global
variable that is not stored in the .data
section, or a label/variable that is not global?
举个简单的例子:
// this is compiled as in the .data section with a .globl directive
char global_int = 11;
int main(int argc, char * argv[])
{
}
会编译成类似的东西:
global_int:
.byte 11
main:
...
但我正在查看这两个术语——全局和在 .data 部分"是否存在.是一样的还是有反例的.
But I'm seeing if the two terms -- global and "in the .data section" are the same thing or if there are counterexamples.
推荐答案
有两个不同的概念:哪个节"是一个变量进入它的可见性"
There are two different concepts: Which "section" a variable goes into and its "visibility"
为了比较,我添加了一个 .bss
部分变量:
For comparison, I've add a .bss
section variable:
char global_int = 11;
char nondata_int;
int
main(int argc, char *argv[])
{
}
使用 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
注意 .data
将 global_int
变量放在数据部分.并且,.comm
将 nondata_int
放入 .bss
部分
Note the .data
to put the global_int
variable in the data section. And, .comm
to put nondata_int
into the .bss
section
另外,注意 .globl
以使变量具有全局可见性(即可以被其他 .o
文件看到).
Also, note the .globl
to make the variables have global visibility (i.e. can be seen by other .o
files).
松散地,.data
和/或 .bss
是变量放入的 sections.并且,全局 [.globl
] 是可见性.如果你这样做了:
Loosely, .data
and/or .bss
are the sections that the variables are put into. And, global [.globl
] are the visibility. If you did:
static int foobar = 63;
然后,foobar
会进入 .data
部分,但是是本地的.在下面的 nm
输出中,不是 D
,而是 d
来表示本地/静态可见性.其他 .o
文件将无法看到这个[或链接到它].
Then, foobar
would go into the .data
section but be local. In the nm
output below, instead of D
, it would be d
to indicate local/static visibility. Other .o
files would not be able to see this [or link to it].
.o
程序的 nm
产生:
0000000000000000 D global_int
0000000000000000 T main
0000000000000001 C nondata_int
并且,最终可执行文件的 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__
更新:
感谢您的回答.关于 And,.comm
将 nondata_int
放入 .bss
部分.你能解释一下吗?我没有看到任何对 .bss 的引用,那么这两个是如何相关的?
thanks for this answer. Regarding And,
.comm
to putnondata_int
into the.bss
section. Could you please explain that a bit? I don't see any reference to .bss so how are those two related?
当然.可能有一个更严格的解释,但松散,当你这样做时:
Sure. There's probably a more rigorous explanation, but loosely, when you do:
int nondata_int;
您正在定义一个公共"段变量[历史渊源来自Fortran的common].
You are defining a "common" section variable [the historical origin is from Fortran's common].
当链接[创建最终的可执行文件]时,如果no其他.o
[或.a
]已经为它声明了一个值,它将作为 B
符号放入 .bss
部分.
When linking [to create the final executable], if no other .o
[or .a
] has declared a value for it, it will be put into the .bss
section as a B
symbol.
但是,如果另一个 .o
已经定义了它(例如define_it.c
):
But, if another .o
has defined it (e.g. define_it.c
):
int nondata_int = 43;
在那里,define_it.o
会将它作为 D
符号放入 .data
部分
There, define_it.o
will put it in the .data
section as a D
symbol
然后,当您将两者联系起来时:
Then, when you link the two:
gcc -o executable fix1.o define_it.o
然后,在executable
中,它会作为D
符号进入.data
部分.
Then, in executable
, it will go to the .data
section as a D
symbol.
因此,.o
文件具有/使用 .comm
[汇编指令] 和 C
公共部分.
So, .o
files have/use .comm
[the assembler directive] and C
common section.
可执行文件只有 .data
和 .bss
.因此,给定 .o
文件,如果它从未被初始化并且 .data
如果 any .o
已经初始化它.
Executables have only .data
, and .bss
. So, given the .o
files a common symbol goes to [is promoted to] .bss
if it has never been initialized and .data
if any .o
has initialized it.
松散地,.comm
/C 是一个建议,.data
和 .bss
是一个承诺"
Loosely, .comm
/C is a suggestion and .data
and .bss
is a "commitment"
这是一种很好的方式.从技术上讲,在 fix1.c
中,如果我们事先知道我们将与 define_it.o
链接,我们会[可能]想要要做:
This is a nicety of sorts. Technically, in fix1.c
, if we knew beforehand that we were going to be linked with define_it.o
, we would [probably] want to do:
extern char nondata_int;
然后,在 fix1.o
中,将被标记为未定义"符号(即 nm
将显示 U
).
Then, in fix1.o
, the would be marked as an "undefined" symbol (i.e. nm
would show U
).
但是,如果fix1.o
没有链接到任何定义符号的东西,链接器就会抱怨一个未定义的符号.
But, then, if fix1.o
were not linked to anything that defined the symbol, the linker would complain about an undefined symbol.
公共符号允许我们拥有多个 .o
文件,每个:
The common symbol allows us to have multiple .o
files that each do:
int nondata_int;
它们都产生 C
符号.链接器将所有内容组合起来以生成单个符号.
They all produce C
symbols. The linker combines all to produce a single symbol.
所以,常见的 C
符号是:
So, again common C
symbols are:
我想要一个名为 X 的全局变量,并且我希望它与任何其他 .o
文件中的 X 相同,但不要抱怨符号被多重定义.如果那些 .o
文件中的 one [和 only one] 给它一个 initialized 值,我想从该价值中受益.
I want a global named X and I want it to be the same X as found in any other .o
files, but don't complain about the symbol being multiply defined. If one [and only one] of those .o
files gives it an initialized value, I'd like to benefit from that value.
历史上......
IIRC [我可能错了],common 被添加到 [链接器] 以支持 Fortran COMMON
声明/变量.
IIRC [and I could be wrong about this], common was added [to the linker] to support Fortran COMMON
declarations/variables.
也就是说,所有的 fortran .o
文件都只是将一个符号声明为 common [其全局概念],但希望 fortran 链接器将它们组合起来.
That is, all fortran .o
files just declared a symbol as common [its concept of global], but the fortran linker was expected to combine them.
经典/旧版 fortran 只能将变量指定为 COMMON
(即在 C 中,相当于 int val;
)但 fortran 却没有有全局初始值设定项(即它没有有 extern int val;
或 int val = 1;
)
Classic/old fortran could only specify a variable as COMMON
(i.e. in C, equivalent to int val;
) but fortran did not have global initializers (i.e. it did not have extern int val;
or int val = 1;
)
这对 C 很有用,因此,在某个时候添加了它.
This common was useful for C, so, at some point it was added.
在过去的美好时光 (tm),常见的链接器类型不存在,除了一个 .o
文件和一个 [并且只有一个] 声明它.声明它的 .o
可以用一个值来定义它(例如)int val = 1;
或 without(例如)intval;
但所有其他 .o
文件必须使用 extern int val;
In the good old days (tm), the common linker type did not exist and one had to have an explicit extern
in all but one .o
file and one [and only one] that declared it. That .o
that declared it could define it with a value (e.g.) int val = 1;
or without (e.g.) int val;
but all other .o
files had to use extern int val;
这篇关于全局变量和 .data 部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!