You can switch to assembly layout in GDB:

(gdb) layout asm

See here for more information. The current assembly instruction will be shown in assembler window.

   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚0x7ffff740d756 <__libc_start_main+214>  mov    0x39670b(%rip),%rax        #β”‚
   β”‚0x7ffff740d75d <__libc_start_main+221>  mov    0x8(%rsp),%rsi              β”‚
   β”‚0x7ffff740d762 <__libc_start_main+226>  mov    0x14(%rsp),%edi             β”‚
   β”‚0x7ffff740d766 <__libc_start_main+230>  mov    (%rax),%rdx                 β”‚
   β”‚0x7ffff740d769 <__libc_start_main+233>  callq  *0x18(%rsp)                 β”‚
  >β”‚0x7ffff740d76d <__libc_start_main+237>  mov    %eax,%edi                   β”‚
   β”‚0x7ffff740d76f <__libc_start_main+239>  callq  0x7ffff7427970 <exit>       β”‚
   β”‚0x7ffff740d774 <__libc_start_main+244>  xor    %edx,%edx                   β”‚
   β”‚0x7ffff740d776 <__libc_start_main+246>  jmpq   0x7ffff740d6b9 <__libc_startβ”‚
   β”‚0x7ffff740d77b <__libc_start_main+251>  mov    0x39ca2e(%rip),%rax        #β”‚
   β”‚0x7ffff740d782 <__libc_start_main+258>  ror    $0x11,%rax                  β”‚
   β”‚0x7ffff740d786 <__libc_start_main+262>  xor    %fs:0x30,%rax               β”‚
   β”‚0x7ffff740d78f <__libc_start_main+271>  callq  *%rax                       β”‚
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
multi-thre process 3718 In: __libc_start_main     Line: ??   PC: 0x7ffff740d76d
#3  0x00007ffff7466eb5 in _IO_do_write () from /lib/x86_64-linux-gnu/libc.so.6
#4  0x00007ffff74671ff in _IO_file_overflow ()
   from /lib/x86_64-linux-gnu/libc.so.6
#5  0x0000000000408756 in ?? ()
#6  0x0000000000403980 in ?? ()
#7  0x00007ffff740d76d in __libc_start_main ()
   from /lib/x86_64-linux-gnu/libc.so.6
(gdb)
Answer from ks1322 on Stack Overflow
🌐
Swarthmore College
cs.swarthmore.edu β€Ί ~newhall β€Ί cs31 β€Ί resources β€Ί ia32_gdb.php
gdb assembly debuggin
ddd is a gui interface on top of a debugger (gdb in this case). It has a nicer interface for viewing assembly, registers, and stepping through IA32 instruction execution than command line gdb:
Top answer
1 of 9
427

You can switch to assembly layout in GDB:

(gdb) layout asm

See here for more information. The current assembly instruction will be shown in assembler window.

   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚0x7ffff740d756 <__libc_start_main+214>  mov    0x39670b(%rip),%rax        #β”‚
   β”‚0x7ffff740d75d <__libc_start_main+221>  mov    0x8(%rsp),%rsi              β”‚
   β”‚0x7ffff740d762 <__libc_start_main+226>  mov    0x14(%rsp),%edi             β”‚
   β”‚0x7ffff740d766 <__libc_start_main+230>  mov    (%rax),%rdx                 β”‚
   β”‚0x7ffff740d769 <__libc_start_main+233>  callq  *0x18(%rsp)                 β”‚
  >β”‚0x7ffff740d76d <__libc_start_main+237>  mov    %eax,%edi                   β”‚
   β”‚0x7ffff740d76f <__libc_start_main+239>  callq  0x7ffff7427970 <exit>       β”‚
   β”‚0x7ffff740d774 <__libc_start_main+244>  xor    %edx,%edx                   β”‚
   β”‚0x7ffff740d776 <__libc_start_main+246>  jmpq   0x7ffff740d6b9 <__libc_startβ”‚
   β”‚0x7ffff740d77b <__libc_start_main+251>  mov    0x39ca2e(%rip),%rax        #β”‚
   β”‚0x7ffff740d782 <__libc_start_main+258>  ror    $0x11,%rax                  β”‚
   β”‚0x7ffff740d786 <__libc_start_main+262>  xor    %fs:0x30,%rax               β”‚
   β”‚0x7ffff740d78f <__libc_start_main+271>  callq  *%rax                       β”‚
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
multi-thre process 3718 In: __libc_start_main     Line: ??   PC: 0x7ffff740d76d
#3  0x00007ffff7466eb5 in _IO_do_write () from /lib/x86_64-linux-gnu/libc.so.6
#4  0x00007ffff74671ff in _IO_file_overflow ()
   from /lib/x86_64-linux-gnu/libc.so.6
#5  0x0000000000408756 in ?? ()
#6  0x0000000000403980 in ?? ()
#7  0x00007ffff740d76d in __libc_start_main ()
   from /lib/x86_64-linux-gnu/libc.so.6
(gdb)
2 of 9
204

