23 comments

[ 5.7 ms ] story [ 62.3 ms ] thread
Using GDB to debug Asm is... certainly a choice.
What's the better choice?
Setting a breakpoint in the debug registers DB0 through DB7 and dumping registers and memory in your own debug exception handler.
Gdb is an excellent debugger for assembly, even when the original code was written in C

I would automatically type

(gdb) x/4i $pc

when opening a coredump out of habit.

But using nasm, then looking as gas style assembly in the debugger might be a bit more jarring.

"set disassembly-flavor intel" was one of the first customizations I made to gdb when I started using it in anger.
I once ported the runtime of my toy L98 compiler from Intel to AT&T syntax, it was enough as a learning exercise I don't plan ever to repeat, the reasoning was to only depend on GAS.

Alone the mental exercise to always convert into official documents and AT&T syntax isn't worth the trouble.

Why? Back in the day, after the pain of debugging on Timex, and MS-DOS debug, the confort of Turbo Assembler debugger felt really nice.
Turbo Assembler!!! I think that was pretty much the standard in the demoscene, at least in my circles. I wrote most of our DOS demos with it. Anything that ran in real mode, doing all the wild things like modifying code loaded already in memory... Then for actual 32-bit code (using protected mode) watcom c+asm compilers became the go-to. I still hand rolled some assembly, but with the advent of Pentium processors, their pre-fetch and dual pipeline execution watcom C did a fairly good job to compile highly efficient/optimised code, so asm coding mostly went away. (did use it later professionally for microchip controller programming though) As for nostalgia, I'd rather pick up a virtual console nowadays. The limited resolution, colours, etc. gives enough mental exercise without going back to x86 asm. :)
We had better tools 30 years ago when pure assembly work was more common. You'd often run in the debugger by default.

Yet GDB lives on

I've been writing a lot of assembly over recent months (the runtime routines for a lisp compiler, and of course debugging the generated assembly my compiler emits itself).

Mostly all I do is run a backtrace from the segfaults, and otherwise single-step through the code to verify my assumptions.

GDB has sufficed pretty well, though I admit I spent a long time writing the stop&copy garbage collector, and tracing through it trying to understand why I was getting segfaults.

I'm sure there are better tools, but for simple debugging it was sufficient.

It's very common to use GDB with Asm, but only when combined with some plugins. Nowadays this is mostly done when reverse engineering software, or when testing low-level memory corruption exploits.

The screenshots of this popular gdb plugin are a good example: pwndbg.re/stable/features

Why would one choose NASM over FASM? The makers of KolibriOS (an OS written entirely in assembler) chose FASM but the reason eludes me.
I have not used FASM so I can't comment on it, but there are quite large differences between assemblers in general. Each is essentially a (non-optimizing) compiler for a different extension language. Writing your own assembler that literally just assembles is trivial, but writing raw assembly instruction by instruction is tedious and not especially practical. If you're serious about writing it, you'll want macros and other forms of metaprogramming; as a programmer, the entire point of your existence is to automate tedious, repetitive tasks, and better assemblers help with that. Programming your own assembler is a natural progression of metaprogramming if you stick with assembly long enough, but first you should learn with using an existing one so you can begin to understand your own workflow well enough to know what tools you want for reducing repetition and where the existing one falls short.
And why not? You can just use CALL and make subroutines for repetitive tasks. Why would one need macro functionality which is basically inlining code like in C/C++. Inlining also makes the executable needlessly large. It may have its uses but I suspect most of the time just calling a function or subroutine is more desirable.
Calls have overhead, so they shouldn't be used for everything, especially in hot paths. The entire point of writing assembly is to optimize performance. Even on very limited hardware, or rather especially on limited hardware, you'd usually much rather trade code size for performance.
Anyone noticing some pretty heavy skill atrophy from all the Claude/Codex use in the last few months?

I feel like this is a great way to get back to basics and keep the eng skills sharp. Maybe I should try something similar...

Here’s an archive.org mirror of the broken “Why no one should use the AT&T syntax ever, for any reason, under any circumstances” link: https://web.archive.org/web/20251128060318/https://outerprod...
Literally came here to post this, thank you
If "historical" UNIX is one's focus, then need to be able to read (and edit) ATT assembly

The author claims Intel syntax is ubiquitous. True. But so is "historical" UNIX

Long rants about asm syntax are old, tired tropes. Perhaps they are entertaining to beginning programmers but today such rants achieve nothing except to put the sanity (and hence the judgment) of their authors into question

The existing ATT syntax assembler in "historical" UNIX source trees will not be translated it into Intel syntax

By all means, _use_ Intel syntax^1

But if "historical" UNIX is one's focus, comfort with _reading and editing_ ATT syntax, despite all of its alleged flaws, will continue to be useful

1. The author's own footnote:

"You can tell GCC to use Intel syntax for its inline assembly with -masm=intel. This doesn't work with Clang; complain to them. (Or just don't use inline assembly; it's usually not a great idea anyway.) For objdump, pass -Mintel. And for gdb, put set disassembly-flavor intel in your ~/.gdbinit."

Perhaps some HN readers might like this:

https://raw.githubusercontent.com/pirate/assembly-repl/main/...

(requires clang)

> I’ve developed an unusual little nighttime routine: after reading bedtime stories to the kids, I hop into bed and instead of reaching for a fiction book, I’m turning on my 14-year old Asus eeePC 701 (wikipedia.org) miniature laptop and writing x86 assembly language

I don’t understand how people do this without wrecking their sleep. I’m studying to be a CPA and that little One More Thing just before bed time totally wrecks my sleep. Studying (even something as boring as tax laws) gets my mind excited and I’ll be up till 6am no matter how physically/mentally tired I am.

For context, from the same author, all about Forth: https://news.ycombinator.com/item?id=45639250

And the final implementation: https://ratfactor.com/repos/nasmjf/

Here's the Programming from the Ground Up book the author references at the end of the post: https://programminggroundup.blogspot.com/2007/01/programming... https://download.savannah.gnu.org/releases/pgubook/

And the source for asmtutor, which appears to be down: https://github.com/DGivney/assemblytutorials

I'm very interested in this rabbithole, see the similar origin story for uxn: https://100r.co/site/weathering_software_winter.html