(* Bibliothèque pour produire du code X86-64

   2008 Jean-Christophe Filliâtre (CNRS)
   2013 Kim Nguyen (Université Paris Sud)
*)

open Format

type size = [`B | `W | `L | `Q]

type 'size register =  string

let rax = "%rax"
let rbx = "%rbx"
let rcx = "%rcx"
let rdx = "%rdx"
let rsi = "%rsi"
let rdi = "%rdi"
let rbp = "%rbp"
let rsp = "%rsp"
let r8  = "%r8"
let r9  = "%r9"
let r10 = "%r10"
let r11 = "%r11"
let r12 = "%r12"
let r13 = "%r13"
let r14 = "%r14"
let r15 = "%r15"

let eax = "%eax"
let ebx = "%ebx"
let ecx = "%ecx"
let edx = "%edx"
let esi = "%esi"
let edi = "%edi"
let ebp = "%ebp"
let esp = "%esp"
let r8d  = "%r8d"
let r9d  = "%r9d"
let r10d = "%r10d"
let r11d = "%r11d"
let r12d = "%r12d"
let r13d = "%r13d"
let r14d = "%r14d"
let r15d = "%r15d"

let ax = "%ax"
let bx = "%bx"
let cx = "%cx"
let dx = "%dx"
let si = "%si"
let di = "%di"
let bp = "%bp"
let sp = "%sp"
let r8w  = "%r8w"
let r9w  = "%r9w"
let r10w = "%r10w"
let r11w = "%r11w"
let r12w = "%r12w"
let r13w = "%r13w"
let r14w = "%r14w"
let r15w = "%r15w"

let al = "%al"
let bl = "%bl"
let cl = "%cl"
let dl = "%dl"
let ah = "%ah"
let bh = "%bh"
let ch = "%ch"
let dh = "%dh"
let sil = "%sil"
let dil = "%dil"
let bpl = "%bpl"
let spl = "%spl"
let r8b  = "%r8b"
let r9b  = "%r9b"
let r10b = "%r10b"
let r11b = "%r11b"
let r12b = "%r12b"
let r13b = "%r13b"
let r14b = "%r14b"
let r15b = "%r15b"

let register8 = function
  | "%rax" -> al
  | "%rbx" -> bl
  | "%rcx" -> cl
  | "%rdx" -> dl
  | "%rsi" -> sil
  | "%rdi" -> dil
  | "%rbp" -> bpl
  | "%rsp" -> spl
  | "%r8"  -> r8b
  | "%r9"  -> r9b
  | "%r10" -> r10b
  | "%r11" -> r11b
  | "%r12" -> r12b
  | "%r13" -> r13b
  | "%r14" -> r14b
  | "%r15" -> r15b
  | _ -> assert false

type label = string

type 'size operand = formatter -> unit -> unit

let mangle_none fmt (l: label) = fprintf fmt "%s" l
let _mangle_leading_underscore fmt (l: label) = fprintf fmt "_%s" l
let mangle = mangle_none

let reg r = fun fmt () -> fprintf fmt "%s" r
let (!%) = reg
let imm i = fun fmt () -> fprintf fmt "$%i" i
let imm32 i = fun fmt () -> fprintf fmt "$%ld" i
let imm64 i = fun fmt () -> fprintf fmt "$%Ld" i
let ind ?(ofs=0) ?index ?(scale=1) r = fun fmt () -> match index with
  | None -> fprintf fmt "%d(%s)" ofs r
  | Some r1 -> fprintf fmt "%d(%s,%s,%d)" ofs r r1 scale
let abslab (l: label) = fun fmt () -> fprintf fmt "%a" mangle l
let _rellab (l: label) = fun fmt () -> fprintf fmt "%a(%%rip)" mangle l
let lab = abslab
let ilab (l: label) = fun fmt () -> fprintf fmt "$%a" mangle l

(* le code est une corde *)
type 'a asm =
  | Nop
  | S of string
  | Cat of 'a asm * 'a asm

let nop = Nop
let inline s = S s
let (++) x y = Cat (x, y)

type text = [`text ] asm
type data = [`data ] asm

let buf = Buffer.create 17
let fmt = formatter_of_buffer buf
let ins x =
  Buffer.add_char buf '\t';
  kfprintf (fun fmt ->
    fprintf fmt "\n";
    pp_print_flush fmt ();
    let s = Buffer.contents buf in
    Buffer.clear buf;
    S s
  ) fmt x

let pr_list fmt pr = function
  | []      -> ()
  | [i]     -> pr fmt i
  | i :: ll -> pr fmt i; List.iter (fun i -> fprintf fmt ", %a" pr i) ll