You can do

display/i $pc

and every time GDB stops, it will display the disassembly of the next instruction.

GDB-7.0 also supports set disassemble-next-line on, which will disassemble the entire next line, and give you more of the disassembly context.

🌐
University of Maryland, Baltimore County
userpages.cs.umbc.edu β€Ί chang β€Ί cs313.f04 β€Ί gdb_help.shtml
Using gdb for Assembly Language Debugging
Using a debugger is more important for assembly language programming than a high-level programming language because printing out values from an assembly language program is non-trivial, hence adding debugging code to an assembly language program might itself introduce new bugs, or at least make the bug behave differently. If your program contains portions written in C, those portions should be compiled using the -g option to retain debugging information in the a.out file. Although the NASM documentation describes a similar -g option for NASM, this option doesn't do anything when the output is in ELF format. The complete documentation for gdb is available on the Linux system using the "info" command:
🌐
Ncona
ncona.com β€Ί 2019 β€Ί 12 β€Ί debugging-assembly-with-gdb
Debugging assembly with GDB
This article shows how to use gdb to debug a simple assembly program. Most commands are similar to the ones used for debugging any other programming language, but we also go over how to access registers and memory addresses, which is more commonly needed when working at assembly level.
🌐
Sonoma State University
bob.cs.sonoma.edu β€Ί IntroCompOrg-x64 β€Ί bookap3.html
C Using the gdb Debugger for Assembly Language
The gdb debugger allows you to load another program into memory and use gdb commands to control the execution of the other program β€” the target program β€” and to observe the states of its variables.
🌐
Swarthmore College
cs.swarthmore.edu β€Ί ~zpalmer β€Ί cs75 β€Ί s23 β€Ί guides β€Ί gdb
CS75: Debugging x86-64 Assembly with GDB
The first line will ensure that GDB shows assembly in Intel syntax (which we are using in the class) rather than AT&T syntax (which we are not). The next line defines a layout mode which displays the contents of registers at the top, the disassembled program in the middle, and the command window at the bottom. When you are debugging, you can run layout asmreg to switch to this view mode.
🌐
Diveintosystems
diveintosystems.org β€Ί book β€Ί C3-C_debug β€Ί gdb_assembly.html
3.5. Debugging Assembly Code
Doing so enables GDB to list disassembled code sequences from functions, set breakpoints at the assembly instruction level, step through program execution one assembly instruction at a time, and examine the values stored in machine registers and in stack and heap memory addresses at runtime.
🌐
Infosec Institute
infosecinstitute.com β€Ί resources β€Ί secure-coding β€Ί debugging-your-first-x86-program
Master Debugging x86 Assembly Programs with GDB | Infosec
Debugging the compiled programs ... written in the code is to debug the program using a debugger. GDB is one of the most popular debuggers available for debugging Linux-based executables....
Find elsewhere
🌐
Kauffman77
kauffman77.github.io β€Ί tutorials β€Ί gdb.html
Quick Guide to gdb: The GNU Debugger
>> gcc -g collatz.s # compile assembly code with debug symbols >> gdb ./a.out # run gdb on executable (gdb) tui enable # enable text user interface mode (gdb) break main # set a break point at main (gdb) run # run to the break point (gdb) step # step a couple times to see position in assembly (gdb) s # shorthand for step (gdb) layout regs # start displaying registers (gdb) step # step to see changes in registers (gdb) break collatz.s:15 # break at another source line (gdb) continue # run to the source line (gdb) step # step (gdb) winheight regs +2 # show more of the register window for eflags (gdb) quit # exit the debugger
🌐
Coding Confessions
blog.codingconfessions.com β€Ί p β€Ί debugging-x86-64-assembly-with-gdb
Debugging X86-64 Assembly with GDB - by Abhinav Upadhyay
May 26, 2025 - If the object file produced by ... earlier that was crashing: The simplest way to debug a program with gdb is to start the program with gdb as shown below....
Top answer
1 of 1
3

After running GDB on the executable1:
Use start or starti to set a breakpoint in main or _start respectively and run the program.

Or set breakpoints yourself with b 12 to set a breakpoint on source line 12 (if you built with enough debug info for this to work), or b *0x00401007 to set a breakpoint on an address you copy/pasted from disas output.

layout asm / layout reg puts GDB into text-UI mode with "windows" in your terminal for disassembly and registers. (This can be a bit flaky, you sometimes need control-L to redraw the screen, and sometimes GDB crashes when your process exits although I'm not sure if that's specifically from TUI.)
Otherwise without TUI mode, info reg and disas can be useful.

See the bottom of https://stackoverflow.com/tags/x86/info for more asm debugging tips.

Especially strace ./test is highly useful to see the system calls your program makes, decoded into C style. In toy programs you're playing with for your own experimentation, this basically works as an alternative to checking for error return values.


Footnote 1: You're not doing that part correctly:

No executable file specified.

That means no file called test existed in the directory where you ran gdb test.

