Assembly 将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

我正在通过将简单的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

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
    的内容来清理推送到堆栈上的val
  • 然后对于函数本身:

    push 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是自动生成的