i'm sorry, starting with "you can ask AI to … [but it'll do an incomplete and bad job]" and then launching forth into a hundred words of AI-produced text is not very appetizing
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
>> You can ask an AI to explain how vtables work in x86. It will give you something that sounds right. What it won’t give you is what Windows actually expects the vtable to look like, why method dispatch behaves the way it does at the instruction level, or what breaks when you deviate from convention. This volume of The Art of 64-Bit Assembly closes the gap between a plausible explanation and genuine understanding.
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'm skeptical of that statement to begin with. I would be surprised if models weren't trained on plenty of x86 and Windows internals information. If nothing else, they could be prompted to download the relevant material and then write well-commented source code to explain the implementation details.
This reads more like marketing copy targeting the kneejerk AI backlash crowd than anything.
One book probably doesn't do it. I know the LLMs have been trained on one particular book that explains some crucial things about the grammar of a low-resource language. The LLMs will sort of use the information, terms, and concepts in the book to explain things but they fail to understand and continue to confidently mangle the language and plagerize the content of that book.
> Once LLMs are trained with the content of this book
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).
I cannot get a faint idea about how you managed to get such a twisted misunderstanding.
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...
But even then your prompt has to be explicit enough to get that answer and not the 'wrong one'. Of course they will prioritize stuff that is more often in the training data. That's why AI will be a dead end long term
The Linux kernel prefers GAS (or clang) w/ the C preprocessor. Luckily most of clang's assembler unit tests (and LLVM's MC layer unit tests) also use GAS style syntax.
All of the major kernel ABIs are using C function interfaces as their stable ABI (except Linux, which uses an assembly syscall instruction as the stable interface, although you still rely on a lot of the ancillary C ABI for things like struct layout or stack layout).
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.
It’s part of the MSVC x64 ABI, not a part of the kernel ABI. The kernel and user mode (Win32) APIs all use C linkage so vtables are not relevant and the ABI is a convention of the compiler not the OS. Practically speaking though if your software runs on Windows it will probably use the MSVC ABI.
Last time I checked, software compiled with both Cygwin and MSYS2 internally uses SysV calling convention, only switching to WINAPI when calling, well, Win32 API.
Yes, you either follow Itanium ABI (non Win) or MSVC ABI. Technically nothing stops _your_ compiler from implementing totally own conventions but it will only be compatible with itself
GHC uses its own calling convention yet it's compatible with Win API just fine. The secret, of course, is to implement not only your bespoke calling convention, but also the other ones that you care to interoperate with.
Is anyone still writing assembly in the age of LLMs? Asking seriously because most assembly is just doing one very simple thing very fast and because it's so simple conceptually, an LLM can easily code it without errors.
Yep. In my experience, LLMs easily go in circles with even simple assembly, creating fixes that result in 2x slower code and then fixing those with even slower code. They are pretty great as a reference or finding needle in the haystack bugs though!
I was able to use Claude to translate a few thousand lines of assembler from one syntax+toolchain to another. Process was definitely iterative; had to keep adding a few rules along the lines of "don't do this...here's the equivalent pattern." But in the end it did a good job and saved me a ton of time. Allowed me to move a ton of unit tests off a hand rolled broken+bad assembler to a modern production toolchain.
yes, i write c and asm professionally for small hard real-time mcus. llms give me wrong code nonstop in what little i have tried in my field. not a force multiplier
I'm not being flippant but I think part of your answer is in the first two words of the title.
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.
Yes. Mostly for learning purposes and for fun. Also, there are things you must drop down to assembly level in order to achieve. Implementing coroutines, a JIT compiler, etc. It's fun to learn about these.
> Is anyone still writing assembly in the age of LLMs ...
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.
You could've also asked if people still wrote assembly in the age of compilers, and the answer would be the same. Sometimes we want/need to control or understand what is emitted by the tool.
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.)
Because it's not portable. The world we find ourselves in is at least x86 and ARM, and assembly for one isn't good for the other. LLVM has a hardware agnostic intermediate representation (IR) that one could use though.
Except for some odd corner cases, it is very hard for a good engineer to beat compilers these days (they are very good now). Not to mention, tuning depends on the platform, and often the exact model of chip.
If you need better performance than a higher level language affords you, I would not recommend programming directly in asm. Instead, I would write a compiler. Raw asm is seductive since the start up cost is relatively low. You can get started in an afternoon. The trouble is that writing correct assembly is much harder than high level code. You have to hold in your head the register state at all times. You have to know if the function you are calling will clobber registers that you need after the call and manually save/restore them. This will slow down your velocity and the resulting code will be long and difficult to read. It will also rely on a lot of undocumented information that only resided in your head while writing and has since been evicted. Good luck debugging a program written in assembly that no one has looked at for two months.
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.
I am more curious about how they would cleanly manage hierarchical labels (usually called "namespaces"), register naming, and stack management with deep register spilling, description of the register state on the various entries from the various dominators of a code block.
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.
fasmg[12] is much more powerful than gas or nasm(~yasm): it is not a classic pre-processor. With CALM, it is basically a language able to implement assemblers supporting various binary file formats.
The pre-processor of an assembler is specific to that very assembler.
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).
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
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.
This reads more like marketing copy targeting the kneejerk AI backlash crowd than anything.
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...
- for x64
- on Windows
- using MASM
There are other 64-bit OSes, CPUs and assemblers for them, and people do use them.
I'm not a Windows-knower, are vtable layouts part of the user<->kernel ABI?
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.
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.
It’s a hobby.
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.
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.)
https://www.youtube.com/watch?v=IUo0UwZOaRw
1) All Assembly/C++ books by Daniel Kusswurm.
2) Low-level Programming: C, Assembly, and Program Execution on Intel 64 Architecture by Igor Zhirkov.
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.
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).