Why Learning Assembly Language Is Still a Good Idea (2004)(onlamp.com)
onlamp.com
Why Learning Assembly Language Is Still a Good Idea (2004)
http://onlamp.com/pub/a/onlamp/2004/05/06/writegreatcode.html
53 comments
>If you wanna have fun writing assembly language, pick a processor microarchitecture that you can comfortably fit in your head, and an environment where you'll only have to deal with one or two implementations of that microarchitecture.
For those of you who read this and want to try it out, I highly recommend the Propeller. The transistors were for the most part laid out by a single guy, using only his brain and the silicon-tracing equivalent of notepad, but it is powerful enough to run about the same applications you might find on a commodore64.
http://www.parallax.com/propeller/
For those of you who read this and want to try it out, I highly recommend the Propeller. The transistors were for the most part laid out by a single guy, using only his brain and the silicon-tracing equivalent of notepad, but it is powerful enough to run about the same applications you might find on a commodore64.
http://www.parallax.com/propeller/
I've also had a ton of fun doing this for PIC24 (the 16bit PIC family of microcontrollers), which has an incredibly straightforward instruction set. They're also quite fast, as far as microcontrollers go and while I do love the Propeller architecture, the 8-core goodness makes them a little more complex to thoroughly understand (though their deterministic nature and the fact that you can actually count cycles reasonably easily makes them less complex than most multi-core processors)
I could make your words mine, just s/6502/Z80, it was really fun in the old days. :) But I'll add that x86 was pretty approachable, say up to the 386/486 times when I've written some minor stuff, mostly low-level graphics... even with quirks like segment registers, one could learn enough to hand-code expertly (beating the hell of any compiler of the time) with modest effort. Pentium onwards though, things got much more complicated esp. microarchitectural performance (have to consider out of order execution / ILP, use tricks like prefetching for cache perf etc.).
Having worked with assembly a little bit (MIPS, for Coursera's Compilers class -- but it's supposed to be better than x86!) and with LLVM IR a bit more (I'm writing my own compiler for a language that compiles to IR), I really wonder about the trade-offs for learning LLVM IR vs assembly if your goal is to learn lower-level details.
In particular, LLVM IR is just so much easier to use, even though it lives at a very similar level as "real" assembly. Granted, you don't have to take care of register allocation yourselves, and the instructions are slightly more abstract (an abstraction which is inevitably leaky), but it does really drive home the differences between registers and memory, how pointers and addressing are used at the lower level, that there are different calling conventions (but you don't have to learn the niggly little details for each), it's portable, etc.
Anyone who has used both more extensively who can comment?
In particular, LLVM IR is just so much easier to use, even though it lives at a very similar level as "real" assembly. Granted, you don't have to take care of register allocation yourselves, and the instructions are slightly more abstract (an abstraction which is inevitably leaky), but it does really drive home the differences between registers and memory, how pointers and addressing are used at the lower level, that there are different calling conventions (but you don't have to learn the niggly little details for each), it's portable, etc.
Anyone who has used both more extensively who can comment?
If more of the "how to do X" articles focused on formal verification/etc or assembly routines, I wouldn't feel as much that HN is bogus.
And since it was actually relevant, I will reproduce SparrowOS's comment below:
"If you love programming more than anything, you are probably the kind of person who wants to know assembly language. If your full heart is not into programming, maybe not."
And since it was actually relevant, I will reproduce SparrowOS's comment below:
"If you love programming more than anything, you are probably the kind of person who wants to know assembly language. If your full heart is not into programming, maybe not."
It doesn't help that the SparrowOS dude is certifiable.
It does help that he wrote an OS. (From scratch IIRC.)
Sure. So did I...
[deleted]
link to source?
http://ww.com/task.cc.txt
It's a 32 bit QnX clone, this is the kernel. The project is not buildable since the original scaffolding (djgpp) is going to be pretty hard to come by. I probably could still put together a bunch of images to get it to boot if I spend a month on it but I don't see any point in doing so.
Still, it was a fun project and I learned an awful lot doing it.
It's a 32 bit QnX clone, this is the kernel. The project is not buildable since the original scaffolding (djgpp) is going to be pretty hard to come by. I probably could still put together a bunch of images to get it to boot if I spend a month on it but I don't see any point in doing so.
Still, it was a fun project and I learned an awful lot doing it.
With all due respect I'm not sure that that is a fair comparison. Your OS seems to be pretty barebones (I'm not sure if what you posted is all of it but it does not even seem to have a file system). SparrowOS is some 130KLOC and has a lot of shit going on for it.
Here is the breakdown http://www.sparrowos.com/Wb/Accts/TS/Wb2/LineCnt.html#l711. But note that not all of it is code (for example the bible).
EDIT: It seems that QnX is a microkernel hence the lack of FS. But it's not really a fair comparison regardless.
Here is the breakdown http://www.sparrowos.com/Wb/Accts/TS/Wb2/LineCnt.html#l711. But note that not all of it is code (for example the bible).
EDIT: It seems that QnX is a microkernel hence the lack of FS. But it's not really a fair comparison regardless.
This is just the kernel, the OS has a filesystem, networking, graphics, GUI (both basic elements and a window manager), does multi-user multi tasking.
It is the largest project I ever worked on, but as I wrote it does not currently build so there is not much point in releasing the source in its entirety. I just posted the kernel code as proof that I did indeed write an OS.
I won't make a comparison between SparrowOS and what I put together but I think that if such a comparison where to be made I'd first have to put in a lot of time to get it serviceable again and I have other things to do.
The filesystem was a port of the Minix FS, the networking stack was a full TCP/IP stack adapted from freebsd to work as a stand-alone process. The GUI/WM were written from scratch. It relied heavily on DJGPP for the bootstrapping of the development process and at some point became self-hosting.
The one tricky part which I really have no idea on how to solve today was that for the bootstrap it used a mixed mode program written in borland C to get the initial configuration and the first few processes loaded into ram before starting up the OS proper.
All of this would have to be updated and repaired before you could get a working OS out of it.
So with all due respect I think that it was a pretty fair comparison.
It is the largest project I ever worked on, but as I wrote it does not currently build so there is not much point in releasing the source in its entirety. I just posted the kernel code as proof that I did indeed write an OS.
I won't make a comparison between SparrowOS and what I put together but I think that if such a comparison where to be made I'd first have to put in a lot of time to get it serviceable again and I have other things to do.
The filesystem was a port of the Minix FS, the networking stack was a full TCP/IP stack adapted from freebsd to work as a stand-alone process. The GUI/WM were written from scratch. It relied heavily on DJGPP for the bootstrapping of the development process and at some point became self-hosting.
The one tricky part which I really have no idea on how to solve today was that for the bootstrap it used a mixed mode program written in borland C to get the initial configuration and the first few processes loaded into ram before starting up the OS proper.
All of this would have to be updated and repaired before you could get a working OS out of it.
So with all due respect I think that it was a pretty fair comparison.
Yeah, I was not sure if that was all of it or not. Just release it, even if it does not build. If you figure out how to build it at some point, good, but if not, it's better for it to be released than not released even if it does not build.
I'll think about it. Releasing code like that is not a trivial thing and I don't want to end up having to maintain it or to become a focal point for a bunch of attention.
[deleted]
Yeah what's the deal there? I always assumed he was a spam bot...
He's schizophrenic and the parts of his comments that look like spam are actually algorithmically generated Christian songs.
Lest anyone take this as a mean-spirited joke: This is the actual truth. He suffers from schizophrenia and has a long-standing interest in algorithmically generated Christian messages, which he seems to find meaningful.
[deleted]
To amplify/correct what's been said: The parts of his post that look like Bayesian poisoning are what he believes to be God speaking to him.
http://en.wikipedia.org/wiki/Bayesian_poisoning
http://qaa.ath.cx/LoseThos.html
http://en.wikipedia.org/wiki/Bayesian_poisoning
http://qaa.ath.cx/LoseThos.html
If starting with x86 assembly seems overwhelming to you there are a few alternatives that might help.
First are virtual machines that were developed to be programmed directly in a kind of assembly language. CHIP-8 [1] is a good example of one of those, being a VM standard developed to make games run across a broad range of otherwise incompatible mid-1970s hardware. It gained a new popularity in the early 2000s and as a result you can now find CHIP-8 emulators for virtually any platform, including your mobile phone, as well as a range of assemblers and other development tools. It's a fascinating bit of history in its own right and also a great platform to emulate in the first emulator you write. A bit further away from the syntax of "real" assemblers is Linoleum [2], which is meant to be a kind of a cross-platform assembly language targeted towards graphics applications, but the principles behind programming in it are largely the same. I can recommend both from personal experience, although CHIP-8 is probably a better starting point.
Second, if you want something closer to real hardware I'd suggest learning how to program for the MOS 6502, the CPU used in the Apple II and (with some modifications) in the Commodore 64 and the NES gaming console. One way to get started with it is Easy6502 [3], which is an online introductory course on 6502 programming bundled with an in-browser emulator.
[1] https://en.wikipedia.org/wiki/CHIP-8
[2] https://en.wikipedia.org/wiki/Linoleum_%28programming_langua...
[3] http://skilldrick.github.com/easy6502/
First are virtual machines that were developed to be programmed directly in a kind of assembly language. CHIP-8 [1] is a good example of one of those, being a VM standard developed to make games run across a broad range of otherwise incompatible mid-1970s hardware. It gained a new popularity in the early 2000s and as a result you can now find CHIP-8 emulators for virtually any platform, including your mobile phone, as well as a range of assemblers and other development tools. It's a fascinating bit of history in its own right and also a great platform to emulate in the first emulator you write. A bit further away from the syntax of "real" assemblers is Linoleum [2], which is meant to be a kind of a cross-platform assembly language targeted towards graphics applications, but the principles behind programming in it are largely the same. I can recommend both from personal experience, although CHIP-8 is probably a better starting point.
Second, if you want something closer to real hardware I'd suggest learning how to program for the MOS 6502, the CPU used in the Apple II and (with some modifications) in the Commodore 64 and the NES gaming console. One way to get started with it is Easy6502 [3], which is an online introductory course on 6502 programming bundled with an in-browser emulator.
[1] https://en.wikipedia.org/wiki/CHIP-8
[2] https://en.wikipedia.org/wiki/Linoleum_%28programming_langua...
[3] http://skilldrick.github.com/easy6502/
Randall Hyde is a boss. I was thinking about him the other day. I used to read everything of his that I could find when I was taking courses at a place that had no Randall Hyde. I couldn't find a reference to it, but he used to have an annual-ish day of destruction for insolent computing equipment.
Nowadays I'm an electronics instructor at a JuCo. I don't teach any assembly. I barely mention it. It was in the curriculum, and I specifically threw it out [1]. There just isn't enough time to do everything, that everyone might want us to do. I replaced it with Python and C [2].
C lets us get to building systems much quicker.
C covers more potential job opportunities than any particular architecture, and no company can ever have a monopoly on C. C is portable assembly language.
Most people [3], when faced with the choice of optimize vs buy a better microcontroller, they spend the extra two bucks.
Even though solving problems with assembly can be tremendously fun and fascinating, I still prefer C. (sorry Randall).
[1] But I'm always interested in good arguments about the subject.
[2] and LabView, I'm embarrassed to say.
[3] people also includes the companies that hire our graduates.
Nowadays I'm an electronics instructor at a JuCo. I don't teach any assembly. I barely mention it. It was in the curriculum, and I specifically threw it out [1]. There just isn't enough time to do everything, that everyone might want us to do. I replaced it with Python and C [2].
C lets us get to building systems much quicker.
C covers more potential job opportunities than any particular architecture, and no company can ever have a monopoly on C. C is portable assembly language.
Most people [3], when faced with the choice of optimize vs buy a better microcontroller, they spend the extra two bucks.
Even though solving problems with assembly can be tremendously fun and fascinating, I still prefer C. (sorry Randall).
[1] But I'm always interested in good arguments about the subject.
[2] and LabView, I'm embarrassed to say.
[3] people also includes the companies that hire our graduates.
Eventually every high-level programmer gets a fault on a line of code. It may contain five or six dereferences, some temporary constructors, result assignment.
Without knowing assembler it can be impossible to discover exactly which was at fault. The programmer can thrash around for half a day swearing and struggling.
And also, did I just call 'C' a high-level language?
Without knowing assembler it can be impossible to discover exactly which was at fault. The programmer can thrash around for half a day swearing and struggling.
And also, did I just call 'C' a high-level language?
>>Eventually every high-level programmer gets a
I'm hoping that any of my JuCo grads who go on to get real programmer jobs (there have been a few) will get some more practice/training, than I can give them in a couple semesters; maybe find a mentor to work with for a bit too.
>>Eventually every high-level programmer gets a... And also, did I just call 'C' a high-level language?
Sure looks that way ;)
I'm hoping that any of my JuCo grads who go on to get real programmer jobs (there have been a few) will get some more practice/training, than I can give them in a couple semesters; maybe find a mentor to work with for a bit too.
>>Eventually every high-level programmer gets a... And also, did I just call 'C' a high-level language?
Sure looks that way ;)
In the domain I work in (firmware for digital instruments and industrial systems), knowing assembly isn't necessary for performance reasons so much as for sanity reasons - a lot of vendor compilers for embedded devices are incredibly flaky, and if you can't inspect the generated assembly you'll never know what the hell is going on in cases where the code doesn't behave the way you expected it to.
Heck, even when I have the privilege to be treading a more well-worn path (eg. ARM/GCC), it's helpful to be able to tell what the compiler is transforming (on a less charitable day I'd say "munging") my code into.
Heck, even when I have the privilege to be treading a more well-worn path (eg. ARM/GCC), it's helpful to be able to tell what the compiler is transforming (on a less charitable day I'd say "munging") my code into.
Very much agree. Assembler is not about efficiency; its about debugging.
The article focuses on writing great code, but there's another reason to learn assembly language: for some specific aspects of a machine that were not modelled in the higher level languags, this may be the only way to go.
For example, for HP Integrity Virtual Machines (sort of VMware for HP big iron servers), I spent a lot of time writing low level vector code that just cannot be written in any other language because it executes in some specific restricted environment that the C compiler cannot deal with. Specifically, it runs off a few reserved registers, has no valid stack (a TLB handler may be triggererd by a TLB miss on the stack), and frequently use instructions that are at best supported by compilers as inline assembly.
So it's not just about performance or style, it's also about semantics. And that's part of the reason why in XL, all low-level operations are connected with the machine explicitly. I reasoned that what worked for an addition would alo work for a more bizarre machine instruction.
So in XL you have for the imperative dialect:
Does not solve the whole problem, e.g. The compiler still has to assume things like "there's a stack", but getting closer to connecting machine and high level languages.
For example, for HP Integrity Virtual Machines (sort of VMware for HP big iron servers), I spent a lot of time writing low level vector code that just cannot be written in any other language because it executes in some specific restricted environment that the C compiler cannot deal with. Specifically, it runs off a few reserved registers, has no valid stack (a TLB handler may be triggererd by a TLB miss on the stack), and frequently use instructions that are at best supported by compilers as inline assembly.
So it's not just about performance or style, it's also about semantics. And that's part of the reason why in XL, all low-level operations are connected with the machine explicitly. I reasoned that what worked for an addition would alo work for a more bizarre machine instruction.
So in XL you have for the imperative dialect:
function Add(x,y:integer) return integer written x+y is XL.Bytecode.Add
And for the functional dialect: X:integer + Y:integer as integer -> opcode Add
The list of opcodes is machine specific, but the way to connect to them is not.Does not solve the whole problem, e.g. The compiler still has to assume things like "there's a stack", but getting closer to connecting machine and high level languages.
I used to teach OS classes a local university, every summer I would teach 3 to 5 students how to build a bootstrap and a simple 'kernel' just using asm. The rest of the class would just use GRUB and do something better, faster.
Anyway, I don't think this matters to our usual professional life.
(this person deserves to be heard, he built a large OS, dead comment)
he wrote:
"If you love programming more than anything, you are probably the kind of person who wants to know assembly language. If your full heart is not into programming, maybe not."
Anyway, I don't think this matters to our usual professional life.
(this person deserves to be heard, he built a large OS, dead comment)
he wrote:
"If you love programming more than anything, you are probably the kind of person who wants to know assembly language. If your full heart is not into programming, maybe not."
When will we be in a world when we don't have to deal with assembly language at all? When can we just get the job done without having to understand or know any of the things which go down there? Because that stuff pisses me off. Bits? Bytes? I just want that freaking login box and implement some functionality and never have to deal what's under. Is it really that hard? Sigh.
When will we be in a world when we don't have to deal with molecules at all? When we can just get the job done without having to understand or know any of the things which go down there? Because that stuff pisses me off. Protons? Electrons? I just want that freaking light to come on and implement some functionality and never have to deal [with] what's under[neath]. Is it really that hard? Sigh.
--
I don't particularly like that style of arguing a point but this is just asking for it. Knowing a higher level of abstraction without knowing a lower level of abstraction is just fine. But knowing a lower level of abstraction will give you a definite edge and if there is one thing that hackers are always looking for then it is a way to have an edge over the rest. A way to do something that is deemed impossible simply by knowing a bit more, a way to achieve some feat by exploiting knowledge that is maybe a bit harder to come by but not impossible. The ultimate level playing field, you get as many tools as you're willing to learn how to use, with only your attitude towards learning and your perseverance as the limiting factors.
--
I don't particularly like that style of arguing a point but this is just asking for it. Knowing a higher level of abstraction without knowing a lower level of abstraction is just fine. But knowing a lower level of abstraction will give you a definite edge and if there is one thing that hackers are always looking for then it is a way to have an edge over the rest. A way to do something that is deemed impossible simply by knowing a bit more, a way to achieve some feat by exploiting knowledge that is maybe a bit harder to come by but not impossible. The ultimate level playing field, you get as many tools as you're willing to learn how to use, with only your attitude towards learning and your perseverance as the limiting factors.
I was going to write a similar analogy, but not as abstract as that. I was thinking more like the automotive industry.
Most people want to just be able to buy and drive it off the lot without having to understand how it works or what makes it tick inside. But there will always be a need for automotive engineers.
Most people want to just be able to buy and drive it off the lot without having to understand how it works or what makes it tick inside. But there will always be a need for automotive engineers.
The answer is probably never. There will be deeper levels of abstraction, and the OS, for the most part, will do a marvelous job hiding it, but without a strong understanding of assembly you'll never be able to work on things like memory management, efficiency algorithms, and so forth. For example, assembly forces you to think in terms of bits, so knowing word-aligned vs non word-aligned code can make drastic differences in speed. Also, knowing how 64-bit is different from 32-bit makes a world of difference. Assembly forces you to think in those contexts.
For the most part, the average programmer today already does not need to know assembly. But if you want to work on other low-level aspects of code (or optimize your code for efficiency), knowledge of assembly is critical. You might not have to write very much assembly, but things like context-switching that happens on the CPU level (e.g kernel land vs user land) can only be done by sending the right instructions to the CPU.
For the most part, the average programmer today already does not need to know assembly. But if you want to work on other low-level aspects of code (or optimize your code for efficiency), knowledge of assembly is critical. You might not have to write very much assembly, but things like context-switching that happens on the CPU level (e.g kernel land vs user land) can only be done by sending the right instructions to the CPU.
You don't have to deal with what's down under. Your loss really. So I don't understand what's bothering you.
On the other hand, those that do understand what's going on down under have to endure with the high-level crap of unimaginable proportions every day.
If "programming" is so easy that you don't really have to know anything to do it the result is going to suck. Case in point: Android and iOS.
The world would be a better place everyone were required to know assembly before doing an web app.
On the other hand, those that do understand what's going on down under have to endure with the high-level crap of unimaginable proportions every day.
If "programming" is so easy that you don't really have to know anything to do it the result is going to suck. Case in point: Android and iOS.
The world would be a better place everyone were required to know assembly before doing an web app.
Someone will always have to understand every part of the stack. If that person's not you, then just move on. I don't give a crap about browser UI and I wish I lived in a world where we didn't have to deal with that. But in reality, I'm glad somebody cares about it, and if someone writes an article about that world - more power to them.
A large portion of professional software development doesn't ever touch asm, so the answer can be "today" if you want.
My day-to-day job is web dev. But yesterday, I dug up references I haven't read in years and wrote a bootloader. Why? Because it turns out that for some things, speed and simplicity really matter.
Also, I haven't had this much fun doing development in ages.
Also, I haven't had this much fun doing development in ages.
So here's the tricky question...
Why was it fun?
Why was it fun?
Good question. I think it's something to do with the impression that if something doesn't work, I can have absolute confidence that it's something that I've done wrong. There's no question of "bugs in the framework"[0]. There's also the matter that this is one area where code golf is actually practical, and can make the difference between being able to do something and simply not.
[0] Yes, I know there are hardware bugs. In the sort of thing I'm doing? Not hugely relevant.
[0] Yes, I know there are hardware bugs. In the sort of thing I'm doing? Not hugely relevant.
So ignorance is bliss? I guess there will always be a fundamental requirement to know the root of all operations. But, good luck in hoping otherwise.
[deleted]
When we actually get to use qubits may be?
Not sure why you're being downvoted. It's an opinion, people.
we?
If it's not your bag my friend, walk on.
If it's not your bag my friend, walk on.
Ten years later, this article still resonates on so many levels. I hope we reach a day that we all aspire to like those that refuse to download the next x-behemoth flavor-of-the-day framework for all the reasons stated in this article instead of deriding them.
I hope only the best frameworks and tools, written by the best programmers, get stadarized, so the application developers can focus on business logic, data science/engineering and interaction design with a robust abstraction below.
If the best ever won out, that might be a rational hope.
A 6502 is a really stupidly simple machine. If you've had previous exposure to programming in assembly, you can get a pretty complete understanding of the machine in an afternoon. It doesn't take very much experience to get to the point where you can take a look at a subroutine and figure out exactly how many cycles it will take to execute, on which exact cycle this I/O operation will occur, etc.
I've tried that approach with x86 (not even x86-64!) manuals before, and I ran away screaming. I don't know how long it would take me just to be aware of all of those instructions, let alone be able to even roughly estimate their execution time across the hundreds of differing x86(-64) implementations! Just peeking at Agner Fog's optimization manuals[1], I remember that some instructions can take 20~ cycles on a Pentium 4 (probably the oldest x86 processor still in common public use), and 1~2 cycles on anything past the Core series. Some instructions an Intel Atom will choke to death upon. With some similar pairs of instructions, one of the two is faster on every machine except the Atoms! How am I supposed to reconcile all of these discrepancies and write something that is anywhere near optimal for a large portion of the x86 userbase?
You can make the argument that you don't need to know all of the x86 instructions to write a decent assembly language program. That's probably true. Yet, part of the fun of working on a simpler system is that you can write a piece of code and know that it is very close to optimal -- maybe you could rewrite the whole thing and save a few bytes or a few cycles, but you still feel like you've put your repertoire of tricks to good use and made something that you would be feel reasonably comfortable showing off to the experts. If I can't get that feeling on x86, only getting to beat a compiler that has to work within the limitations of its language, and producing a result where no one really cares (and can't even tell!) that I shaved a few cycles here and there, there is little point, and not as much fun.
If you want to have fun writing assembly language, pick a processor microarchitecture that you can comfortably fit in your head, and an environment where you'll only have to deal with one or two implementations of that microarchitecture. Intel and AMD, in the (very well justified) interest of developing the most powerful machines on the market, have turned x86 into something that is not fun to write assembly for, and not possible to fit in your head (at least, without serious commitment on the level of "I am going to make a career out being the x86 guy/gal"). Don't bother! Don't even bother writing something for a platform where you need libraries to print something to the screen, or convert a line of text into a number. Find a platform that lets you turn lights on and off by poking addresses, and go from there.
In the mean time, I'm not at all surprised that no one tries to write optimal software for x86 PCs. No user will feel the effort you put into shaving cycles off of anything but the tightest loops and most critical of paths, and there isn't even a scene of ``expert programmers'' comparable to the ones currently around the 6502 or 68000 to appreciate what you do. The best you get is a mention on Hacker News and a few wistful comments about the good ol' days.
</stupid rant>
[1] http://www.agner.org/optimize/
Lots of very useful information here, even if you don't ever want to attempt programming in x86 assembly.
EDIT: The funny thing about all this is that even ``back in the day,'' a 6502 was fast enough that you could get away with all kinds of inefficiencies. You find a game that blew your mind as a kid and stuff it into a debugging emulator, trying to understand bits and pieces of how the engine works, and find yourself laughing at trivial inefficiencies all over the place, even in critical loops! Yet, even with all the hundreds or thousands of bytes and cycles wasted here and there, then end result still feels plenty ``fast.''