let pr_ilist fmt l =
  pr_list fmt (fun fmt i -> fprintf fmt "%i" i) l

let pr_alist fmt l =
  pr_list fmt (fun fmt (a : label) -> fprintf fmt "%s" a) l

let movb a b = ins "movb %a, %a" a () b ()
let movw a b = ins "movw %a, %a" a () b ()
let movl a b = ins "movl %a, %a" a () b ()
let movq a b = ins "movq %a, %a" a () b ()

let movabsq a b = ins "movabsq %a, %s" a () b

let movsbw a b = ins "movsbw %a, %s" a () b
let movsbl a b = ins "movsbl %a, %s" a () b
let movsbq a b = ins "movsbq %a, %s" a () b
let movswl a b = ins "movswl %a, %s" a () b
let movswq a b = ins "movswq %a, %s" a () b
let movslq a b = ins "movslq %a, %s" a () b

let movzbw a b = ins "movzbw %a, %s" a () b
let movzbl a b = ins "movzbl %a, %s" a () b
let movzbq a b = ins "movzbq %a, %s" a () b
let movzwl a b = ins "movzwl %a, %s" a () b
let movzwq a b = ins "movzwq %a, %s" a () b

let cmove  a b = ins "cmove %a, %a" a () b ()
let cmovz  a b = ins "cmovz %a, %a" a () b ()
let cmovne a b = ins "cmovne %a, %a" a () b ()
let cmovnz a b = ins "cmovnz %a, %a" a () b ()
let cmovs  a b = ins "cmovs %a, %a" a () b ()
let cmovns a b = ins "cmovns %a, %a" a () b ()
let cmovg  a b = ins "cmovg %a, %a" a () b ()
let cmovge a b = ins "cmovge %a, %a" a () b ()
let cmovl  a b = ins "cmovl %a, %a" a () b ()
let cmovle a b = ins "cmovle %a, %a" a () b ()
let cmova  a b = ins "cmova %a, %a" a () b ()
let cmovae a b = ins "cmovae %a, %a" a () b ()
let cmovb  a b = ins "cmovb %a, %a" a () b ()
let cmovbe a b = ins "cmovbe %a, %a" a () b ()

let leab op r = ins "leab %a, %s" op () r
let leaw op r = ins "leaw %a, %s" op () r
let leal op r = ins "leal %a, %s" op () r
let leaq op r = ins "leaq %a, %s" op () r

let incb a = ins "incb %a" a ()
let incw a = ins "incw %a" a ()
let incl a = ins "incl %a" a ()
let incq a = ins "incq %a" a ()

let decb a = ins "decb %a" a ()
let decw a = ins "decw %a" a ()
let decl a = ins "decl %a" a ()
let decq a = ins "decq %a" a ()

let negb a = ins "negb %a" a ()
let negw a = ins "negw %a" a ()
let negl a = ins "negl %a" a ()
let negq a = ins "negq %a" a ()

let addb a b = ins "addb %a, %a" a () b ()
let addw a b = ins "addw %a, %a" a () b ()
let addl a b = ins "addl %a, %a" a () b ()
let addq a b = ins "addq %a, %a" a () b ()

let subb a b = ins "subb %a, %a" a () b ()
let subw a b = ins "subw %a, %a" a () b ()
let subl a b = ins "subl %a, %a" a () b ()
let subq a b = ins "subq %a, %a" a () b ()

let imulw a b = ins "imulw %a, %a" a () b ()
let imull a b = ins "imull %a, %a" a () b ()
let imulq a b = ins "imulq %a, %a" a () b ()

let idivq a = ins "idivq %a" a ()
let cqto = S "\tcqto\n"

let notb a = ins "notb %a" a ()
let notw a = ins "notw %a" a ()
let notl a = ins "notl %a" a ()
let notq a = ins "notq %a" a ()

let andb a b = ins "andb %a, %a" a () b ()
let andw a b = ins "andw %a, %a" a () b ()
let andl a b = ins "andl %a, %a" a () b ()
let andq a b = ins "andq %a, %a" a () b ()

let orb  a b = ins "orb %a, %a" a () b ()
let orw  a b = ins "orw %a, %a" a () b ()
let orl  a b = ins "orl %a, %a" a () b ()
let orq  a b = ins "orq %a, %a" a () b ()

let xorb a b = ins "xorb %a, %a" a () b ()
let xorw a b = ins "xorw %a, %a" a () b ()
let xorl a b = ins "xorl %a, %a" a () b ()
let xorq a b = ins "xorq %a, %a" a () b ()

