I have been having some issues debugging code assembled by nasm with gdb: it seems like gdb doesn't do well with nasm local labels. nasm generates a local symbol named «function».label, which seems to confuse gdb, as it loses track of which function it is in.
Here is one scenario in which it gives a sub-optimal debugging experience:
section .text
global _start
_start:
call foo
ud2
foo:
push rbp
mov rbp, rsp
call bar
.end:
pop rbp
ret
bar:
ret
Compile and debug:
$ nasm -f elf64 -g -F DWARF example.asm -o example.o
$ ld example.o -o example
$ gdb ./example
Reading symbols from ./example...done.
(gdb) b foo
Breakpoint 1 at 0x400087: file example.asm, line 10.
(gdb) run
Starting program: /home/mvanotti/orga2/gdb/example
Breakpoint 1, foo () at example.asm:10
10 push rbp
(gdb) ni
11 mov rbp, rsp
(gdb) ni
12 call bar
(gdb) ni
Program received signal SIGILL, Illegal instruction.
_start () at example.asm:7
7 ud2
As you can see, nexti continues execution even after the return from the bar function call. I believe this is caused because the next instruction in foo belongs to the foo.end symbol, causing gdb to not recognize that as the return point of the function. Adding any other instruction before the .end label in the asm file fixes the issue.
Similarly, the backtrace gets all messed up when it steps into a local label:
(gdb)
foo.end () at example.asm:14
14 pop rbp
(gdb) bt
#0 foo.end () at example.asm:14
#1 0x0000000000000000 in ?? ()
(gdb)
This also affects yasm and lldb.
There is not a clear workaround for this. I couldn't find an option in nasm to not emit the function.label symbols, or an easy way to remove them. strip for example, lets you specify the --wildcard option, but the regexp syntax is too basic and cannot match something like .+\.*. The closest I got was strip --wildcard -N "*.*", but that also matches .something
In gas, this is solved by creating a label in the form of .Llocal_label$ which gets discarded automatically by ld.