summaryrefslogtreecommitdiff
path: root/libs/luajit-cmake/luajit/src/jit/bcsave.lua
diff options
context:
space:
mode:
authorsanine <sanine.not@pm.me>2023-03-11 15:58:20 -0600
committersanine <sanine.not@pm.me>2023-03-11 15:58:20 -0600
commitebc50b387ab209c9f9a0d92e340ac293d5697274 (patch)
treeea8c8b3677a18c994d2b9d33dbef3461dcf18113 /libs/luajit-cmake/luajit/src/jit/bcsave.lua
parentc2329b4c8258baa9429c77566c9def97d00e96d7 (diff)
build & link with luajit instead of lua5.1
Diffstat (limited to 'libs/luajit-cmake/luajit/src/jit/bcsave.lua')
-rw-r--r--libs/luajit-cmake/luajit/src/jit/bcsave.lua705
1 files changed, 705 insertions, 0 deletions
diff --git a/libs/luajit-cmake/luajit/src/jit/bcsave.lua b/libs/luajit-cmake/luajit/src/jit/bcsave.lua
new file mode 100644
index 0000000..90fe9da
--- /dev/null
+++ b/libs/luajit-cmake/luajit/src/jit/bcsave.lua
@@ -0,0 +1,705 @@
+----------------------------------------------------------------------------
+-- LuaJIT module to save/list bytecode.
+--
+-- Copyright (C) 2005-2022 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+--
+-- This module saves or lists the bytecode for an input file.
+-- It's run by the -b command line option.
+--
+------------------------------------------------------------------------------
+
+local jit = require("jit")
+assert(jit.version_num == 20100, "LuaJIT core/library version mismatch")
+local bit = require("bit")
+
+-- Symbol name prefix for LuaJIT bytecode.
+local LJBC_PREFIX = "luaJIT_BC_"
+
+local type, assert = type, assert
+local format = string.format
+local tremove, tconcat = table.remove, table.concat
+
+------------------------------------------------------------------------------
+
+local function usage()
+ io.stderr:write[[
+Save LuaJIT bytecode: luajit -b[options] input output
+ -l Only list bytecode.
+ -s Strip debug info (default).
+ -g Keep debug info.
+ -n name Set module name (default: auto-detect from input name).
+ -t type Set output file type (default: auto-detect from output name).
+ -a arch Override architecture for object files (default: native).
+ -o os Override OS for object files (default: native).
+ -F name Override filename (default: input filename).
+ -e chunk Use chunk string as input.
+ -- Stop handling options.
+ - Use stdin as input and/or stdout as output.
+
+File types: c h obj o raw (default)
+]]
+ os.exit(1)
+end
+
+local function check(ok, ...)
+ if ok then return ok, ... end
+ io.stderr:write("luajit: ", ...)
+ io.stderr:write("\n")
+ os.exit(1)
+end
+
+local function readfile(ctx, input)
+ if type(input) == "function" then return input end
+ if ctx.filename then
+ local data
+ if input == "-" then
+ data = io.stdin:read("*a")
+ else
+ local fp = assert(io.open(input, "rb"))
+ data = assert(fp:read("*a"))
+ assert(fp:close())
+ end
+ return check(load(data, ctx.filename))
+ else
+ if input == "-" then input = nil end
+ return check(loadfile(input))
+ end
+end
+
+local function savefile(name, mode)
+ if name == "-" then return io.stdout end
+ return check(io.open(name, mode))
+end
+
+local function set_stdout_binary(ffi)
+ ffi.cdef[[int _setmode(int fd, int mode);]]
+ ffi.C._setmode(1, 0x8000)
+end
+
+------------------------------------------------------------------------------
+
+local map_type = {
+ raw = "raw", c = "c", h = "h", o = "obj", obj = "obj",
+}
+
+local map_arch = {
+ x86 = { e = "le", b = 32, m = 3, p = 0x14c, },
+ x64 = { e = "le", b = 64, m = 62, p = 0x8664, },
+ arm = { e = "le", b = 32, m = 40, p = 0x1c0, },
+ arm64 = { e = "le", b = 64, m = 183, p = 0xaa64, },
+ arm64be = { e = "be", b = 64, m = 183, },
+ ppc = { e = "be", b = 32, m = 20, },
+ mips = { e = "be", b = 32, m = 8, f = 0x50001006, },
+ mipsel = { e = "le", b = 32, m = 8, f = 0x50001006, },
+ mips64 = { e = "be", b = 64, m = 8, f = 0x80000007, },
+ mips64el = { e = "le", b = 64, m = 8, f = 0x80000007, },
+ mips64r6 = { e = "be", b = 64, m = 8, f = 0xa0000407, },
+ mips64r6el = { e = "le", b = 64, m = 8, f = 0xa0000407, },
+}
+
+local map_os = {
+ linux = true, windows = true, osx = true, freebsd = true, netbsd = true,
+ openbsd = true, dragonfly = true, solaris = true,
+}
+
+local function checkarg(str, map, err)
+ str = str:lower()
+ local s = check(map[str], "unknown ", err)
+ return type(s) == "string" and s or str
+end
+
+local function detecttype(str)
+ local ext = str:lower():match("%.(%a+)$")
+ return map_type[ext] or "raw"
+end
+
+local function checkmodname(str)
+ check(str:match("^[%w_.%-]+$"), "bad module name")
+ return str:gsub("[%.%-]", "_")
+end
+
+local function detectmodname(str)
+ if type(str) == "string" then
+ local tail = str:match("[^/\\]+$")
+ if tail then str = tail end
+ local head = str:match("^(.*)%.[^.]*$")
+ if head then str = head end
+ str = str:match("^[%w_.%-]+")
+ else
+ str = nil
+ end
+ check(str, "cannot derive module name, use -n name")
+ return str:gsub("[%.%-]", "_")
+end
+
+------------------------------------------------------------------------------
+
+local function bcsave_tail(fp, output, s)
+ local ok, err = fp:write(s)
+ if ok and output ~= "-" then ok, err = fp:close() end
+ check(ok, "cannot write ", output, ": ", err)
+end
+
+local function bcsave_raw(output, s)
+ if output == "-" and jit.os == "Windows" then
+ local ok, ffi = pcall(require, "ffi")
+ check(ok, "FFI library required to write binary file to stdout")
+ set_stdout_binary(ffi)
+ end
+ local fp = savefile(output, "wb")
+ bcsave_tail(fp, output, s)
+end
+
+local function bcsave_c(ctx, output, s)
+ local fp = savefile(output, "w")
+ if ctx.type == "c" then
+ fp:write(format([[
+#ifdef __cplusplus
+extern "C"
+#endif
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+const unsigned char %s%s[] = {
+]], LJBC_PREFIX, ctx.modname))
+ else
+ fp:write(format([[
+#define %s%s_SIZE %d
+static const unsigned char %s%s[] = {
+]], LJBC_PREFIX, ctx.modname, #s, LJBC_PREFIX, ctx.modname))
+ end
+ local t, n, m = {}, 0, 0
+ for i=1,#s do
+ local b = tostring(string.byte(s, i))
+ m = m + #b + 1
+ if m > 78 then
+ fp:write(tconcat(t, ",", 1, n), ",\n")
+ n, m = 0, #b + 1
+ end
+ n = n + 1
+ t[n] = b
+ end
+ bcsave_tail(fp, output, tconcat(t, ",", 1, n).."\n};\n")
+end
+
+local function bcsave_elfobj(ctx, output, s, ffi)
+ ffi.cdef[[
+typedef struct {
+ uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7];
+ uint16_t type, machine;
+ uint32_t version;
+ uint32_t entry, phofs, shofs;
+ uint32_t flags;
+ uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx;
+} ELF32header;
+typedef struct {
+ uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7];
+ uint16_t type, machine;
+ uint32_t version;
+ uint64_t entry, phofs, shofs;
+ uint32_t flags;
+ uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx;
+} ELF64header;
+typedef struct {
+ uint32_t name, type, flags, addr, ofs, size, link, info, align, entsize;
+} ELF32sectheader;
+typedef struct {
+ uint32_t name, type;
+ uint64_t flags, addr, ofs, size;
+ uint32_t link, info;
+ uint64_t align, entsize;
+} ELF64sectheader;
+typedef struct {
+ uint32_t name, value, size;
+ uint8_t info, other;
+ uint16_t sectidx;
+} ELF32symbol;
+typedef struct {
+ uint32_t name;
+ uint8_t info, other;
+ uint16_t sectidx;
+ uint64_t value, size;
+} ELF64symbol;
+typedef struct {
+ ELF32header hdr;
+ ELF32sectheader sect[6];
+ ELF32symbol sym[2];
+ uint8_t space[4096];
+} ELF32obj;
+typedef struct {
+ ELF64header hdr;
+ ELF64sectheader sect[6];
+ ELF64symbol sym[2];
+ uint8_t space[4096];
+} ELF64obj;
+]]
+ local symname = LJBC_PREFIX..ctx.modname
+ local ai = assert(map_arch[ctx.arch])
+ local is64, isbe = ai.b == 64, ai.e == "be"
+
+ -- Handle different host/target endianess.
+ local function f32(x) return x end
+ local f16, fofs = f32, f32
+ if ffi.abi("be") ~= isbe then
+ f32 = bit.bswap
+ function f16(x) return bit.rshift(bit.bswap(x), 16) end
+ if is64 then
+ local two32 = ffi.cast("int64_t", 2^32)
+ function fofs(x) return bit.bswap(x)*two32 end
+ else
+ fofs = f32
+ end
+ end
+
+ -- Create ELF object and fill in header.
+ local o = ffi.new(is64 and "ELF64obj" or "ELF32obj")
+ local hdr = o.hdr
+ if ctx.os == "bsd" or ctx.os == "other" then -- Determine native hdr.eosabi.
+ local bf = assert(io.open("/bin/ls", "rb"))
+ local bs = bf:read(9)
+ bf:close()
+ ffi.copy(o, bs, 9)
+ check(hdr.emagic[0] == 127, "no support for writing native object files")
+ else
+ hdr.emagic = "\127ELF"
+ hdr.eosabi = ({ freebsd=9, netbsd=2, openbsd=12, solaris=6 })[ctx.os] or 0
+ end
+ hdr.eclass = is64 and 2 or 1
+ hdr.eendian = isbe and 2 or 1
+ hdr.eversion = 1
+ hdr.type = f16(1)
+ hdr.machine = f16(ai.m)
+ hdr.flags = f32(ai.f or 0)
+ hdr.version = f32(1)
+ hdr.shofs = fofs(ffi.offsetof(o, "sect"))
+ hdr.ehsize = f16(ffi.sizeof(hdr))
+ hdr.shentsize = f16(ffi.sizeof(o.sect[0]))
+ hdr.shnum = f16(6)
+ hdr.shstridx = f16(2)
+
+ -- Fill in sections and symbols.
+ local sofs, ofs = ffi.offsetof(o, "space"), 1
+ for i,name in ipairs{
+ ".symtab", ".shstrtab", ".strtab", ".rodata", ".note.GNU-stack",
+ } do
+ local sect = o.sect[i]
+ sect.align = fofs(1)
+ sect.name = f32(ofs)
+ ffi.copy(o.space+ofs, name)
+ ofs = ofs + #name+1
+ end
+ o.sect[1].type = f32(2) -- .symtab
+ o.sect[1].link = f32(3)
+ o.sect[1].info = f32(1)
+ o.sect[1].align = fofs(8)
+ o.sect[1].ofs = fofs(ffi.offsetof(o, "sym"))
+ o.sect[1].entsize = fofs(ffi.sizeof(o.sym[0]))
+ o.sect[1].size = fofs(ffi.sizeof(o.sym))
+ o.sym[1].name = f32(1)
+ o.sym[1].sectidx = f16(4)
+ o.sym[1].size = fofs(#s)
+ o.sym[1].info = 17
+ o.sect[2].type = f32(3) -- .shstrtab
+ o.sect[2].ofs = fofs(sofs)
+ o.sect[2].size = fofs(ofs)
+ o.sect[3].type = f32(3) -- .strtab
+ o.sect[3].ofs = fofs(sofs + ofs)
+ o.sect[3].size = fofs(#symname+2)
+ ffi.copy(o.space+ofs+1, symname)
+ ofs = ofs + #symname + 2
+ o.sect[4].type = f32(1) -- .rodata
+ o.sect[4].flags = fofs(2)
+ o.sect[4].ofs = fofs(sofs + ofs)
+ o.sect[4].size = fofs(#s)
+ o.sect[5].type = f32(1) -- .note.GNU-stack
+ o.sect[5].ofs = fofs(sofs + ofs + #s)
+
+ -- Write ELF object file.
+ local fp = savefile(output, "wb")
+ fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs))
+ bcsave_tail(fp, output, s)
+end
+
+local function bcsave_peobj(ctx, output, s, ffi)
+ ffi.cdef[[
+typedef struct {
+ uint16_t arch, nsects;
+ uint32_t time, symtabofs, nsyms;
+ uint16_t opthdrsz, flags;
+} PEheader;
+typedef struct {
+ char name[8];
+ uint32_t vsize, vaddr, size, ofs, relocofs, lineofs;
+ uint16_t nreloc, nline;
+ uint32_t flags;
+} PEsection;
+typedef struct __attribute((packed)) {
+ union {
+ char name[8];
+ uint32_t nameref[2];
+ };
+ uint32_t value;
+ int16_t sect;
+ uint16_t type;
+ uint8_t scl, naux;
+} PEsym;
+typedef struct __attribute((packed)) {
+ uint32_t size;
+ uint16_t nreloc, nline;
+ uint32_t cksum;
+ uint16_t assoc;
+ uint8_t comdatsel, unused[3];
+} PEsymaux;
+typedef struct {
+ PEheader hdr;
+ PEsection sect[2];
+ // Must be an even number of symbol structs.
+ PEsym sym0;
+ PEsymaux sym0aux;
+ PEsym sym1;
+ PEsymaux sym1aux;
+ PEsym sym2;
+ PEsym sym3;
+ uint32_t strtabsize;
+ uint8_t space[4096];
+} PEobj;
+]]
+ local symname = LJBC_PREFIX..ctx.modname
+ local ai = assert(map_arch[ctx.arch])
+ local is64 = ai.b == 64
+ local symexport = " /EXPORT:"..symname..",DATA "
+
+ -- The file format is always little-endian. Swap if the host is big-endian.
+ local function f32(x) return x end
+ local f16 = f32
+ if ffi.abi("be") then
+ f32 = bit.bswap
+ function f16(x) return bit.rshift(bit.bswap(x), 16) end
+ end
+
+ -- Create PE object and fill in header.
+ local o = ffi.new("PEobj")
+ local hdr = o.hdr
+ hdr.arch = f16(assert(ai.p))
+ hdr.nsects = f16(2)
+ hdr.symtabofs = f32(ffi.offsetof(o, "sym0"))
+ hdr.nsyms = f32(6)
+
+ -- Fill in sections and symbols.
+ o.sect[0].name = ".drectve"
+ o.sect[0].size = f32(#symexport)
+ o.sect[0].flags = f32(0x00100a00)
+ o.sym0.sect = f16(1)
+ o.sym0.scl = 3
+ o.sym0.name = ".drectve"
+ o.sym0.naux = 1
+ o.sym0aux.size = f32(#symexport)
+ o.sect[1].name = ".rdata"
+ o.sect[1].size = f32(#s)
+ o.sect[1].flags = f32(0x40300040)
+ o.sym1.sect = f16(2)
+ o.sym1.scl = 3
+ o.sym1.name = ".rdata"
+ o.sym1.naux = 1
+ o.sym1aux.size = f32(#s)
+ o.sym2.sect = f16(2)
+ o.sym2.scl = 2
+ o.sym2.nameref[1] = f32(4)
+ o.sym3.sect = f16(-1)
+ o.sym3.scl = 2
+ o.sym3.value = f32(1)
+ o.sym3.name = "@feat.00" -- Mark as SafeSEH compliant.
+ ffi.copy(o.space, symname)
+ local ofs = #symname + 1
+ o.strtabsize = f32(ofs + 4)
+ o.sect[0].ofs = f32(ffi.offsetof(o, "space") + ofs)
+ ffi.copy(o.space + ofs, symexport)
+ ofs = ofs + #symexport
+ o.sect[1].ofs = f32(ffi.offsetof(o, "space") + ofs)
+
+ -- Write PE object file.
+ local fp = savefile(output, "wb")
+ fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs))
+ bcsave_tail(fp, output, s)
+end
+
+local function bcsave_machobj(ctx, output, s, ffi)
+ ffi.cdef[[
+typedef struct
+{
+ uint32_t magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags;
+} mach_header;
+typedef struct
+{
+ mach_header; uint32_t 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;
+ uint32_t reserved1, reserved2;
+} mach_section;
+typedef struct {
+ char sectname[16], segname[16];
+ uint64_t addr, size;
+ uint32_t offset, align, reloff, nreloc, flags;
+ uint32_t 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 {
+ int32_t strx;
+ uint8_t type, sect;
+ uint16_t desc;
+ uint64_t value;
+} mach_nlist_64;
+typedef struct
+{
+ int32_t magic, nfat_arch;
+} mach_fat_header;
+typedef struct
+{
+ int32_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[2];
+ struct {
+ mach_header hdr;
+ mach_segment_command seg;
+ mach_section sec;
+ mach_symtab_command sym;
+ } arch[2];
+ mach_nlist sym_entry;
+ uint8_t space[4096];
+} mach_fat_obj;
+typedef struct {
+ mach_fat_header fat;
+ mach_fat_arch fat_arch[2];
+ struct {
+ mach_header_64 hdr;
+ mach_segment_command_64 seg;
+ mach_section_64 sec;
+ mach_symtab_command sym;
+ } arch[2];
+ mach_nlist_64 sym_entry;
+ uint8_t space[4096];
+} mach_fat_obj_64;
+]]
+ local symname = '_'..LJBC_PREFIX..ctx.modname
+ local isfat, is64, align, mobj = false, false, 4, "mach_obj"
+ if ctx.arch == "x64" then
+ is64, align, mobj = true, 8, "mach_obj_64"
+ elseif ctx.arch == "arm" then
+ isfat, mobj = true, "mach_fat_obj"
+ elseif ctx.arch == "arm64" then
+ is64, align, isfat, mobj = true, 8, true, "mach_fat_obj_64"
+ else
+ check(ctx.arch == "x86", "unsupported architecture for OSX")
+ end
+ local function aligned(v, a) return bit.band(v+a-1, -a) end
+ local be32 = bit.bswap -- Mach-O FAT is BE, supported archs are LE.
+
+ -- Create Mach-O object and fill in header.
+ local o = ffi.new(mobj)
+ local mach_size = aligned(ffi.offsetof(o, "space")+#symname+2, align)
+ local cputype = ({ x86={7}, x64={0x01000007}, arm={7,12}, arm64={0x01000007,0x0100000c} })[ctx.arch]
+ local cpusubtype = ({ x86={3}, x64={3}, arm={3,9}, arm64={3,0} })[ctx.arch]
+ if isfat then
+ o.fat.magic = be32(0xcafebabe)
+ o.fat.nfat_arch = be32(#cpusubtype)
+ end
+
+ -- Fill in sections and symbols.
+ for i=0,#cpusubtype-1 do
+ local ofs = 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.
+ ofs = ffi.offsetof(o, "arch") + i*ffi.sizeof(o.arch[0])
+ a.offset = be32(ofs)
+ a.size = be32(mach_size-ofs+#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 = 1
+ 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
+ a.seg.cmdsize = ffi.sizeof(a.seg)+ffi.sizeof(a.sec)
+ a.seg.vmsize = #s
+ a.seg.fileoff = mach_size-ofs
+ a.seg.filesize = #s
+ a.seg.maxprot = 1
+ a.seg.initprot = 1
+ 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-ofs
+ a.sym.cmd = 2
+ a.sym.cmdsize = ffi.sizeof(a.sym)
+ a.sym.symoff = ffi.offsetof(o, "sym_entry")-ofs
+ a.sym.nsyms = 1
+ a.sym.stroff = ffi.offsetof(o, "sym_entry")+ffi.sizeof(o.sym_entry)-ofs
+ 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)
+ local ok, ffi = pcall(require, "ffi")
+ check(ok, "FFI library required to write this file type")
+ if output == "-" and jit.os == "Windows" then
+ set_stdout_binary(ffi)
+ end
+ if ctx.os == "windows" then
+ return bcsave_peobj(ctx, output, s, ffi)
+ elseif ctx.os == "osx" then
+ return bcsave_machobj(ctx, output, s, ffi)
+ else
+ return bcsave_elfobj(ctx, output, s, ffi)
+ end
+end
+
+------------------------------------------------------------------------------
+
+local function bclist(ctx, input, output)
+ local f = readfile(ctx, input)
+ require("jit.bc").dump(f, savefile(output, "w"), true)
+end
+
+local function bcsave(ctx, input, output)
+ local f = readfile(ctx, input)
+ local s = string.dump(f, ctx.strip)
+ local t = ctx.type
+ if not t then
+ t = detecttype(output)
+ ctx.type = t
+ end
+ if t == "raw" then
+ bcsave_raw(output, s)
+ else
+ if not ctx.modname then ctx.modname = detectmodname(input) end
+ if t == "obj" then
+ bcsave_obj(ctx, output, s)
+ else
+ bcsave_c(ctx, output, s)
+ end
+ end
+end
+
+local function docmd(...)
+ local arg = {...}
+ local n = 1
+ local list = false
+ local ctx = {
+ strip = true, arch = jit.arch, os = jit.os:lower(),
+ type = false, modname = false,
+ }
+ while n <= #arg do
+ local a = arg[n]
+ if type(a) == "string" and a:sub(1, 1) == "-" and a ~= "-" then
+ tremove(arg, n)
+ if a == "--" then break end
+ for m=2,#a do
+ local opt = a:sub(m, m)
+ if opt == "l" then
+ list = true
+ elseif opt == "s" then
+ ctx.strip = true
+ elseif opt == "g" then
+ ctx.strip = false
+ else
+ if arg[n] == nil or m ~= #a then usage() end
+ if opt == "e" then
+ if n ~= 1 then usage() end
+ arg[1] = check(loadstring(arg[1]))
+ elseif opt == "n" then
+ ctx.modname = checkmodname(tremove(arg, n))
+ elseif opt == "t" then
+ ctx.type = checkarg(tremove(arg, n), map_type, "file type")
+ elseif opt == "a" then
+ ctx.arch = checkarg(tremove(arg, n), map_arch, "architecture")
+ elseif opt == "o" then
+ ctx.os = checkarg(tremove(arg, n), map_os, "OS name")
+ elseif opt == "F" then
+ ctx.filename = "@"..tremove(arg, n)
+ else
+ usage()
+ end
+ end
+ end
+ else
+ n = n + 1
+ end
+ end
+ if list then
+ if #arg == 0 or #arg > 2 then usage() end
+ bclist(ctx, arg[1], arg[2] or "-")
+ else
+ if #arg ~= 2 then usage() end
+ bcsave(ctx, arg[1], arg[2])
+ end
+end
+
+------------------------------------------------------------------------------
+
+-- Public module functions.
+return {
+ start = docmd -- Process -b command line option.
+}
+