You have to assemble + link test.S into an executable called test before you can run GDB on that file. If ls -l test shows it, then gdb test can debug it. (And ./test can run it.)


Often gcc -no-pie foo.S is a good choice to make debugging easier: addresses will be fixed at link time, so objdump -drwC -Mintel test output will match the addresses you see at run-time. And the addresses will be numerically smaller, so it's easier to visually spot a code (.text) address vs. .rodata (modern ld puts it in a separate page so it can avoid exec permission) vs. .data / .bss.

Either way, stack addresses are still easy to distinguish from code either way, 0x555... or 0x0000...XXXXXX is in the executable, 0x7fffff... is in the stack, other addresses from mmap are randomized. (But libc also gets mapped to a high address near the stack, with or without PIE.)

(Or if you're writing _start instead of main, gcc -nostdlib -static foo.S implies -no-pie)

🌐
Dbp-consulting
dbp-consulting.com β€Ί tutorials β€Ί debugging β€Ί basicAsmDebuggingGDB.html
Asm Debugging With GDB
I step through the assembler with si (step instruction), and you'll see that gdb will tell you which line of the assembler will be executed next by marking it on the left with =>. Each time you tell gdb to step to the next instruction, the => will move down one, but the line of C won't change until you si off the bottom of the assembler lines that correspond to the line of C. When you start doing mixed assembler and C/C++ debugging there will be times you, by habit, type n (next) or s (step) and go to the next line of C when you meant to type ni (next instruction) or si (step instruction).
🌐
Gerryyang
gerryyang.com β€Ί debuggers β€Ί 2020 β€Ί 05 β€Ί 04 β€Ί debugging-assembly-code-with-gdb.html
Debugging Assembly Code with GDB | Gerry’s blog
May 4, 2020 - gdb is the GNU source-level debugger that is standard on linux (and many other unix) systems. It can be used both for programs written in high-level languages like C and C++ and for assembly code programs; this document concentrates on the latter.
🌐
Mourtada
mourtada.se β€Ί debug-x86-assembly-with-gdb
Debug x86 assembly with GDB | Mourtada.se
December 4, 2021 - Start gdb with gdb <your_assemlby_program> to enter its interactive shell. You can set breakpoints by writing break <function_name or line number>. By default gdb uses AT&T flavor to change to intel flavor type set dissambly-flavor intel. To start debugging the program type run.
🌐
Daniel Lemire's blog
lemire.me β€Ί blog β€Ί 2022 β€Ί 06 β€Ί 28 β€Ί looking-at-assembly-code-with-gdb
Looking at assembly code with gdb – Daniel Lemire's blog
April 17, 2025 - The general lesson is that looking at the generated assembly is not so difficult and with little training, it can make you a better programmer. Tip: It helps sometimes to disable pagination (set pagination off). Useful script: I often write automated script in bash to locate addresses such as this one: ADDRESS=$(gdb -q ./tests/wpt_tests -ex "info functions parse_url[^]]*$" -ex quit | grep -o "0x[0-9a-fA-F]*") gdb -q ./tests/wpt_tests -ex "set pagination off" -ex "set print asm-demangle" -ex "disas "$ADDRESS -ex quit
🌐
Chang Ge
www-users.cse.umn.edu β€Ί ~kauffman β€Ί tutorials β€Ί gdb.html
CSCI 2021 Quick Guide to gdb: The GNU Debugger
> gcc -g collatz.s # compile assembly code with debug symbols > gdb ./a.out # run gdb on executable gdb> tui enable # enable text user interface mode gdb> break main # set a break point at main gdb> run # run to the break point gdb> step # step a couple times to see position in assembly gdb> s # shorthand for step gdb> layout regs # start displaying registers gdb> step # step to see changes in registers gdb> break collatz.s:15 # break at another source line gdb> continue # run to the source line gdb> step # step gdb> winheight regs +2 # show more of the register window for eflags gdb> quit # exit the debugger
🌐
Raspberry Pi Forums
forums.raspberrypi.com β€Ί board index β€Ί programming β€Ί bare metal, assembly language
Debugging Assembly code using GDB - Raspberry Pi Forums
I have a script to fire up qemu and gdb with serial via a telnet session on port 1235 ... #!/bin/bash make || exit # Start up qemu in the background qemu-system-arm -nographic -M versatilepb -cpu arm1136-r2 -m 128 -device sp804 -device pl011 -serial telnet:192.168.1.4:1235,server,nowait -kernel ./bin/kernel.elf -s -S & # And fire up the debugger arm-none-eabi-gdb -nx -x "./gdbinit" --tui ./bin/kernel.elf That's for a stock qemu v0.15.0, there may be later versions or forks that better mimic the Pi hardware.
🌐
Browncs1260
browncs1260.github.io β€Ί notes β€Ί 11
Debugging assembly | CSCI 1260 - Compilers
(In homework assignments this is typically lisp_entry; in the class compiler it is entry.) Then let gdb run your program until it reaches this breakpoint. ... At this point you can see the state of all register values and flags, and which line of assembly code will be executed next.