This page does not represent the most current semester of this course; it is present merely as an archive.
We'll start today with a discussion of bitmasks and some related fiddles. In particular, we'll discuss
Code | Behavior |
---|---|
!!x |
x != 0 ? 1 : 0 |
~(!!x)+1 |
x != 0 ? 0xffffffff : 0 |
a&B | ((~a)&C) |
a ? B : C , assuming that a was either 0 or 0xffffffff |
x<<32 |
does nothing (shifts must be between 0 and 31) |
~((~0)<<x) |
0s followed by exactly x 1s. |
pushl
and popl
, arguments and returnsAs described in the textbook. We'll take questions, if there are none we'll move on.
rdtsc
x86 has a special assembly operations rdtsc
that r
ead
s the t
ime s
tamp c
ounter, a 64-bit counter that is incremented every single clock cycle. It lets us measure the exact time taken by each operation.
We can use GCC's inline assembly options to access the time stamp counter:
/*------------------- BEGIN CYCLE COUNTER CODE -----------------------*/
#if defined(__i386__)
static __inline__ unsigned long long rdtsc(void) {
unsigned long long x;
__asm__ volatile ("rdtsc": "=A" (x));
return x;
}
#elif defined(__x86_64__)
static __inline__ unsigned long long rdtsc(void) {
unsigned hi, lo;
__asm__ __volatile__ ("rdtsc": "=a"(lo), "=d"(hi));
return (((unsigned long long)hi)<<32) | ((unsigned long long)lo);
}
#else
#error "No cycle counter available"
#endif
/*-------------------- END CYCLE COUNTER CODE ------------------------*/
You can get this code from this lectures' template .c file. See also this lectures' template .s file.
We'll work today on exploring the impact of the ISA by hand-crafting assembly code and comparing it to GCC's generated assembly.
To add assembly for a method we write extern
in front of the method header in the c code, as e.g.
extern unsigned cruton(int x, unsigned y);
and we add a .s file that contains the code
.globl cruton
cruton:
// header code
pushl %ebp
movl %esp, %ebp
// load the arguments
movl 8(%ebp), %eax /* eax = first parameter */
movl 12(%ebp), %ecx /* ecx = second parameter */
// main code goes here
// footer code
popl %ebp
ret
Some guidelines for GCC assembly files:
You may use //
comments, but only if they are a line by themselves
Block comments /*
and */
can be placed anywhere
;
and newline mean the same thing (no need to write ;
)
gcc -S
will generate labels starting with a period. But labels starting with a period will confuse GCC, so if you use that code change the labels to not have periods in their names.
You can ignore any non-label lines that gcc -S
adds if they start with a period, excepting .globl
which makes the label visible to C.
Traditionally, methods begin with the lines
pushl %ebp
movl %esp, %ebp
which saves the old stack base pointer (ebp) and stores a new one; end with the lines
popl %ebp
ret
which restores the saved value of ebp, then returns. You can omit the ebp lines if you aren't planning on using the base pointer. You do need the ret
line.
You can use %eax
, %ecx
, and %edx
directly. If you use other registers, you have to push/pop them so they don't change as a result of your function running.
Fast code =
Just for fun, Eternal Flame's first verse is about coding assembly:
I was taught assembler in my second year of school.
It's kinda like construction work — with a toothpick for a tool.
So when I made my senior year, I threw my code away,
And learned the way to program that I still prefer today.