Assembly 将C代码转换为程序集
我正在通过将简单的C代码转换成汇编代码来练习我在汇编中学到的东西 这是C语言的代码Assembly 将C代码转换为程序集,assembly,masm,Assembly,Masm,我正在通过将简单的C代码转换成汇编代码来练习我在汇编中学到的东西 这是C语言的代码 int square_me (int val) { return (val* val) } 这是我转换成汇编的代码(我声明了val并将其初始化为4) 但当我看到文档中的答案时,它与我的答案大不相同,下面是他如何将其转换为汇编的 Push EBP mov EBP, ESP mov EAX, DWORD PTR [EBP + 8] XOR EDX, EDX mov EBX, EAX MUL EBX
int square_me (int val)
{
return (val* val)
}
这是我转换成汇编的代码(我声明了val并将其初始化为4)
但当我看到文档中的答案时,它与我的答案大不相同,下面是他如何将其转换为汇编的
Push EBP
mov EBP, ESP
mov EAX, DWORD PTR [EBP + 8]
XOR EDX, EDX
mov EBX, EAX
MUL EBX
MOV ESP, EBP
POP EBP
Ret
问题1:我是否正确地将上面看到的C代码转换为汇编代码
问题2:这是干什么用的
mov EAX,DWORD PTR[EBP+8]
问题3:他为什么要这样做?EDX在那句话之后就不用了,那又有什么意义呢
XOR-EDX,E
有什么想法吗
谢谢 XOR-EDX,EDX
他为什么要这么做?EDX在那句话之后就不用了,那又有什么意义呢
它被清零了 在较大的程序中,edx可能大于0,并且可能具有有价值的数据 如果数字足够大,mul无论如何都会覆盖它,但是通过输入“xor dx,dx”,程序员已经向您发送了一个烟雾信号,在这个例程中dx有时会被烤熟,因此您需要先推送或存储dx ============= mov EAX,DWORD PTR[EBP+8]
在您的示例中,您的代码中有两个部分刚刚拼凑在一起。希望这只是一个格式错误。否则代码就没有意义了 首先,调用函数的部分。这可能是某个较大程序的一个片段,该程序对结果执行某些操作并最终退出
val dw 4
push val
call square_me
push EIP
这里的问题是:
推送EIP
不是有效的指令。你不能推EIP注册,即使可以,你为什么要推add ESP,4
的内容来清理推送到堆栈上的valpush EBP
mov EBP, ESP
这一点很好-您正在设置堆栈框架。但下一行的目的是什么
push val
首先,您要访问全局变量val,而不是传递给函数的参数。如果您想按名称访问参数,我相信您可以将其设置为MASM中PROC
指令的一部分,否则您需要使用[ebp+8]
来访问堆栈上的第一个参数
但是,无论您如何访问它,都不需要在这里保存堆栈上的值。它已经在记忆中了——你不会失去它的
对于乘法,这不是有效的指令:
mul val, val
不能将两个内存引用相乘-只能使用EAX寄存器相乘。因此,您需要首先将您的值加载到eax中。大概是这样的:
mov EAX,[EBP+8]
mul EAX,EAX
push EBP
mov EBP, ESP
mov EAX, [EBP + 8]
mul EAX, EAX
mov ESP, EBP
pop EBP
ret
val // push val
return address // call square_me
STACK TOP: EBP // push ebp
在这一点上,结果将是EAX(和EDX-但我们不关心高位词),这是函数返回答案所需要的。但接下来你要做的是:
mov eax, val
这将覆盖刚刚计算的乘法结果
pop val
此pop假定与初始的push val
一起出现,同样可以删除
mov ESP, EBP
pop EBP
这些都很好-这只是清理堆栈框架。但是你不需要这个:
leave
leave
指令与mov-esp、ebp/pop-ebp
基本相同。你不需要两者兼而有之
简而言之,您的函数应该更像这样:
mov EAX,[EBP+8]
mul EAX,EAX
push EBP
mov EBP, ESP
mov EAX, [EBP + 8]
mul EAX, EAX
mov ESP, EBP
pop EBP
ret
val // push val
return address // call square_me
STACK TOP: EBP // push ebp
至于文件中给出的答案,也不是很好。没有理由将EDX设置为零。正如ady已经说过的,mul
指令无论如何都会覆盖EDX
我可以理解,在mul
指令之后,可能会将其设置为零,因为考虑到对有符号整数使用无符号乘法,结果在技术上是不正确的。这并不重要,因为不管怎样,您都将丢弃高位词(EDX)。在我看来,使用imul
会更清晰
我也不明白为什么他们觉得有必要将参数同时移入EBX和EAX,而他们本可以将EAX与自身相乘。也许这样做有一些性能方面的原因,但我对此表示怀疑
关于使用[EBP+8]
访问函数参数,您需要了解函数中堆栈的外观
调用函数时,首先推送val,然后调用将其返回地址推送到堆栈上,然后在函数内部推送EBP。因此,此时,堆栈将如下所示:
mov EAX,[EBP+8]
mul EAX,EAX
push EBP
mov EBP, ESP
mov EAX, [EBP + 8]
mul EAX, EAX
mov ESP, EBP
pop EBP
ret
val // push val
return address // call square_me
STACK TOP: EBP // push ebp
现在,当您执行
mov EBP,ESP
时,您将已将EBP设置为指向堆栈顶部。因此,在[EBP+0]
中有保存的EBP副本,在[EBP+4]
中有呼叫者的返回地址,在[EBP+8]
中有调用中传递的val参数。确定。所以在C语言中,这就像初始化一个字符串为null以避免垃圾?你能告诉我我是否正确地在汇编中转换了那个代码吗?谢谢,我会读一读这篇文章的,你正在做的是我不使用的C调用约定哇!这真的很有帮助,说真的!!非常感谢。是的,你是对的,这是主{val dw 4(\n)push val(\n)call square\u me(\n)push EIP}的一部分。我不应该把它放在那里,无论如何,我包括了push EIP,以便ret在执行函数后知道返回到哪里。我在什么地方读过。你是否有更好的想法如何做呢?不过我有几个问题,1)这是否意味着对于所有的数学运算,我们必须单独使用EAX?假设我想把这个数学运算转换成汇编,SUM=a+b+c+d;这将涉及到大量向堆栈中推送值,以及大量的[EBP+某物]来获取我们推送的内容?{push a(\n)push b(\n)push c(\n)pop eax(\n)add eax,[ebp+8](\n)add eax,[eax+16]}2)我只是想澄清一下,EDX是自动生成的