【问题标题】:Global variables and the .data section全局变量和 .data 部分
【发布时间】:2020-10-31 22:15:50
【问题描述】:

根据定义存储在.data 部分中的变量是否是具有程序范围的全局变量?换句话说,这两个词是同义词,一个暗示另一个,或者,例如,是否有可能有一个未存储在.data 部分中的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 部分中”是否相同,或者是否有反例。

【问题讨论】:

  • 鉴于const char x = 0;,我相信编译器可以将x放入.rodata部分,甚至.bss部分。
  • @user3386109 谢谢,是的,我在编译器资源管理器中尝试过,它进入了.rodata。为什么.bss
  • .bss 在加载时归零。因此,任何初始化为零的变量都可能被放入 .bss 部分。
  • 提示:看看static char nonglobal_int = 11;会发生什么,在main内部或外部定义。
  • .data 部分用于静态存储类中的可变数据。并非每个这样的数据都是全局的(例如本地 static 变量不是)。并非所有全局数据都在其中(例如,线程本地存储类的变量不存在)。

标签: c assembly static global-variables sections


【解决方案1】:

有两个不同的概念:变量进入哪个“部分”及其“可见性”


为了比较,我添加了一个.bss 部分变量:

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

注意.dataglobal_int 变量放入数据部分。并且,.commnondata_int 放入.bss 部分

另外,请注意 .globl 以使变量具有全局可见性(即可以被其他 .o 文件看到)。

简单地说,.data 和/或.bss 是变量所在的。而且,全局 [.globl] 是可见性。如果你这样做了:

static int foobar = 63;

然后,foobar 将进入 .data 部分,但在本地。在下面的nm 输出中,而不是D,它将是d 来指示本地/静态可见性。其他.o 文件将能够看到这个[或链接到它]。


.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,.commnondata_int 放入 .bss 部分。你能解释一下吗?我没有看到任何对 .bss 的引用,那么这两者有什么关系?

当然。可能有更严格的解释,但松散,当你这样做时:

int nondata_int;

您正在定义一个“通用”部分变量[历史起源来自 Fortran 的通用]。

当链接[创建最终的可执行文件]时,如果没有其他.o[或.a]已经为其声明了一个值,它将被放入.bss部分B 符号。

但是,如果 另一个 .o 定义了它(例如define_it.c):

int nondata_int = 43;

在那里,define_it.o 将把它作为D 符号放在.data 部分中

那么,当你把两者联系起来时:

gcc -o executable fix1.o define_it.o

然后,在executable 中,它将作为D 符号转到.data 部分。

所以,.o 文件具有/使用 .comm [汇编程序指令] 和 C 通用部分。

可执行文件只有.data.bss。因此,给定 .o 文件,如果 从未 初始化了一个通用符号,则该通用符号将转到 [被提升为] .bss,如果 any 则为 .o .data已经初始化了。

简单地说,.comm/C 是一个建议,.data.bss 是一个“承诺”

这是一种很好的方式。从技术上讲,在fix1.c 中,如果我们事先知道我们将与define_it.o 链接,我们[可能] 想做:

extern char nondata_int;

然后,在fix1.o 中, 将被标记为“未定义”符号(即nm 将显示U)。

但是,如果fix1.o没有链接到任何定义该符号的东西,链接器会抱怨未定义的符号。

通用符号允许我们拥有 多个 .o 文件,每个都可以这样做:

int nondata_int;

它们都产生C 符号。链接器将所有内容组合起来生成一个 single 符号。

所以,同样常见的C 符号是:

我想要一个名为 X 的全局变量,并且我希望它与在任何其他 .o 文件中找到的 X 相同,但不要抱怨符号被多重定义。如果那些.o 文件中的一个 [和 个] 给它一个已初始化 值,我想从该值中受益。

历史上...

IIRC [我可能错了],common 被添加到 [链接器] 以支持 Fortran COMMON 声明/变量。

也就是说,所有 fortran .o 文件只是将一个符号声明为通用 [它的全局概念],但预期 fortran 链接器会将它们组合起来。

Classic/old fortran 只能将变量指定为 COMMON(即在 C 中,等同于 int val;)但 fortran 没有有全局初始化器(即它有 not 有extern int val;int val = 1;)

这个通用对 C 很有用,所以在某个时候它被添加了。

在过去的美好时光 (tm),通用链接器类型 存在,除了一个 .o 文件和一个 [并且只有一个] 宣布它。声明它的.o 可以用值(例如)int val = 1;没有(例如)int val; 定义它,但所有其他.o 文件必须使用extern int val;

【讨论】:

  • 感谢您的回答。关于And, .comm to put nondata_int into the .bss section。你能解释一下吗?例如,从这里sourceware.org/binutils/docs/as/Comm.html#Comm 我看不到任何对 .bss 的引用,那么这两者有什么关系?
  • 感谢更新!还有关于Executables have only .data, and .bss.——rodata 部分呢?或者您是否将其包含在data 部分?
  • 是的,你是对的。我想我所说的可以更好地表述为“没有.comm 部分”。当您有特殊的链接要求时,您可以添加(例如):__attribute__((section(".init3")) 并让链接器根据需要将它们捆绑在一起。
猜你喜欢
  • 1970-01-01
  • 2023-03-14
  • 1970-01-01
  • 2012-08-12
  • 1970-01-01
  • 1970-01-01
  • 2019-04-04
  • 2013-10-06
  • 2012-06-09
相关资源
最近更新 更多