x86_64 Assembler

Register Names

64-bit register 32-bit sub-register 16-bit sub-register 8-bit sub-register
%rax %eax %ax %al
%rbx %ebx %bx %bl
%rcx %ecx %cx %cl
%rdx %edx %dx %dl
%rsi %esi %si %sil
%rdi %edi %di %dil
%rbp %ebp %bp %bpl
%rsp %esp %sp %spl
%r8 %r8d %r8w %r8b
%r9 %r9d %r9w %r9b
%r10 %r10d %r10w %r10b
%r11 %r11d %r11w %r11b
%r12 %r12d %r12w %r12b
%r13 %r13d %r13w %r13b
%r14 %r14d %r14w %r14b
%r15 %r15d %r15w %r15b

architecture: byte order

references to memory

  • -16(%rsp)
  • 8(%rbp)
  • 127(%rip)

relative addressing

syntax: disp(base,index,scale) -> base + index*scale +disp
eg: -3(%rbp,%rdi,8)
;typically used to access %rbp[%rdi] where each array element is 8 bytes long and you’re 
;accessing at -3 bytes from it

addressing modes

;immediate:
mov $10, %eax
;register to register
mov %r8l, %al
;indirect
mov 1234(%rcx,%rax,8), %r8w
;it sometime is necessary to add a size postfix to instructions: movb, movw, movl, movq (b = byte, w = word, l = long, q = quadword)
;rip-relative:
movb 12(%rip), %al

a simple example

sum numbers 1 to 10 in register %eax

	xor %eax, %eax	# zero %eax – why not “mov $0, %eax” ?
	mov $10, %ecx 	# set the loop index
lab:
	add %ecx, %eax  # %eax += %ecx
	loop lab				# dec %ecx, jump to lab if not zero

common instruction

MOV

movl $1, 0x604892    		#direct (address is constant value)
movl $1, (%rax)			 		#indirect (address is in register %rax)
movl $1, -24(%rbp)	 		#address = base(%rbp) + displacement(-24)
movl $1, 8(%rsp,%rdi,4) #address = %rsp + 8 + %rdi*4

MOV V LEA

mov d(b,i,s), %rax is like rax = *(b+s*i+d)
lea d(b,i,s), %rax is like rax = (b+s*i+d)

CMOV

**CMOVcc instructions can replace two instructions in situations like **

"if ecx == 5 then eax = ebx”

    cmp $5, %ecx
    jnz continue
    mov %ebx, %eax
continue:
;it equals to 
	cmp $5, %ecx
    cmovz %ebx, %eax

push and pop

push <src> is like dec %rsp; mov <src>,(%rsp) 
pop <dst> is like mov (%rsp),<dst>; inc %rsp

testmax3.c

#include <stdio.h>
#include <inttypes.h>

int64_t maxofthree(int64_t, int64_t, int64_t);

int main() {
    printf("%ld\n", maxofthree(1, -4, -7));
    printf("%ld\n", maxofthree(2, -6, 1));
    printf("%ld\n", maxofthree(2, 3, 1));
    printf("%ld\n", maxofthree(-2, 4, 3));
    printf("%ld\n", maxofthree(2, -6, 5));
    printf("%ld\n", maxofthree(2, 4, 6));
    return 0;
}

max3.s

        .globl  _maxofthree
        
        .text
_maxofthree:
        mov     %rdi, %rax              # result (rax) initially holds x
        cmp     %rsi, %rax              # is x less than y?
        cmovl   %rsi, %rax              # if so, set result to y
        cmp     %rdx, %rax              # is max(x,y) less than z?
        cmovl   %rdx, %rax              # if so, set result to z
        ret                

complie and link

clang -o result testmax3.c max3.s 

then execute the result file

calling conventions

Register Convention
%rip Instruction pointer
%rsp Stack pointer
%rax Return value
%rdi 1st argument
%rsi 2nd argument
%rdx 3rd argument
%rcx 4th argument
%r8 5th argument
%r9 6th argument
%r10,%r11 Callee-owned
%rbx,%rbp,%r12-%15 Caller-owned