将C代码转换成汇编

通过将简单的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代码转换为Assembly?

问题2:这是什么

mov EAX,DWORD PTR [EBP + 8]

问题3:他为什么需要这样做? 在该声明之后,EDX并没有使用,所以有什么意义?

XOR EDX,E

任何想法?

谢谢!


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

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

val dw 4
push val
call square_me
push EIP

这里的问题是:

  • push 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
    

    在这一点上,结果将在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参数。


    XOR EDX,EDX

    他为什么需要这样做? 在该声明之后,EDX并没有使用,所以有什么意义?


    它被清除为零

    在一个更大的程序中,edx可能会大于0并且可能有宝贵的数据

    无论如何,如果数字足够大,mul会覆盖它,但通过放入“xor dx,dx”,程序员向您发送了smokesignal,dx有时会在此例程中烤面包,所以您需要先推送或存储dx

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

    mov EAX,DWORD PTR [EBP + 8]

    MOV EAX,DWORD PTR SS的含义是什么:[EBP + 8h]以及如何将它转换为AT&T格式?

    在这种情况下,OllyDbg和Assembler中的EBP + 8是什么意思?

    链接地址: http://www.djcxy.com/p/67093.html

    上一篇: converting C code into assembly

    下一篇: Jumping to the next "instruction" using gdb