Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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!

like image 798
Yichen Avatar asked Dec 18 '22 06:12

Yichen


2 Answers

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 x86 tag wiki. The tag wiki is full of links to docs and guides.

like image 172
Peter Cordes Avatar answered Dec 28 '22 08:12

Peter Cordes


You should do p &buffer not p $buffer. The $ is the assembler syntax for an immediate operand, while in gdb that is a convenience variable (and register) prefix. To print the contents use something like x/12c &buffer or p (char[12])buffer

PS: debug info works for locals too, you don't need it to be global.

like image 23
Jester Avatar answered Dec 28 '22 09:12

Jester