我正在尝试学习如何理解汇编程序中的c函数。我使用“gcc code.c -m32 -o code -S -fno-stack-protector”编译了以下c程序
#include <stdio.h>
void function( int a, int b, int c )
{
char buffer1[5];
char buffer2[10];
}
void main()
{
function( 1, 2, 3 );
}
声明输出如下:
.section __TEXT,__text,regular,pure_instructions
.globl _function
.align 4, 0x90
_function:
pushl %ebp
movl %esp, %ebp
subl $28, %esp
movl 16(%ebp), %eax
movl 12(%ebp), %ecx
movl 8(%ebp), %edx
movl %edx, -4(%ebp)
movl %ecx, -8(%ebp)
movl %eax, -12(%ebp)
addl $28, %esp
popl %ebp
ret
.globl _main
.align 4, 0x90
_main:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl $1, (%esp)
movl $2, 4(%esp)
movl $3, 8(%esp)
call _function
addl $24, %esp
popl %ebp
ret
.subsections_via_symbols
esp和ebp寄存器不能相等,因为定义int a,b,c的偏移量在_main和_function中是不同的。什么行从ebp中减去4?
谢谢!
答案 0 :(得分:2)
调用函数通常是这样的:
1)在函数外部,参数被压入堆栈
subl $24, %esp
movl $1, (%esp)
movl $2, 4(%esp)
movl $3, 8(%esp)
2)在函数内部,在堆栈上分配空间来保存参数和局部变量。
subl $ 28,%esp
在这种情况下,你有3个整数和15个字符,总共27个字节;这与4字节边界对齐。
3)然后将参数复制到本地堆栈空间。
movl 16(%ebp), %eax
movl 12(%ebp), %ecx
movl 8(%ebp), %edx
movl %edx, -4(%ebp)
movl %ecx, -8(%ebp)
movl %eax, -12(%ebp)
这里,16(%ebp)和friends是外推的参数的地址,-4(%ebp)是新分配的堆栈空间中的地址,这些值被复制到这些地址中。
答案 1 :(得分:1)
没有必要在任何地方减去4,因为它是返回地址(给定32位架构)将消耗堆栈中的前4个字节。
因此,当引用堆栈上的元素时,$ 4的差异。在 call
指令之前,尚未推送返回地址。因此抵消$ 0 $ 4和$ 8在主要方面是正常的:
movl $1, (%esp)
movl $2, 4(%esp)
movl $3, 8(%esp)
执行:
call _function
main中的将eip(返回地址)的内容推送到堆栈上,从而将esp提高4。
在函数中,返回地址(消耗4个字节)将位于堆栈顶部,正确的偏移量为 - $ 4, - $ 8和 - $ 12这正是函数中使用的值:
movl %edx, -4(%ebp)
movl %ecx, -8(%ebp)
movl %eax, -12(%ebp)