2

I'm writing a compiler, and it emitted the following (Intel-syntax) assembly code for Linux (x86-64):

lea r13, _s1
mov qword ptr [rbp + -2*8], r13
mov r10, qword ptr [rbp + -2*8]
lea r13, qword ptr [r10 + 8]

If I'm reading this correctly, this code is supposed to load the address of label _s1 into r13, store it on the stack, read it from the stack into r10, add 8, and store the reuslt in r13. That matches the expected behaviour of my program, and it seems to work as expected (program doesn't crash here) when I am not debugging the program.

However, when I try to debug the program using VSCode with CodeLLDB, as I step through the program, I see behaviour that I can't understand. This is what seems to happen according to CodeLLDB:

  • lea r13, [0x425290]: 0x425290 is loaded into r13
  • mov qword ptr [rbp - 0x10], r13: 0x425290 is written to address 0x7fffffffe1f0; I confirmed this by running memory read -s1 $rbp-0x10 in LLDB
  • mov r10, qword ptr [rbp - 0x10]: 0xffffe6f400000000 is read into r10. Why?
  • lea r13, [r10 + 0x8]: 0xffffe6f400000008 is loaded into r13

Why is the value that I read back from the stack different from the value that I wrote into it?

Edit: It seems like this weird behaviour doesn't happen when I use VSCode's built-in GDB debugger. Am I misusing LLDB?

laptou
  • 6,389
  • 2
  • 28
  • 59
  • Did you remember to adjust the stack pointer to the bottom of your stack frame? Some debugger features need scratch memory in the program's address space, and will often use the stack below the stack pointer. What's the value in `rsp` while this is going on? – Nate Eldredge Apr 18 '23 at 22:58
  • Did you even set up `rbp` to point to your stack frame? – Jester Apr 18 '23 at 23:01
  • @NateEldredge @Jester I used `enter 0x140, 0` to set up the stack frame. `rbp = 0x00007fffffffe200`, `rsp = 0x00007fffffffe0c0` – laptou Apr 18 '23 at 23:04
  • That certainly looks correct. – Jester Apr 18 '23 at 23:16
  • @Jester it's a total head-scratcher, because it works fine when I use a different debugger (such as command-line GDB, or CLion GDB) or no debugger – laptou Apr 18 '23 at 23:40
  • 1
    Could you show the complete transcript of your debugger session? – Nate Eldredge Apr 18 '23 at 23:53
  • `lea r13, _s1` is odd, using a `[disp32]` absolute addressing mode. In GAS Intel syntax, you want `lea r13, [rip + _s1]` for a normal RIP-relative addressing mode that will work when loaded at any address. Probably not your problem, though, since you do show the address being in the low 31 bits of virtual address space, where you could have used `mov r13d, OFFSET _s1` if you wanted to take advantage of it fitting in 32-bit absolute. ([How to load address of function or label into register](https://stackoverflow.com/q/57212012)) – Peter Cordes Apr 19 '23 at 00:48
  • This isn't a [mcve], at least without the info from comments about RSP and RBP values. You're sure that there's no signal handler that might have a pointer to that stack space? Or that you didn't execute a `leave` or something before these instructions, or especially *between* them so RBP points somewhere else? (BTW, `enter` is pretty inefficient; use `push rbp` / `mov rbp, rsp` / `sub rsp, ...` like GCC/clang do. `leave` is not bad, GCC uses it when a single `pop rbp` won't do.) – Peter Cordes Apr 19 '23 at 00:51

0 Answers0