main
is in the code we've been writing
long long result = 1; while ( num > 1 ) { result *= num; num--; } return result;Translating to x86, assuming
num
is in %rcx
:
movl $1, %rax # result cmp $1, %rcx # while num > 1 jle done # if less, jump to end loop_top: imul %rcx, %rax # result *= num sub $1, %rcx # num -= 1 cmp $1, %rcx # compare num to 1 jne loop_top # if not equal, return to loop top done: ret # done, result in rax
loop_top
, done
?
loop_top
is the address of the imul
instruction
jmp
: jump to label (unconditionally)
cmp
: compare values for conditional jumps
cmp X, Y
: sets flags based on Y - X
je
: jump if ZF = 1
jne
: jump if ZF = 0
jg
: jump if SF = 0, ZF = 0
jge
: jump if SF = 0 or ZF = 1
jc
, jo
]
sub
is the same as cmp
, cmp
just tosses the result
loop
, similar items: ignore
hlt
, nop
, lock
,
wait
nop
: this doesn't actually exist as an instruction!
xchg %eax,%eax
because it's short and has no effect (including not affecting flags)
# count number of bits that are set in an integer # eg: 0xA3 (10100011) has 4 bits set # assumption: %ebx is the value to count bits in # %ecx = 0 # while %ebx != 0 # if lsb(%ebx) == 1, add 1 to %ecx # shift %ebx right by one position (shr %reg, 1)
counting_bits.asm
, counting_bits.cpp
for an implementation
source: .space 4 ; allow 4 bytes for the info count: .space 4In OnlineGDB, would have
.globl source .globl count .bss .align 8 source: .space 4 count: .space 4
mov %eax, count
fact.c
in factorials demo code -
note last_number
global variable
fact.s
for declaring last_number:
.text .globl last_number .align 8 last_number: .space 8 # quadword
last_number = result;
movq %rax, last_number(%rip) # %rax: result # %rip: current "instruction pointer" (address of the current instruction) # last_number: offset from that place - effectively computing an # address based on the offset between instructions and last_number
main
%ebp
or %rbp
(depending on
32-bit or 64-bit model) is the base address of a function's frame
last_number(%rip)
computes an address -
it's where to store a result, not a register that holds the result
int x;
declares x
and defines its address, but does not define its value
int x; cout << x;
prints a "random" value!
init_array.c
in demo code
optimized_init_array.s
%rcx
movq %1, (%rcx)
(%rcx)
: %rcx
is the address of
the array, not a value
(%register)
: treat this as an address, not a value
movq
- can't determine how much to move
by simply checking the size of the register
destination[i] = i * destination[i - 1]
:
i
: in %rax
imulq -8(%rcx,%rax,8), %rdx
-8(%ebp,%esi,4)
:
address is %ebp + %esi * 4 - 8
(%rcx)
: equivalent to 0(%rcx,0,1)
%rax
and (%rax)
(without notes)
-8(%rcx,%rax,8)
: %rcx + %rax*8 - 8
(i - 1)
%movq %rdx, (%rcx,%rax,8)
: store result in array at
address %rcx + %rax*8
(that
is, destination[i]
)
rcx
is the address of the array -
where from?
main
: leaq 32(%rsp), %rcx
lea
: load effective address - not a mov!
factorials
in the stack frame
%rcx
initialize_factorials
returns, have
movl 144(%rsp), %eax
fully_optimized_init_array.s
in demo code directory
gcc -S -O4 init_array.c
-O4
: optimization level 4 (the max)
initialize_factorials
simply loads the values into
the array with an "unrolled" loop!
movl $1278945280, %eax
jmp
, conditional jumps
cmp
, SF (sign flag), ZF (zero flag), CF (carry flag)
.data
, .text
, .globl
, .align
are also pseudo-instructions
offset(base,index,scale)