In the old days programming assembly language was nasty because one mistake could mean your computer had to be rebooted and you lost your work. Not anymore.
If all you want is a basic understanding of how things work, that level is ok. If you want to play/program, it is a completely different story.
I'd even go so far to say: Why do assembly if your goal is not to be better than the compiler, at least in some respect? Beating the compiler, now tell me that it's simple stuff.
Why learn assembly?, well for one, the non-abstract aspect of assembly is less abstract, and arguably easier to understand than even the simplest high level languages. Secondly, learning assembly is also learning how computers work and that paradigm will help you even as you largely work in a high level language.
And beating the compiler isn't as hard as you might think if that becomes necessary some day.
googles Intel CPU data sheet
Ah, here we go.
https://www.intel.com/content/www/us/en/products/docs/proces...
Just two volumes and 1000 pages of reading. Simple!
I've found working with a simpler, smaller processor can be an absolute joy.
Eventually I actually read the first chapter properly and added MOV AH,4CH / MOV AL,0 / INT 21H. When my executable returned to the DOS prompt this time after running it, I felt like my mind had just expanded 10-fold as I realised what had been happening.
And then you wonder what can you think to tell it to do. The wonder of computers.
Anything beyond that gets complex quickly, in one way or another. On simple architectures, like the 6502, even doing a simple division is complex (heck, even additions are verbose, since 8 bits are too few for a lot of operations). On more complex architectures, like x64, there is a monstrous ISA full of inconsistencies.
Learning assembly as in learning an instruction set also doesn't include a lot of details of computer architecture, although at least some modern assembly books mix both domains.
Writing an assembler for 8-bit CPUS like 6502/Z80 was doable; I wrote a 6502 cross assembler (in Z80) so a Z80 development machine could output 6502 in 1985. It got harder with 8086 and 68000 chips.
But you also need to know about calling conventions of your operating system if you want to do any form of system call, which you very likely want to. Which registers supply arguments, which registers have to be saved, addresses of system functions which can change with OS or kernel version. You also need to learn what these function do. How would anyone know that writing a 48 into your accumulator and calling interrupt at address 80 opens a socket on Linux?
Thinking about this again makes assembly seem like a terrible, terrible idea...
To start with I would either recommend x86_64 for either Windows and Linux. I would prefer Linux here but I believe UEFI for example uses the Windows calling conventions, so taking a look at that might be practical. But these combinations usually offer the most learning helpers.
Usually you should only cause general protection faults at worst if you have something newer than a 386. But no guarantee...
Hack Club is a group of teenagers from all over the world, and we decided to learn assembly together from scratch and see what happened.
We ended up making this guide as we learned, since a lot of the resources we were working with weren't the easiest to parse.
Happy to answer any questions :)
If you want to check out some fun assembly code in a larger program, I suggest checking out the leaked furby source code. [1] The assembly for the lunar landing modules from the 1960s is also pretty wild [2]
And... OH MY GOD FURBY SOURCECODE THIS IS AWESOME THANK YOU
what happens when a member hits 20?
There's quite a big difficulty spike so to speak in the later section as you go towards the code examples. The beginning explains relatively simple concepts like binary, then basically jmps into an instruction table which won't make sense to anyone who hasn't done some form of programming (they would know binary then, right?).
The tone is also a bit off putting, although I might be out of touch with today's teenagers. When I was learning asm as a teen I learned it from grungy 1337 h4x0r sites (well, they didn't actually use 1337speak except ironically, much like today) which were at least a great deal.. meaner? less nice?.. than the tone of the article.
From what I wrote I gather my main criticism is that it doesn't know its audience. However, it seemingly _was_ produced by an actual group of teenager as per the author's HN comment:
> Hack Club is a group of teenagers from all over the world, and we decided to learn assembly together from scratch and see what happened.
Although it probably means a trained adult was lightly helped by some teenagers in producing it.
I hope this didn't sound too harsh, the effort is very good and so are the illustrations. It needs some fleshing and perhaps a little less "yay!!". Learning assembly is not actually that fun, it's rather painful. It's what you do with it that is fun.
As a teen, I taught myself assembler circa 1982 on my Radio Shack Color Computer (with 4k of RAM!). It was indeed painfully challenging, especially due to the complete lack of information available and the fact I didn't know anyone else who knew anything about it. The only reason I persisted was that the BASIC interpreter in ROM was too slow to write any really cool games. The other thing that kept me going was that assembler was arcane hidden knowledge which bestowed power on those who could figure it out. I didn't want to "learn" assembler, I just wanted to use it and that required knowing how it worked.
I succeeded only because my teenage self somehow pulled off a phone call to Motorola sales where I claimed to be an engineer "evaluating" the 6809 CPU and they sent me the manual and a quick reference card. Due to my complete lack of background in computers or electronics, the manual was pretty cryptic but that quick reference card was my constant companion that entire Summer as I used the BASIC PEEK and POKE commands to write programs. I ordered a "Monitor Program" from a small ad in the back of a garage-published computer magazine. When that cassette tape arrived it allowed me to actually read and write assembler mnemonics into memory, set breakpoints and look at registers. The next breakthrough was realizing I could use it to examine the ROM assembler code. When I finally convinced my parents to buy a dot matrix printer, I printed the entire 8k of the BASIC on fan-fold paper and went through it, commenting by hand.
To your point, the fact that it was so hard combined with it being arcane knowledge was perhaps what kept me going. That and the reality it was the only way forward to get the computer to do more cool stuff.
The feeling of mysticism and challenge is dispersed when put into an easy to grasp format. This enables more people to learn enough to reach the skill floor, but it doesn't teach those with an able mind to reach for the ceiling. I see this nowadays a lot, most people around me who didn't grow up with this culture are much worse debuggers. That's not because of their technical skills, but a lack of tenacity. Having answers be far far away means that when you start finding them regardless, you gain an inner mindset of "no matter how hard this is, eventually it is understandable". Seeing what other people could reverse engineer with extremely poor resources inspires one to try harder when there's no solution in sight. It's also taught me that I am _nowhere near as smart_ as I thought I was. To a hilarious degree. Somehow this is not a paradox.
lol that is such a nice story
Which ones?
[0] https://store.steampowered.com/app/375820/Human_Resource_Mac...
Also I didn’t realize Rollercoaster Tycoon was primarily written in Assembly. That’s nuts.
Conceptual flaws (mainly down the line rather than introductory):
One issue with it down the line is that processors spend a lot of their design budgets avoiding carting memory around. You don't have to mention that explicitly but in my skim reading I would've (if I were writing it) tried to emphasize something more akin to a postal sorting room than a warehouse as per se.
Maybe that's too advanced, but I understood it when I was 18 or 19 so YMMV.
One interesting demo is to see how much assembly you can fit in a single memory access latency.
Just off the top of my head, some possibilities are:
* More cores
* More numerous/powerful execution units that can do e.g. vectorized math
* Architectural features such as virtualization and security defenses
* Bigger and more flexible caches
* Complex pipelining/out-of-order/speculation logic that allows more instructions to be executed (on average) per clock cycle
* Special-purpose functional units that dramatically accelerate particular applications (e.g. AES encryption, video encoding/decoding) and are idle the rest of the time
* Replacing "deep" networks of logic gates with equivalent "wider" ones, which occupy more die area but have a shorter critical path, enabling faster clock speeds
2. Modern CPUs have a very complicated instruction reordering mechanism and data dependency analysis mechanism that allows CPUs to execute multiple instructions in parallel, when it's possible.
3. A lot of transistors are used for caches (instruction and data caches, and other kinds of buffers like the one used for branch prediction etc).
4. Even a single core has multiple copies of the execution units which allow to execute some instructions in parallel (see above).
You see the machine executing a sequence of instructions, and that is exactly what happens - eventually.
But behind the scenes, the goal of the hardware is to execute those instructions as quickly as possible. Since there's a limit to how fast silicon can work, the way to achieve this is via a number of tricks that effectively throw yet more circuitry at the problem, taking you from millions to billions of transistors.
Just one of these tricks for example is caching. Instead of writing directly to memory (as it appears to your assembler code), the CPU actually writes data to the L1 cache, a smaller but much faster block of memory on the CPU itself. At a later time, the data can be transferred from the cache out to RAM. In fact a modern CPU will have caches feeding into caches - e.g. CPU feeds into the L1 cache, which itself feeds into the L2 cache, then into the L3 cache, and finally into RAM. At each step, the cache gets larger and slower - so while the L1 cache is measured in KB, the L3 cache in a modern CPU might be up to 64MB in size.
You don't see any of this when you are writing assembler code. To all intents and purposes the caches are invisible to you. There are obscure instructions like CLFLUSH that provide very limited control of the cache but these are not typically something you'd use.
It's easy to see how managing these caches enormously increases the circuitry in the chip, without any need for you, the assembler programmer, to even think about them.
As other commenters have noted, other areas where extra circuitry is thrown at the problem include area is pipelining. In your mental model, the CPU is probably plodding along executing instructions one after another. In practice the CPU is aggressively trying to reorder those instructions and execute them in parallel as much as possible. This is an incredibly complex process, requiring enormous amounts of circuitry.
TLDR; what you see as a relatively simple CPU instruction set is really an abstraction - behind the scenes is an enormously complex collection of moving parts that break your code down and try and execute it as quickly as possible.
And I'm sure I've barely scratched the surface.
https://ocw.mit.edu/courses/6-004-computation-structures-spr...
But the scoring mechanism was heavily weighted towards lines of code and the turbo Pascal entry one even though it took about six minutes to complete.
That pissed me off so much I never really messed with assembly again.
Something about being _in the code_ while stepping through lines one by one with explanations is just so much easier to follow. I wish more learning resources took this approach.
I just go straight to the code. Same with SO - I'm not reading words, I'm reading code. Even with zero familiarity I find code is easier to read with inline docs vs. digging through someone's word salad. Truth is most of us aren't great technical writers.
That being said I did skim the content for this resource and found it to be pretty to the point and clear-cut. Even the metaphors and extra information were applicable to providing a good primer. I wish more devs would write with the same succinct technical clarity as this and maybe I wouldn't skip the word salad as much ha
It's also why we put it in GitHub, so it could live alongside the code examples :)
A lot of resources show a snippet of code, followed by an impenetrable paragraph that tries to explain multiple concepts from the snippet all at once. Maybe that works for others, but for me it makes it impossible to parse and overwhelms me, so nothing sticks.
mul rcx, rax ; multiply our result by our base, save into rcx
This should probably be using rbx, since that's the designated base, not rax, which is the exponent.In the explanation just above, there's a 2*8 step missing, while this one is incorrect:
4. result = 16 * 2, result is now 16
Since 2*16 is not 16.https://www.gamesindustry.biz/articles/2011-03-30-machine-co...
Also there is a book called Programming from the Ground Up that starts with assembly and moves up to C and beyond.
Hubris?
Frankly, depending on their experience, assembly may well be familiar, efficient and effective.
Some people who got going early on in games, in the 8 bit era, went right for assembly language because that is where the speed necessary to make magic happen on the screen was.
Action / arcade games pretty much demanded it, unless they sharply limited what happens on screen.
You might find some of the early stories informative. Nasir, for example, did his first dozen or so games with the mini line assembler in his Apple 2. No source code, no labels, etc...
On some of the projects I did on 8 bit computers, it was all about assembly. One planned out a few things, worked around where the screen was, or needed to be (depending on hardware capability), on screen graphics, other data needed, and then build in chunks, saving stuff off to disk.
Every so often, load several in, tie them together, save that off, then run it. It is a different style of thinking for sure.
I bet that developer knew how to build something up that way and went with what worked, was performant, and that was probably the easiest path for them.
Not sure how true it is, but I heard that keeping track of a lot of objects required plenty of optimization, and apparently such levels of detail may have not been in games before. RCT was the second Tycoon game by Chris Sawyer, after Transport Tycoon from 1994—which is also in assembly and which keeps track of buses and trucks each with its own parameters, trains with each car, signals on the roads; of every passenger and every batch of goods: where it's from, how long it's on the way, etc. (At least if OpenTTD recreates the mechanics faithfully.) You can also pop up several windows with views to different parts of the map or following various vehicles.
As a developer who didn't learn via a scholastic setting, taking the time to sit down and learn a bit of assembly was something I see as a critical point in my career.
Starting with a high level scripting language, my brain had a hard time dealing with so much abstraction and taking what felt like a crazy amount of axioms as given.
I took a few months to sit down and go through the excellent book Programming From the Ground Up. After doing some bit twiddling, writing a basic allocator, and a handful of the other exercises from the book, I felt way more prepared to handle abstractions higher up.
Anything that I couldn't infer based on the underlying knowledge was something I could google, then quickly form the missing links between starting from the bottom.
I feel like learning C could give the same benefits, though I do hear some struggle with pointers, and in assembly you get to look face first at what they actually are. Everyone has different levels of abstraction that they're comfortable with as well. Assembly was enough to fill the seeming void of knowledge that I felt was holding me back, but for others it may be higher depending on which aspects are puzzling (memory management, intermediate representations, etc).
I also appreciate how much information modern VM authors publish about the inner workings of their platforms. It helps a lot in the same manner to reason about the systems (v8, JVM, CLR, etc).
If you are still interested in learning more, ARM and PowerPC are also both interesting assembly targets.
Prior to Bell Labs (college) my assembly experience was 8085 bare metal (no OS) or Z80 under CP/M and MP/M. I wrote a couple console management applications for MP/M that had to dig into BIOS/BDOS routines. It was fun, and that was the thing that made my EE self realize that I wanted to work on software in embedded systems.
I have used some assembly language stuff, including 6502, Knuth's MIX and MMIX, and virtual codes such as Z-code and Glulx.
I have written small amounts of old x86 assembly code (for the older 16-bit PC), too. (I think that the new x86 is too messy and too complicated, compared with the old x86 which is not bad.)
I have been trying to learn TRON assembly code too, although I cannot find enough information. I found some documents, but they are in Japanese and some important diagrams seem to be missing. There is some English documentation too but it does not explain much.
In using assembler I find the hardest part is to represent the task at hand into a form of a sequence of elementary operations over the dynamic set of data pieces and their locations.
Perhaps, when the problem scope is on a lower level with a limited sets of data and operations, this maps easier. But when the task is on a macro level, that extra step of mapping the context onto a lower level scope is just too much effort.
In a way, in a higher level scope the programmers create their specific 'assembler' with a different set of registers and opcodes and sequences of operation, and even busses.
https://github.com/hackclub/some-assembly-required/tree/main...
I’m definitely not an assembly guy, but it would be fun if there was a REPL to play with this. Not sure if that would accidentally invert the universe or it’s too low level for a REPL, but conceptually it would be fun to play with in a sandbox.