A wide grin formed on my face, after successfully completing an exercise (from Computer Systems a Programmer’s perspective) that required me to write C code, based off a sequence of a six assembly instructions:
void decode1(long *xp, long *yp, long *zp) { /* xp stored in %rdi, yp in %rsi, zp in %rdx) decode1: movq (%rdi), %r8 movq (%rsi), %rcx movq (%rdx), %rax movq %r8, (%rsi) movq %rcx, (%rdx) movq %rax, (%rdi)
The exercise consists of solely of mov instructions, which is capable of moving bytes (movq specifically moves a quad word) from:
- register to memory
- register to register
- immediate value to register
- immediate value to memory
So, I pulled a pen and paper from my backpack and began tracing the flow of data between the multiple registers and memory locations. I then took that chicken scratch, and wrote the corresponding C code. Finally, I flipped to the end of the chapter to compare my code. Bingo—the C code I wrote mapped exactly to the author’s answer key.
I celebrated the tiny victory.
The purpose of the exercise is two fold. First, the exercise illustrates that higher level programming languages—including C, Python, and Java—compile into a lower level language: assembly. Moreover, this compels programmers, I think, to pause while writing code and question the performance implication; does this line require two instructions, three, four? Second, the exercise demystifies the concept of C pointers, a construct that many novice programmers stumble over. But after completing this exercise, I find pointers intuitive—nothing more than a value of a memory address.