let shlb a b = ins "shlb %a, %a" a () b ()
let shlw a b = ins "shlw %a, %a" a () b ()
let shll a b = ins "shll %a, %a" a () b ()
let shlq a b = ins "shlq %a, %a" a () b ()

let shrb a b = ins "shrb %a, %a" a () b ()
let shrw a b = ins "shrw %a, %a" a () b ()
let shrl a b = ins "shrl %a, %a" a () b ()
let shrq a b = ins "shrq %a, %a" a () b ()

let sarb a b = ins "sarb %a, %a" a () b ()
let sarw a b = ins "sarw %a, %a" a () b ()
let sarl a b = ins "sarl %a, %a" a () b ()
let sarq a b = ins "sarq %a, %a" a () b ()

let jmp (z: label) = ins "jmp %a" mangle z
let jmp_star o = ins "jmp *%a" o ()

let call (z: label) = ins "call %a" mangle z
let call_star z = ins "call *%a" z ()
let leave = ins "leave"
let ret = ins "ret"

let je (z: label) = ins "je %a" mangle z
let jz (z: label) = ins "jz %a" mangle z
let jne(z: label) = ins "jne %a" mangle z
let jnz(z: label) = ins "jnz %a" mangle z
let js (z: label) = ins "js %a" mangle z
let jns(z: label) = ins "jns %a" mangle z
let jg (z: label) = ins "jg %a" mangle z
let jge(z: label) = ins "jge %a" mangle z
let jl (z: label) = ins "jl %a" mangle z
let jle(z: label) = ins "jle %a" mangle z
let ja (z: label) = ins "ja %a" mangle z
let jae(z: label) = ins "jae %a" mangle z
let jb (z: label) = ins "jb %a" mangle z
let jbe(z: label) = ins "jbe %a" mangle z

let cmpb a b = ins "cmpb %a, %a" a () b ()
let cmpw a b = ins "cmpw %a, %a" a () b ()
let cmpl a b = ins "cmpl %a, %a" a () b ()
let cmpq a b = ins "cmpq %a, %a" a () b ()

let testb a b = ins "testb %a, %a" a () b ()
let testw a b = ins "testw %a, %a" a () b ()
let testl a b = ins "testl %a, %a" a () b ()
let testq a b = ins "testq %a, %a" a () b ()

let sete  a = ins "sete %a" a ()
let setne a = ins "setne %a" a ()
let setz  a = ins "setz %a" a ()
let setnz a = ins "setnz %a" a ()
let sets  a = ins "sets %a" a ()
let setns a = ins "setns %a" a ()
let setg  a = ins "setg %a" a ()
let setge a = ins "setge %a" a ()
let setl  a = ins "setl %a" a ()
let setle a = ins "setle %a" a ()
let seta  a = ins "seta %a" a ()
let setae a = ins "setae %a" a ()
let setb  a = ins "setb %a" a ()
let setbe a = ins "setbe %a" a ()

let label (s : label) = S (asprintf "%a:\n" mangle s)
let globl (s: label) = S (asprintf "\t.globl\t%a\n" mangle s)

let comment s = S ("#" ^ s ^ "\n")

let aligned_call_wrapper ~f ~newf =
  S (sprintf "%s:\n\
              \tpushq   %%rbp\n\
              \tmovq    %%rsp, %%rbp\n\
              \tandq    $-16, %%rsp  # 16-byte stack alignment\n\
              \tcall    %s\n\
              \tmovq    %%rbp, %%rsp\n\
              \tpopq    %%rbp\n\
              \tret\n" newf f)

let _align n = ins ".align %i" n

let dbyte l = ins ".byte %a" pr_ilist l
let dint  l = ins ".int %a" pr_ilist l
let dword l = ins ".word %a" pr_ilist l
let dquad l = ins ".quad %a" pr_ilist l
let string s = ins ".string %S" s

let address l = ins ".quad %a" pr_alist l
let space n = ins ".space %d" n

let pushq a = ins "pushq %a" a ()
let popq r = ins "popq %s" r

type program = {
  text : [ `text ] asm;
  data : [ `data ] asm;
}

let rec pr_asm fmt = function
  | Nop          -> ()
  | S s          -> fprintf fmt "%s" s
  | Cat (a1, a2) -> pr_asm fmt a1; pr_asm fmt a2

let print_program fmt p =
  fprintf fmt "\t.text\n";
  pr_asm fmt p.text;
  fprintf fmt "\t.data\n";
  pr_asm fmt p.data;
  pp_print_flush fmt ()

let print_in_file ~file p =
  let c = open_out file in
  let fmt = formatter_of_out_channel c in
  print_program fmt p;
  close_out c

This document was generated using caml2html