1184 lines
34 KiB
OCaml
1184 lines
34 KiB
OCaml
open Asm;;
|
|
open Common;;
|
|
|
|
(* Mach-O writer. *)
|
|
|
|
let log (sess:Session.sess) =
|
|
Session.log "obj (mach-o)"
|
|
sess.Session.sess_log_obj
|
|
sess.Session.sess_log_out
|
|
;;
|
|
|
|
let iflog (sess:Session.sess) (thunk:(unit -> unit)) : unit =
|
|
if sess.Session.sess_log_obj
|
|
then thunk ()
|
|
else ()
|
|
;;
|
|
|
|
let (cpu_arch_abi64:int64) = 0x01000000L
|
|
;;
|
|
|
|
let (mh_magic:int64) = 0xfeedfaceL
|
|
;;
|
|
|
|
let cpu_subtype_intel (f:int64) (m:int64) : int64 =
|
|
Int64.add f (Int64.shift_left m 4)
|
|
;;
|
|
|
|
type cpu_type =
|
|
(* Maybe support more later. *)
|
|
CPU_TYPE_X86
|
|
| CPU_TYPE_X86_64
|
|
| CPU_TYPE_ARM
|
|
| CPU_TYPE_POWERPC
|
|
;;
|
|
|
|
type cpu_subtype =
|
|
(* Maybe support more later. *)
|
|
CPU_SUBTYPE_X86_ALL
|
|
| CPU_SUBTYPE_X86_64_ALL
|
|
| CPU_SUBTYPE_ARM_ALL
|
|
| CPU_SUBTYPE_POWERPC_ALL
|
|
;;
|
|
|
|
type file_type =
|
|
MH_OBJECT
|
|
| MH_EXECUTE
|
|
| MH_FVMLIB
|
|
| MH_CORE
|
|
| MH_PRELOAD
|
|
| MH_DYLIB
|
|
| MH_DYLINKER
|
|
| MH_BUNDLE
|
|
| MH_DYLIB_STUB
|
|
| MH_DSYM
|
|
;;
|
|
|
|
let file_type_code (ft:file_type) : int64 =
|
|
match ft with
|
|
MH_OBJECT ->0x1L (* object *)
|
|
| MH_EXECUTE -> 0x2L (* executable *)
|
|
| MH_FVMLIB -> 0x3L (* fixed-VM shared lib *)
|
|
| MH_CORE -> 0x4L (* core *)
|
|
| MH_PRELOAD -> 0x5L (* preloaded executable *)
|
|
| MH_DYLIB -> 0x6L (* dynamic lib *)
|
|
| MH_DYLINKER -> 0x7L (* dynamic linker *)
|
|
| MH_BUNDLE -> 0x8L (* bundle *)
|
|
| MH_DYLIB_STUB -> 0x9L (* shared lib stub *)
|
|
| MH_DSYM -> 0xaL (* debuginfo only *)
|
|
;;
|
|
|
|
type file_flag =
|
|
MH_NOUNDEFS
|
|
| MH_INCRLINK
|
|
| MH_DYLDLINK
|
|
| MH_BINDATLOAD
|
|
| MH_PREBOUND
|
|
| MH_SPLIT_SEGS
|
|
| MH_LAZY_INIT
|
|
| MH_TWOLEVEL
|
|
| MH_FORCE_FLAT
|
|
| MH_NOMULTIDEFS
|
|
| MH_NOFIXPREBINDING
|
|
| MH_PREBINDABLE
|
|
| MH_ALLMODSBOUND
|
|
| MH_SUBSECTIONS_VIA_SYMBOLS
|
|
| MH_CANONICAL
|
|
| MH_WEAK_DEFINES
|
|
| MH_BINDS_TO_WEAK
|
|
| MH_ALLOW_STACK_EXECUTION
|
|
| MH_ROOT_SAFE
|
|
| MH_SETUID_SAFE
|
|
| MH_NO_REEXPORTED_DYLIBS
|
|
| MH_PIE
|
|
;;
|
|
|
|
let file_flag_code (ff:file_flag) : int64 =
|
|
match ff with
|
|
MH_NOUNDEFS -> 0x1L
|
|
| MH_INCRLINK -> 0x2L
|
|
| MH_DYLDLINK -> 0x4L
|
|
| MH_BINDATLOAD -> 0x8L
|
|
| MH_PREBOUND -> 0x10L
|
|
| MH_SPLIT_SEGS -> 0x20L
|
|
| MH_LAZY_INIT -> 0x40L
|
|
| MH_TWOLEVEL -> 0x80L
|
|
| MH_FORCE_FLAT -> 0x100L
|
|
| MH_NOMULTIDEFS -> 0x200L
|
|
| MH_NOFIXPREBINDING -> 0x400L
|
|
| MH_PREBINDABLE -> 0x800L
|
|
| MH_ALLMODSBOUND -> 0x1000L
|
|
| MH_SUBSECTIONS_VIA_SYMBOLS -> 0x2000L
|
|
| MH_CANONICAL -> 0x4000L
|
|
| MH_WEAK_DEFINES -> 0x8000L
|
|
| MH_BINDS_TO_WEAK -> 0x10000L
|
|
| MH_ALLOW_STACK_EXECUTION -> 0x20000L
|
|
| MH_ROOT_SAFE -> 0x40000L
|
|
| MH_SETUID_SAFE -> 0x80000L
|
|
| MH_NO_REEXPORTED_DYLIBS -> 0x100000L
|
|
| MH_PIE -> 0x200000L
|
|
;;
|
|
|
|
|
|
type vm_prot =
|
|
VM_PROT_NONE
|
|
| VM_PROT_READ
|
|
| VM_PROT_WRITE
|
|
| VM_PROT_EXECUTE
|
|
;;
|
|
|
|
|
|
type load_command =
|
|
LC_SEGMENT
|
|
| LC_SYMTAB
|
|
| LC_SYMSEG
|
|
| LC_THREAD
|
|
| LC_UNIXTHREAD
|
|
| LC_LOADFVMLIB
|
|
| LC_IDFVMLIB
|
|
| LC_IDENT
|
|
| LC_FVMFILE
|
|
| LC_PREPAGE
|
|
| LC_DYSYMTAB
|
|
| LC_LOAD_DYLIB
|
|
| LC_ID_DYLIB
|
|
| LC_LOAD_DYLINKER
|
|
| LC_ID_DYLINKER
|
|
| LC_PREBOUND_DYLIB
|
|
| LC_ROUTINES
|
|
| LC_SUB_FRAMEWORK
|
|
| LC_SUB_UMBRELLA
|
|
| LC_SUB_CLIENT
|
|
| LC_SUB_LIBRARY
|
|
| LC_TWOLEVEL_HINTS
|
|
| LC_PREBIND_CKSUM
|
|
| LC_LOAD_WEAK_DYLIB
|
|
| LC_SEGMENT_64
|
|
| LC_ROUTINES_64
|
|
| LC_UUID
|
|
| LC_RPATH
|
|
| LC_CODE_SIGNATURE
|
|
| LC_SEGMENT_SPLIT_INFO
|
|
| LC_REEXPORT_DYLIB
|
|
| LC_LAZY_LOAD_DYLIB
|
|
| LC_ENCRYPTION_INFO
|
|
;;
|
|
|
|
|
|
let cpu_type_code (cpu:cpu_type) : int64 =
|
|
match cpu with
|
|
CPU_TYPE_X86 -> 7L
|
|
| CPU_TYPE_X86_64 -> Int64.logor 7L cpu_arch_abi64
|
|
| CPU_TYPE_ARM -> 12L
|
|
| CPU_TYPE_POWERPC -> 18L
|
|
;;
|
|
|
|
let cpu_subtype_code (cpu:cpu_subtype) : int64 =
|
|
match cpu with
|
|
CPU_SUBTYPE_X86_ALL -> 3L
|
|
| CPU_SUBTYPE_X86_64_ALL -> 3L
|
|
| CPU_SUBTYPE_ARM_ALL -> 0L
|
|
| CPU_SUBTYPE_POWERPC_ALL -> 0L
|
|
;;
|
|
|
|
|
|
let vm_prot_code (vmp:vm_prot) : int64 =
|
|
match vmp with
|
|
VM_PROT_NONE -> 0L
|
|
| VM_PROT_READ -> 1L
|
|
| VM_PROT_WRITE -> 2L
|
|
| VM_PROT_EXECUTE -> 4L
|
|
;;
|
|
|
|
|
|
let lc_req_dyld = 0x80000000L;;
|
|
|
|
let load_command_code (lc:load_command) =
|
|
match lc with
|
|
| LC_SEGMENT -> 0x1L
|
|
| LC_SYMTAB -> 0x2L
|
|
| LC_SYMSEG -> 0x3L
|
|
| LC_THREAD -> 0x4L
|
|
| LC_UNIXTHREAD -> 0x5L
|
|
| LC_LOADFVMLIB -> 0x6L
|
|
| LC_IDFVMLIB -> 0x7L
|
|
| LC_IDENT -> 0x8L
|
|
| LC_FVMFILE -> 0x9L
|
|
| LC_PREPAGE -> 0xaL
|
|
| LC_DYSYMTAB -> 0xbL
|
|
| LC_LOAD_DYLIB -> 0xcL
|
|
| LC_ID_DYLIB -> 0xdL
|
|
| LC_LOAD_DYLINKER -> 0xeL
|
|
| LC_ID_DYLINKER -> 0xfL
|
|
| LC_PREBOUND_DYLIB -> 0x10L
|
|
| LC_ROUTINES -> 0x11L
|
|
| LC_SUB_FRAMEWORK -> 0x12L
|
|
| LC_SUB_UMBRELLA -> 0x13L
|
|
| LC_SUB_CLIENT -> 0x14L
|
|
| LC_SUB_LIBRARY -> 0x15L
|
|
| LC_TWOLEVEL_HINTS -> 0x16L
|
|
| LC_PREBIND_CKSUM -> 0x17L
|
|
| LC_LOAD_WEAK_DYLIB -> Int64.logor lc_req_dyld 0x18L
|
|
| LC_SEGMENT_64 -> 0x19L
|
|
| LC_ROUTINES_64 -> 0x1aL
|
|
| LC_UUID -> 0x1bL
|
|
| LC_RPATH -> Int64.logor lc_req_dyld 0x1cL
|
|
| LC_CODE_SIGNATURE -> 0x1dL
|
|
| LC_SEGMENT_SPLIT_INFO -> 0x1eL
|
|
| LC_REEXPORT_DYLIB -> Int64.logor lc_req_dyld 0x1fL
|
|
| LC_LAZY_LOAD_DYLIB -> 0x20L
|
|
| LC_ENCRYPTION_INFO -> 0x21L
|
|
;;
|
|
|
|
|
|
let fixed_sz_string (sz:int) (str:string) : frag =
|
|
if String.length str > sz
|
|
then STRING (String.sub str 0 sz)
|
|
else SEQ [| STRING str; PAD (sz - (String.length str)) |]
|
|
;;
|
|
|
|
type sect_type =
|
|
S_REGULAR
|
|
| S_ZEROFILL
|
|
| S_CSTRING_LITERALS
|
|
| S_4BYTE_LITERALS
|
|
| S_8BYTE_LITERALS
|
|
| S_LITERAL_POINTERS
|
|
| S_NON_LAZY_SYMBOL_POINTERS
|
|
| S_LAZY_SYMBOL_POINTERS
|
|
| S_SYMBOL_STUBS
|
|
| S_MOD_INIT_FUNC_POINTERS
|
|
| S_MOD_TERM_FUNC_POINTERS
|
|
| S_COALESCED
|
|
| S_GB_ZEROFILL
|
|
| S_INTERPOSING
|
|
| S_16BYTE_LITERALS
|
|
| S_DTRACE_DOF
|
|
| S_LAZY_DYLIB_SYMBOL_POINTERS
|
|
;;
|
|
|
|
let sect_type_code (s:sect_type) : int64 =
|
|
match s with
|
|
S_REGULAR -> 0x0L
|
|
| S_ZEROFILL -> 0x1L
|
|
| S_CSTRING_LITERALS -> 0x2L
|
|
| S_4BYTE_LITERALS -> 0x3L
|
|
| S_8BYTE_LITERALS -> 0x4L
|
|
| S_LITERAL_POINTERS -> 0x5L
|
|
| S_NON_LAZY_SYMBOL_POINTERS -> 0x6L
|
|
| S_LAZY_SYMBOL_POINTERS -> 0x7L
|
|
| S_SYMBOL_STUBS -> 0x8L
|
|
| S_MOD_INIT_FUNC_POINTERS -> 0x9L
|
|
| S_MOD_TERM_FUNC_POINTERS -> 0xaL
|
|
| S_COALESCED -> 0xbL
|
|
| S_GB_ZEROFILL -> 0xcL
|
|
| S_INTERPOSING -> 0xdL
|
|
| S_16BYTE_LITERALS -> 0xeL
|
|
| S_DTRACE_DOF -> 0xfL
|
|
| S_LAZY_DYLIB_SYMBOL_POINTERS -> 0x10L
|
|
;;
|
|
|
|
type sect_attr =
|
|
S_ATTR_PURE_INSTRUCTIONS
|
|
| S_ATTR_NO_TOC
|
|
| S_ATTR_STRIP_STATIC_SYMS
|
|
| S_ATTR_NO_DEAD_STRIP
|
|
| S_ATTR_LIVE_SUPPORT
|
|
| S_ATTR_SELF_MODIFYING_CODE
|
|
| S_ATTR_DEBUG
|
|
| S_ATTR_SOME_INSTRUCTIONS
|
|
| S_ATTR_EXT_RELOC
|
|
| S_ATTR_LOC_RELOC
|
|
;;
|
|
|
|
let sect_attr_code (s:sect_attr) : int64 =
|
|
match s with
|
|
S_ATTR_PURE_INSTRUCTIONS -> 0x80000000L
|
|
| S_ATTR_NO_TOC -> 0x40000000L
|
|
| S_ATTR_STRIP_STATIC_SYMS -> 0x20000000L
|
|
| S_ATTR_NO_DEAD_STRIP -> 0x10000000L
|
|
| S_ATTR_LIVE_SUPPORT -> 0x08000000L
|
|
| S_ATTR_SELF_MODIFYING_CODE -> 0x04000000L
|
|
| S_ATTR_DEBUG -> 0x02000000L
|
|
| S_ATTR_SOME_INSTRUCTIONS -> 0x00000400L
|
|
| S_ATTR_EXT_RELOC -> 0x00000200L
|
|
| S_ATTR_LOC_RELOC -> 0x00000100L
|
|
;;
|
|
|
|
type n_type =
|
|
| N_EXT
|
|
| N_UNDF
|
|
| N_ABS
|
|
| N_SECT
|
|
| N_PBUD
|
|
| N_INDIR
|
|
;;
|
|
|
|
let n_type_code (n:n_type) : int64 =
|
|
match n with
|
|
N_EXT -> 0x1L
|
|
| N_UNDF -> 0x0L
|
|
| N_ABS -> 0x2L
|
|
| N_SECT -> 0xeL
|
|
| N_PBUD -> 0xcL
|
|
| N_INDIR -> 0xaL
|
|
;;
|
|
|
|
|
|
type n_desc_reference_type =
|
|
REFERENCE_FLAG_UNDEFINED_NON_LAZY
|
|
| REFERENCE_FLAG_UNDEFINED_LAZY
|
|
| REFERENCE_FLAG_DEFINED
|
|
| REFERENCE_FLAG_PRIVATE_DEFINED
|
|
| REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY
|
|
| REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY
|
|
;;
|
|
|
|
let n_desc_reference_type_code (n:n_desc_reference_type) : int64 =
|
|
match n with
|
|
REFERENCE_FLAG_UNDEFINED_NON_LAZY -> 0x0L
|
|
| REFERENCE_FLAG_UNDEFINED_LAZY -> 0x1L
|
|
| REFERENCE_FLAG_DEFINED -> 0x2L
|
|
| REFERENCE_FLAG_PRIVATE_DEFINED -> 0x3L
|
|
| REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY -> 0x4L
|
|
| REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY -> 0x5L
|
|
;;
|
|
|
|
type n_desc_flags =
|
|
REFERENCED_DYNAMICALLY
|
|
| N_DESC_DISCARDED
|
|
| N_NO_DEAD_STRIP
|
|
| N_WEAK_REF
|
|
| N_WEAK_DEF
|
|
;;
|
|
|
|
let n_desc_flags_code (n:n_desc_flags) : int64 =
|
|
match n with
|
|
REFERENCED_DYNAMICALLY -> 0x10L
|
|
| N_DESC_DISCARDED -> 0x20L
|
|
| N_NO_DEAD_STRIP -> 0x20L (* Yes, they reuse 0x20. *)
|
|
| N_WEAK_REF -> 0x40L
|
|
| N_WEAK_DEF -> 0x80L
|
|
;;
|
|
|
|
type n_desc_dylib_ordinal = int;;
|
|
|
|
type n_desc = (n_desc_dylib_ordinal *
|
|
(n_desc_flags list) *
|
|
n_desc_reference_type)
|
|
;;
|
|
|
|
let n_desc_code (n:n_desc) : int64 =
|
|
let (dylib_ordinal, flags, ty) = n in
|
|
Int64.logor
|
|
(Int64.of_int (dylib_ordinal lsl 8))
|
|
(Int64.logor
|
|
(fold_flags n_desc_flags_code flags)
|
|
(n_desc_reference_type_code ty))
|
|
;;
|
|
|
|
|
|
let macho_section_command
|
|
(seg_name:string)
|
|
(sect:(string * int * (sect_attr list) * sect_type * fixup))
|
|
: frag =
|
|
let (sect_name, sect_align, sect_attrs, sect_type, sect_fixup) = sect in
|
|
SEQ [|
|
|
fixed_sz_string 16 sect_name;
|
|
fixed_sz_string 16 seg_name;
|
|
WORD (TY_u32, M_POS sect_fixup);
|
|
WORD (TY_u32, M_SZ sect_fixup);
|
|
WORD (TY_u32, F_POS sect_fixup);
|
|
WORD (TY_u32, IMM (Int64.of_int sect_align));
|
|
WORD (TY_u32, IMM 0L); (* reloff *)
|
|
WORD (TY_u32, IMM 0L); (* nreloc *)
|
|
WORD (TY_u32, (IMM (Int64.logor (* flags (and attrs) *)
|
|
(fold_flags sect_attr_code sect_attrs)
|
|
(sect_type_code sect_type))));
|
|
WORD (TY_u32, IMM 0L); (* reserved1 *)
|
|
WORD (TY_u32, IMM 0L); (* reserved2 *)
|
|
|]
|
|
;;
|
|
|
|
let macho_segment_command
|
|
(seg_name:string)
|
|
(seg_fixup:fixup)
|
|
(maxprot:vm_prot list)
|
|
(initprot:vm_prot list)
|
|
(sects:(string * int * (sect_attr list) * sect_type * fixup) array)
|
|
: frag =
|
|
|
|
let cmd_fixup = new_fixup "segment command" in
|
|
let cmd =
|
|
SEQ [|
|
|
WORD (TY_u32, IMM (load_command_code LC_SEGMENT));
|
|
WORD (TY_u32, F_SZ cmd_fixup);
|
|
fixed_sz_string 16 seg_name;
|
|
WORD (TY_u32, M_POS seg_fixup);
|
|
WORD (TY_u32, M_SZ seg_fixup);
|
|
WORD (TY_u32, F_POS seg_fixup);
|
|
WORD (TY_u32, F_SZ seg_fixup);
|
|
WORD (TY_u32, IMM (fold_flags vm_prot_code maxprot));
|
|
WORD (TY_u32, IMM (fold_flags vm_prot_code initprot));
|
|
WORD (TY_u32, IMM (Int64.of_int (Array.length sects)));
|
|
WORD (TY_u32, IMM 0L); (* Flags? *)
|
|
|]
|
|
in
|
|
DEF (cmd_fixup,
|
|
SEQ [|
|
|
cmd;
|
|
SEQ (Array.map (macho_section_command seg_name) sects);
|
|
|])
|
|
;;
|
|
|
|
let macho_thread_command
|
|
(entry:fixup)
|
|
: frag =
|
|
let cmd_fixup = new_fixup "thread command" in
|
|
let x86_THREAD_STATE32 = 1L in
|
|
let regs =
|
|
[|
|
|
WORD (TY_u32, IMM 0x0L); (* eax *)
|
|
WORD (TY_u32, IMM 0x0L); (* ebx *)
|
|
WORD (TY_u32, IMM 0x0L); (* ecx *)
|
|
WORD (TY_u32, IMM 0x0L); (* edx *)
|
|
|
|
WORD (TY_u32, IMM 0x0L); (* edi *)
|
|
WORD (TY_u32, IMM 0x0L); (* esi *)
|
|
WORD (TY_u32, IMM 0x0L); (* ebp *)
|
|
WORD (TY_u32, IMM 0x0L); (* esp *)
|
|
|
|
WORD (TY_u32, IMM 0x0L); (* ss *)
|
|
WORD (TY_u32, IMM 0x0L); (* eflags *)
|
|
WORD (TY_u32, M_POS entry); (* eip *)
|
|
WORD (TY_u32, IMM 0x0L); (* cs *)
|
|
|
|
WORD (TY_u32, IMM 0x0L); (* ds *)
|
|
WORD (TY_u32, IMM 0x0L); (* es *)
|
|
WORD (TY_u32, IMM 0x0L); (* fs *)
|
|
WORD (TY_u32, IMM 0x0L); (* gs *)
|
|
|]
|
|
in
|
|
let cmd =
|
|
SEQ [|
|
|
WORD (TY_u32, IMM (load_command_code LC_UNIXTHREAD));
|
|
WORD (TY_u32, F_SZ cmd_fixup);
|
|
WORD (TY_u32, IMM x86_THREAD_STATE32); (* "flavour" *)
|
|
WORD (TY_u32, IMM (Int64.of_int (Array.length regs)));
|
|
SEQ regs
|
|
|]
|
|
in
|
|
DEF (cmd_fixup, cmd)
|
|
;;
|
|
|
|
let macho_dylinker_command : frag =
|
|
let cmd_fixup = new_fixup "dylinker command" in
|
|
let str_fixup = new_fixup "dylinker lc_str fixup" in
|
|
let cmd =
|
|
SEQ
|
|
[|
|
|
WORD (TY_u32, IMM (load_command_code LC_LOAD_DYLINKER));
|
|
WORD (TY_u32, F_SZ cmd_fixup);
|
|
|
|
(* see definition of lc_str; these things are weird. *)
|
|
WORD (TY_u32, SUB (F_POS (str_fixup), F_POS (cmd_fixup)));
|
|
DEF (str_fixup, ZSTRING "/usr/lib/dyld");
|
|
ALIGN_FILE (4, MARK);
|
|
|]
|
|
in
|
|
DEF (cmd_fixup, cmd);
|
|
;;
|
|
|
|
let macho_dylib_command (dylib:string) : frag =
|
|
|
|
let cmd_fixup = new_fixup "dylib command" in
|
|
let str_fixup = new_fixup "dylib lc_str fixup" in
|
|
let cmd =
|
|
SEQ
|
|
[|
|
|
WORD (TY_u32, IMM (load_command_code LC_LOAD_DYLIB));
|
|
WORD (TY_u32, F_SZ cmd_fixup);
|
|
|
|
(* see definition of lc_str; these things are weird. *)
|
|
WORD (TY_u32, SUB (F_POS (str_fixup), F_POS (cmd_fixup)));
|
|
|
|
WORD (TY_u32, IMM 0L); (* timestamp *)
|
|
WORD (TY_u32, IMM 0L); (* current_version *)
|
|
WORD (TY_u32, IMM 0L); (* compatibility_version *)
|
|
|
|
(* Payload-and-alignment of an lc_str goes at end of command. *)
|
|
DEF (str_fixup, ZSTRING dylib);
|
|
ALIGN_FILE (4, MARK);
|
|
|
|
|]
|
|
in
|
|
DEF (cmd_fixup, cmd)
|
|
;;
|
|
|
|
|
|
let macho_symtab_command
|
|
(symtab_fixup:fixup)
|
|
(nsyms:int64)
|
|
(strtab_fixup:fixup)
|
|
: frag =
|
|
let cmd_fixup = new_fixup "symtab command" in
|
|
let cmd =
|
|
SEQ
|
|
[|
|
|
WORD (TY_u32, IMM (load_command_code LC_SYMTAB));
|
|
WORD (TY_u32, F_SZ cmd_fixup);
|
|
|
|
WORD (TY_u32, F_POS symtab_fixup); (* symoff *)
|
|
WORD (TY_u32, IMM nsyms); (* nsyms *)
|
|
|
|
WORD (TY_u32, F_POS strtab_fixup); (* stroff *)
|
|
WORD (TY_u32, F_SZ strtab_fixup); (* strsz *)
|
|
|]
|
|
in
|
|
DEF (cmd_fixup, cmd)
|
|
;;
|
|
|
|
let macho_dysymtab_command
|
|
(local_defined_syms_index:int64)
|
|
(local_defined_syms_count:int64)
|
|
(external_defined_syms_index:int64)
|
|
(external_defined_syms_count:int64)
|
|
(undefined_syms_index:int64)
|
|
(undefined_syms_count:int64)
|
|
(indirect_symtab_fixup:fixup) : frag =
|
|
let cmd_fixup = new_fixup "dysymtab command" in
|
|
let cmd =
|
|
SEQ
|
|
[|
|
|
WORD (TY_u32, IMM (load_command_code LC_DYSYMTAB));
|
|
WORD (TY_u32, F_SZ cmd_fixup);
|
|
|
|
WORD (TY_u32, IMM local_defined_syms_index); (* ilocalsym *)
|
|
WORD (TY_u32, IMM local_defined_syms_count); (* nlocalsym *)
|
|
|
|
WORD (TY_u32, IMM external_defined_syms_index); (* iextdefsym *)
|
|
WORD (TY_u32, IMM external_defined_syms_count); (* nextdefsym *)
|
|
|
|
WORD (TY_u32, IMM undefined_syms_index); (* iundefsym *)
|
|
WORD (TY_u32, IMM undefined_syms_count); (* nundefsym *)
|
|
|
|
WORD (TY_u32, IMM 0L); (* tocoff *)
|
|
WORD (TY_u32, IMM 0L); (* ntoc *)
|
|
|
|
WORD (TY_u32, IMM 0L); (* modtaboff *)
|
|
WORD (TY_u32, IMM 0L); (* nmodtab *)
|
|
|
|
WORD (TY_u32, IMM 0L); (* extrefsymoff *)
|
|
WORD (TY_u32, IMM 0L); (* nextrefsyms *)
|
|
|
|
WORD (TY_u32, F_POS indirect_symtab_fixup); (* indirectsymoff *)
|
|
WORD (TY_u32, IMM undefined_syms_count); (* nindirectsyms *)
|
|
|
|
WORD (TY_u32, IMM 0L); (* extreloff *)
|
|
WORD (TY_u32, IMM 0L); (* nextrel *)
|
|
|
|
WORD (TY_u32, IMM 0L); (* locreloff *)
|
|
WORD (TY_u32, IMM 0L); (* nlocrel *)
|
|
|]
|
|
in
|
|
DEF (cmd_fixup, cmd)
|
|
;;
|
|
|
|
let macho_header_32
|
|
(cpu:cpu_type)
|
|
(sub:cpu_subtype)
|
|
(ftype:file_type)
|
|
(flags:file_flag list)
|
|
(loadcmds:frag array) : frag =
|
|
let load_commands_fixup = new_fixup "load commands" in
|
|
let cmds = DEF (load_commands_fixup, SEQ loadcmds) in
|
|
SEQ
|
|
[|
|
|
WORD (TY_u32, IMM mh_magic);
|
|
WORD (TY_u32, IMM (cpu_type_code cpu));
|
|
WORD (TY_u32, IMM (cpu_subtype_code sub));
|
|
WORD (TY_u32, IMM (file_type_code ftype));
|
|
WORD (TY_u32, IMM (Int64.of_int (Array.length loadcmds)));
|
|
WORD (TY_u32, F_SZ load_commands_fixup);
|
|
WORD (TY_u32, IMM (fold_flags file_flag_code flags));
|
|
cmds
|
|
|]
|
|
;;
|
|
|
|
let emit_file
|
|
(sess:Session.sess)
|
|
(crate:Ast.crate)
|
|
(code:Asm.frag)
|
|
(data:Asm.frag)
|
|
(sem:Semant.ctxt)
|
|
(dwarf:Dwarf.debug_records)
|
|
: unit =
|
|
|
|
(* FIXME: alignment? *)
|
|
|
|
let mh_execute_header_fixup = new_fixup "__mh_execute header" in
|
|
|
|
let nxargc_fixup = (Semant.provide_native sem SEG_data "NXArgc") in
|
|
let nxargv_fixup = (Semant.provide_native sem SEG_data "NXArgv") in
|
|
let progname_fixup = (Semant.provide_native sem SEG_data "__progname") in
|
|
let environ_fixup = (Semant.provide_native sem SEG_data "environ") in
|
|
let exit_fixup = (Semant.require_native sem REQUIRED_LIB_crt "exit") in
|
|
let (start_fixup, rust_start_fixup) =
|
|
if sess.Session.sess_library_mode
|
|
then (None, None)
|
|
else (Some (new_fixup "start function entry"),
|
|
Some (Semant.require_native sem REQUIRED_LIB_rustrt "rust_start"))
|
|
in
|
|
|
|
let text_sect_align_log2 = 2 in
|
|
let data_sect_align_log2 = 2 in
|
|
|
|
let seg_align = 0x1000 in
|
|
let text_sect_align = 2 lsl text_sect_align_log2 in
|
|
let data_sect_align = 2 lsl data_sect_align_log2 in
|
|
|
|
let align_both align i =
|
|
ALIGN_FILE (align,
|
|
(ALIGN_MEM (align, i)))
|
|
in
|
|
|
|
let def_aligned a f i =
|
|
align_both a
|
|
(SEQ [| DEF(f, i);
|
|
(align_both a MARK)|])
|
|
in
|
|
|
|
(* Segments. *)
|
|
let zero_segment_fixup = new_fixup "__PAGEZERO segment" in
|
|
let text_segment_fixup = new_fixup "__TEXT segment" in
|
|
let data_segment_fixup = new_fixup "__DATA segment" in
|
|
let dwarf_segment_fixup = new_fixup "__DWARF segment" in
|
|
let linkedit_segment_fixup = new_fixup "__LINKEDIT segment" in
|
|
|
|
(* Sections in the text segment. *)
|
|
let text_section_fixup = new_fixup "__text section" in
|
|
|
|
(* Sections in the data segment. *)
|
|
let data_section_fixup = new_fixup "__data section" in
|
|
let const_section_fixup = new_fixup "__const section" in
|
|
let bss_section_fixup = new_fixup "__bss section" in
|
|
let note_rust_section_fixup = new_fixup "__note.rust section" in
|
|
let nl_symbol_ptr_section_fixup = new_fixup "__nl_symbol_ptr section" in
|
|
|
|
let data_section = def_aligned data_sect_align data_section_fixup data in
|
|
let const_section =
|
|
def_aligned data_sect_align const_section_fixup (SEQ [| |])
|
|
in
|
|
let bss_section =
|
|
def_aligned data_sect_align bss_section_fixup (SEQ [| |])
|
|
in
|
|
let note_rust_section =
|
|
def_aligned
|
|
data_sect_align note_rust_section_fixup
|
|
(Asm.note_rust_frags crate.node.Ast.crate_meta)
|
|
in
|
|
|
|
(* Officially Apple doesn't claim to support DWARF sections like this, but
|
|
they work. *)
|
|
let debug_info_section =
|
|
def_aligned data_sect_align
|
|
sem.Semant.ctxt_debug_info_fixup
|
|
dwarf.Dwarf.debug_info
|
|
in
|
|
let debug_abbrev_section =
|
|
def_aligned data_sect_align
|
|
sem.Semant.ctxt_debug_abbrev_fixup
|
|
dwarf.Dwarf.debug_abbrev
|
|
in
|
|
|
|
|
|
(* String, symbol and parallel "nonlazy-pointer" tables. *)
|
|
let symtab_fixup = new_fixup "symtab" in
|
|
let strtab_fixup = new_fixup "strtab" in
|
|
|
|
let symbol_nlist_entry
|
|
(sect_index:int)
|
|
(nty:n_type list)
|
|
(nd:n_desc)
|
|
(nv:Asm.expr64)
|
|
: (frag * fixup) =
|
|
let strtab_entry_fixup = new_fixup "strtab entry" in
|
|
(SEQ
|
|
[|
|
|
WORD (TY_u32, SUB ((F_POS strtab_entry_fixup),
|
|
(F_POS strtab_fixup)));
|
|
BYTE (Int64.to_int (fold_flags n_type_code nty));
|
|
BYTE sect_index;
|
|
WORD (TY_u16, IMM (n_desc_code nd));
|
|
WORD (TY_u32, nv);
|
|
|], strtab_entry_fixup)
|
|
in
|
|
|
|
let sect_symbol_nlist_entry
|
|
(seg:segment)
|
|
(fixup_to_use:fixup)
|
|
: (frag * fixup) =
|
|
let nty = [ N_SECT; N_EXT ] in
|
|
let nd = (0, [], REFERENCE_FLAG_UNDEFINED_NON_LAZY) in
|
|
let (sect_index, _(*seg_fix*)) =
|
|
match seg with
|
|
SEG_text -> (1, text_segment_fixup)
|
|
| SEG_data -> (2, data_segment_fixup)
|
|
in
|
|
symbol_nlist_entry sect_index nty nd (M_POS fixup_to_use)
|
|
in
|
|
|
|
let sect_private_symbol_nlist_entry
|
|
(seg:segment)
|
|
(fixup_to_use:fixup)
|
|
: (frag * fixup) =
|
|
let nty = [ N_SECT; ] in
|
|
let nd = (0, [], REFERENCE_FLAG_UNDEFINED_NON_LAZY) in
|
|
let (sect_index, _(*seg_fix*)) =
|
|
match seg with
|
|
SEG_text -> (1, text_segment_fixup)
|
|
| SEG_data -> (2, data_segment_fixup)
|
|
in
|
|
symbol_nlist_entry sect_index nty nd (M_POS fixup_to_use)
|
|
in
|
|
|
|
let indirect_symbol_nlist_entry (dylib_index:int) : (frag * fixup) =
|
|
let nty = [ N_UNDF; N_EXT ] in
|
|
let nd = (dylib_index, [], REFERENCE_FLAG_UNDEFINED_NON_LAZY) in
|
|
symbol_nlist_entry 0 nty nd (IMM 0L)
|
|
in
|
|
|
|
let indirect_symbols =
|
|
Array.of_list
|
|
(List.concat
|
|
(List.map
|
|
(fun (lib, tab) ->
|
|
(List.map
|
|
(fun (name,fix) -> (lib,name,fix))
|
|
(htab_pairs tab)))
|
|
(htab_pairs sem.Semant.ctxt_native_required)))
|
|
in
|
|
|
|
let dylib_index (lib:required_lib) : int =
|
|
match lib with
|
|
REQUIRED_LIB_rustrt -> 1
|
|
| REQUIRED_LIB_crt -> 2
|
|
| _ -> bug () "Macho.dylib_index on nonstandard required lib."
|
|
in
|
|
|
|
(* Make undef symbols for native imports. *)
|
|
let (undefined_symbols:(string * (frag * fixup)) array) =
|
|
Array.map (fun (lib,name,_) ->
|
|
("_" ^ name,
|
|
indirect_symbol_nlist_entry (dylib_index lib)))
|
|
indirect_symbols
|
|
in
|
|
|
|
(* Make symbols for exports. *)
|
|
let (export_symbols:(string * (frag * fixup)) array) =
|
|
let export_symbols_of_seg (seg, tab) =
|
|
List.map
|
|
begin
|
|
fun (name, fix) ->
|
|
let name = "_" ^ name in
|
|
let sym = sect_symbol_nlist_entry seg fix in
|
|
(name, sym)
|
|
end
|
|
(htab_pairs tab)
|
|
in
|
|
Array.of_list
|
|
(List.concat
|
|
(List.map export_symbols_of_seg
|
|
(htab_pairs sem.Semant.ctxt_native_provided)))
|
|
in
|
|
|
|
(* Make private symbols for items. *)
|
|
let (local_item_symbols:(string * (frag * fixup)) array) =
|
|
Array.map (fun code ->
|
|
let fix = code.Semant.code_fixup in
|
|
("_" ^ fix.fixup_name,
|
|
sect_private_symbol_nlist_entry SEG_text fix))
|
|
(Array.of_list (htab_vals sem.Semant.ctxt_all_item_code))
|
|
in
|
|
|
|
(* Make private symbols for glue. *)
|
|
let (local_glue_symbols:(string * (frag * fixup)) array) =
|
|
Array.map (fun (g, code) ->
|
|
let fix = code.Semant.code_fixup in
|
|
("_" ^ (Semant.glue_str sem g),
|
|
sect_private_symbol_nlist_entry SEG_text fix))
|
|
(Array.of_list (htab_pairs sem.Semant.ctxt_glue_code))
|
|
in
|
|
|
|
let (export_header_symbols:(string * (frag * fixup)) array) =
|
|
let name =
|
|
if sess.Session.sess_library_mode
|
|
then "__mh_dylib_header"
|
|
else "__mh_execute_header"
|
|
in
|
|
[|
|
|
(name, sect_symbol_nlist_entry SEG_text mh_execute_header_fixup);
|
|
|]
|
|
in
|
|
|
|
let export_symbols = Array.concat [ export_symbols;
|
|
export_header_symbols ]
|
|
in
|
|
|
|
let local_symbols = Array.concat [ local_item_symbols;
|
|
local_glue_symbols ]
|
|
in
|
|
|
|
let symbols = Array.concat [ local_symbols;
|
|
export_symbols;
|
|
undefined_symbols ]
|
|
in
|
|
let n_local_syms = Array.length local_symbols in
|
|
let n_export_syms = Array.length export_symbols in
|
|
let n_undef_syms = Array.length undefined_symbols in
|
|
|
|
let indirect_symbols_off = n_local_syms + n_export_syms in
|
|
let indirect_symtab_fixup = new_fixup "indirect symbol table" in
|
|
let indirect_symtab =
|
|
DEF (indirect_symtab_fixup,
|
|
SEQ (Array.mapi
|
|
(fun i _ -> WORD (TY_u32,
|
|
IMM (Int64.of_int
|
|
(i + indirect_symbols_off))))
|
|
indirect_symbols))
|
|
in
|
|
|
|
let nl_symbol_ptr_section =
|
|
def_aligned data_sect_align nl_symbol_ptr_section_fixup
|
|
(SEQ (Array.map
|
|
(fun (_, _, fix) ->
|
|
DEF(fix, WORD(TY_u32, IMM 0L)))
|
|
indirect_symbols))
|
|
in
|
|
let strtab = DEF (strtab_fixup,
|
|
SEQ (Array.map
|
|
(fun (name, (_, fix)) -> DEF(fix, ZSTRING name))
|
|
symbols))
|
|
in
|
|
let symtab = DEF (symtab_fixup,
|
|
SEQ (Array.map (fun (_, (frag, _)) -> frag) symbols))
|
|
in
|
|
|
|
|
|
let load_commands =
|
|
[|
|
|
macho_segment_command "__PAGEZERO" zero_segment_fixup
|
|
[] [] [||];
|
|
|
|
macho_segment_command "__TEXT" text_segment_fixup
|
|
[VM_PROT_READ; VM_PROT_EXECUTE]
|
|
[VM_PROT_READ; VM_PROT_EXECUTE]
|
|
[|
|
|
("__text", text_sect_align_log2, [], S_REGULAR, text_section_fixup)
|
|
|];
|
|
|
|
macho_segment_command "__DATA" data_segment_fixup
|
|
[VM_PROT_READ; VM_PROT_WRITE]
|
|
[VM_PROT_READ; VM_PROT_WRITE]
|
|
[|
|
|
("__data", data_sect_align_log2, [],
|
|
S_REGULAR, data_section_fixup);
|
|
("__const", data_sect_align_log2, [],
|
|
S_REGULAR, const_section_fixup);
|
|
("__bss", data_sect_align_log2, [],
|
|
S_REGULAR, bss_section_fixup);
|
|
("__note.rust", data_sect_align_log2, [],
|
|
S_REGULAR, note_rust_section_fixup);
|
|
("__nl_symbol_ptr", data_sect_align_log2, [],
|
|
S_NON_LAZY_SYMBOL_POINTERS, nl_symbol_ptr_section_fixup)
|
|
|];
|
|
|
|
macho_segment_command "__DWARF" dwarf_segment_fixup
|
|
[VM_PROT_READ]
|
|
[VM_PROT_READ]
|
|
[|
|
|
("__debug_info", data_sect_align_log2, [],
|
|
S_REGULAR, sem.Semant.ctxt_debug_info_fixup);
|
|
("__debug_abbrev", data_sect_align_log2, [],
|
|
S_REGULAR, sem.Semant.ctxt_debug_abbrev_fixup);
|
|
|];
|
|
|
|
macho_segment_command "__LINKEDIT" linkedit_segment_fixup
|
|
[VM_PROT_READ]
|
|
[VM_PROT_READ]
|
|
[|
|
|
|];
|
|
|
|
macho_symtab_command
|
|
symtab_fixup (Int64.of_int (Array.length symbols)) strtab_fixup;
|
|
|
|
|
|
macho_dysymtab_command
|
|
0L
|
|
(Int64.of_int n_local_syms)
|
|
(Int64.of_int n_local_syms)
|
|
(Int64.of_int n_export_syms)
|
|
(Int64.of_int (n_local_syms + n_export_syms))
|
|
(Int64.of_int n_undef_syms)
|
|
indirect_symtab_fixup;
|
|
|
|
macho_dylinker_command;
|
|
|
|
macho_dylib_command "librustrt.dylib";
|
|
|
|
macho_dylib_command "/usr/lib/libSystem.B.dylib";
|
|
|
|
begin
|
|
match start_fixup with
|
|
None -> MARK
|
|
| Some start_fixup ->
|
|
macho_thread_command start_fixup
|
|
end;
|
|
|]
|
|
in
|
|
|
|
let header_and_commands =
|
|
macho_header_32
|
|
CPU_TYPE_X86
|
|
CPU_SUBTYPE_X86_ALL
|
|
(if sess.Session.sess_library_mode then MH_DYLIB else MH_EXECUTE)
|
|
[ MH_BINDATLOAD; MH_DYLDLINK; MH_TWOLEVEL ]
|
|
load_commands
|
|
in
|
|
|
|
let objfile_start e start_fixup rust_start_fixup main_fn_fixup =
|
|
let edx = X86.h X86.edx in
|
|
let edx_pointee =
|
|
Il.Mem ((Il.RegIn (edx, None)), Il.ScalarTy (Il.AddrTy Il.OpaqueTy))
|
|
in
|
|
Il.emit_full e (Some start_fixup) [] Il.Dead;
|
|
|
|
(* zero marks the bottom of the frame chain. *)
|
|
Il.emit e (Il.Push (X86.imm (Asm.IMM 0L)));
|
|
Il.emit e (Il.umov (X86.rc X86.ebp) (X86.ro X86.esp));
|
|
|
|
(* 16-byte align stack for SSE. *)
|
|
Il.emit e (Il.binary Il.AND (X86.rc X86.esp) (X86.ro X86.esp)
|
|
(X86.imm (Asm.IMM 0xfffffffffffffff0L)));
|
|
|
|
(* Store argv. *)
|
|
Abi.load_fixup_addr e edx nxargv_fixup Il.OpaqueTy;
|
|
Il.emit e (Il.lea (X86.rc X86.ecx)
|
|
(Il.Cell (Il.Mem ((Il.RegIn (Il.Hreg X86.ebp,
|
|
Some (X86.word_off_n 2))),
|
|
Il.OpaqueTy))));
|
|
Il.emit e (Il.umov edx_pointee (X86.ro X86.ecx));
|
|
Il.emit e (Il.Push (X86.ro X86.ecx));
|
|
|
|
(* Store argc. *)
|
|
Abi.load_fixup_addr e edx nxargc_fixup Il.OpaqueTy;
|
|
Il.emit e (Il.umov (X86.rc X86.eax)
|
|
(X86.c (X86.word_n (Il.Hreg X86.ebp) 1)));
|
|
Il.emit e (Il.umov edx_pointee (X86.ro X86.eax));
|
|
Il.emit e (Il.Push (X86.ro X86.eax));
|
|
|
|
(* Calculte and store envp. *)
|
|
Il.emit e (Il.binary Il.ADD
|
|
(X86.rc X86.eax) (X86.ro X86.eax)
|
|
(X86.imm (Asm.IMM 1L)));
|
|
Il.emit e (Il.binary Il.UMUL
|
|
(X86.rc X86.eax) (X86.ro X86.eax)
|
|
(X86.imm (Asm.IMM X86.word_sz)));
|
|
Il.emit e (Il.binary Il.ADD (X86.rc X86.eax)
|
|
(X86.ro X86.eax) (X86.ro X86.ecx));
|
|
Abi.load_fixup_addr e edx environ_fixup Il.OpaqueTy;
|
|
Il.emit e (Il.umov edx_pointee (X86.ro X86.eax));
|
|
|
|
(* Push 16 bytes to preserve SSE alignment. *)
|
|
Abi.load_fixup_addr e edx sem.Semant.ctxt_crate_fixup Il.OpaqueTy;
|
|
Il.emit e (Il.Push (X86.ro X86.edx));
|
|
Abi.load_fixup_addr e edx main_fn_fixup Il.OpaqueTy;
|
|
Il.emit e (Il.Push (X86.ro X86.edx));
|
|
let fptr = Abi.load_fixup_codeptr e edx rust_start_fixup true true in
|
|
Il.emit e (Il.call (X86.rc X86.eax) fptr);
|
|
Il.emit e (Il.Pop (X86.rc X86.ecx));
|
|
Il.emit e (Il.Push (X86.ro X86.eax));
|
|
let fptr = Abi.load_fixup_codeptr e edx exit_fixup true true in
|
|
Il.emit e (Il.call (X86.rc X86.eax) fptr);
|
|
Il.emit e (Il.Pop (X86.rc X86.ecx));
|
|
Il.emit e (Il.Pop (X86.rc X86.ecx));
|
|
Il.emit e (Il.Pop (X86.rc X86.ecx));
|
|
Il.emit e (Il.Pop (X86.rc X86.ecx));
|
|
|
|
Il.emit e Il.Ret;
|
|
in
|
|
|
|
let text_section =
|
|
let start_code =
|
|
match (start_fixup, rust_start_fixup,
|
|
sem.Semant.ctxt_main_fn_fixup) with
|
|
(None, _, _)
|
|
| (_, None, _)
|
|
| (_, _, None) -> MARK
|
|
| (Some start_fixup,
|
|
Some rust_start_fixup,
|
|
Some main_fn_fixup) ->
|
|
let e = X86.new_emitter_without_vregs () in
|
|
objfile_start e start_fixup rust_start_fixup main_fn_fixup;
|
|
X86.frags_of_emitted_quads sess e
|
|
in
|
|
def_aligned text_sect_align text_section_fixup
|
|
(SEQ [|
|
|
start_code;
|
|
code
|
|
|])
|
|
in
|
|
|
|
let text_segment =
|
|
def_aligned seg_align text_segment_fixup
|
|
(SEQ [|
|
|
DEF (mh_execute_header_fixup, header_and_commands);
|
|
text_section;
|
|
align_both seg_align MARK;
|
|
|]);
|
|
in
|
|
|
|
let zero_segment = align_both seg_align
|
|
(SEQ [| MEMPOS 0L; DEF (zero_segment_fixup,
|
|
SEQ [| MEMPOS 0x1000L; MARK |] ) |])
|
|
in
|
|
|
|
let data_segment = def_aligned seg_align data_segment_fixup
|
|
(SEQ [|
|
|
DEF(nxargc_fixup, WORD (TY_u32, IMM 0L));
|
|
DEF(nxargv_fixup, WORD (TY_u32, IMM 0L));
|
|
DEF(environ_fixup, WORD (TY_u32, IMM 0L));
|
|
DEF(progname_fixup, WORD (TY_u32, IMM 0L));
|
|
data_section;
|
|
const_section;
|
|
bss_section;
|
|
note_rust_section;
|
|
nl_symbol_ptr_section
|
|
|])
|
|
in
|
|
|
|
let dwarf_segment = def_aligned seg_align dwarf_segment_fixup
|
|
(SEQ [|
|
|
debug_info_section;
|
|
debug_abbrev_section;
|
|
|])
|
|
in
|
|
|
|
let linkedit_segment = def_aligned seg_align linkedit_segment_fixup
|
|
(SEQ [|
|
|
symtab;
|
|
strtab;
|
|
indirect_symtab;
|
|
|])
|
|
in
|
|
|
|
let segments =
|
|
SEQ [|
|
|
DEF (sem.Semant.ctxt_image_base_fixup, MARK);
|
|
zero_segment;
|
|
text_segment;
|
|
data_segment;
|
|
dwarf_segment;
|
|
linkedit_segment;
|
|
|]
|
|
in
|
|
write_out_frag sess true segments
|
|
;;
|
|
|
|
|
|
let sniff
|
|
(sess:Session.sess)
|
|
(filename:filename)
|
|
: asm_reader option =
|
|
try
|
|
let stat = Unix.stat filename in
|
|
if (stat.Unix.st_kind = Unix.S_REG) &&
|
|
(stat.Unix.st_size > 4)
|
|
then
|
|
let ar = new_asm_reader sess filename in
|
|
let _ = log sess "sniffing Mach-O file" in
|
|
if (ar.asm_get_u32()) = (Int64.to_int mh_magic)
|
|
then (ar.asm_seek 0; Some ar)
|
|
else None
|
|
else
|
|
None
|
|
with
|
|
_ -> None
|
|
;;
|
|
|
|
let get_sections
|
|
(sess:Session.sess)
|
|
(ar:asm_reader)
|
|
: (string,(int*int)) Hashtbl.t =
|
|
let sects = Hashtbl.create 0 in
|
|
let _ = log sess "reading sections" in
|
|
let magic = ar.asm_get_u32() in
|
|
let _ = assert (magic = (Int64.to_int mh_magic)) in
|
|
let _ = ar.asm_adv_u32() in (* cpu type *)
|
|
let _ = ar.asm_adv_u32() in (* cpu subtype *)
|
|
let _ = ar.asm_adv_u32() in (* file type *)
|
|
let n_load_cmds = ar.asm_get_u32() in
|
|
let _ = ar.asm_adv_u32() in
|
|
let _ = log sess "Mach-o file with %d load commands" n_load_cmds in
|
|
let _ = ar.asm_adv_u32() in (* flags *)
|
|
let lc_seg = Int64.to_int (load_command_code LC_SEGMENT) in
|
|
for i = 0 to n_load_cmds - 1 do
|
|
let load_cmd_code = ar.asm_get_u32() in
|
|
let load_cmd_size = ar.asm_get_u32() in
|
|
let _ = log sess "load command %d:" i in
|
|
if load_cmd_code != lc_seg
|
|
then ar.asm_adv (load_cmd_size - 8)
|
|
else
|
|
begin
|
|
let seg_name = ar.asm_get_zstr_padded 16 in
|
|
let _ = log sess "LC_SEGMENT %s" seg_name in
|
|
let _ = ar.asm_adv_u32() in (* seg mem pos *)
|
|
let _ = ar.asm_adv_u32() in (* seg mem sz *)
|
|
let _ = ar.asm_adv_u32() in (* seg file pos *)
|
|
let _ = ar.asm_adv_u32() in (* seg file sz *)
|
|
let _ = ar.asm_adv_u32() in (* maxprot *)
|
|
let _ = ar.asm_adv_u32() in (* initprot *)
|
|
let n_sects = ar.asm_get_u32() in
|
|
let _ = ar.asm_get_u32() in (* flags *)
|
|
let _ = log sess "%d sections" in
|
|
for j = 0 to n_sects - 1 do
|
|
let sect_name = ar.asm_get_zstr_padded 16 in
|
|
let _ = ar.asm_adv 16 in (* seg name *)
|
|
let _ = ar.asm_adv_u32() in (* sect mem pos *)
|
|
let m_sz = ar.asm_get_u32() in
|
|
let f_pos = ar.asm_get_u32() in
|
|
let _ = ar.asm_adv_u32() in (* sect align *)
|
|
let _ = ar.asm_adv_u32() in (* reloff *)
|
|
let _ = ar.asm_adv_u32() in (* nreloc *)
|
|
let _ = ar.asm_adv_u32() in (* flags *)
|
|
let _ = ar.asm_adv_u32() in (* reserved1 *)
|
|
let _ = ar.asm_adv_u32() in (* reserved2 *)
|
|
let _ =
|
|
log sess
|
|
" section %d: 0x%x - 0x%x %s "
|
|
j f_pos (f_pos + m_sz) sect_name
|
|
in
|
|
let len = String.length sect_name in
|
|
let sect_name =
|
|
if (len > 2
|
|
&& sect_name.[0] = '_'
|
|
&& sect_name.[1] = '_')
|
|
then "." ^ (String.sub sect_name 2 (len-2))
|
|
else sect_name
|
|
in
|
|
Hashtbl.add sects sect_name (f_pos, m_sz)
|
|
done
|
|
end
|
|
done;
|
|
sects
|
|
;;
|
|
|
|
|
|
(*
|
|
* 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:
|
|
*)
|