GCC 编译代码:为什么整数声明需要多个语句?
GCC compiled code: why integer declaration needs several statements?
我正在学习AT&T汇编,我知道arrays/variables可以用.int/.long来声明,或者用.equ来声明一个符号,那是要用汇编来代替的。
它们在.data 段(已初始化)或.bss 段(未初始化)中声明。
但是当我使用 gcc 编译一个非常简单的 .c 文件并使用 '-S' 命令行选项来检查反汇编代码时,我注意到:
(1) .s 不是同时使用 .data 和 .bss,而只使用 .data
(2) 一个整数(.long)的声明花费了好几条语句,其中一些对我来说似乎是多余的或无用的。
如下所示,我根据自己的问题添加了一些评论。
$猫n.c
int i=23;
int j;
int main(){
return 0;
}
$ gcc -S n.c
$猫n.s
.file "n.c"
.globl i
.data
.align 4
.type i, @object #declare i, I think it's useless
.size i, 4 #There's '.long 23', we know it's 4 bytes, why need this line?
i:
.long 23 #Only this line is needed, I think
.comm j,4,4 #Why j is not put inside .bss .section?
.text
.globl main
.type main, @function
main:
.LFB0: #What does this symbol mean, I don't find it useful.
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl [=11=], %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0: #What does this symbol mean, I don't find it useful.
.size main, .-main
.ident "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.2) 5.4.0 20160609"
.section .note.GNU-stack,"",@progbits
我所有的问题都在上面的评论里,我在这里再次强调一下:
.type i, @object
.size i, 4
i:
.long 23
我真的认为上面的代码是多余的,应该像这样简单:
i:
.long 23
此外,"j" 没有符号标记,也没有放在 .bss 部分。
我是不是搞错了什么?请帮忙指正。非常感谢。
(我猜你正在使用一些 Linux 系统)
They're declared insided either .data section(initialzed),or .bss section(uninitialzed).
不,您还有许多其他部分,特别是 .comm
(对于 "common" 部分,初始化数据 common 到几个目标文件,即链接器将 "merge") 和 .rodata
用于只读数据。 ELF 格式足够灵活,可以允许许多部分和许多段(其中一些未加载 - 更准确地说是内存映射 - 在内存中)。
ELF 文件中各部分的描述比您认为的要复杂得多。花时间阅读更多,例如链接器和加载器,莱文。另请阅读 GNU binutils 的文档和 scripts 以及 ld(1) & as(1)。使用 objdump(1) 和 readelf(1) 探索现有的 ELF 可执行文件、目标文件和共享对象。另请阅读 execve(2) & elf(5)
But when I used gcc
to compiled a very simple .c
file with -S
command line option
在检查由 gcc
生成的汇编文件时,我强烈建议至少传递 -fverbose-asm
以要求 gcc
在汇编文件中发出一些额外的有用注释。我通常还建议使用一些优化标志 - 例如-O1
至少(或者 -Og
最近版本的 gcc
)。
I noticed that:
(1) .s is not using both .data and .bss, but only .data
不,您生成的代码使用 .comm
部分并将 j
的值放在那里。
(2) The declaration of an integer(.long) cost several statements, some of them seems redundant or useless to me.
这些大多不是汇编程序语句(翻译成机器码)而是汇编程序指令;它们非常有用(并且它们不会在 ld
产生的内存段中浪费 space,但 ELF 格式在其他地方有信息)。特别是 .size
和 .type
都是必需的,因为 ELF 文件中的符号表包含的不仅仅是地址(它还有大小的概念和非常原始的类型概念)。
.LFB0
是一个gcc
(实际上是cc1
-)生成的标签。 GCC 不关心生成无用的标签(对于 GCC 后端的汇编程序生成器来说更简单),因为它们不会出现在目标文件中。
There's '.long 23', we know it's 4 bytes,
您可能知道 long 是 4 个字节,但该信息(j
的大小)应该进入 ELF 文件,因此需要明确的汇编程序指令....
(我没有space也没有时间解释ELF格式,你需要阅读很多关于它的页面,它比什么更复杂更完整你相信)
顺便说一句,Drepper 的 How To Write Shared Libraries 相当长(超过 40 页)并且解释了很多关于 ELF 文件的内容,重点是共享库。
我正在学习AT&T汇编,我知道arrays/variables可以用.int/.long来声明,或者用.equ来声明一个符号,那是要用汇编来代替的。
它们在.data 段(已初始化)或.bss 段(未初始化)中声明。
但是当我使用 gcc 编译一个非常简单的 .c 文件并使用 '-S' 命令行选项来检查反汇编代码时,我注意到: (1) .s 不是同时使用 .data 和 .bss,而只使用 .data (2) 一个整数(.long)的声明花费了好几条语句,其中一些对我来说似乎是多余的或无用的。
如下所示,我根据自己的问题添加了一些评论。
$猫n.c
int i=23;
int j;
int main(){
return 0;
}
$ gcc -S n.c $猫n.s
.file "n.c"
.globl i
.data
.align 4
.type i, @object #declare i, I think it's useless
.size i, 4 #There's '.long 23', we know it's 4 bytes, why need this line?
i:
.long 23 #Only this line is needed, I think
.comm j,4,4 #Why j is not put inside .bss .section?
.text
.globl main
.type main, @function
main:
.LFB0: #What does this symbol mean, I don't find it useful.
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl [=11=], %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0: #What does this symbol mean, I don't find it useful.
.size main, .-main
.ident "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.2) 5.4.0 20160609"
.section .note.GNU-stack,"",@progbits
我所有的问题都在上面的评论里,我在这里再次强调一下:
.type i, @object
.size i, 4
i:
.long 23
我真的认为上面的代码是多余的,应该像这样简单:
i:
.long 23
此外,"j" 没有符号标记,也没有放在 .bss 部分。
我是不是搞错了什么?请帮忙指正。非常感谢。
(我猜你正在使用一些 Linux 系统)
They're declared insided either .data section(initialzed),or .bss section(uninitialzed).
不,您还有许多其他部分,特别是 .comm
(对于 "common" 部分,初始化数据 common 到几个目标文件,即链接器将 "merge") 和 .rodata
用于只读数据。 ELF 格式足够灵活,可以允许许多部分和许多段(其中一些未加载 - 更准确地说是内存映射 - 在内存中)。
ELF 文件中各部分的描述比您认为的要复杂得多。花时间阅读更多,例如链接器和加载器,莱文。另请阅读 GNU binutils 的文档和 scripts 以及 ld(1) & as(1)。使用 objdump(1) 和 readelf(1) 探索现有的 ELF 可执行文件、目标文件和共享对象。另请阅读 execve(2) & elf(5)
But when I used
gcc
to compiled a very simple.c
file with-S
command line option
在检查由 gcc
生成的汇编文件时,我强烈建议至少传递 -fverbose-asm
以要求 gcc
在汇编文件中发出一些额外的有用注释。我通常还建议使用一些优化标志 - 例如-O1
至少(或者 -Og
最近版本的 gcc
)。
I noticed that: (1) .s is not using both .data and .bss, but only .data
不,您生成的代码使用 .comm
部分并将 j
的值放在那里。
(2) The declaration of an integer(.long) cost several statements, some of them seems redundant or useless to me.
这些大多不是汇编程序语句(翻译成机器码)而是汇编程序指令;它们非常有用(并且它们不会在 ld
产生的内存段中浪费 space,但 ELF 格式在其他地方有信息)。特别是 .size
和 .type
都是必需的,因为 ELF 文件中的符号表包含的不仅仅是地址(它还有大小的概念和非常原始的类型概念)。
.LFB0
是一个gcc
(实际上是cc1
-)生成的标签。 GCC 不关心生成无用的标签(对于 GCC 后端的汇编程序生成器来说更简单),因为它们不会出现在目标文件中。
There's '.long 23', we know it's 4 bytes,
您可能知道 long 是 4 个字节,但该信息(j
的大小)应该进入 ELF 文件,因此需要明确的汇编程序指令....
(我没有space也没有时间解释ELF格式,你需要阅读很多关于它的页面,它比什么更复杂更完整你相信)
顺便说一句,Drepper 的 How To Write Shared Libraries 相当长(超过 40 页)并且解释了很多关于 ELF 文件的内容,重点是共享库。