The Art of 64-bit Assembly
nostarch.com
nostarch.com
But somehow, the discussion has three themes. It's 50+ comments of "I don't like the first sentence of the marketing copy", "I don't like the tool the author is using", and "what would happen if we train an LLM on this book?". Has anyone read the sample chapter? Did you like it? Anyone here owns volume 1 and has opinions about that?
I also read his Write Great Code series and generally found it to have some pretty good advice, but it was also full of things like recommendations to never trust compilers and to write lots of arcane unreadable magic code to unlock ultimate speedy hacker cred.
That being said, if you want to learn about ASM in TYOOL 2026 then you could do a lot worse than learning it from someone who doesn't trust compilers and does everything themselves.
Not bad advice, but the Fasm forums used to be pretty good for asking questions, no clue if they are around and active still, but there were a lot of programs people had written and even a few simple OSs(including KolibriOS) which had a ton of code to read through that mostly was commented. Once you get the basics it is pretty easy to do stuff, and most of learning is doing stuff.
That's weird, GNU as should default to AT&T syntax. Maybe the author switched to Intel syntax by adding the .intel_syntax directive at the beginning of the code?
Edit: i checked. it is for 32 bit. works on Linux. and uses Nasm.
A Marketing and propaganda rule is that the very first thing people read/see sets the tone for the entire discussion. If you get everyone off track right from the jump it degrades the entire discussion and, ultimately, the usefulness of hacker news.
i hope this is the publisher's fault and the author replaces it with something decent of their own. contrary to the opinions i've heard around (including elsewhere on this thread) learning asm is still meaningful today and it's something i'd like to get better at so i will consider getting this book or one like it once $work is a bit less hectic
It's also one of the reasons its insanely popular in ESL countries and frustrating/disliked in English-speaking countries because it makes things easier in one and harder in the other.
It was never the goal, but it is the reality. The same style people call AI, was often called being a pedant or being wordy 10 years ago.
The thing that frustrates me the most about AI is how every thread in every forum spend half the time arguing whether an article is AI or not, as if bad writing only started to exist with AI. Just fucking don't read it.
Em-dashes as the signal is the most-upsetting for me. I have been using them properly and frequently for decades.
Slop is slop. If it is AI-slop then fine, go ahead and call it out.
To me, it's all fairly human-ai neutral except for this sentence which is oh-so AI cliche and casts doubt on the rest of it:
> This volume of The Art of 64-Bit Assembly closes the gap between a plausible explanation and genuine understanding.
"closes the gap" is a favored phrase by our artificial friends and the phrases "plausible explanation" and "genuine understanding" are just... so ... dramatic for the context.
The rest of it is pretty tame in comparison. In my armchair opinion, I'd guess it's mostly a composite of (professional) human-written/ai-revised and/or vice versa. Which is not necessarily a bad thing.
When comparing GNU Assembler and MASM, GAS is missing many features: while loop, string processing (.e.g strlen)
> page 3: "It’s important to understand that MASM converts macro invocation arguments to text values before doing the macro expansion"
Like MASM, GAS uses call-by-name evaluation by default. While GAS's altmacro mode does allow for expression evaluation using syntax like `%(1+2)`, it has strict limitations: it only supports absolute expressions and is restricted to argument positions.
In contrast, MASM's % operator (page 8) looks far more general.
On Linux, the "standard" assembler for humans is "nasm", though there are also others.
For anyone writing a non-negligible amount of code in an assembly language it is essential to develop or get from elsewhere a comprehensive library of macros, for avoiding to write huge amounts of boilerplate.
At least since UNIX v4.
All good Assemblers have come from Amiga, Atari, PC world.
- for x64
- on Windows
- using MASM
There are other 64-bit OSes, CPUs and assemblers for them, and people do use them.
In any case, today nasm is mostly equivalent with it, if not better, while being kept much more up-to-date with the Intel-AMD ISA extensions.
Randell’s got another (large) book on ARM assembly. He’s also got a handful of other great books on software engineering in general - he’s more than aware that “there are other 64-bit OSes, CPUs and assemblers for them, and people do use them.”
This particular title, “the art of assembly” has been around for a while. This x64 version is the latest iteration - it’s a great book compared to the previous version which introduced and focused on “high-level-assembly”, basically a collection of masm macros that effectively constituted a small language.
It’s fair to say that anyone even remotely interested on x86/64 assembly is aware of AoA.
https://www.amazon.com/Art-ARM-Assembly-Randall-Hyde/dp/1718... ?
Mmm nice. Will give it a try since ARM-based Mac is my main working environment nowadays.
Another excellent classic which you should checkout if you are interested in all things ARM is ARM System Developer's Guide: Designing and Optimizing System Software by Sloss, Symes and Wright. It is old and so does not cover newer ARM architectures but will give you a solid foundation for system programming.
Anybody who is even cursorily interested in Assembly Programming knows of Randall Hyde and his works since he has been at it since the 16-bit days. One of the few authors with truly great depth.
Makes me think that most people commenting here know nothing about assembly and are simply posting empty comments for the heck of it. This has been a trend on HN lately of similar meaningless/useless comments on any topic.
Unless, you want to use open source MASM-compatible assemblers like JWASM or UASM.
Yes I understand, other folks may prefer Linux/BSD, NASM/FASM, ARM etc etc.
I am doing all that with a basic C pre-processor in my assembly source code. But the more I think about this, the more I think I should write my own pre-processor, which "should" be much simpler than a C pre-processor in the end and would do a cleaner job since taylored for those usages (the "annoying" thing is the arithmetics expression evaluation).
I would write this pre-processor in assembly, namely design a binary specification (that to be ready for other ISA implementations).
Then, they are the really important things: for all micro-architectures, how to be friendly to conditional branch predicition, how to handle BTB entries layout in a cache line, show how important the "cache line" is ubiquitous, etc.
I remember clearly one of the TheHeavyThing developers telling me than with a basic and naive hand compilation of gzip, he was beating the best compilers, at that time, by a consistent 10/15%. Let me remind people here of something: nobody is supposed to be able to beat a compiler on deep and hairy compilation units. If it is the case, something is wrong in that compiler.
For instance, with a C pre-processor, I have a very lean C pre-processor dialect which allows me to assemble simple x86_64 code with... fasmg[12] or nasm(probably yasm) or gas(intel syntax).
A big project which was bitten by specific pre-processor abuse: ffmpeg with nasm (but it is still much less toxic than to start to be hard dependent on advanced and specific C compiler extensions... look a the failure from linux on that matter).
1) All Assembly/C++ books by Daniel Kusswurm.
2) Low-level Programming: C, Assembly, and Program Execution on Intel 64 Architecture by Igor Zhirkov.
FASM is cool (and still being development), but since it's written in 32-bit x86 asm, let's just say macOS is a 2nd class citizen.
GNU Assembler (GAS) ≥2.45 on x86-64: call and jmp to global labels in Intel syntax cause operand type mismatch errors. RCC emits .intel_syntax noprefix by default, but GAS ≥2.45 rejects direct branches to global symbols in this mode. Local labels (.L.xxx) work fine. Tests with user-defined function calls (bitops-1, fprintf-1, etc.) may fail to assemble under these versions. Root cause: rcc emits lea r11, [rip + sI] but GAS requires AT&T sI(%rip) for globals.
Who else remembers the flamewars of the 90s between all the different factions of Asm programmers? MASM vs TASM vs RosAsm vs HLA (basically no one took GAS seriously at all)... it was in some ways quite similar to the Chrysler vs Ford vs GM wars.
I remember during the DOS era TASM was all the rage; it was wicked fast. Unfortunately didn't get an opportunity to do much assembly programming after moving to Windows/Unix.
When Randall Hyde published his HLA (https://en.wikipedia.org/wiki/High_Level_Assembly) i remember thinking it was a good idea since it allowed many high-level language programmers to easily learn assembly programming as it included all the well-known higher-level programming constructs. It was a proper new language, but the assembly purists were all outraged and Hyde caught a lot of flak which i think was unjustified.
I'm not a Windows-knower, are vtable layouts part of the user<->kernel ABI?
MSYS environment is just Cygwin and it uses Itanium IIRC for C and C++ non-Win32 calls since it emulates POSIX. If it links with Windows C runtime they use __cdecl. Win32 API calls always use __stdcall convention / ABI.
However, Mingw environments (Mingw64, UCRT, CLANG etc.) are intended for native Windows development, hence, they use normal MSVC __cdecl ABI for C library calls and internal function calls too. Win32 calls are again __stdcall.
Unlike C, for C++ all MSYS environments use Itanium ABI since they link with GNU libstdc++ or Clang libc++. I think it is possible to use MSVC C++ ABI with Clang but it could be complicated since it requires recompilation of at least libc++.
For C++ ABIs, there are really only 2.5 major ABIs: the MSVC ABI, used by MSVC and clang wanting to be compatible with MSVC, and the Itanium ABI, used for everything else. There are some slight variants on the Itanium ABI which makes the ".5": ARM uses a different layout for exception handling tables, and there are some flags you can set to use a more compressed vtable layout (32-bit offsets instead of 64-bit pointers). (There are other older ABIs, but either companies stopped making a C++ compiler or they switched to Itanium.)
Windows COM APIs (which isn't part of the kernel, they're still userspace libraries) rely on an IDL which is meant to be directly compatible with the C++ vtable. That said, they also use a restricted subset of C++ that all of the ABIs are going to agree on for vtable layout--if you don't overload any functions, and you don't have any virtual inheritance, there's pretty much only one possible sane vtable layout, and everyone does that.
That used to be the case anyway. It's possible they binned the C support in the switch to 64-bit. I haven't looked since.
The Layout of a COM Object by Raymond Chen - https://devblogs.microsoft.com/oldnewthing/20040205-00/?p=40...
On the other hand, if you write your own non optimizing compiler, you can avoid a lot of these problems by, for example, tracking what registers a function writes and ensuring they are saved before a call and restored after. Then you can actually get the raw performance of handwritten asm without the pitfalls (the resulting code would still he harder to read and maintain than equivalent high level code, but at least it would be tractable). Even better, you can write your own high level assembler that is actually portable to other architectures. For example, instead of directly modeling x86_64, your compiler can model a cpu with 16 general purpose registers and a set of instructions that map to x86_64 instructions. An arm port would be straightforward since arm also has 16 general purpose registers and you can model x86_64 instructions as one or more arm instructions (and you have extra registers for x86_64 instructions that must be modeled as multiple arm instructions). Or you could do the reverse and model 32 general purpose registers using arm instructions and use predefined memory slots as virtual registers on x86_64.
Sure, they might make all sorts of dumb hypotheses at first, but as long as the results of those stay in their context, they do seem to eventually “run out of ways to be stupid.” (Which is to say, LLMs seem to experience in-context learning even via self-directed trial-and-error, if given a sufficiently-large number of iterations and no way to cheat.)
It also is an excellent radare2/rizin/ghidra driver as well. Maybe it's because its ~cyber~ capabilities (pretty much linked with assembly-level knowledge) aren't guardrailed off?
Yes. Its "simplicity" is exactly why we pick and assemble piece by hand - we imagine the leanest way.
LLMs are (not just in Assembly, but especially) very precious as a natural language manual.
> an LLM can easily code it without errors
One day it will probably also be able to have sex, and yet we think we will not pass on the experience - unless, like some kind of coding, it will be a "strictly professional only for money" operation (like in Monty Python's Argument sketch).
Edit: as esteemed emptybits wrote above, rephrasing: it's /the Art of/ Assembly.
Professionally, assembly is the last thing I would let an LLM generate for me. That's because if you need to write something in assembly, it's because it's critical: operating system context switch, interrupt handler, that kind of thing. You don't want to be 99% correct, you need that code to be 100% good.
I can imagine some other professional scenarios that I'm less familiar with, where you want to write a tight numeric loop of NEON64 assembly and let the LLM do it, because it's frankly a pain to do by hand, and you can test it to some degree of confidence.
IME while LLMs may help delivery utility in a finished work, humans often value the absorption, mastery, style, or constraint of performing a mundane activity hands-on and brains-on.
However, I want to point out the obvious fact that people are still playing the piano in the age of the self-playing piano. Humans are experiential creatures, and we enjoy a wide range of activities for their own sake that may have nothing to do with efficiency of output.
can't tell if sarcasm or not. Just in case it's not.. in that case why don't we all vibe everything in assembly? No need for abstractions anymore since that's a human concept. LLM can do it without errors, as you say, and we'll reap the benefits of speed!
I really loved this retort, but we have to reply: from that cone of perspective, it would be probably better to "vibecode" in C and not hope that the LLM does a better job than the compiler (for efficiency, not for absence of bugs as per the original). (Edit: for clarity: some compilers of low level languages are specialized in ASM optimization - the LLM will hardly beat them.)
The original SSE (SIMD) extensions were actually written with this use case in mind. When they first came out, the compilers were awful. They've since caught up.
I keep hearing this for the last 20 odd years, yet I see evidence to the contrary each and every day. It is hard and honest work though.
Assembly has unique advantages like guaranteed execution duration for cryptography or exact optimization of hot-loop computation.
99% of the even performance-sensive code doesn't need assembly and compilers beat good engineers in this category since API surface is big and complicated. For 1% very hot code or very sensitive code due to execution duration / predictability / throughput, humans usually code better than compilers. This is due to specialization and limited DoF problems that can be solved and optimized to hell.
It’s a hobby.
My output is linux/amd64 assembly language which is compiled by nasm. I don't link to glibc, so I had to implement my "print int", "print string", and similar primitives in raw assembly.
I successfully implemented a stop© garbage collector, and other interfaces to the OS such as reading command-line arguments, environmental variables, and so on. All in assembly. Though my compiler is written in golang the runtime, and all supporting functions have to be in assembly to make sure that the binaries it produced are static.
(I wrote a lisp interpreter which can be compiled, and which can be used to run itself, so I got an indirect REPL.)
But assembly? I'm not sure, honestly. Architectures change, and you can easily converge to good code by talking to an LLM.
May I ask why you didn't use LLVM as a target?
In the future I might try to repeat the process with QBE, or similar, but LLVM is a big dependency and a bit of a moving target too.
I'm only writing toy languages for fun, and for local problem solving. I have no delusions of grandeur and expect that for every compiler/language I come up with I'll have one user at the most, possibly two.
An LLM knowns nothing of the taste of ginger.
There are other questions around AI (like what the
economy of it will actually look like in the end),
but "is it useful" is no longer one of those
questions. Anybody who doubts that clearly hasn't
actually used it.
And no, AI isn't perfect. But Christ, anybody who
points to the problems at AI had better be looking
in the mirror and pointing at themselves at the
same time.
https://lore.kernel.org/all/CAHk-%3Dwi4zC%2BZe8e%2Bp3tMv8TtG...Once LLMs are trained with the content of this book, then this statement will no longer be true.
If this book becomes even a bit popular, these LLMs will get access for sure to the content of this book in their next training.
I strongly believe that the "future" should be LLM+Corpus - something beyond LoRA or RAG or context, but what we need and will have will be a generally strong LLM augmented with the most proper learning from the "selected library of relevant material".
And in parallel, also the reasoner over the corpus will be implemented (something that properly studies, not just reads, and achieves the pinnacle of reflection over the corpus).
Let us reformulate through the framework: the learned wrote books; the learners read them books, as many as possible in a ranked list; we may one day achieve automated learners; learned learners are our consultants; we benefit from the level of learning of them consultants; we would benefit greatly from the Perfected Learner; I gave a few lines of the general directions towards "thinking of them in view of building them" in the post above...
This reads more like marketing copy targeting anti-AI sentiment than anything.