【发布时间】:2018-10-10 20:21:11
【问题描述】:
我试图编译一个非常简单的 C 程序并将其转换为汇编语言。
我使用的是 Ubuntu,操作系统类型是 64 位。
这是 C 程序。
void add();
int main() {
add();
return 0;
}
如果我使用 gcc -S -m32 -fno-asynchronous-unwind-tables -o simple.S simple.c 这就是我的汇编源代码文件的样子:
.file "main1.c"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
call add
movl $0, %eax
movl %ebp, %esp
popl %ebp
ret
.size main, .-main
.ident "GCC: (Debian 4.4.5-8) 4.4.5" // this part should say Ubuntu instead of Debian
.section .note.GNU-stack,"",@progbits
但它看起来像这样:
.file "main0.c"
.text
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ebx
pushl %ecx
call __x86.get_pc_thunk.ax
addl $_GLOBAL_OFFSET_TABLE_, %eax
movl %eax, %ebx
call add@PLT
movl $0, %eax
popl %ecx
popl %ebx
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.section
.text.__x86.get_pc_thunk.ax,"axG",@progbits,__x86.get_pc_thunk.ax,comdat
.globl __x86.get_pc_thunk.ax
.hidden __x86.get_pc_thunk.ax
.type __x86.get_pc_thunk.ax, @function
__x86.get_pc_thunk.ax:
movl (%esp), %eax
ret
.ident "GCC: (Ubuntu 6.3.0-12ubuntu2) 6.3.0 20170406"
.section .note.GNU-stack,"",@progbits
在我的大学,如果我使用 64 位 Linux 版本,他们告诉我使用标志 -m32。有人可以告诉我我做错了什么吗? 我是否使用了正确的标志?
在 -fno-pie 之后编辑
.file "main0.c"
.text
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $4, %esp
call add
movl $0, %eax
addl $4, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.ident "GCC: (Ubuntu 6.3.0-12ubuntu2) 6.3.0 20170406"
.section .note.GNU-stack,"",@progbits
看起来更好,但并不完全相同。 例如,leal 是什么意思?
【问题讨论】:
-
尝试在命令行中添加
-fno-pie。如果可行,我会解释。 -
@zwol thx 我试过了,但结果并不完全相同。我在上面发布了结果
-
lea是 gcc 将esp对齐 16 的非常笨拙代码的一部分。它仅在 32 位代码中的main中执行此操作,或者如果它需要超过 16 字节其他功能中的本地人对齐。 gcc 将返回地址复制到帧指针的正上方,并无缘无故地使用ecx进行过度复杂的操作,保存/恢复指向%esp上方4 个字节的指针。LEAis not complicated -
编译器可以生成它想要的任何代码,只要它是正确的,你的代码是正确的,不能保证你会得到完全相同的代码。为此,您还需要使用相同版本的编译器和编译选项(并且 - 编译器结果的二进制稳定性 - 实际上是 gcc 和许多其他编译器的功能,编译器每次都可能产生不同的输出,并且它仍然可以用作编译器(但为编译器创建者本身调试它会是一场噩梦),所以不要认为这是理所当然的,这实际上是努力工作的结果。
-
我专门针对对齐序言提出了一个新问题:stackoverflow.com/q/50106490/379897
标签: c function assembly call flags