“Dang Ben,” you say, “it’s absurd how good you are at Starcraft 2!” Well, yeah, you’re right. But what’s almost as absurd is how cool assembly is.

Assembly is the code that your C/C++ gets compiled to (other languages too, but fuck ’em). It’s a super low-level, close-to-the-metal language, where each line of code represents exactly one task for the processor. There’s a bunch of different flavors of assembly, depending on your processor, but we’re talking about 32-bit x86 assembly here.

Let’s see what the code int firstNum = 10; int secondNum = 31; int thirdNum = firstNum + secondNum; looks like in assembly:

mov dword ptr [firstNum],0Ah
mov dword ptr [secondNum],1Fh
mov eax,dword ptr [firstNum]
add eax,dword ptr [secondNum]
mov dword ptr [thirdNum],eax

As you can see, lines of code in assembly are structured command var1 var2.

  • command is one of a preset list of commands, called the instruction set. These instructions are the only things your processor can do; all your code is expressed in terms of these instructions.
  • var1 is the destination, and var2 is the source.
  • [x] means “don’t look at x, look at the memory at the address held in x“. So, it’s a pointer-dereference, like * in C.
  • dword ptr means x is 32 bits long, or double the size of a 16-bit word ptr.
  • mov means “move”, and 0Ah means “hex byte 0A”, so mov dword ptr [firstNum],0Ah writes 0x0A into firstNum.
  • Sometimes var1 is used as a source as well as a destination — add var1 var2 means var1 = var1 + var2

Cool! So that tells us everything, except… what is eax? Remember that processors can only do arithmetic and logic on data in registers. eax isn’t a variable, it’s a handle to a physical register! x86 assembly has only eight registers that you can read and modify at will, and eax is the one you’ll see most (because it’s favored for arithmetic). If you want to know more about the differences between the eight registers (oh my god are there differences), then CLICK HERE to expand a whole aside on them.

Anyhow, assembly isn’t just some academic concept. You can read the assembly your code gets compiled into, and even insert your own assembly in-line with C/C++ code for sick micro-optimizations (sort of — there’s caveats).

In Visual Studio, stick a breakpoint in some code and hit alt+8 when you hit it. Congratulations! You’re looking at assembly! You can even step through individual instructions to get some hot debugging action. This is a really powerful tool for learning low-level architecture, and I totally encourage you to play with it. There’s no abstractions left when you’re reading assembly. Check out how for and while loops are actually implemented — it’s all just GOTO instructions (well, the instruction is called JMP).

If you want to write in assembly, you can do that too! Maybe. You can write inline assembly for x86 processors, but compilers for newer x64 processors don’t accept inline assembly and recommend you use a predefined set of highly-optimized, low-level intrinsic functions instead.

This isn’t because of any hardware changes in x64. Instead, it’s because inline assembly isn’t necessarily a speed boost. Having inline assembly defeats a ton of compile-time optimizations, since it means the compiler doesn’t get full control over what data is in which registers at any time. You can string intrinsics together to get the speedy low-level behavior you want, and you aren’t fighting the compiler by doing so.

So, you may not want to use inline assembly as a performance tool, since support for it is going away and it can hurt your perf by ruining compiler optimizations. However, it’s still a great learning tool, so don’t be afraid to try it out! To add inline assembly, just use the __asm{ ... } command. For instance:

int myNum = 10;

__asm {
   mov eax, dword ptr [myNum]
   mov ebx, 20
   add eax, ebx
   mov dword ptr [myNum], eax

if(myNum == 30)
   cout << "OH DAAAAAAMN";

Anyhow, that's enough. I'm off to perfect my reaper-into-battlecruiser build. Happy coding!

Leave a Reply

Your email address will not be published.