C 如何导航和描述此函数试图从给定的汇编代码中实现什么?
在我的教科书中,我在x86-64汇编中获得了以下功能:C 如何导航和描述此函数试图从给定的汇编代码中实现什么?,c,assembly,x86,x86-64,C,Assembly,X86,X86 64,在我的教科书中,我在x86-64汇编中获得了以下功能: foo: # line 1 movl $0, %eax # line 2 movl $0, %r8d # line 3 jmp .L2 # line 4 .L3: # line 5 addl
foo: # line 1
movl $0, %eax # line 2
movl $0, %r8d # line 3
jmp .L2 # line 4
.L3: # line 5
addl $1, %eax # line 6
.L2: # line 7
cmpl %esi, %eax # line 8
jge .L5 # line 9
movslq %eax, %rcx # line 10
cmpl %edx, (%rdi,%rcx,4) # line 11
jne .L3 # line 12
addl $1, %r8d # line 13
jmp .L3 # line 14
.L5: # line 15
movl %r8d, %eax # line 16
ret # line 17
到目前为止,我认为我已经能够用适当的C类型计算出函数的C签名。由于大小说明符都是l,我假设它返回一个int,函数的所有参数也都是int
int foo(int arg1, int arg2, int arg3)
通过进一步检查,此函数还包含for循环。使用与所用寄存器名相对应的变量名,例如,将eax用于%eax,我认为循环结构如下:
for (eax = 0; eax < esi; eax++)
然而,我在描述这个函数实际要实现的功能时遇到了很多困难。跳转指令和movslq%eax,%rcx是让我感到困惑的东西。有人能帮我浏览这个函数的集合并帮助我理解它想要实现什么吗?我对汇编还比较陌生,我还不完全习惯阅读它。为了提高我对汇编的理解,任何帮助或建议都将不胜感激。您看到的movslq实际上是指令,在AT&T语法中被称为movslq是的,愚蠢,我知道。后缀l long=4字节,q fourple=8字节表示两个操作数的大小。在EAX到RCX的情况下,这是一个简单的移动,符号扩展从较小的寄存器到较大的寄存器
跳转有点复杂,但您可以将程序集转换为伪C代码,如下所示:
傅:
movl$0,%eax eax=0
movl$0,%r8d r8d=0
jmp.L2转到L2
.L3:
添加$1,%eax eax++
.L2:
cmpl%esi,%eax如果eax>=esi
jge.L5转到L5
movslq%eax,%rcx rcx=eax
cmpl%edx、%rdi、%rcx,如果rdi[rcx]!=4edx
jne.L3转到L3
加成$1,%r8d r8d++
jmp.L3转到L3
.L5:
移动%r8d,%eax
返回r8d
这里的要点是:
x86-64 System V调用约定使用RDI、RSI、RDX、[…]作为参数,RAX作为返回值。
我们可以看到RDI按原样使用,而其他两个参数被视为4字节参数:我们只看到ESI和EDX出现。
要返回的实际值位于R8D中,也是4个字节。
循环变量为EAX,初始cmpl%esi,%EAX;L5是循环的控制条件,这意味着ESI保存数组的总长度。此外,JGE指令是有符号的,这意味着EAX和ESI被视为有符号的4字节整数,即C int。
比较cmpl%edx,%rdi,%rcx,4使我们了解到rdi用作4字节元素数组的基址,例如int,因为此操作取消了rdi+rcx*4的引用,以获取AT&T术语l后缀中的长4字节。
该比较检查EDX第二个参数是否等于RDI引用的数组中位置RCX处的元素。我们可以看到RCX直接来自EAX,因此这是在检查当前索引处的元素。
如果比较失败,我们就不增加R8D。否则,如果成功,我们将增加R8D。这是反向逻辑,但我们可以简单地否定它,以理解只有当当前索引处的元素等于EDX第三个参数时,R8D才会增加。
考虑到所有这些,我们可以继续简化代码:
int funcint*rdi,int esi,int edx{
int-eax=0;
int r8d=0;
for;;eax++{
如果eax>=esi
返回r8d;
int rcx=eax;
如果rdi[rcx]!=edx
持续
r8d++;
}
返回r8d;
}
此时,应该非常清楚该函数的作用:它扫描一个整数数组,计算与给定值匹配的元素数
我们可以更简洁地将其改写为:
int funcint*rdi,int esi,int edx{
int r8d=0;
int eax;
对于eax=0;eax