Supported architectures: x86, x64, arm Selecting arm, produces FAT object file for: armv6, armv7, armv7s & x86 (simulator). --- src/jit/bcsave.lua | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 154 insertions(+), 1 deletion(-) diff --git a/src/jit/bcsave.lua b/src/jit/bcsave.lua index bf69e00..6f32c29 100644 --- a/src/jit/bcsave.lua +++ b/src/jit/bcsave.lua @@ -398,7 +398,160 @@ typedef struct { end local function bcsave_machobj(ctx, output, s, ffi) - check(false, "NYI: no support for writing OSX object files") + check(({ x86=true, x64=true, arm=true })[ctx.arch], "only x86, x64 and arm architectures are allowed for osx") + ffi.cdef[[ +typedef struct +{ + uint32_t magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags; +} mach_header; +typedef struct +{ + uint32_t magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags, reserved; +} mach_header_64; +typedef struct { + uint32_t cmd, cmdsize; + char segname[16]; + uint32_t vmaddr, vmsize, fileoff, filesize; + uint32_t maxprot, initprot, nsects, flags; +} mach_segment_command; +typedef struct { + uint32_t cmd, cmdsize; + char segname[16]; + uint64_t vmaddr, vmsize, fileoff, filesize; + uint32_t maxprot, initprot, nsects, flags; +} mach_segment_command_64; +typedef struct { + char sectname[16], segname[16]; + uint32_t addr, size; + uint32_t offset, align, reloff, nreloc, flags, reserved1, reserved2; +} mach_section; +typedef struct { + char sectname[16], segname[16]; + uint64_t addr, size; + uint32_t offset, align, reloff, nreloc, flags, reserved1, reserved2, reserved3; +} mach_section_64; +typedef struct { + uint32_t cmd, cmdsize, symoff, nsyms, stroff, strsize; +} mach_symtab_command; +typedef struct { + int32_t strx; + uint8_t type, sect; + int16_t desc; + uint32_t value; +} mach_nlist; +typedef struct { + uint32_t strx; + uint8_t type, sect; + uint16_t desc; + uint64_t value; +} mach_nlist_64; +typedef struct +{ + uint32_t magic, nfat_arch; +} mach_fat_header; +typedef struct +{ + uint32_t cputype, cpusubtype, offset, size, align; +} mach_fat_arch; +typedef struct { + struct { + mach_header hdr; + mach_segment_command seg; + mach_section sec; + mach_symtab_command sym; + } arch[1]; + mach_nlist sym_entry; + uint8_t space[4096]; +} mach_obj; +typedef struct { + struct { + mach_header_64 hdr; + mach_segment_command_64 seg; + mach_section_64 sec; + mach_symtab_command sym; + } arch[1]; + mach_nlist_64 sym_entry; + uint8_t space[4096]; +} mach_obj_64; +typedef struct { + mach_fat_header fat; + mach_fat_arch fat_arch[4]; + struct { + mach_header hdr; + mach_segment_command seg; + mach_section sec; + mach_symtab_command sym; + } arch[4]; + mach_nlist sym_entry; + uint8_t space[4096]; +} mach_fat_obj; +]] + local symname = '_'..LJBC_PREFIX..ctx.modname + local is64, align = false, 4 + local isfat = (ctx.arch == "arm") + if ctx.arch == "x64" then + is64 = true + align = 8 + end + local function aligned(v,a) return v + (a - (v % a)) % a end + -- Assuming we are running on LE machine. + local be32 = bit.bswap + + -- Create Mach-O object and fill in header. + local o = ffi.new(({ x86="mach_obj", x64="mach_obj_64", arm="mach_fat_obj" })[ctx.arch]) + local mach_size = aligned(ffi.offsetof(o, "space")+#symname+2, align) + local cputype = ({ x86={7}, x64={0x01000007}, arm={7,12,12,12} })[ctx.arch] + local cpusubtype = ({ x86={3}, x64={3}, arm={3, 6, 9,11} })[ctx.arch] + if isfat then + o.fat.magic = be32(0xcafebabe) + o.fat.nfat_arch = be32(#cpusubtype) + end + for i = 0, #cpusubtype-1 do + local offset = 0 + if isfat then + local a = o.fat_arch[i] + a.cputype = be32(cputype[i+1]) + a.cpusubtype = be32(cpusubtype[i+1]) + -- Subsequent slices overlap each other to share data. + offset = ffi.sizeof(o.fat) + ffi.sizeof(o.fat_arch) + i*ffi.sizeof(o.arch[0]) + a.offset = be32(offset) + a.size = be32(mach_size-offset+#s) + end + local a = o.arch[i] + a.hdr.magic = is64 and 0xfeedfacf or 0xfeedface + a.hdr.cputype = cputype[i+1] + a.hdr.cpusubtype = cpusubtype[i+1] + a.hdr.filetype = 0x1 -- obj + a.hdr.ncmds = 2 + a.hdr.sizeofcmds = ffi.sizeof(a.seg)+ffi.sizeof(a.sec)+ffi.sizeof(a.sym) + a.seg.cmd = is64 and 0x19 or 0x1 -- segment + a.seg.cmdsize = ffi.sizeof(a.seg)+ffi.sizeof(a.sec) + a.seg.vmsize = #s + a.seg.fileoff = mach_size-offset + a.seg.filesize = #s + a.seg.maxprot = 0x1 -- readonly + a.seg.initprot = 0x1 + a.seg.nsects = 1 + ffi.copy(a.sec.sectname, "__data") + ffi.copy(a.sec.segname, "__DATA") + a.sec.size = #s + a.sec.offset = mach_size-offset + a.sym.cmd = 0x2 -- symbol table + a.sym.cmdsize = ffi.sizeof(a.sym) + a.sym.symoff = ffi.offsetof(o, "sym_entry")-offset + a.sym.nsyms = 1 + a.sym.stroff = ffi.offsetof(o, "sym_entry")+ffi.sizeof(o.sym_entry)-offset + a.sym.strsize = aligned(#symname+2, align) + end + o.sym_entry.type = 0xf + o.sym_entry.sect = 1 + o.sym_entry.strx = 1 + ffi.copy(o.space+1, symname) + + -- Write Macho-O object file. + local fp = savefile(output, "wb") + fp:write(ffi.string(o, mach_size)) + bcsave_tail(fp, output, s) end local function bcsave_obj(ctx, output, s) -- 1.7.10.2 (Apple Git-33)