我正致力于将汇编语言转换为C程序。据我所知,在下面的函数中,有一个参数设置为0,并将其与某些东西进行比较(我不确定这是为什么我感到困惑)。如果x小于或等于它被比较的任何东西,那么函数将跳转到f2,然后将0复制到局部变量,但如果不是,它将1复制到局部变量并将其复制到寄存器a中返回。我不明白在前几行中与参数进行比较的内容。有人能指出我正确的方向吗?
这是语言:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
cmpl $0, 8(%ebp)
jle . f2
movl $1, -4(%ebp)
jmp. f3
.f2:
movl $0, -4(%ebp)
.f3:
movl -4(%ebp), %eax
leave
ret
我认为这应该是在C:
中的样子 fn(int x)
{
x = 0;
if x <= ? :
int y = 0;
else
int y = 1;
}
return y;
先谢谢你了
答案 0 :(得分:2)
(首先,抱歉,但我会转换为英特尔语法,我真的不能把我的想法包围在AT&amp; T)
push ebp
mov ebp,esp
sub esp,4
这是通常的功能序幕;保存基指针,将堆栈指针设置为基指针,在堆栈上为一个局部变量创建空间(以后称为[ebp-4]
);我们称这个变量为int ret
。
cmp dword ptr[ebp + 8], 0
将ebp+8
的值与0
进行比较,并相应地设置标志寄存器,以便以后任何条件跳转指令都可以根据比较结果进行操作。 ebp+8
处的位置可能是32位函数参数(ebp+4
通常是函数的返回值);我们称这个参数为int x
。
jle .f2
mov dword ptr[ebp-4], 1
jmp .f3
.f2:
mov dword ptr[ebp-4], 0
.f3:
这是相当简单的;如果在最后一次比较中第一个操作数(AT&amp; T语法情况下的第二个操作数)小于或等于第二个操作数,则跳转到标签.f2
,否则直行(并且在mov
之后,跳转到.f3
)。
最终结果是:x<=0
,ret=0
,否则为ret=0
。
mov eax,dword ptr[ebp-4]
这将ret
移动到eax
,这是许多调用约定中返回值的位置。
leave
ret
这是标准功能结尾;它将ebp
和esp
修复为上一个状态,然后ret
返回给调用者。
所以,整个事情归结为:
int f(int x)
{
int ret;
if(x<=0)
ret=0;
else
ret=1;
return ret;
}
或者,更简洁:
int f(int x)
{
return x>0;
}
顺便说一句,总而言之这看起来就像禁用了优化的gcc
的输出:编译我用-m32 -c -S
写的第一个函数我得到了:
.LFE0:
.size g, .-g
.globl f
.type f, @function
f:
.LFB1:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
subl $16, %esp
cmpl $0, 8(%ebp)
jg .L4
movl $0, -4(%ebp)
jmp .L5
.L4:
movl $1, -4(%ebp)
.L5:
movl -4(%ebp), %eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
,删除cfi-directives之后,就是你发布的内容。
(添加-O3
,它肯定更聪明:
movl 4(%esp), %edx
xorl %eax, %eax
testl %edx, %edx
setg %al
ret
)
答案 1 :(得分:0)
在您使用的汇编语言语法中,$0
表示实际值为零。所以说明
cmpl $0, 8(%ebp)
将内存位置8(%ebp)
中的值与零值进行比较。您已在示例代码中用x
表示此值,但它不需要是变量。
8(%ebp)
部分代表内存访问。要了解这是什么,请考虑对此函数的调用可能如下:
pushl $5
call fn
这会将值5
推入堆栈,然后调用您的函数。然后call
指令将返回地址压入堆栈。因此,在调用此函数时,堆栈上有两个单词。函数中的第一条指令将另一个单词(%ebp
的前一个值)推入堆栈,因此我们有:
+----------------+
| 5 |
+----------------+
| return address |
+----------------+
| old %ebp |
+----------------+ <- %ebp
%ebp
的新值指向此底部。偏移量为8的值(此处为32位字)为5,即函数的参数。因此,在C中启动函数可能需要看起来更像:
int fn(int x)
{
if (x <= 0) ...