Search code examples
assemblygdbelfdebug-symbolsgnu-assembler

The variable name defined in .bss section can not be found in gdb


I'm trying a simple assembly code:

.section .data
output:
    .ascii "The processor Vendor ID is 'xxxxxxxxxxxx'\n"
.section .bss
    .lcomm buffer, 12
.section .text
.code32
.globl _start
_start:
    movl $0, %eax
    cpuid
    movl $output, %edi

In .bss section I defined a variable named with "buffer"

When I try to get its address/value in gdb, it just prints:

(gdb) p $buffer
$1 = void

Using objdump, I found the name is not in ELF file, so how to keep such name information when running as and ld? Thank you!


Solution

  • Using objdump, I found the name is not in ELF file

    Works for me on Arch Linux with GNU binutils 2.28.0-3. Maybe you stripped your binary after linking?

    $ gcc -Wall -m32 -nostdlib gas-symbols.S
    $ file a.out
    a.out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, BuildID[sha1]=d5fdff41cc52e9de3b4cdae34cf4129de2b4a69f, not stripped
    
    $ nm a.out 
    080490ee B __bss_start
    080490f0 b buffer           ### local symbol in the bss
    080490ee D _edata
    080490fc B _end
    080490c4 d output
    080480b8 T _start
    

    I didn't need -g to preserve symbols in the executable. And also, on my system, -static is the default for -nostdlib. This is not always the case, see this Q&A about building asm source into 32 or 64-bit static or dynamic binaries, with gcc or with as and ld directly. Or with NASM and ld.

    (Note that .code32 doesn't change the object file format. You need to use build options, so it's probably better to omit .code32 so you're more likely to get errors (e.g. from push %ebx) if you try to build 32-bit code into a 64-bit object file.)

    Using as and ld directly (which gcc does under the hood, use gcc -v to see how), I also get the same result.

    $ as gas-symbols.S -o gas-symbols.o  --32 && 
      ld -o a.out gas-symbols.o  -m elf_i386
    $ nm a.out 
    ...
    080490b0 b buffer        ## Still there
    ...
    

    In GDB, as Jester points out, print the address not the value. GDB doesn't know it's an array, since you didn't use any directives to create debug info. (I wouldn't recommend trying to write such directives by hand. e.g. look at what gcc -S emits for static char foo[100]; (in a file by itself.)

    Anyway, GDB works if you use it right:

    $ gdb ./a.out
    (gdb) b _start
    (gdb) r
    Starting program: /home/peter/src/SO/a.out
    
    Breakpoint 1, _start () at gas-symbols.S:10
    (gdb) p buffer
    $1 = 0
    (gdb) p &buffer
    $2 = (<data variable, no debug info> *) 0x80490f0 <buffer>
    (gdb) ptype buffer
    type = <data variable, no debug info>
    

    You can work around the lack of type info by casting it, or using the x command:

    (gdb) p (char[12])buffer
    $4 = '\000' <repeats 11 times>
    (gdb) p /x (char[12])buffer
    $5 = {0x0 <repeats 12 times>}
    (gdb) x /4w &buffer             # eXamine the memory as 4 "words" (32-bit).  
    0x80490f0 <buffer>:     0x00000000      0x00000000      0x00000000      0x00000000
    (gdb) help x   # read this to learn about options for dumping memory
    

    For debugging asm, I have this in my ~/.gdbinit:

    set disassembly-flavor intel
    layout reg
    set print static-members off
    

    But since you're writing in AT&T syntax, you probably don't want intel-style disassembly. layout asm / layout reg is fantastic, though. See also debugging tips at the end of the tag wiki. The tag wiki is full of links to docs and guides.