diff options
| author | Mike Pall <mike> | 2011-08-17 00:13:39 +0200 |
|---|---|---|
| committer | Mike Pall <mike> | 2011-08-17 00:13:39 +0200 |
| commit | a9dd47b7fcde95bbca06485c50326b7b90d930a8 (patch) | |
| tree | a0f3482d7519adaffd81b5c5c8a2b9bd3e99afaf /lib | |
| parent | aad7ea3c02b0baed5b700565eea36c9b33d7c6b1 (diff) | |
| download | luajit-a9dd47b7fcde95bbca06485c50326b7b90d930a8.tar.gz luajit-a9dd47b7fcde95bbca06485c50326b7b90d930a8.tar.bz2 luajit-a9dd47b7fcde95bbca06485c50326b7b90d930a8.zip | |
Extend -b to generate c/h/obj/o files with embedded bytecode.
Supported object file formats: ELF or PE/COFF object files.
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/bcsave.lua | 447 |
1 files changed, 410 insertions, 37 deletions
diff --git a/lib/bcsave.lua b/lib/bcsave.lua index 6c6d9f0a..92626241 100644 --- a/lib/bcsave.lua +++ b/lib/bcsave.lua | |||
| @@ -10,10 +10,12 @@ | |||
| 10 | -- | 10 | -- |
| 11 | ------------------------------------------------------------------------------ | 11 | ------------------------------------------------------------------------------ |
| 12 | 12 | ||
| 13 | -- Cache some library functions and objects. | ||
| 14 | local jit = require("jit") | 13 | local jit = require("jit") |
| 15 | assert(jit.version_num == 20000, "LuaJIT core/library version mismatch") | 14 | assert(jit.version_num == 20000, "LuaJIT core/library version mismatch") |
| 16 | 15 | ||
| 16 | -- Symbol name prefix for LuaJIT bytecode. | ||
| 17 | local LJBC_PREFIX = "luaJIT_BC_" | ||
| 18 | |||
| 17 | ------------------------------------------------------------------------------ | 19 | ------------------------------------------------------------------------------ |
| 18 | 20 | ||
| 19 | local function usage() | 21 | local function usage() |
| @@ -22,41 +24,390 @@ Save LuaJIT bytecode: luajit -b[options] input output | |||
| 22 | -l Only list bytecode. | 24 | -l Only list bytecode. |
| 23 | -s Strip debug info (default). | 25 | -s Strip debug info (default). |
| 24 | -g Keep debug info. | 26 | -g Keep debug info. |
| 27 | -n name Set module name (default: auto-detect from input name). | ||
| 28 | -t type Set output file type (default: auto-detect from output name). | ||
| 29 | -a arch Override architecture for object files (default: native). | ||
| 30 | -o os Override OS for object files (default: native). | ||
| 25 | -e chunk Use chunk string as input. | 31 | -e chunk Use chunk string as input. |
| 26 | -- Stop handling options. | 32 | -- Stop handling options. |
| 27 | - Use stdin as input and/or stdout as output. | 33 | - Use stdin as input and/or stdout as output. |
| 34 | |||
| 35 | File types: c h obj o raw (default) | ||
| 28 | ]] | 36 | ]] |
| 29 | os.exit(1) | 37 | os.exit(1) |
| 30 | end | 38 | end |
| 31 | 39 | ||
| 40 | local function check(ok, ...) | ||
| 41 | if ok then return ok, ... end | ||
| 42 | io.stderr:write("luajit: ", ...) | ||
| 43 | io.stderr:write("\n") | ||
| 44 | os.exit(1) | ||
| 45 | end | ||
| 46 | |||
| 32 | local function readfile(input) | 47 | local function readfile(input) |
| 33 | if type(input) == "function" then return input end | 48 | if type(input) == "function" then return input end |
| 34 | if input == "-" then input = nil end | 49 | if input == "-" then input = nil end |
| 35 | local f, err = loadfile(input) | 50 | return check(loadfile(input)) |
| 36 | if not f then | 51 | end |
| 37 | io.stderr:write("luajit: ", err, "\n") | 52 | |
| 38 | os.exit(1) | 53 | local function savefile(name, mode) |
| 54 | if name == "-" then return io.stdout end | ||
| 55 | return check(io.open(name, mode)) | ||
| 56 | end | ||
| 57 | |||
| 58 | ------------------------------------------------------------------------------ | ||
| 59 | |||
| 60 | local map_type = { | ||
| 61 | raw = "raw", c = "c", h = "h", o = "obj", obj = "obj", | ||
| 62 | } | ||
| 63 | |||
| 64 | local map_arch = { | ||
| 65 | x86 = true, x64 = true, arm = true, ppc = true, ppcspe = true, | ||
| 66 | } | ||
| 67 | |||
| 68 | local map_os = { | ||
| 69 | linux = true, windows = true, osx = true, freebsd = true, netbsd = true, | ||
| 70 | openbsd = true, solaris = true, | ||
| 71 | } | ||
| 72 | |||
| 73 | local function checkarg(str, map, err) | ||
| 74 | str = string.lower(str) | ||
| 75 | local s = check(map[str], "unknown ", err) | ||
| 76 | return s == true and str or s | ||
| 77 | end | ||
| 78 | |||
| 79 | local function detecttype(str) | ||
| 80 | local ext = string.match(string.lower(str), "%.(%a+)$") | ||
| 81 | return map_type[ext] or "raw" | ||
| 82 | end | ||
| 83 | |||
| 84 | local function checkmodname(str) | ||
| 85 | check(string.match(str, "^[%w_.%-]+$"), "bad module name") | ||
| 86 | return string.gsub(str, "[%.%-]", "_") | ||
| 87 | end | ||
| 88 | |||
| 89 | local function detectmodname(str) | ||
| 90 | if type(str) == "string" then | ||
| 91 | local tail = string.match(str, "[^/\\]+$") | ||
| 92 | if tail then str = tail end | ||
| 93 | local head = string.match(str, "^(.*)%.[^.]*$") | ||
| 94 | if head then str = head end | ||
| 95 | str = string.match(str, "^[%w_.%-]+") | ||
| 96 | else | ||
| 97 | str = nil | ||
| 39 | end | 98 | end |
| 40 | return f | 99 | check(str, "cannot derive module name, use -n name") |
| 100 | return string.gsub(str, "[%.%-]", "_") | ||
| 101 | end | ||
| 102 | |||
| 103 | ------------------------------------------------------------------------------ | ||
| 104 | |||
| 105 | local function bcsave_tail(fp, output, s) | ||
| 106 | local ok, err = fp:write(s) | ||
| 107 | if ok and output ~= "-" then ok, err = fp:close() end | ||
| 108 | check(ok, "cannot write ", output, ": ", err) | ||
| 41 | end | 109 | end |
| 42 | 110 | ||
| 43 | local function readstring(input) | 111 | local function bcsave_raw(output, s) |
| 44 | local f, err = loadstring(input) | 112 | local fp = savefile(output, "wb") |
| 45 | if not f then | 113 | bcsave_tail(fp, output, s) |
| 46 | io.stderr:write("luajit: ", err, "\n") | 114 | end |
| 47 | os.exit(1) | 115 | |
| 116 | local function bcsave_c(ctx, output, s) | ||
| 117 | local fp = savefile(output, "w") | ||
| 118 | if ctx.type == "c" then | ||
| 119 | fp:write(string.format([[ | ||
| 120 | #ifdef _cplusplus | ||
| 121 | extern "C" | ||
| 122 | #endif | ||
| 123 | #ifdef _WIN32 | ||
| 124 | __declspec(dllexport) | ||
| 125 | #endif | ||
| 126 | const char %s%s[] = { | ||
| 127 | ]], LJBC_PREFIX, ctx.modname)) | ||
| 128 | else | ||
| 129 | fp:write(string.format([[ | ||
| 130 | #define %s%s_SIZE %d | ||
| 131 | static const char %s%s[] = { | ||
| 132 | ]], LJBC_PREFIX, ctx.modname, #s, LJBC_PREFIX, ctx.modname)) | ||
| 48 | end | 133 | end |
| 49 | return f | 134 | local t, n, m = {}, 0, 0 |
| 135 | for i=1,#s do | ||
| 136 | local b = tostring(string.byte(s, i)) | ||
| 137 | m = m + #b + 1 | ||
| 138 | if m > 78 then | ||
| 139 | fp:write(table.concat(t, ",", 1, n), ",\n") | ||
| 140 | n, m = 0, #b + 1 | ||
| 141 | end | ||
| 142 | n = n + 1 | ||
| 143 | t[n] = b | ||
| 144 | end | ||
| 145 | bcsave_tail(fp, output, table.concat(t, ",", 1, n).."\n};\n") | ||
| 50 | end | 146 | end |
| 51 | 147 | ||
| 52 | local function savefile(name, mode) | 148 | local function bcsave_elfobj(ctx, output, s, ffi) |
| 53 | if name == "-" then return io.stdout end | 149 | ffi.cdef[[ |
| 54 | local fp, err = io.open(name, mode) | 150 | typedef struct { |
| 55 | if not fp then | 151 | uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7]; |
| 56 | io.stderr:write("luajit: cannot write ", err, "\n") | 152 | uint16_t type, machine; |
| 57 | os.exit(1) | 153 | uint32_t version; |
| 154 | uint32_t entry, phofs, shofs; | ||
| 155 | uint32_t flags; | ||
| 156 | uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx; | ||
| 157 | } ELF32header; | ||
| 158 | typedef struct { | ||
| 159 | uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7]; | ||
| 160 | uint16_t type, machine; | ||
| 161 | uint32_t version; | ||
| 162 | uint64_t entry, phofs, shofs; | ||
| 163 | uint32_t flags; | ||
| 164 | uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx; | ||
| 165 | } ELF64header; | ||
| 166 | typedef struct { | ||
| 167 | uint32_t name, type, flags, addr, ofs, size, link, info, align, entsize; | ||
| 168 | } ELF32sectheader; | ||
| 169 | typedef struct { | ||
| 170 | uint32_t name, type; | ||
| 171 | uint64_t flags, addr, ofs, size; | ||
| 172 | uint32_t link, info; | ||
| 173 | uint64_t align, entsize; | ||
| 174 | } ELF64sectheader; | ||
| 175 | typedef struct { | ||
| 176 | uint32_t name, value, size; | ||
| 177 | uint8_t info, other; | ||
| 178 | uint16_t sectidx; | ||
| 179 | } ELF32symbol; | ||
| 180 | typedef struct { | ||
| 181 | uint32_t name; | ||
| 182 | uint8_t info, other; | ||
| 183 | uint16_t sectidx; | ||
| 184 | uint64_t value, size; | ||
| 185 | } ELF64symbol; | ||
| 186 | typedef struct { | ||
| 187 | ELF32header hdr; | ||
| 188 | ELF32sectheader sect[6]; | ||
| 189 | ELF32symbol sym[2]; | ||
| 190 | uint8_t space[4096]; | ||
| 191 | } ELF32obj; | ||
| 192 | typedef struct { | ||
| 193 | ELF64header hdr; | ||
| 194 | ELF64sectheader sect[6]; | ||
| 195 | ELF64symbol sym[2]; | ||
| 196 | uint8_t space[4096]; | ||
| 197 | } ELF64obj; | ||
| 198 | ]] | ||
| 199 | local symname = LJBC_PREFIX..ctx.modname | ||
| 200 | local is64, isbe = false, false | ||
| 201 | if ctx.arch == "x64" then | ||
| 202 | is64 = true | ||
| 203 | elseif ctx.arch == "ppc" or ctx.arch == "ppcspe" then | ||
| 204 | isbe = true | ||
| 205 | end | ||
| 206 | |||
| 207 | -- Handle different host/target endianess. | ||
| 208 | local function f32(x) return x end | ||
| 209 | local f16, fofs = f32, f32 | ||
| 210 | if ffi.abi("be") ~= isbe then | ||
| 211 | f32 = bit.bswap | ||
| 212 | function f16(x) return bit.rshift(bit.bswap(x), 16) end | ||
| 213 | if is64 then | ||
| 214 | function fofs(x) return bit.bswap(x)*(2ll^32) end | ||
| 215 | else | ||
| 216 | fofs = f32 | ||
| 217 | end | ||
| 218 | end | ||
| 219 | |||
| 220 | -- Create ELF object and fill in header. | ||
| 221 | local o = ffi.new(is64 and "ELF64obj" or "ELF32obj") | ||
| 222 | local hdr = o.hdr | ||
| 223 | if ctx.os == "bsd" or ctx.os == "other" then -- Determine native hdr.eosabi. | ||
| 224 | local bf = assert(io.open("/bin/ls", "rb")) | ||
| 225 | local bs = bf:read(9) | ||
| 226 | bf:close() | ||
| 227 | ffi.copy(o, bs, 9) | ||
| 228 | check(hdr.emagic[0] == 127, "no support for writing native object files") | ||
| 229 | else | ||
| 230 | hdr.emagic = "\127ELF" | ||
| 231 | hdr.eosabi = ({ freebsd=9, netbsd=2, openbsd=12, solaris=6 })[ctx.os] or 0 | ||
| 232 | end | ||
| 233 | hdr.eclass = is64 and 2 or 1 | ||
| 234 | hdr.eendian = isbe and 2 or 1 | ||
| 235 | hdr.eversion = 1 | ||
| 236 | hdr.type = f16(1) | ||
| 237 | hdr.machine = f16(({ x86=3, x64=62, arm=40, ppc=20, ppcspe=20 })[ctx.arch]) | ||
| 238 | hdr.version = f32(1) | ||
| 239 | hdr.shofs = fofs(ffi.offsetof(o, "sect")) | ||
| 240 | hdr.ehsize = f16(ffi.sizeof(hdr)) | ||
| 241 | hdr.shentsize = f16(ffi.sizeof(o.sect[0])) | ||
| 242 | hdr.shnum = f16(6) | ||
| 243 | hdr.shstridx = f16(2) | ||
| 244 | |||
| 245 | -- Fill in sections and symbols. | ||
| 246 | local sofs, ofs = ffi.offsetof(o, "space"), 1 | ||
| 247 | for i,name in ipairs{ | ||
| 248 | ".symtab", ".shstrtab", ".strtab", ".rodata", ".note.GNU-stack", | ||
| 249 | } do | ||
| 250 | local sect = o.sect[i] | ||
| 251 | sect.align = fofs(1) | ||
| 252 | sect.name = f32(ofs) | ||
| 253 | ffi.copy(o.space+ofs, name) | ||
| 254 | ofs = ofs + #name+1 | ||
| 255 | end | ||
| 256 | o.sect[1].type = f32(2) -- .symtab | ||
| 257 | o.sect[1].link = f32(3) | ||
| 258 | o.sect[1].info = f32(1) | ||
| 259 | o.sect[1].align = fofs(8) | ||
| 260 | o.sect[1].ofs = fofs(ffi.offsetof(o, "sym")) | ||
| 261 | o.sect[1].entsize = fofs(ffi.sizeof(o.sym[0])) | ||
| 262 | o.sect[1].size = fofs(ffi.sizeof(o.sym)) | ||
| 263 | o.sym[1].name = f32(1) | ||
| 264 | o.sym[1].sectidx = f16(4) | ||
| 265 | o.sym[1].size = fofs(#s) | ||
| 266 | o.sym[1].info = 17 | ||
| 267 | o.sect[2].type = f32(3) -- .shstrtab | ||
| 268 | o.sect[2].ofs = fofs(sofs) | ||
| 269 | o.sect[2].size = fofs(ofs) | ||
| 270 | o.sect[3].type = f32(3) -- .strtab | ||
| 271 | o.sect[3].ofs = fofs(sofs + ofs) | ||
| 272 | o.sect[3].size = fofs(#symname+1) | ||
| 273 | ffi.copy(o.space+ofs+1, symname) | ||
| 274 | ofs = ofs + #symname + 2 | ||
| 275 | o.sect[4].type = f32(1) -- .rodata | ||
| 276 | o.sect[4].flags = fofs(2) | ||
| 277 | o.sect[4].ofs = fofs(sofs + ofs) | ||
| 278 | o.sect[4].size = fofs(#s) | ||
| 279 | o.sect[5].type = f32(1) -- .note.GNU-stack | ||
| 280 | o.sect[5].ofs = fofs(sofs + ofs + #s) | ||
| 281 | |||
| 282 | -- Write ELF object file. | ||
| 283 | local fp = savefile(output, "wb") | ||
| 284 | fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs)) | ||
| 285 | bcsave_tail(fp, output, s) | ||
| 286 | end | ||
| 287 | |||
| 288 | local function bcsave_peobj(ctx, output, s, ffi) | ||
| 289 | ffi.cdef[[ | ||
| 290 | typedef struct { | ||
| 291 | uint16_t arch, nsects; | ||
| 292 | uint32_t time, symtabofs, nsyms; | ||
| 293 | uint16_t opthdrsz, flags; | ||
| 294 | } PEheader; | ||
| 295 | typedef struct { | ||
| 296 | char name[8]; | ||
| 297 | uint32_t vsize, vaddr, size, ofs, relocofs, lineofs; | ||
| 298 | uint16_t nreloc, nline; | ||
| 299 | uint32_t flags; | ||
| 300 | } PEsection; | ||
| 301 | typedef struct __attribute((packed)) { | ||
| 302 | union { | ||
| 303 | char name[8]; | ||
| 304 | uint32_t nameref[2]; | ||
| 305 | }; | ||
| 306 | uint32_t value; | ||
| 307 | int16_t sect; | ||
| 308 | uint16_t type; | ||
| 309 | uint8_t scl, naux; | ||
| 310 | } PEsym; | ||
| 311 | typedef struct __attribute((packed)) { | ||
| 312 | uint32_t size; | ||
| 313 | uint16_t nreloc, nline; | ||
| 314 | uint32_t cksum; | ||
| 315 | uint16_t assoc; | ||
| 316 | uint8_t comdatsel, unused[3]; | ||
| 317 | } PEsymaux; | ||
| 318 | typedef struct { | ||
| 319 | PEheader hdr; | ||
| 320 | PEsection sect[2]; | ||
| 321 | // Must be an even number of symbol structs. | ||
| 322 | PEsym sym0; | ||
| 323 | PEsymaux sym0aux; | ||
| 324 | PEsym sym1; | ||
| 325 | PEsymaux sym1aux; | ||
| 326 | PEsym sym2; | ||
| 327 | PEsym sym3; | ||
| 328 | uint32_t strtabsize; | ||
| 329 | uint8_t space[4096]; | ||
| 330 | } PEobj; | ||
| 331 | ]] | ||
| 332 | local symname = LJBC_PREFIX..ctx.modname | ||
| 333 | local is64, isbe = false, false | ||
| 334 | if ctx.arch == "x86" then | ||
| 335 | symname = "_"..symname | ||
| 336 | elseif ctx.arch == "x64" then | ||
| 337 | is64 = true | ||
| 338 | elseif ctx.arch == "ppc" or ctx.arch == "ppcspe" then | ||
| 339 | isbe = true | ||
| 340 | end | ||
| 341 | local symexport = " /EXPORT:"..symname..",DATA " | ||
| 342 | |||
| 343 | -- Handle different host/target endianess. | ||
| 344 | local function f32(x) return x end | ||
| 345 | local f16 = f32 | ||
| 346 | if ffi.abi("be") ~= isbe then | ||
| 347 | f32 = bit.bswap | ||
| 348 | function f16(x) return bit.rshift(bit.bswap(x), 16) end | ||
| 349 | end | ||
| 350 | |||
| 351 | -- Create PE object and fill in header. | ||
| 352 | local o = ffi.new("PEobj") | ||
| 353 | local hdr = o.hdr | ||
| 354 | hdr.arch = f16(({ x86=0x14c, x64=0x8664, arm=0x1c0, ppc=0x1f1 })[ctx.arch]) | ||
| 355 | hdr.nsects = f16(2) | ||
| 356 | hdr.symtabofs = f32(ffi.offsetof(o, "sym0")) | ||
| 357 | hdr.nsyms = f32(6) | ||
| 358 | |||
| 359 | -- Fill in sections and symbols. | ||
| 360 | o.sect[0].name = ".drectve" | ||
| 361 | o.sect[0].size = f32(#symexport) | ||
| 362 | o.sect[0].flags = f32(0x00100a00) | ||
| 363 | o.sym0.sect = f16(1) | ||
| 364 | o.sym0.scl = 3 | ||
| 365 | o.sym0.name = ".drectve" | ||
| 366 | o.sym0.naux = 1 | ||
| 367 | o.sym0aux.size = f32(#symexport) | ||
| 368 | o.sect[1].name = ".rdata" | ||
| 369 | o.sect[1].size = f32(#s) | ||
| 370 | o.sect[1].flags = f32(0x40300040) | ||
| 371 | o.sym1.sect = f16(2) | ||
| 372 | o.sym1.scl = 3 | ||
| 373 | o.sym1.name = ".rdata" | ||
| 374 | o.sym1.naux = 1 | ||
| 375 | o.sym1aux.size = f32(#s) | ||
| 376 | o.sym2.sect = f16(2) | ||
| 377 | o.sym2.scl = 2 | ||
| 378 | o.sym2.nameref[1] = f32(4) | ||
| 379 | o.sym3.sect = f16(-1) | ||
| 380 | o.sym3.scl = 2 | ||
| 381 | o.sym3.value = f32(1) | ||
| 382 | o.sym3.name = "@feat.00" -- Mark as SafeSEH compliant. | ||
| 383 | ffi.copy(o.space, symname) | ||
| 384 | local ofs = #symname + 1 | ||
| 385 | o.strtabsize = f32(ofs + 4) | ||
| 386 | o.sect[0].ofs = f32(ffi.offsetof(o, "space") + ofs) | ||
| 387 | ffi.copy(o.space + ofs, symexport) | ||
| 388 | ofs = ofs + #symexport | ||
| 389 | o.sect[1].ofs = f32(ffi.offsetof(o, "space") + ofs) | ||
| 390 | |||
| 391 | -- Write PE object file. | ||
| 392 | local fp = savefile(output, "wb") | ||
| 393 | fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs)) | ||
| 394 | bcsave_tail(fp, output, s) | ||
| 395 | end | ||
| 396 | |||
| 397 | local function bcsave_machobj(ctx, output, s, ffi) | ||
| 398 | check(false, "NYI: no support for writing OSX object files") | ||
| 399 | end | ||
| 400 | |||
| 401 | local function bcsave_obj(ctx, output, s) | ||
| 402 | local ok, ffi = pcall(require, "ffi") | ||
| 403 | check(ok, "FFI library required to write this file type") | ||
| 404 | if ctx.os == "windows" then | ||
| 405 | return bcsave_peobj(ctx, output, s, ffi) | ||
| 406 | elseif ctx.os == "osx" then | ||
| 407 | return bcsave_machobj(ctx, output, s, ffi) | ||
| 408 | else | ||
| 409 | return bcsave_elfobj(ctx, output, s, ffi) | ||
| 58 | end | 410 | end |
| 59 | return fp | ||
| 60 | end | 411 | end |
| 61 | 412 | ||
| 62 | ------------------------------------------------------------------------------ | 413 | ------------------------------------------------------------------------------ |
| @@ -66,15 +417,23 @@ local function bclist(input, output) | |||
| 66 | require("jit.bc").dump(f, savefile(output, "w"), true) | 417 | require("jit.bc").dump(f, savefile(output, "w"), true) |
| 67 | end | 418 | end |
| 68 | 419 | ||
| 69 | local function bcsave(input, output, strip) | 420 | local function bcsave(ctx, input, output) |
| 70 | local f = readfile(input) | 421 | local f = readfile(input) |
| 71 | local s = string.dump(f, strip) | 422 | local s = string.dump(f, ctx.strip) |
| 72 | local fp = savefile(output, "wb") | 423 | local t = ctx.type |
| 73 | local ok, err = fp:write(s) | 424 | if not t then |
| 74 | if ok and output ~= "-" then ok, err = fp:close() end | 425 | t = detecttype(output) |
| 75 | if not ok then | 426 | ctx.type = t |
| 76 | io.stderr:write("luajit: cannot write ", arg[2], ": ", err, "\n") | 427 | end |
| 77 | os.exit(1) | 428 | if t == "raw" then |
| 429 | bcsave_raw(output, s) | ||
| 430 | else | ||
| 431 | if not ctx.modname then ctx.modname = detectmodname(input) end | ||
| 432 | if t == "obj" then | ||
| 433 | bcsave_obj(ctx, output, s) | ||
| 434 | else | ||
| 435 | bcsave_c(ctx, output, s) | ||
| 436 | end | ||
| 78 | end | 437 | end |
| 79 | end | 438 | end |
| 80 | 439 | ||
| @@ -82,27 +441,41 @@ local function docmd(...) | |||
| 82 | local arg = {...} | 441 | local arg = {...} |
| 83 | local n = 1 | 442 | local n = 1 |
| 84 | local list = false | 443 | local list = false |
| 85 | local strip = true | 444 | local ctx = { |
| 445 | strip = true, arch = jit.arch, os = string.lower(jit.os), | ||
| 446 | type = false, modname = false, | ||
| 447 | } | ||
| 86 | while n <= #arg do | 448 | while n <= #arg do |
| 87 | local a = arg[n] | 449 | local a = arg[n] |
| 88 | if type(a) == "string" and string.sub(a, 1, 1) == "-" and a ~= "-" then | 450 | if type(a) == "string" and string.sub(a, 1, 1) == "-" and a ~= "-" then |
| 89 | if a == "--" then table.remove(arg, n); break end | 451 | table.remove(arg, n) |
| 452 | if a == "--" then break end | ||
| 90 | for m=2,#a do | 453 | for m=2,#a do |
| 91 | local opt = string.sub(a, m, m) | 454 | local opt = string.sub(a, m, m) |
| 92 | if opt == "l" then | 455 | if opt == "l" then |
| 93 | list = true | 456 | list = true |
| 94 | elseif opt == "s" then | 457 | elseif opt == "s" then |
| 95 | strip = true | 458 | ctx.strip = true |
| 96 | elseif opt == "g" then | 459 | elseif opt == "g" then |
| 97 | strip = false | 460 | ctx.strip = false |
| 98 | elseif opt == "e" then | ||
| 99 | if n ~= 1 or #arg < 2 or m ~= #a then usage() end | ||
| 100 | arg[2] = readstring(arg[2]) | ||
| 101 | else | 461 | else |
| 102 | usage() | 462 | if arg[n] == nil or m ~= #a then usage() end |
| 463 | if opt == "e" then | ||
| 464 | if n ~= 1 then usage() end | ||
| 465 | arg[1] = check(loadstring(arg[1])) | ||
| 466 | elseif opt == "n" then | ||
| 467 | ctx.modname = checkmodname(table.remove(arg, n)) | ||
| 468 | elseif opt == "t" then | ||
| 469 | ctx.type = checkarg(table.remove(arg, n), map_type, "file type") | ||
| 470 | elseif opt == "a" then | ||
| 471 | ctx.arch = checkarg(table.remove(arg, n), map_arch, "architecture") | ||
| 472 | elseif opt == "o" then | ||
| 473 | ctx.os = checkarg(table.remove(arg, n), map_os, "OS name") | ||
| 474 | else | ||
| 475 | usage() | ||
| 476 | end | ||
| 103 | end | 477 | end |
| 104 | end | 478 | end |
| 105 | table.remove(arg, n) | ||
| 106 | else | 479 | else |
| 107 | n = n + 1 | 480 | n = n + 1 |
| 108 | end | 481 | end |
| @@ -112,7 +485,7 @@ local function docmd(...) | |||
| 112 | bclist(arg[1], arg[2] or "-") | 485 | bclist(arg[1], arg[2] or "-") |
| 113 | else | 486 | else |
| 114 | if #arg ~= 2 then usage() end | 487 | if #arg ~= 2 then usage() end |
| 115 | bcsave(arg[1], arg[2], strip) | 488 | bcsave(ctx, arg[1], arg[2]) |
| 116 | end | 489 | end |
| 117 | end | 490 | end |
| 118 | 491 | ||
