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.lua119
1 files changed, 69 insertions, 50 deletions
diff --git a/src/jit/bcsave.lua b/src/jit/bcsave.lua
index 086d5f88..6227d136 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 == 20005, "LuaJIT core/library version mismatch") 14assert(jit.version_num == 20100, "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()
@@ -56,6 +60,11 @@ local function savefile(name, mode)
56 return check(io.open(name, mode)) 60 return check(io.open(name, mode))
57end 61end
58 62
63local function set_stdout_binary(ffi)
64 ffi.cdef[[int _setmode(int fd, int mode);]]
65 ffi.C._setmode(1, 0x8000)
66end
67
59------------------------------------------------------------------------------ 68------------------------------------------------------------------------------
60 69
61local map_type = { 70local map_type = {
@@ -63,8 +72,18 @@ local map_type = {
63} 72}
64 73
65local map_arch = { 74local map_arch = {
66 x86 = true, x64 = true, arm = true, ppc = true, ppcspe = true, 75 x86 = { e = "le", b = 32, m = 3, p = 0x14c, },
67 mips = true, mipsel = true, 76 x64 = { e = "le", b = 64, m = 62, p = 0x8664, },
77 arm = { e = "le", b = 32, m = 40, p = 0x1c0, },
78 arm64 = { e = "le", b = 64, m = 183, p = 0xaa64, },
79 arm64be = { e = "be", b = 64, m = 183, },
80 ppc = { e = "be", b = 32, m = 20, },
81 mips = { e = "be", b = 32, m = 8, f = 0x50001006, },
82 mipsel = { e = "le", b = 32, m = 8, f = 0x50001006, },
83 mips64 = { e = "be", b = 64, m = 8, f = 0x80000007, },
84 mips64el = { e = "le", b = 64, m = 8, f = 0x80000007, },
85 mips64r6 = { e = "be", b = 64, m = 8, f = 0xa0000407, },
86 mips64r6el = { e = "le", b = 64, m = 8, f = 0xa0000407, },
68} 87}
69 88
70local map_os = { 89local map_os = {
@@ -73,33 +92,33 @@ local map_os = {
73} 92}
74 93
75local function checkarg(str, map, err) 94local function checkarg(str, map, err)
76 str = string.lower(str) 95 str = str:lower()
77 local s = check(map[str], "unknown ", err) 96 local s = check(map[str], "unknown ", err)
78 return s == true and str or s 97 return type(s) == "string" and s or str
79end 98end
80 99
81local function detecttype(str) 100local function detecttype(str)
82 local ext = string.match(string.lower(str), "%.(%a+)$") 101 local ext = str:lower():match("%.(%a+)$")
83 return map_type[ext] or "raw" 102 return map_type[ext] or "raw"
84end 103end
85 104
86local function checkmodname(str) 105local function checkmodname(str)
87 check(string.match(str, "^[%w_.%-]+$"), "bad module name") 106 check(str:match("^[%w_.%-]+$"), "bad module name")
88 return string.gsub(str, "[%.%-]", "_") 107 return str:gsub("[%.%-]", "_")
89end 108end
90 109
91local function detectmodname(str) 110local function detectmodname(str)
92 if type(str) == "string" then 111 if type(str) == "string" then
93 local tail = string.match(str, "[^/\\]+$") 112 local tail = str:match("[^/\\]+$")
94 if tail then str = tail end 113 if tail then str = tail end
95 local head = string.match(str, "^(.*)%.[^.]*$") 114 local head = str:match("^(.*)%.[^.]*$")
96 if head then str = head end 115 if head then str = head end
97 str = string.match(str, "^[%w_.%-]+") 116 str = str:match("^[%w_.%-]+")
98 else 117 else
99 str = nil 118 str = nil
100 end 119 end
101 check(str, "cannot derive module name, use -n name") 120 check(str, "cannot derive module name, use -n name")
102 return string.gsub(str, "[%.%-]", "_") 121 return str:gsub("[%.%-]", "_")
103end 122end
104 123
105------------------------------------------------------------------------------ 124------------------------------------------------------------------------------
@@ -111,6 +130,11 @@ local function bcsave_tail(fp, output, s)
111end 130end
112 131
113local function bcsave_raw(output, s) 132local function bcsave_raw(output, s)
133 if output == "-" and jit.os == "Windows" then
134 local ok, ffi = pcall(require, "ffi")
135 check(ok, "FFI library required to write binary file to stdout")
136 set_stdout_binary(ffi)
137 end
114 local fp = savefile(output, "wb") 138 local fp = savefile(output, "wb")
115 bcsave_tail(fp, output, s) 139 bcsave_tail(fp, output, s)
116end 140end
@@ -118,19 +142,19 @@ end
118local function bcsave_c(ctx, output, s) 142local function bcsave_c(ctx, output, s)
119 local fp = savefile(output, "w") 143 local fp = savefile(output, "w")
120 if ctx.type == "c" then 144 if ctx.type == "c" then
121 fp:write(string.format([[ 145 fp:write(format([[
122#ifdef __cplusplus 146#ifdef __cplusplus
123extern "C" 147extern "C"
124#endif 148#endif
125#ifdef _WIN32 149#ifdef _WIN32
126__declspec(dllexport) 150__declspec(dllexport)
127#endif 151#endif
128const char %s%s[] = { 152const unsigned char %s%s[] = {
129]], LJBC_PREFIX, ctx.modname)) 153]], LJBC_PREFIX, ctx.modname))
130 else 154 else
131 fp:write(string.format([[ 155 fp:write(format([[
132#define %s%s_SIZE %d 156#define %s%s_SIZE %d
133static const char %s%s[] = { 157static const unsigned char %s%s[] = {
134]], LJBC_PREFIX, ctx.modname, #s, LJBC_PREFIX, ctx.modname)) 158]], LJBC_PREFIX, ctx.modname, #s, LJBC_PREFIX, ctx.modname))
135 end 159 end
136 local t, n, m = {}, 0, 0 160 local t, n, m = {}, 0, 0
@@ -138,13 +162,13 @@ static const char %s%s[] = {
138 local b = tostring(string.byte(s, i)) 162 local b = tostring(string.byte(s, i))
139 m = m + #b + 1 163 m = m + #b + 1
140 if m > 78 then 164 if m > 78 then
141 fp:write(table.concat(t, ",", 1, n), ",\n") 165 fp:write(tconcat(t, ",", 1, n), ",\n")
142 n, m = 0, #b + 1 166 n, m = 0, #b + 1
143 end 167 end
144 n = n + 1 168 n = n + 1
145 t[n] = b 169 t[n] = b
146 end 170 end
147 bcsave_tail(fp, output, table.concat(t, ",", 1, n).."\n};\n") 171 bcsave_tail(fp, output, tconcat(t, ",", 1, n).."\n};\n")
148end 172end
149 173
150local function bcsave_elfobj(ctx, output, s, ffi) 174local function bcsave_elfobj(ctx, output, s, ffi)
@@ -199,12 +223,8 @@ typedef struct {
199} ELF64obj; 223} ELF64obj;
200]] 224]]
201 local symname = LJBC_PREFIX..ctx.modname 225 local symname = LJBC_PREFIX..ctx.modname
202 local is64, isbe = false, false 226 local ai = assert(map_arch[ctx.arch])
203 if ctx.arch == "x64" then 227 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 228
209 -- Handle different host/target endianess. 229 -- Handle different host/target endianess.
210 local function f32(x) return x end 230 local function f32(x) return x end
@@ -237,10 +257,8 @@ typedef struct {
237 hdr.eendian = isbe and 2 or 1 257 hdr.eendian = isbe and 2 or 1
238 hdr.eversion = 1 258 hdr.eversion = 1
239 hdr.type = f16(1) 259 hdr.type = f16(1)
240 hdr.machine = f16(({ x86=3, x64=62, arm=40, ppc=20, ppcspe=20, mips=8, mipsel=8 })[ctx.arch]) 260 hdr.machine = f16(ai.m)
241 if ctx.arch == "mips" or ctx.arch == "mipsel" then 261 hdr.flags = f32(ai.f or 0)
242 hdr.flags = f32(0x50001006)
243 end
244 hdr.version = f32(1) 262 hdr.version = f32(1)
245 hdr.shofs = fofs(ffi.offsetof(o, "sect")) 263 hdr.shofs = fofs(ffi.offsetof(o, "sect"))
246 hdr.ehsize = f16(ffi.sizeof(hdr)) 264 hdr.ehsize = f16(ffi.sizeof(hdr))
@@ -336,12 +354,8 @@ typedef struct {
336} PEobj; 354} PEobj;
337]] 355]]
338 local symname = LJBC_PREFIX..ctx.modname 356 local symname = LJBC_PREFIX..ctx.modname
339 local is64 = false 357 local ai = assert(map_arch[ctx.arch])
340 if ctx.arch == "x86" then 358 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 " 359 local symexport = " /EXPORT:"..symname..",DATA "
346 360
347 -- The file format is always little-endian. Swap if the host is big-endian. 361 -- The file format is always little-endian. Swap if the host is big-endian.
@@ -355,7 +369,7 @@ typedef struct {
355 -- Create PE object and fill in header. 369 -- Create PE object and fill in header.
356 local o = ffi.new("PEobj") 370 local o = ffi.new("PEobj")
357 local hdr = o.hdr 371 local hdr = o.hdr
358 hdr.arch = f16(({ x86=0x14c, x64=0x8664, arm=0x1c0, ppc=0x1f2, mips=0x366, mipsel=0x366 })[ctx.arch]) 372 hdr.arch = f16(assert(ai.p))
359 hdr.nsects = f16(2) 373 hdr.nsects = f16(2)
360 hdr.symtabofs = f32(ffi.offsetof(o, "sym0")) 374 hdr.symtabofs = f32(ffi.offsetof(o, "sym0"))
361 hdr.nsyms = f32(6) 375 hdr.nsyms = f32(6)
@@ -477,13 +491,13 @@ typedef struct {
477} mach_obj_64; 491} mach_obj_64;
478typedef struct { 492typedef struct {
479 mach_fat_header fat; 493 mach_fat_header fat;
480 mach_fat_arch fat_arch[4]; 494 mach_fat_arch fat_arch[2];
481 struct { 495 struct {
482 mach_header hdr; 496 mach_header hdr;
483 mach_segment_command seg; 497 mach_segment_command seg;
484 mach_section sec; 498 mach_section sec;
485 mach_symtab_command sym; 499 mach_symtab_command sym;
486 } arch[4]; 500 } arch[2];
487 mach_nlist sym_entry; 501 mach_nlist sym_entry;
488 uint8_t space[4096]; 502 uint8_t space[4096];
489} mach_fat_obj; 503} mach_fat_obj;
@@ -494,6 +508,8 @@ typedef struct {
494 is64, align, mobj = true, 8, "mach_obj_64" 508 is64, align, mobj = true, 8, "mach_obj_64"
495 elseif ctx.arch == "arm" then 509 elseif ctx.arch == "arm" then
496 isfat, mobj = true, "mach_fat_obj" 510 isfat, mobj = true, "mach_fat_obj"
511 elseif ctx.arch == "arm64" then
512 is64, align, isfat, mobj = true, 8, true, "mach_fat_obj"
497 else 513 else
498 check(ctx.arch == "x86", "unsupported architecture for OSX") 514 check(ctx.arch == "x86", "unsupported architecture for OSX")
499 end 515 end
@@ -503,8 +519,8 @@ typedef struct {
503 -- Create Mach-O object and fill in header. 519 -- Create Mach-O object and fill in header.
504 local o = ffi.new(mobj) 520 local o = ffi.new(mobj)
505 local mach_size = aligned(ffi.offsetof(o, "space")+#symname+2, align) 521 local mach_size = aligned(ffi.offsetof(o, "space")+#symname+2, align)
506 local cputype = ({ x86={7}, x64={0x01000007}, arm={7,12,12,12} })[ctx.arch] 522 local cputype = ({ x86={7}, x64={0x01000007}, arm={7,12}, arm64={0x01000007,0x0100000c} })[ctx.arch]
507 local cpusubtype = ({ x86={3}, x64={3}, arm={3,6,9,11} })[ctx.arch] 523 local cpusubtype = ({ x86={3}, x64={3}, arm={3,9}, arm64={3,0} })[ctx.arch]
508 if isfat then 524 if isfat then
509 o.fat.magic = be32(0xcafebabe) 525 o.fat.magic = be32(0xcafebabe)
510 o.fat.nfat_arch = be32(#cpusubtype) 526 o.fat.nfat_arch = be32(#cpusubtype)
@@ -562,6 +578,9 @@ end
562local function bcsave_obj(ctx, output, s) 578local function bcsave_obj(ctx, output, s)
563 local ok, ffi = pcall(require, "ffi") 579 local ok, ffi = pcall(require, "ffi")
564 check(ok, "FFI library required to write this file type") 580 check(ok, "FFI library required to write this file type")
581 if output == "-" and jit.os == "Windows" then
582 set_stdout_binary(ffi)
583 end
565 if ctx.os == "windows" then 584 if ctx.os == "windows" then
566 return bcsave_peobj(ctx, output, s, ffi) 585 return bcsave_peobj(ctx, output, s, ffi)
567 elseif ctx.os == "osx" then 586 elseif ctx.os == "osx" then
@@ -603,16 +622,16 @@ local function docmd(...)
603 local n = 1 622 local n = 1
604 local list = false 623 local list = false
605 local ctx = { 624 local ctx = {
606 strip = true, arch = jit.arch, os = string.lower(jit.os), 625 strip = true, arch = jit.arch, os = jit.os:lower(),
607 type = false, modname = false, 626 type = false, modname = false,
608 } 627 }
609 while n <= #arg do 628 while n <= #arg do
610 local a = arg[n] 629 local a = arg[n]
611 if type(a) == "string" and string.sub(a, 1, 1) == "-" and a ~= "-" then 630 if type(a) == "string" and a:sub(1, 1) == "-" and a ~= "-" then
612 table.remove(arg, n) 631 tremove(arg, n)
613 if a == "--" then break end 632 if a == "--" then break end
614 for m=2,#a do 633 for m=2,#a do
615 local opt = string.sub(a, m, m) 634 local opt = a:sub(m, m)
616 if opt == "l" then 635 if opt == "l" then
617 list = true 636 list = true
618 elseif opt == "s" then 637 elseif opt == "s" then
@@ -625,13 +644,13 @@ local function docmd(...)
625 if n ~= 1 then usage() end 644 if n ~= 1 then usage() end
626 arg[1] = check(loadstring(arg[1])) 645 arg[1] = check(loadstring(arg[1]))
627 elseif opt == "n" then 646 elseif opt == "n" then
628 ctx.modname = checkmodname(table.remove(arg, n)) 647 ctx.modname = checkmodname(tremove(arg, n))
629 elseif opt == "t" then 648 elseif opt == "t" then
630 ctx.type = checkarg(table.remove(arg, n), map_type, "file type") 649 ctx.type = checkarg(tremove(arg, n), map_type, "file type")
631 elseif opt == "a" then 650 elseif opt == "a" then
632 ctx.arch = checkarg(table.remove(arg, n), map_arch, "architecture") 651 ctx.arch = checkarg(tremove(arg, n), map_arch, "architecture")
633 elseif opt == "o" then 652 elseif opt == "o" then
634 ctx.os = checkarg(table.remove(arg, n), map_os, "OS name") 653 ctx.os = checkarg(tremove(arg, n), map_os, "OS name")
635 else 654 else
636 usage() 655 usage()
637 end 656 end
@@ -653,7 +672,7 @@ end
653------------------------------------------------------------------------------ 672------------------------------------------------------------------------------
654 673
655-- Public module functions. 674-- Public module functions.
656module(...) 675return {
657 676 start = docmd -- Process -b command line option.
658start = docmd -- Process -b command line option. 677}
659 678