(* * machine-specific assembler routines. *) open Common;; type asm_glue = { asm_activate_glue : Llvm.llvalue; asm_yield_glue : Llvm.llvalue; asm_upcall_glues : Llvm.llvalue array; } ;; let n_upcall_glues = 7 ;; (* x86-specific asm. *) let x86_glue (llctx:Llvm.llcontext) (llmod:Llvm.llmodule) (abi:Llabi.abi) (sess:Session.sess) : asm_glue = let (prefix,align) = match sess.Session.sess_targ with Linux_x86_elf | Win32_x86_pe -> ("",4) | MacOS_x86_macho -> ("_", 16) in let save_callee_saves = ["pushl %ebp"; "pushl %edi"; "pushl %esi"; "pushl %ebx";] in let restore_callee_saves = ["popl %ebx"; "popl %esi"; "popl %edi"; "popl %ebp";] in let load_esp_from_rust_sp = ["movl 12(%edx), %esp"] in let load_esp_from_runtime_sp = ["movl 8(%edx), %esp"] in let store_esp_to_rust_sp = ["movl %esp, 12(%edx)"] in let store_esp_to_runtime_sp = ["movl %esp, 8(%edx)"] in let list_init i f = (Array.to_list (Array.init i f)) in let list_init_concat i f = List.concat (list_init i f) in let glue = [ ("rust_activate_glue", String.concat "\n\t" (["movl 4(%esp), %edx # edx = rust_task"] @ save_callee_saves @ store_esp_to_runtime_sp @ load_esp_from_rust_sp (* * This 'add' instruction is a bit surprising. * See lengthy comment in boot/be/x86.ml activate_glue. *) @ ["addl $20, 12(%edx)"] @ restore_callee_saves @ ["ret"])); ("rust_yield_glue", String.concat "\n\t" (["movl 0(%esp), %edx # edx = rust_task"] @ load_esp_from_rust_sp @ save_callee_saves @ store_esp_to_rust_sp @ load_esp_from_runtime_sp @ restore_callee_saves @ ["ret"])) ] @ list_init n_upcall_glues begin fun i -> (* * 0, 4, 8, 12 are callee-saves * 16 is retpc * 20 is taskptr * 24 is callee * 28 .. (7+i) * 4 are args *) ((Printf.sprintf "rust_upcall_%d" i), String.concat "\n\t" (save_callee_saves @ ["movl %esp, %ebp # ebp = rust_sp"; "movl 20(%esp), %edx # edx = rust_task"] @ store_esp_to_rust_sp @ load_esp_from_runtime_sp @ [Printf.sprintf "subl $%d, %%esp # esp -= args" ((i+1)*4); "andl $~0xf, %esp # align esp down"; "movl %edx, (%esp) # arg[0] = rust_task "] @ (list_init_concat i begin fun j -> [ Printf.sprintf "movl %d(%%ebp),%%edx" ((j+7)*4); Printf.sprintf "movl %%edx,%d(%%esp)" ((j+1)*4) ] end) @ ["movl 24(%ebp), %edx # edx = callee"; "call *%edx # call *%edx"; "movl 20(%ebp), %edx # edx = rust_task"] @ load_esp_from_rust_sp @ restore_callee_saves @ ["ret"])) end in let _ = Llvm.set_module_inline_asm llmod begin String.concat "\n" begin List.map begin fun (sym,asm) -> Printf.sprintf "\t.globl %s%s\n\t.balign %d\n%s%s:\n\t%s" prefix sym align prefix sym asm end glue end end in let decl_cdecl_fn name out_ty arg_tys = let ty = Llvm.function_type out_ty arg_tys in let fn = Llvm.declare_function name ty llmod in Llvm.set_function_call_conv Llvm.CallConv.c fn; fn in let decl_glue s = let task_ptr_ty = Llvm.pointer_type abi.Llabi.task_ty in let void_ty = Llvm.void_type llctx in decl_cdecl_fn s void_ty [| task_ptr_ty |] in let decl_upcall n = let task_ptr_ty = Llvm.pointer_type abi.Llabi.task_ty in let word_ty = abi.Llabi.word_ty in let callee_ty = word_ty in let args_ty = Array.append [| task_ptr_ty; callee_ty |] (Array.init n (fun _ -> word_ty)) in let name = Printf.sprintf "rust_upcall_%d" n in decl_cdecl_fn name word_ty args_ty in { asm_activate_glue = decl_glue "rust_activate_glue"; asm_yield_glue = decl_glue "rust_yield_glue"; asm_upcall_glues = Array.init n_upcall_glues decl_upcall; } ;; (* x64-specific asm. *) (* arm-specific asm. *) (* ... *) let get_glue (llctx:Llvm.llcontext) (llmod:Llvm.llmodule) (abi:Llabi.abi) (sess:Session.sess) : asm_glue = match sess.Session.sess_targ with Linux_x86_elf | Win32_x86_pe | MacOS_x86_macho -> x86_glue llctx llmod abi sess ;; (* * Local Variables: * fill-column: 78; * indent-tabs-mode: nil * buffer-file-coding-system: utf-8-unix * compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; * End: *)