Search code examples
assemblygdbx86-64movyasm

Why isn't gdb showing me the change in a BSS array when I calculate the address with the same expression as the addressing mode?


Wrote simple program with large buffer in .bss segment

h_vals:
    resq 99999

then tried to increment value of some array cell.

mov rcx, [h_vals+8*rax]
inc rcx
mov [h_vals+8*rax], rcx

Still in gdb see the same value(0) both before and after third instruction execution.

x/dg &h_vals &h_vals + 8 * $rax
0x6d68c0: 0

Why am I still seeing 0 when I try to inspect the address I stored to?


Solution

  • mov obviously does move data; Your program would segfault if it failed.

    The default size for symbols with no debug info is 4 bytes. You can use ptype h_vals to check what gdb thinks about it.

    Remember that gdb's syntax works like C, even if you're debugging asm. In C, adding something to a pointer offsets by that many elements, not that many bytes.

    &h_vals &h_vals + 8 * $rax isn't evaluating in gdb to the address you expect. (Also, I think &h_vals &h_vals is a typo, and isn't what you actually ran.)

    Since gdb thinks &h_vals is an int*, &h_vals + offset will produce a byte offset of 4 * offset, just like h_vals[offset] in C. So the address you're examining in gdb is actually [h_vals + 8 * 4 * rax].

    Another way to check: p /x &h_vals and p /x $rax separately. You can work out the math yourself and compare to the address you saw in the x/ output.


    The safest solution here is to cast to char*:

    x /dg  8 * $rax + (char*)&h_vals
    

    Or: define your symbols in a .c so the compiler will generate debug info for them (because you don't want to do that by hand).

    e.g. put unsigned long h_vals[99999]; in a .c that you compile with gcc -c -g vars.c, and link the resulting .o with the .o YASM creates from your .asm.