Assembly: back to basics

When it comes to programming languages, there are limitless possibilities. We have hundreds of choices, filling just about every niche you can think of. Some languages are optimized for speed (C, C++), some for use in a particular environment (Lua), some to be highly readable (Python), some for a kind of purity (Haskell), and some for sheer perversity (Perl). Whatever you want to do, there’s a programming language out there for you.

But there is one language that underlies all the others. If you’ll pardon the cliché, there is one language to rule them all. And that’s assembly language. It’s the original, in a sense, as it existed even before the first compilers. It’s the native language of a computer, too. Like native languages, though, each computer has its own. So we can’t really talk about “assembly language” in the general sense, except to make a few statements. Rather, we have to talk about a specific kind of assembly, like x86, 6502, and so on. (We can also talk about “intermediate languages” as a form of assembly, like .NET’s IL or the LLVM instruction set. Here, I’ll mostly be focusing on processor-specific assembly.)

The reason for assembly

Of course, assembly is the lowest of low-level languages, at least of those a programmer can access. And that is the first hurdle, especially in these days of ever-increasing abstraction. When you have Python and JavaScript and Ruby, why would you ever want to do anything with assembly?

The main, overriding purpose of assembly today is speed. There’s literally nothing faster. Nothing can possibly be faster, because everything basically gets turned into assembly, anyway. Yes, compilers are good at optimizing. They’re great. On modern architectures, they’re almost always better than writing assembly by hand. But sometimes they aren’t. New processors have new features that older compiler versions might not know about, for example. And high-level languages, with their object systems and exceptions and lambdas, can get awfully slow. In a few cases, even the relatively tiny overhead of C might be too much.

So, for raw speed, you might need to throw out the trappings of the high level and drop down to the low. But size is also a factor, and for many of the same reasons. Twenty or thirty years ago, everybody worried about the size of a program. Memory was much smaller, hard drives less spacious (or absent altogether, in the earlier days), and networking horrendously slow or nonexistent. Size mattered.

At some point, size stopped mattering. Programs could be distributed on CDs, then DVDs, and those were both seen (in their own times) as near-infinite in capacity. And hard drives and installed memory were always growing. From about the mid 90s to the late 2000s, size was unimportant. (In a way, we’re starting to see that again, as “anti-piracy” measures. Look at PC games that now take tens of gigabytes of storage, including uncompressed audio and video.)

Then, just as suddenly, size became a big factor once again. The tipping point seems to be sometime around 2008 or so. While hard drives, network speeds, and program footprints kept on increasing, we started becoming more aware of the cost of size. That’s because of cache. Cache, if you don’t know, is nothing more than a very fast bit of memory tucked away inside your computer’s CPU. It’s way faster than regular RAM, but it’s much more limited. (That’s relative, of course. Today’s processors actually have more cache memory than my first PC had total RAM.) To get the most out of cache—to prevent the slowdowns that come from needing to fetch data from main memory—we do need to look at size. And there’s nothing smaller than assembly.

Finally, there are other reasons to study at least the basics of assembly language. It’s fun, in a bizarre sort of way. (So fun that there’s a game for it, which is just as bizarre.) It’s informative, in that you get an understanding of computers at the hardware level. And there are still a few places where it’s useful, like microcontrollers (such as the Arduino) and the code generators of compilers.

To be continued

If you made it this far, then you might even be a little interested. That’s great! Next week, we’ll look at assembly language in some of its different guises throughout history.

Leave a Reply

Your email address will not be published. Required fields are marked *