我尝试将一个非常简单的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”是什么意思?
lea
是 gcc 用于将esp
对齐到 16 的非常笨重的代码的一部分。它仅在 32 位代码中的main
中执行此操作,或者如果其他函数的本地变量需要超过 16 字节的对齐方式。gcc 将返回地址复制到帧指针正上方,并且出于无意义的原因对ecx
进行了过于复杂的处理,在进入时保存/恢复了一个指向%esp
上方 4 个字节的指针。[LEA
不是复杂的] (//stackoverflow.com/a/46597375) - Peter Cordes