I’m really new to assembly language, and I’m trying to decode an assembly file generated from a binary (with gdb). I’m having trouble understanding the following code (this is the start of a new function). I am on an x64 machine and %rdi holds 6 digits (my input). So let’s just say that’s 0 1 2 3 4 5)
400e79: 55 push %rbp
400e7a: 48 89 e5 mov %rsp,%rbp
400e7d: 48 83 ec 30 sub $0x30,%rsp
400e81: 48 89 7d d8 mov %rdi,-0x28(%rbp)
400e85: 48 8d 75 e0 lea -0x20(%rbp),%rsi
400e89: 48 8b 7d d8 mov -0x28(%rbp),%rdi
If I may, I want to show you what I THINK is going on:
400e79: So when we start a function, we push the old base pointer onto the stack. So the stack looks like:
RETURN ADDRESS
old %rbp value <--- %rsp
400e7a: Stack looks like:
RETURN ADDRESS
old %rbp value <---- %rsp, %rbp
400e7d: Stack looks like:
RETURN ADDRESS
old %rbp value <----%rbp
----empty----
----empty----
----empty----
----empty----
----empty----
----empty---- <---%rsp
400e81: The stuff from here is what’s really confusing me. We are moving what’s in %rdi (0 1 2 3 4 5) into -0x28(%rbp). So the stack looks like:
RETURN ADDRESS
old %rbp value <----%rbp
----empty----
----empty----
----empty----
----empty----
0 1 2 3 4 5
----empty---- <---%rsp
However, when I try to see what’s in -0x28(%rbp) by running x/s $rbp-0x28 on gdb, I don’t get 0 1 2 3 4 5 as I’d expect, but I get "\020C". Am I running this correctly?
400e85: Stack:
RETURN ADDRESS
old %rbp value <----%rbp
----empty----
----empty----
----empty----
----empty---- <--- %rsi
0 1 2 3 4 5
----empty---- <---%rsp
400e89: I don’t understand this at all. We just did mov %rdi,-0x28(%rbp) earlier, why are we now doing mov -0x28(%rbp),%rdi? Isn’t this repetitive?
Thanks a lot! I know this is really long, I appreciate your time helping me out!
Your analysis is correct.
The reason you get a weird result when you run
x/s $rbp-0x28is that you can’t put a string in a register. The value the register contains is most likely a pointer to that string, which means you need another level of indirection to read it. I believe this will work:As for the useless load, that is common for code which has been compiled without optimization. The compiler blindly converts each line to assembly without considering the current register values. I have seen code which passed a single value through several registers back to the register it was originally in.