2

In a gdb session, how are the addresses list in the comments of the assembly output computed? To give an example, I am currently on the following instruction:

 0x0000555555556140  ? jmpq   *0x7af5a(%rip)        # 0x5555555d10a0 <strlen@got.plt>

We can confirm that the instruction pointer matches the address shown in the left column:

(gdb) p $rip
$1 = (void (*)()) 0x555555556140 <strlen@plt>

From here, we are going to jump to the address pointed at by $rip + 0x7af5a. The address with the jump pointer

(gdb) p/z ($rip + 0x7af5a)
$2 = 0x00005555555d109a

points to

(gdb) x/g ($rip + 0x7af5a)
0x5555555d109a <getpwuid@got.plt+2>:    0xd1e0000055555555

This does not match the address in the comment for this instruction (0x5555555d10a0), which I naively expected was meant to convey where the jump was going to go.

That address turns out to be 7af60 from the current instruction:

(gdb) p/z 0x5555555d10a0 - 0x0000555555556140  # commented address - current address
$3 = 0x000000000007af60

i.e., $rip + 0x7af60, which is 6 bytes beyond the jump pointer ($rip + 0x7af5a). What is the significance of commenting an address 6 bytes beyond the jump pointer?

How can the jump address be displayed in the GDB console without relying on the comments provided by GDB's disassembly? Or assigned to a GDB variable for use when scripting GDB.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
user001
  • 1,850
  • 4
  • 27
  • 42
  • 4
    RIP-relative addressing is relative to the *end* of the instruction, not the start. Same as for relative jumps. – Peter Cordes Jan 12 '20 at 21:38
  • @PeterCordes: Thanks, so that means that the instruction is 6 bytes long, and the RIP-relative address points to the final byte of the instruction? What is the best way to show an instruction in gdb given its RIP-relative address, particularly if we don't know the length of the instruction a priori? – user001 Jan 12 '20 at 21:41
  • Yes, in this case opcode(1) + modrm(1) + rel32(4) is 6 bytes. You can think of it as RIP = address of next instruction during execution of this one. I'm not sure what the easiest way to get GDB to show you the target address given just the machine code and *starting* address for an instruction in general; it's non-trivial because instructions are variable-length. – Peter Cordes Jan 12 '20 at 21:45
  • Doesn't GDB's decoding produce a comment with the target address for you? Or are you wanting to do this programmatically in a GDB script? If so, maybe you should edit your question to ask that specifically. Otherwise it's basically a duplicate of how does RIP-relative work in machine code; looking for a suitable duplicate now. e.g. [About the je in assembly](//stackoverflow.com/q/6017571) – Peter Cordes Jan 12 '20 at 21:48
  • @PeterCordes: Thanks, opcode I am guessing is `jmp` in this case, and rel32 I suppose is `0x7af5a`, but what is `modrm`? Just to be clear, is the RIP-relative address (end of target instruction minus end of this instruction) or (end of target instruction minus start of this instruction) or something else? Yes, GDB does comment the address for me, but I was also wondering how to compute that address within the gdb console. Thanks again. – user001 Jan 12 '20 at 21:52
  • No, the *opcode* is `FF /4`, for that form of the jmp mnemonic. https://www.felixcloutier.com/x86/jmp. A ModRM byte (and optional SIB, rel32, disp8, or disp32) is how x86 machine code encodes register / memory operands. – Peter Cordes Jan 12 '20 at 21:53
  • Try this to get the length of an instruction: `(gdb) python import gdb; print(gdb.selected_frame().architecture().disassemble(0x0000555555556140)[0]['length'])` – Mark Plotnick Jan 13 '20 at 21:13
  • @MarkPlotnick: I think my python setup must be awry, since I get `No symbol "gdb" in current context.` after importing and attempting to run the print statement. – user001 Jan 13 '20 at 21:18
  • @MarkPlotnick: Yes, I had recognized that `(gdb)` was the prompt. The `import` appears to work fine (no warning or error at least), bu the print statement fails: `print(gdb.selected_frame().architecture().disassemble(0x5555555d10a8)[0]['length']) ==> No symbol "gdb" in current context.` The `gdb` object whose `selected_frame()` method is called is, for some reason, not found (despite `import` apparently working). – user001 Jan 13 '20 at 22:34
  • @MarkPlotnick: Yes, that works; it prints a very large list. – user001 Jan 13 '20 at 22:51
  • 1
    Sorry, just trying to figure out how you were getting a gdb command line error message from a `python` command. Were you typing `print` on a separate line? The formatting in comments isn't too great. My suggestion relies on typing that entire `python` command on a single line. – Mark Plotnick Jan 13 '20 at 22:53
  • @MarkPlotnick: Oh, I see. Yes, I executed `import` as one line, then `print` as another line. It works now, thanks. – user001 Jan 13 '20 at 23:02

0 Answers0