converting C code into assembly
I'm practicing what I have learned in assembly by converting simple C codes into assembly code.
This is the code in C
int square_me (int val)
{
return (val* val)
}
Here's my code converted into Assembly (I declared val and initialized it into 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
But when I looked at the answer written in the document, it is far different from mine, here's how he converted it into assembly
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
Question 1: Did I correctly convert the C code seen above to Assembly?
Question 2: What is this for
mov EAX, DWORD PTR [EBP + 8]
Question 3: Why does he need to do this? EDX wasnt use after that statement so what's the point?
XOR EDX, E
Any idea?
Thanks!
There are two parts to your code which have just been jammed together in your example. Hopefully that's just a formatting mistake. Otherwise the code makes no sense.
First, the part that calls the function. This assumedly would be a snippet from some larger program that does something with the result and eventually exits.
val dw 4
push val
call square_me
push EIP
The problems here are:
push EIP
isn't a valid instruction. You can't push the EIP register, and even if you could, why would you want to? add ESP,4
to clean up the val that you pushed onto the stack. Then for the function itself:
push EBP
mov EBP, ESP
That bit is good - you're setting up the stack frame. But what is the purpose of this next line?
push val
First you're accessing the global variable val rather than the parameter passed to the function. If you want to access parameters by name, I believe you can set that up as part of the PROC
directive in MASM, otherwise you need to use [ebp+8]
to get to the first parameter on the stack.
Regardless of how you access it, though, there is no need to save the value on the stack here. It's already in memory - you're not going to lose it.
As for the multiply, this isn't a valid instruction:
mul val, val
You can't multiply two memory references together - you can only multiply something with the EAX register. So you need to load your value into eax first. Something like this:
mov EAX,[EBP+8]
mul EAX,EAX
At this point the result will be in EAX (and EDX - but we don't care about the high word), which is what you want for the function to return the answer. But then you are doing this:
mov eax, val
That's just going to overwrite the multiplication result that you just calculated.
pop val
This pop assumedly goes with the initial push val
, and can likewise be removed.
mov ESP, EBP
pop EBP
Those are fine - that just cleans up stack frame. But then you don't need this:
leave
The leave
instruction is essentially identical to mov esp,ebp / pop ebp
. You don't need both of them.
In short, your function should look something more like this:
push EBP
mov EBP, ESP
mov EAX, [EBP + 8]
mul EAX, EAX
mov ESP, EBP
pop EBP
ret
As for the answer given in the document, that wasn't great either. There is no reason for setting EDX to zero. As ady has already said, the mul
instruction is going to override EDX anyway.
I could understand maybe setting it to zero after the mul
instruction, because the result is technically incorrect given that you are using an unsigned multiplication on signed integers. It just doesn't matter because you are going to be discarding the high word (EDX) anyway. In my opinion, it would have been clearer to use imul
instead.
I also don't see why they felt the need to move the parameter into both EBX and EAX when they could have just multiplied EAX with itself. Perhaps there is some performance reason for doing that, but I doubt it.
Regarding the use of [EBP+8]
to access the function parameter, you need to understand what your stack looks like inside the function.
When calling the function, you first push val, then the call pushes its return address onto the stack, and then inside the function you push EBP. So at that point, your stack would look like this:
val // push val
return address // call square_me
STACK TOP: EBP // push ebp
Now when you do mov EBP,ESP
you will have set EBP to point to the top of the stack. So at [EBP+0]
you have the saved copy of EBP, at [EBP+4]
you have the return address of the caller, and at [EBP+8]
you have the val parameter that was passed in the call.
XOR EDX, EDX
Why does he need to do this? EDX wasnt use after that statement so what's the point?
It's being cleared to zero
In a larger program edx will probbly be >0 and may have valuable data
The mul will overwrite it anyway, if the numbers are big enough, but by putting "xor dx,dx" the programmer has sent you a smokesignal that dx is sometimes toast in this routine so you will need to push or store dx first
=============
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?
链接地址: http://www.djcxy.com/p/67094.html上一篇: volatile语句的负载障碍在哪里?
下一篇: 将C代码转换成汇编