我正在致力于将汇编语言转换为 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;
提前谢谢您
最佳答案
(首先,抱歉,我会翻译成 Intel 语法,我真的无法全神贯注于 AT&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&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
)
关于c - 需要帮助在 C 代码中编写汇编语言,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23598034/