aboutsummaryrefslogtreecommitdiff
path: root/src/jit/bcsave.lua
diff options
context:
space:
mode:
Diffstat (limited to 'src/jit/bcsave.lua')
-rw-r--r--src/jit/bcsave.lua326
1 files changed, 152 insertions, 174 deletions
diff --git a/src/jit/bcsave.lua b/src/jit/bcsave.lua
index 11b0b853..7d19cb06 100644
--- a/src/jit/bcsave.lua
+++ b/src/jit/bcsave.lua
@@ -11,12 +11,16 @@
11------------------------------------------------------------------------------ 11------------------------------------------------------------------------------
12 12
13local jit = require("jit") 13local jit = require("jit")
14assert(jit.version_num == 20099, "LuaJIT core/library version mismatch") 14assert(jit.version_num == 20199, "LuaJIT core/library version mismatch")
15local bit = require("bit") 15local bit = require("bit")
16 16
17-- Symbol name prefix for LuaJIT bytecode. 17-- Symbol name prefix for LuaJIT bytecode.
18local LJBC_PREFIX = "luaJIT_BC_" 18local LJBC_PREFIX = "luaJIT_BC_"
19 19
20local type, assert = type, assert
21local format = string.format
22local tremove, tconcat = table.remove, table.concat
23
20------------------------------------------------------------------------------ 24------------------------------------------------------------------------------
21 25
22local function usage() 26local function usage()
@@ -25,15 +29,19 @@ Save LuaJIT bytecode: luajit -b[options] input output
25 -l Only list bytecode. 29 -l Only list bytecode.
26 -s Strip debug info (default). 30 -s Strip debug info (default).
27 -g Keep debug info. 31 -g Keep debug info.
32 -W Generate 32 bit (non-GC64) bytecode.
33 -X Generate 64 bit (GC64) bytecode.
34 -d Generate bytecode in deterministic manner.
28 -n name Set module name (default: auto-detect from input name). 35 -n name Set module name (default: auto-detect from input name).
29 -t type Set output file type (default: auto-detect from output name). 36 -t type Set output file type (default: auto-detect from output name).
30 -a arch Override architecture for object files (default: native). 37 -a arch Override architecture for object files (default: native).
31 -o os Override OS for object files (default: native). 38 -o os Override OS for object files (default: native).
39 -F name Override filename (default: input filename).
32 -e chunk Use chunk string as input. 40 -e chunk Use chunk string as input.
33 -- Stop handling options. 41 -- Stop handling options.
34 - Use stdin as input and/or stdout as output. 42 - Use stdin as input and/or stdout as output.
35 43
36File types: c h obj o raw (default) 44File types: c cc h obj o raw (default)
37]] 45]]
38 os.exit(1) 46 os.exit(1)
39end 47end
@@ -45,10 +53,23 @@ local function check(ok, ...)
45 os.exit(1) 53 os.exit(1)
46end 54end
47 55
48local function readfile(input) 56local function readfile(ctx, input)
49 if type(input) == "function" then return input end 57 if ctx.string then
50 if input == "-" then input = nil end 58 return check(loadstring(input, nil, ctx.mode))
51 return check(loadfile(input)) 59 elseif ctx.filename then
60 local data
61 if input == "-" then
62 data = io.stdin:read("*a")
63 else
64 local fp = assert(io.open(input, "rb"))
65 data = assert(fp:read("*a"))
66 assert(fp:close())
67 end
68 return check(load(data, ctx.filename, ctx.mode))
69 else
70 if input == "-" then input = nil end
71 return check(loadfile(input, ctx.mode))
72 end
52end 73end
53 74
54local function savefile(name, mode) 75local function savefile(name, mode)
@@ -56,15 +77,30 @@ local function savefile(name, mode)
56 return check(io.open(name, mode)) 77 return check(io.open(name, mode))
57end 78end
58 79
80local function set_stdout_binary(ffi)
81 ffi.cdef[[int _setmode(int fd, int mode);]]
82 ffi.C._setmode(1, 0x8000)
83end
84
59------------------------------------------------------------------------------ 85------------------------------------------------------------------------------
60 86
61local map_type = { 87local map_type = {
62 raw = "raw", c = "c", h = "h", o = "obj", obj = "obj", 88 raw = "raw", c = "c", cc = "c", h = "h", o = "obj", obj = "obj",
63} 89}
64 90
65local map_arch = { 91local map_arch = {
66 x86 = true, x64 = true, arm = true, ppc = true, ppcspe = true, 92 x86 = { e = "le", b = 32, m = 3, p = 0x14c, },
67 mips = true, mipsel = true, 93 x64 = { e = "le", b = 64, m = 62, p = 0x8664, },
94 arm = { e = "le", b = 32, m = 40, p = 0x1c0, },
95 arm64 = { e = "le", b = 64, m = 183, p = 0xaa64, },
96 arm64be = { e = "be", b = 64, m = 183, },
97 ppc = { e = "be", b = 32, m = 20, },
98 mips = { e = "be", b = 32, m = 8, f = 0x50001006, },
99 mipsel = { e = "le", b = 32, m = 8, f = 0x50001006, },
100 mips64 = { e = "be", b = 64, m = 8, f = 0x80000007, },
101 mips64el = { e = "le", b = 64, m = 8, f = 0x80000007, },
102 mips64r6 = { e = "be", b = 64, m = 8, f = 0xa0000407, },
103 mips64r6el = { e = "le", b = 64, m = 8, f = 0xa0000407, },
68} 104}
69 105
70local map_os = { 106local map_os = {
@@ -73,33 +109,33 @@ local map_os = {
73} 109}
74 110
75local function checkarg(str, map, err) 111local function checkarg(str, map, err)
76 str = string.lower(str) 112 str = str:lower()
77 local s = check(map[str], "unknown ", err) 113 local s = check(map[str], "unknown ", err)
78 return s == true and str or s 114 return type(s) == "string" and s or str
79end 115end
80 116
81local function detecttype(str) 117local function detecttype(str)
82 local ext = string.match(string.lower(str), "%.(%a+)$") 118 local ext = str:lower():match("%.(%a+)$")
83 return map_type[ext] or "raw" 119 return map_type[ext] or "raw"
84end 120end
85 121
86local function checkmodname(str) 122local function checkmodname(str)
87 check(string.match(str, "^[%w_.%-]+$"), "bad module name") 123 check(str:match("^[%w_.%-]+$"), "bad module name")
88 return string.gsub(str, "[%.%-]", "_") 124 return str:gsub("[%.%-]", "_")
89end 125end
90 126
91local function detectmodname(str) 127local function detectmodname(str)
92 if type(str) == "string" then 128 if type(str) == "string" then
93 local tail = string.match(str, "[^/\\]+$") 129 local tail = str:match("[^/\\]+$")
94 if tail then str = tail end 130 if tail then str = tail end
95 local head = string.match(str, "^(.*)%.[^.]*$") 131 local head = str:match("^(.*)%.[^.]*$")
96 if head then str = head end 132 if head then str = head end
97 str = string.match(str, "^[%w_.%-]+") 133 str = str:match("^[%w_.%-]+")
98 else 134 else
99 str = nil 135 str = nil
100 end 136 end
101 check(str, "cannot derive module name, use -n name") 137 check(str, "cannot derive module name, use -n name")
102 return string.gsub(str, "[%.%-]", "_") 138 return str:gsub("[%.%-]", "_")
103end 139end
104 140
105------------------------------------------------------------------------------ 141------------------------------------------------------------------------------
@@ -111,6 +147,11 @@ local function bcsave_tail(fp, output, s)
111end 147end
112 148
113local function bcsave_raw(output, s) 149local function bcsave_raw(output, s)
150 if output == "-" and jit.os == "Windows" then
151 local ok, ffi = pcall(require, "ffi")
152 check(ok, "FFI library required to write binary file to stdout")
153 set_stdout_binary(ffi)
154 end
114 local fp = savefile(output, "wb") 155 local fp = savefile(output, "wb")
115 bcsave_tail(fp, output, s) 156 bcsave_tail(fp, output, s)
116end 157end
@@ -118,19 +159,21 @@ end
118local function bcsave_c(ctx, output, s) 159local function bcsave_c(ctx, output, s)
119 local fp = savefile(output, "w") 160 local fp = savefile(output, "w")
120 if ctx.type == "c" then 161 if ctx.type == "c" then
121 fp:write(string.format([[ 162 fp:write(format([[
122#ifdef __cplusplus 163#ifdef __cplusplus
123extern "C" 164extern "C"
124#endif 165#endif
125#ifdef _WIN32 166#ifdef _WIN32
126__declspec(dllexport) 167__declspec(dllexport)
168#elif (defined(__ELF__) || defined(__MACH__) || defined(__psp2__)) && !((defined(__sun__) && defined(__svr4__)) || defined(__CELLOS_LV2__))
169__attribute__((visibility("default")))
127#endif 170#endif
128const char %s%s[] = { 171const unsigned char %s%s[] = {
129]], LJBC_PREFIX, ctx.modname)) 172]], LJBC_PREFIX, ctx.modname))
130 else 173 else
131 fp:write(string.format([[ 174 fp:write(format([[
132#define %s%s_SIZE %d 175#define %s%s_SIZE %d
133static const char %s%s[] = { 176static const unsigned char %s%s[] = {
134]], LJBC_PREFIX, ctx.modname, #s, LJBC_PREFIX, ctx.modname)) 177]], LJBC_PREFIX, ctx.modname, #s, LJBC_PREFIX, ctx.modname))
135 end 178 end
136 local t, n, m = {}, 0, 0 179 local t, n, m = {}, 0, 0
@@ -138,13 +181,13 @@ static const char %s%s[] = {
138 local b = tostring(string.byte(s, i)) 181 local b = tostring(string.byte(s, i))
139 m = m + #b + 1 182 m = m + #b + 1
140 if m > 78 then 183 if m > 78 then
141 fp:write(table.concat(t, ",", 1, n), ",\n") 184 fp:write(tconcat(t, ",", 1, n), ",\n")
142 n, m = 0, #b + 1 185 n, m = 0, #b + 1
143 end 186 end
144 n = n + 1 187 n = n + 1
145 t[n] = b 188 t[n] = b
146 end 189 end
147 bcsave_tail(fp, output, table.concat(t, ",", 1, n).."\n};\n") 190 bcsave_tail(fp, output, tconcat(t, ",", 1, n).."\n};\n")
148end 191end
149 192
150local function bcsave_elfobj(ctx, output, s, ffi) 193local function bcsave_elfobj(ctx, output, s, ffi)
@@ -199,12 +242,8 @@ typedef struct {
199} ELF64obj; 242} ELF64obj;
200]] 243]]
201 local symname = LJBC_PREFIX..ctx.modname 244 local symname = LJBC_PREFIX..ctx.modname
202 local is64, isbe = false, false 245 local ai = assert(map_arch[ctx.arch])
203 if ctx.arch == "x64" then 246 local is64, isbe = ai.b == 64, ai.e == "be"
204 is64 = true
205 elseif ctx.arch == "ppc" or ctx.arch == "ppcspe" or ctx.arch == "mips" then
206 isbe = true
207 end
208 247
209 -- Handle different host/target endianess. 248 -- Handle different host/target endianess.
210 local function f32(x) return x end 249 local function f32(x) return x end
@@ -237,10 +276,8 @@ typedef struct {
237 hdr.eendian = isbe and 2 or 1 276 hdr.eendian = isbe and 2 or 1
238 hdr.eversion = 1 277 hdr.eversion = 1
239 hdr.type = f16(1) 278 hdr.type = f16(1)
240 hdr.machine = f16(({ x86=3, x64=62, arm=40, ppc=20, ppcspe=20, mips=8, mipsel=8 })[ctx.arch]) 279 hdr.machine = f16(ai.m)
241 if ctx.arch == "mips" or ctx.arch == "mipsel" then 280 hdr.flags = f32(ai.f or 0)
242 hdr.flags = f32(0x50001006)
243 end
244 hdr.version = f32(1) 281 hdr.version = f32(1)
245 hdr.shofs = fofs(ffi.offsetof(o, "sect")) 282 hdr.shofs = fofs(ffi.offsetof(o, "sect"))
246 hdr.ehsize = f16(ffi.sizeof(hdr)) 283 hdr.ehsize = f16(ffi.sizeof(hdr))
@@ -336,12 +373,8 @@ typedef struct {
336} PEobj; 373} PEobj;
337]] 374]]
338 local symname = LJBC_PREFIX..ctx.modname 375 local symname = LJBC_PREFIX..ctx.modname
339 local is64 = false 376 local ai = assert(map_arch[ctx.arch])
340 if ctx.arch == "x86" then 377 local is64 = ai.b == 64
341 symname = "_"..symname
342 elseif ctx.arch == "x64" then
343 is64 = true
344 end
345 local symexport = " /EXPORT:"..symname..",DATA " 378 local symexport = " /EXPORT:"..symname..",DATA "
346 379
347 -- The file format is always little-endian. Swap if the host is big-endian. 380 -- The file format is always little-endian. Swap if the host is big-endian.
@@ -355,7 +388,7 @@ typedef struct {
355 -- Create PE object and fill in header. 388 -- Create PE object and fill in header.
356 local o = ffi.new("PEobj") 389 local o = ffi.new("PEobj")
357 local hdr = o.hdr 390 local hdr = o.hdr
358 hdr.arch = f16(({ x86=0x14c, x64=0x8664, arm=0x1c0, ppc=0x1f2, mips=0x366, mipsel=0x366 })[ctx.arch]) 391 hdr.arch = f16(assert(ai.p))
359 hdr.nsects = f16(2) 392 hdr.nsects = f16(2)
360 hdr.symtabofs = f32(ffi.offsetof(o, "sym0")) 393 hdr.symtabofs = f32(ffi.offsetof(o, "sym0"))
361 hdr.nsyms = f32(6) 394 hdr.nsyms = f32(6)
@@ -411,23 +444,11 @@ typedef struct
411typedef struct { 444typedef struct {
412 uint32_t cmd, cmdsize; 445 uint32_t cmd, cmdsize;
413 char segname[16]; 446 char segname[16];
414 uint32_t vmaddr, vmsize, fileoff, filesize;
415 uint32_t maxprot, initprot, nsects, flags;
416} mach_segment_command;
417typedef struct {
418 uint32_t cmd, cmdsize;
419 char segname[16];
420 uint64_t vmaddr, vmsize, fileoff, filesize; 447 uint64_t vmaddr, vmsize, fileoff, filesize;
421 uint32_t maxprot, initprot, nsects, flags; 448 uint32_t maxprot, initprot, nsects, flags;
422} mach_segment_command_64; 449} mach_segment_command_64;
423typedef struct { 450typedef struct {
424 char sectname[16], segname[16]; 451 char sectname[16], segname[16];
425 uint32_t addr, size;
426 uint32_t offset, align, reloff, nreloc, flags;
427 uint32_t reserved1, reserved2;
428} mach_section;
429typedef struct {
430 char sectname[16], segname[16];
431 uint64_t addr, size; 452 uint64_t addr, size;
432 uint32_t offset, align, reloff, nreloc, flags; 453 uint32_t offset, align, reloff, nreloc, flags;
433 uint32_t reserved1, reserved2, reserved3; 454 uint32_t reserved1, reserved2, reserved3;
@@ -438,130 +459,78 @@ typedef struct {
438typedef struct { 459typedef struct {
439 int32_t strx; 460 int32_t strx;
440 uint8_t type, sect; 461 uint8_t type, sect;
441 int16_t desc;
442 uint32_t value;
443} mach_nlist;
444typedef struct {
445 uint32_t strx;
446 uint8_t type, sect;
447 uint16_t desc; 462 uint16_t desc;
448 uint64_t value; 463 uint64_t value;
449} mach_nlist_64; 464} mach_nlist_64;
450typedef struct
451{
452 uint32_t magic, nfat_arch;
453} mach_fat_header;
454typedef struct
455{
456 uint32_t cputype, cpusubtype, offset, size, align;
457} mach_fat_arch;
458typedef struct {
459 struct {
460 mach_header hdr;
461 mach_segment_command seg;
462 mach_section sec;
463 mach_symtab_command sym;
464 } arch[1];
465 mach_nlist sym_entry;
466 uint8_t space[4096];
467} mach_obj;
468typedef struct { 465typedef struct {
469 struct { 466 mach_header_64 hdr;
470 mach_header_64 hdr; 467 mach_segment_command_64 seg;
471 mach_segment_command_64 seg; 468 mach_section_64 sec;
472 mach_section_64 sec; 469 mach_symtab_command sym;
473 mach_symtab_command sym;
474 } arch[1];
475 mach_nlist_64 sym_entry;
476 uint8_t space[4096];
477} mach_obj_64; 470} mach_obj_64;
478typedef struct { 471typedef struct {
479 mach_fat_header fat; 472 mach_nlist_64 sym_entry;
480 mach_fat_arch fat_arch[4];
481 struct {
482 mach_header hdr;
483 mach_segment_command seg;
484 mach_section sec;
485 mach_symtab_command sym;
486 } arch[4];
487 mach_nlist sym_entry;
488 uint8_t space[4096]; 473 uint8_t space[4096];
489} mach_fat_obj; 474} mach_obj_64_tail;
490]] 475]]
491 local symname = '_'..LJBC_PREFIX..ctx.modname 476 local symname = '_'..LJBC_PREFIX..ctx.modname
492 local isfat, is64, align, mobj = false, false, 4, "mach_obj" 477 local cputype, cpusubtype = 0x01000007, 3
493 if ctx.arch == "x64" then 478 if ctx.arch ~= "x64" then
494 is64, align, mobj = true, 8, "mach_obj_64" 479 check(ctx.arch == "arm64", "unsupported architecture for OSX")
495 elseif ctx.arch == "arm" then 480 cputype, cpusubtype = 0x0100000c, 0
496 isfat, mobj = true, "mach_fat_obj"
497 else
498 check(ctx.arch == "x86", "unsupported architecture for OSX")
499 end 481 end
500 local function aligned(v, a) return bit.band(v+a-1, -a) end 482 local function aligned(v, a) return bit.band(v+a-1, -a) end
501 local be32 = bit.bswap -- Mach-O FAT is BE, supported archs are LE.
502 483
503 -- Create Mach-O object and fill in header. 484 -- Create Mach-O object and fill in header.
504 local o = ffi.new(mobj) 485 local o = ffi.new("mach_obj_64")
505 local mach_size = aligned(ffi.offsetof(o, "space")+#symname+2, align) 486 local t = ffi.new("mach_obj_64_tail")
506 local cputype = ({ x86={7}, x64={0x01000007}, arm={7,12,12,12} })[ctx.arch] 487 local ofs_bc = ffi.sizeof(o)
507 local cpusubtype = ({ x86={3}, x64={3}, arm={3,6,9,11} })[ctx.arch] 488 local sz_bc = aligned(#s, 8)
508 if isfat then 489 local ofs_sym = ofs_bc + sz_bc
509 o.fat.magic = be32(0xcafebabe)
510 o.fat.nfat_arch = be32(#cpusubtype)
511 end
512 490
513 -- Fill in sections and symbols. 491 -- Fill in sections and symbols.
514 for i=0,#cpusubtype-1 do 492 o.hdr.magic = 0xfeedfacf
515 local ofs = 0 493 o.hdr.cputype = cputype
516 if isfat then 494 o.hdr.cpusubtype = cpusubtype
517 local a = o.fat_arch[i] 495 o.hdr.filetype = 1
518 a.cputype = be32(cputype[i+1]) 496 o.hdr.ncmds = 2
519 a.cpusubtype = be32(cpusubtype[i+1]) 497 o.hdr.sizeofcmds = ffi.sizeof(o.seg)+ffi.sizeof(o.sec)+ffi.sizeof(o.sym)
520 -- Subsequent slices overlap each other to share data. 498 o.seg.cmd = 0x19
521 ofs = ffi.offsetof(o, "arch") + i*ffi.sizeof(o.arch[0]) 499 o.seg.cmdsize = ffi.sizeof(o.seg)+ffi.sizeof(o.sec)
522 a.offset = be32(ofs) 500 o.seg.vmsize = #s
523 a.size = be32(mach_size-ofs+#s) 501 o.seg.fileoff = ofs_bc
524 end 502 o.seg.filesize = #s
525 local a = o.arch[i] 503 o.seg.maxprot = 1
526 a.hdr.magic = is64 and 0xfeedfacf or 0xfeedface 504 o.seg.initprot = 1
527 a.hdr.cputype = cputype[i+1] 505 o.seg.nsects = 1
528 a.hdr.cpusubtype = cpusubtype[i+1] 506 ffi.copy(o.sec.sectname, "__data")
529 a.hdr.filetype = 1 507 ffi.copy(o.sec.segname, "__DATA")
530 a.hdr.ncmds = 2 508 o.sec.size = #s
531 a.hdr.sizeofcmds = ffi.sizeof(a.seg)+ffi.sizeof(a.sec)+ffi.sizeof(a.sym) 509 o.sec.offset = ofs_bc
532 a.seg.cmd = is64 and 0x19 or 0x1 510 o.sym.cmd = 2
533 a.seg.cmdsize = ffi.sizeof(a.seg)+ffi.sizeof(a.sec) 511 o.sym.cmdsize = ffi.sizeof(o.sym)
534 a.seg.vmsize = #s 512 o.sym.symoff = ofs_sym
535 a.seg.fileoff = mach_size-ofs 513 o.sym.nsyms = 1
536 a.seg.filesize = #s 514 o.sym.stroff = ofs_sym + ffi.offsetof(t, "space")
537 a.seg.maxprot = 1 515 o.sym.strsize = aligned(#symname+2, 8)
538 a.seg.initprot = 1 516 t.sym_entry.type = 0xf
539 a.seg.nsects = 1 517 t.sym_entry.sect = 1
540 ffi.copy(a.sec.sectname, "__data") 518 t.sym_entry.strx = 1
541 ffi.copy(a.sec.segname, "__DATA") 519 ffi.copy(t.space+1, symname)
542 a.sec.size = #s
543 a.sec.offset = mach_size-ofs
544 a.sym.cmd = 2
545 a.sym.cmdsize = ffi.sizeof(a.sym)
546 a.sym.symoff = ffi.offsetof(o, "sym_entry")-ofs
547 a.sym.nsyms = 1
548 a.sym.stroff = ffi.offsetof(o, "sym_entry")+ffi.sizeof(o.sym_entry)-ofs
549 a.sym.strsize = aligned(#symname+2, align)
550 end
551 o.sym_entry.type = 0xf
552 o.sym_entry.sect = 1
553 o.sym_entry.strx = 1
554 ffi.copy(o.space+1, symname)
555 520
556 -- Write Mach-O object file. 521 -- Write Mach-O object file.
557 local fp = savefile(output, "wb") 522 local fp = savefile(output, "wb")
558 fp:write(ffi.string(o, mach_size)) 523 fp:write(ffi.string(o, ofs_bc))
559 bcsave_tail(fp, output, s) 524 fp:write(s, ("\0"):rep(sz_bc - #s))
525 bcsave_tail(fp, output, ffi.string(t, ffi.offsetof(t, "space") + o.sym.strsize))
560end 526end
561 527
562local function bcsave_obj(ctx, output, s) 528local function bcsave_obj(ctx, output, s)
563 local ok, ffi = pcall(require, "ffi") 529 local ok, ffi = pcall(require, "ffi")
564 check(ok, "FFI library required to write this file type") 530 check(ok, "FFI library required to write this file type")
531 if output == "-" and jit.os == "Windows" then
532 set_stdout_binary(ffi)
533 end
565 if ctx.os == "windows" then 534 if ctx.os == "windows" then
566 return bcsave_peobj(ctx, output, s, ffi) 535 return bcsave_peobj(ctx, output, s, ffi)
567 elseif ctx.os == "osx" then 536 elseif ctx.os == "osx" then
@@ -573,14 +542,14 @@ end
573 542
574------------------------------------------------------------------------------ 543------------------------------------------------------------------------------
575 544
576local function bclist(input, output) 545local function bclist(ctx, input, output)
577 local f = readfile(input) 546 local f = readfile(ctx, input)
578 require("jit.bc").dump(f, savefile(output, "w"), true) 547 require("jit.bc").dump(f, savefile(output, "w"), true)
579end 548end
580 549
581local function bcsave(ctx, input, output) 550local function bcsave(ctx, input, output)
582 local f = readfile(input) 551 local f = readfile(ctx, input)
583 local s = string.dump(f, ctx.strip) 552 local s = string.dump(f, ctx.mode)
584 local t = ctx.type 553 local t = ctx.type
585 if not t then 554 if not t then
586 t = detecttype(output) 555 t = detecttype(output)
@@ -603,35 +572,43 @@ local function docmd(...)
603 local n = 1 572 local n = 1
604 local list = false 573 local list = false
605 local ctx = { 574 local ctx = {
606 strip = true, arch = jit.arch, os = string.lower(jit.os), 575 mode = "bt", arch = jit.arch, os = jit.os:lower(),
607 type = false, modname = false, 576 type = false, modname = false, string = false,
608 } 577 }
578 local strip = "s"
579 local gc64 = ""
609 while n <= #arg do 580 while n <= #arg do
610 local a = arg[n] 581 local a = arg[n]
611 if type(a) == "string" and string.sub(a, 1, 1) == "-" and a ~= "-" then 582 if type(a) == "string" and a:sub(1, 1) == "-" and a ~= "-" then
612 table.remove(arg, n) 583 tremove(arg, n)
613 if a == "--" then break end 584 if a == "--" then break end
614 for m=2,#a do 585 for m=2,#a do
615 local opt = string.sub(a, m, m) 586 local opt = a:sub(m, m)
616 if opt == "l" then 587 if opt == "l" then
617 list = true 588 list = true
618 elseif opt == "s" then 589 elseif opt == "s" then
619 ctx.strip = true 590 strip = "s"
620 elseif opt == "g" then 591 elseif opt == "g" then
621 ctx.strip = false 592 strip = ""
593 elseif opt == "W" or opt == "X" then
594 gc64 = opt
595 elseif opt == "d" then
596 ctx.mode = ctx.mode .. opt
622 else 597 else
623 if arg[n] == nil or m ~= #a then usage() end 598 if arg[n] == nil or m ~= #a then usage() end
624 if opt == "e" then 599 if opt == "e" then
625 if n ~= 1 then usage() end 600 if n ~= 1 then usage() end
626 arg[1] = check(loadstring(arg[1])) 601 ctx.string = true
627 elseif opt == "n" then 602 elseif opt == "n" then
628 ctx.modname = checkmodname(table.remove(arg, n)) 603 ctx.modname = checkmodname(tremove(arg, n))
629 elseif opt == "t" then 604 elseif opt == "t" then
630 ctx.type = checkarg(table.remove(arg, n), map_type, "file type") 605 ctx.type = checkarg(tremove(arg, n), map_type, "file type")
631 elseif opt == "a" then 606 elseif opt == "a" then
632 ctx.arch = checkarg(table.remove(arg, n), map_arch, "architecture") 607 ctx.arch = checkarg(tremove(arg, n), map_arch, "architecture")
633 elseif opt == "o" then 608 elseif opt == "o" then
634 ctx.os = checkarg(table.remove(arg, n), map_os, "OS name") 609 ctx.os = checkarg(tremove(arg, n), map_os, "OS name")
610 elseif opt == "F" then
611 ctx.filename = "@"..tremove(arg, n)
635 else 612 else
636 usage() 613 usage()
637 end 614 end
@@ -641,9 +618,10 @@ local function docmd(...)
641 n = n + 1 618 n = n + 1
642 end 619 end
643 end 620 end
621 ctx.mode = ctx.mode .. strip .. gc64
644 if list then 622 if list then
645 if #arg == 0 or #arg > 2 then usage() end 623 if #arg == 0 or #arg > 2 then usage() end
646 bclist(arg[1], arg[2] or "-") 624 bclist(ctx, arg[1], arg[2] or "-")
647 else 625 else
648 if #arg ~= 2 then usage() end 626 if #arg ~= 2 then usage() end
649 bcsave(ctx, arg[1], arg[2]) 627 bcsave(ctx, arg[1], arg[2])
@@ -653,7 +631,7 @@ end
653------------------------------------------------------------------------------ 631------------------------------------------------------------------------------
654 632
655-- Public module functions. 633-- Public module functions.
656module(...) 634return {
657 635 start = docmd -- Process -b command line option.
658start = docmd -- Process -b command line option. 636}
659 637