I'm confused about the use of "&" when examining a label using GDB.
I'm following a book from 2008. The author's debugger apparently shows the value stored at the label. However, I can't get the same debugger and am using GDB. I found somewhere that I can see the value using:
(gdb) x/8c &Snippet
0x804a000 <Snippet>: 107 'k' 97 'a' 78 'N' 71 'G' 65 'A' 82 'R' 79 'O' 79 'O'
If I instead call x/8c Snippet
, I get an error, "'Snippet' has unknown type; cast it to its declared type".
The x
command takes an address and I understand that &
works as the "address of" operator, like in C. In the code, I don't need to use &
. Isn't a label just a human readable handle for a memory address? I'm confused about why I need to use &
in GDB.
The code defines the bytes "KANGAROO" at Snippet
. It then loops 8 times, switching the letters at Snippet
to lowercase.
;; kangaroo.asm
section .data
Snippet db "KANGAROO"
section .text
global _start
_start:
nop ; start experiment
mov ebx, Snippet
mov eax, 8
DoMore: add byte [ebx], 32
inc ebx
dec eax
jnz DoMore
nop ; end experiment
section .bss
CodePudding user response:
GDB is not just an asm debugger, and is in fact primarily designed to debug compiled C programs and stuff like that. And its treatment of variable names / labels is designed around C variable-name semantics, not asm label semantics.
If GDB doesn't have symbol-type information, it doesn't know whether it should have value semantics like a C int
global variable, where using the bare name loads from that address (with some width that's also unknown to GDB), or like a C array where using the bare name decays to the address (in most contexts). Or whether it's a code label.
Older GDB I think used to have a default, but current GDB doesn't.
You're correct that an asm label is best thought of as having semantics like C char label[]
(at global scope).
Especially in NASM syntax where mov reg, name
is a mov-immediate of the absolute address, unlike GAS .intel_syntax noprefix
where it's a load, like MASM.
For more philosophical musings about the meaning of life (for an asm label), see Is every variable and register name just a pointer in NASM Assembly?
If you're debugging a program compiled from C with debug info which does define a char foo[8] = {1,2,3};
you should be able to use x /8c foo
to see the contents of memory there.
Indeed, I tested that and it works with this C program, on x86-64 Arch GNU/Linux
char foo[8] = {1,2,3};
int main(){}
$ gcc -g foo.c
$ gdb ./a.out
(gdb) ptype foo
type = char [8]
(gdb) p foo
$1 = "\001\002\003\000\000\000\000"
(gdb) x /8c foo
0x4028 <foo>: 1 '\001' 2 '\002' 3 '\003' 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000'
(It's a PIE executable that I haven't start
ed, so the address is just an offset relative to the image base at this point.)
I wouldn't recommend trying to write your own debug-info metadata by hand in asm. If you want to see what GCC does, though, you can look at it's gcc -g -S
output, e.g. on https://godbolt.org/z/q7EPT8jGG if you uncheck the directives filter. It's mostly numeric like:
.section .debug_info,"",@progbits
.Ldebug_info0:
.long 0x84
.value 0x5
.byte 0x1
.byte 0x8
.long .Ldebug_abbrev0
.uleb128 0x2
...
.long .LASF3
.uleb128 0x5
.string "foo"
.byte 0x1
.byte 0x1
.byte 0x6
.long 0x2e
.uleb128 0x9
.byte 0x3
.quad foo
.uleb128 0x6
.long .LASF5
.byte 0x1
.byte 0x3
.byte 0x5
.long 0x80
.quad .LFB0
.quad .LFE0-.LFB0
...
Next to the asm that defines the static storage in .data
for foo[]
itself, there's this which is still around without gcc -g
, but it's not sufficient for GDB to know how to treat it.
.type foo, @object
.size foo, 8
(This is GAS syntax; I'm not sure of the NASM equivalents.)