diff options
Diffstat (limited to 'src/jit/bcsave.lua')
| -rw-r--r-- | src/jit/bcsave.lua | 326 |
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 | ||
| 13 | local jit = require("jit") | 13 | local jit = require("jit") |
| 14 | assert(jit.version_num == 20099, "LuaJIT core/library version mismatch") | 14 | assert(jit.version_num == 20199, "LuaJIT core/library version mismatch") |
| 15 | local bit = require("bit") | 15 | local bit = require("bit") |
| 16 | 16 | ||
| 17 | -- Symbol name prefix for LuaJIT bytecode. | 17 | -- Symbol name prefix for LuaJIT bytecode. |
| 18 | local LJBC_PREFIX = "luaJIT_BC_" | 18 | local LJBC_PREFIX = "luaJIT_BC_" |
| 19 | 19 | ||
| 20 | local type, assert = type, assert | ||
| 21 | local format = string.format | ||
| 22 | local tremove, tconcat = table.remove, table.concat | ||
| 23 | |||
| 20 | ------------------------------------------------------------------------------ | 24 | ------------------------------------------------------------------------------ |
| 21 | 25 | ||
| 22 | local function usage() | 26 | local 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 | ||
| 36 | File types: c h obj o raw (default) | 44 | File types: c cc h obj o raw (default) |
| 37 | ]] | 45 | ]] |
| 38 | os.exit(1) | 46 | os.exit(1) |
| 39 | end | 47 | end |
| @@ -45,10 +53,23 @@ local function check(ok, ...) | |||
| 45 | os.exit(1) | 53 | os.exit(1) |
| 46 | end | 54 | end |
| 47 | 55 | ||
| 48 | local function readfile(input) | 56 | local 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 | ||
| 52 | end | 73 | end |
| 53 | 74 | ||
| 54 | local function savefile(name, mode) | 75 | local 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)) |
| 57 | end | 78 | end |
| 58 | 79 | ||
| 80 | local function set_stdout_binary(ffi) | ||
| 81 | ffi.cdef[[int _setmode(int fd, int mode);]] | ||
| 82 | ffi.C._setmode(1, 0x8000) | ||
| 83 | end | ||
| 84 | |||
| 59 | ------------------------------------------------------------------------------ | 85 | ------------------------------------------------------------------------------ |
| 60 | 86 | ||
| 61 | local map_type = { | 87 | local 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 | ||
| 65 | local map_arch = { | 91 | local 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 | ||
| 70 | local map_os = { | 106 | local map_os = { |
| @@ -73,33 +109,33 @@ local map_os = { | |||
| 73 | } | 109 | } |
| 74 | 110 | ||
| 75 | local function checkarg(str, map, err) | 111 | local 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 |
| 79 | end | 115 | end |
| 80 | 116 | ||
| 81 | local function detecttype(str) | 117 | local 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" |
| 84 | end | 120 | end |
| 85 | 121 | ||
| 86 | local function checkmodname(str) | 122 | local 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("[%.%-]", "_") |
| 89 | end | 125 | end |
| 90 | 126 | ||
| 91 | local function detectmodname(str) | 127 | local 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("[%.%-]", "_") |
| 103 | end | 139 | end |
| 104 | 140 | ||
| 105 | ------------------------------------------------------------------------------ | 141 | ------------------------------------------------------------------------------ |
| @@ -111,6 +147,11 @@ local function bcsave_tail(fp, output, s) | |||
| 111 | end | 147 | end |
| 112 | 148 | ||
| 113 | local function bcsave_raw(output, s) | 149 | local 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) |
| 116 | end | 157 | end |
| @@ -118,19 +159,21 @@ end | |||
| 118 | local function bcsave_c(ctx, output, s) | 159 | local 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 |
| 123 | extern "C" | 164 | extern "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 |
| 128 | const char %s%s[] = { | 171 | const 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 |
| 133 | static const char %s%s[] = { | 176 | static 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") |
| 148 | end | 191 | end |
| 149 | 192 | ||
| 150 | local function bcsave_elfobj(ctx, output, s, ffi) | 193 | local 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 | |||
| 411 | typedef struct { | 444 | typedef 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; | ||
| 417 | typedef 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; |
| 423 | typedef struct { | 450 | typedef 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; | ||
| 429 | typedef 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 { | |||
| 438 | typedef struct { | 459 | typedef 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; | ||
| 444 | typedef 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; |
| 450 | typedef struct | ||
| 451 | { | ||
| 452 | uint32_t magic, nfat_arch; | ||
| 453 | } mach_fat_header; | ||
| 454 | typedef struct | ||
| 455 | { | ||
| 456 | uint32_t cputype, cpusubtype, offset, size, align; | ||
| 457 | } mach_fat_arch; | ||
| 458 | typedef 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; | ||
| 468 | typedef struct { | 465 | typedef 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; |
| 478 | typedef struct { | 471 | typedef 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)) | ||
| 560 | end | 526 | end |
| 561 | 527 | ||
| 562 | local function bcsave_obj(ctx, output, s) | 528 | local 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 | ||
| 576 | local function bclist(input, output) | 545 | local 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) |
| 579 | end | 548 | end |
| 580 | 549 | ||
| 581 | local function bcsave(ctx, input, output) | 550 | local 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. |
| 656 | module(...) | 634 | return { |
| 657 | 635 | start = docmd -- Process -b command line option. | |
| 658 | start = docmd -- Process -b command line option. | 636 | } |
| 659 | 637 | ||
