将C代码转换为程序集

时间:2013-05-20 09:32:46

标签: assembly masm

我正在练习通过将简单的C代码转换为汇编代码而在汇编中学到的东西。

这是C

中的代码
int square_me (int val)

{

return (val* val)

}

这是我的代码转换为Assembly(我声明为val并将其初始化为4)

    val dw 4    ; declaration and initialization of the val variable (in main)

    push val    ; push val onto the stack so that you still have a copy of the original value of val incase i'll be needing it in some methods or functions (in main)

    call square_me  ; calling the function square_me, (in main)

    push EIP   ; pushing the value of EIP onto the stack so the code knows where to go back after the function

    push EBP    ; creating the stack frame for the function

    mov EBP, ESP    ; same with the one above

    push val     ; save the value of val so that ill have a copy of the original value of val in case I made some changes to it

    mul val, val   ; multiply to val to itself, and save it to val

    mov eax, val  ; move the value of val to eax

    pop val    ; pop the original value of val from the stack

    mov ESP, EBP   ; to restore the stack frame

    pop EBP    ; same with the one above

    leave     

    ret     ; return to the caller

但是当我看到文件中写的答案时,它与我的差别很大,这就是他如何将其转换为汇编

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

有什么想法吗?

谢谢!

2 个答案:

答案 0 :(得分:3)

您的代码中有两个部分刚刚在您的示例中被卡在一起。希望这只是一个格式错误。否则代码没有意义。

首先,调用该函数的部分。这假定是一些较大程序的片段,它会对结果做出某些决定并最终退出。

val dw 4
push val
call square_me
push EIP

这里的问题是:

  1. push EIP不是有效的指令。你不能推EIP注册,即使你可以,你为什么要这样做?
  2. 对于这种调用格式,调用者负责清理堆栈,因此您需要使用add ESP,4之类的内容来跟踪该调用,以清理您推送到的 val 堆栈。
  3. 然后是函数本身:

    push EBP
    mov EBP, ESP
    

    这一点很好 - 你正在设置堆栈帧。但下一行的目的是什么?

    push val
    

    首先,您要访问全局变量 val 而不是传递给函数的参数。如果您想按名称访问参数,我相信您可以将其设置为MASM中PROC指令的一部分,否则您需要使用[ebp+8]来获取堆栈中的第一个参数。 / p>

    无论您如何访问它,都不需要在此处将值保存在堆栈中。它已经在记忆中 - 你不会失去它。

    对于乘法,这不是有效的指令:

    mul val, val
    

    您不能将两个内存引用相乘 - 您只能将某些内容与EAX寄存器相乘。所以你需要先将你的值加载到eax中。像这样:

    mov EAX,[EBP+8]
    mul EAX,EAX
    

    此时结果将是EAX(和EDX - 但我们不关心高字),这是函数返回答案所需的内容。但是你这样做了:

    mov eax, val
    

    这只会覆盖你刚才计算的乘法结果。

    pop val
    

    此弹出式假设与初始push val一致,同样可以删除。

    mov ESP, EBP
    pop EBP
    

    那些很好 - 只是清理堆栈帧。但是你不需要这个:

    leave
    

    leave指令与mov esp,ebp / pop ebp基本相同。你不需要他们两个。

    简而言之,您的功能应该更像这样:

    push EBP
    mov EBP, ESP
    mov EAX, [EBP + 8]
    mul EAX, EAX
    mov ESP, EBP
    pop EBP
    ret
    

    至于文件中给出的答案,这也不是很好。没有理由将EDX设置为零。正如ady已经说过的那样,mul指令无论如何都将覆盖EDX。

    我可以理解在mul指令之后可能将其设置为零,因为鉴于您在有符号整数上使用无符号乘法,结果在技术上是不正确的。这无关紧要,因为无论如何你都要抛弃高位词(EDX)。在我看来,使用imul代替它会更清楚。

    我也不明白为什么他们觉得有必要将参数移动到EBX和EAX中,因为它们可能只是将EAX与自身相乘。也许有一些表现理由,但我对此表示怀疑。

    关于使用[EBP+8]访问函数参数,您需要了解函数内堆栈的样子。

    调用该函数时,首先按 val ,然后调用将其返回地址压入堆栈,然后在函数内推送EBP。那么在那时,你的堆栈看起来像这样:

               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 参数在电话中通过了。

答案 1 :(得分:0)

XOR EDX,EDX

为什么他需要这样做?在该声明之后,EDX没有使用,那么重点是什么?


它被清除为零

在较大的程序中,edx很可能> 0并且可能具有有价值的数据

如果数字足够大,mul会覆盖它,但是通过输入“xor dx,dx”,程序员已经发送了一个smx信号,dx有时会在此例程中吐司,所以你需要推送或存储dx第一

=============

mov EAX,DWORD PTR [EBP + 8]

What's the meaning of MOV EAX, DWORD PTR SS:[EBP+8h] and how can I translate it into AT&T format?

What does EBP+8 in this case in OllyDbg and Assembler mean?