bcsave.lua 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. ----------------------------------------------------------------------------
  2. -- LuaJIT module to save/list bytecode.
  3. --
  4. -- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
  5. -- Released under the MIT license. See Copyright Notice in luajit.h
  6. ----------------------------------------------------------------------------
  7. --
  8. -- This module saves or lists the bytecode for an input file.
  9. -- It's run by the -b command line option.
  10. --
  11. ------------------------------------------------------------------------------
  12. local jit = require("jit")
  13. assert(jit.version_num == 20199, "LuaJIT core/library version mismatch")
  14. local bit = require("bit")
  15. -- Symbol name prefix for LuaJIT bytecode.
  16. local LJBC_PREFIX = "luaJIT_BC_"
  17. local type, assert = type, assert
  18. local format = string.format
  19. local tremove, tconcat = table.remove, table.concat
  20. ------------------------------------------------------------------------------
  21. local function usage()
  22. io.stderr:write[[
  23. Save LuaJIT bytecode: luajit -b[options] input output
  24. -l Only list bytecode.
  25. -s Strip debug info (default).
  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).
  31. -F name Override filename (default: input filename).
  32. -e chunk Use chunk string as input.
  33. -- Stop handling options.
  34. - Use stdin as input and/or stdout as output.
  35. File types: c cc h obj o raw (default)
  36. ]]
  37. os.exit(1)
  38. end
  39. local function check(ok, ...)
  40. if ok then return ok, ... end
  41. io.stderr:write("luajit: ", ...)
  42. io.stderr:write("\n")
  43. os.exit(1)
  44. end
  45. local function readfile(ctx, input)
  46. if type(input) == "function" then return input end
  47. if ctx.filename then
  48. local data
  49. if input == "-" then
  50. data = io.stdin:read("*a")
  51. else
  52. local fp = assert(io.open(input, "rb"))
  53. data = assert(fp:read("*a"))
  54. assert(fp:close())
  55. end
  56. return check(load(data, ctx.filename))
  57. else
  58. if input == "-" then input = nil end
  59. return check(loadfile(input))
  60. end
  61. end
  62. local function savefile(name, mode)
  63. if name == "-" then return io.stdout end
  64. return check(io.open(name, mode))
  65. end
  66. local function set_stdout_binary(ffi)
  67. ffi.cdef[[int _setmode(int fd, int mode);]]
  68. ffi.C._setmode(1, 0x8000)
  69. end
  70. ------------------------------------------------------------------------------
  71. local map_type = {
  72. raw = "raw", c = "c", cc = "c", h = "h", o = "obj", obj = "obj",
  73. }
  74. local map_arch = {
  75. x86 = { e = "le", b = 32, m = 3, p = 0x14c, },
  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, },
  87. }
  88. local map_os = {
  89. linux = true, windows = true, osx = true, freebsd = true, netbsd = true,
  90. openbsd = true, dragonfly = true, solaris = true,
  91. }
  92. local function checkarg(str, map, err)
  93. str = str:lower()
  94. local s = check(map[str], "unknown ", err)
  95. return type(s) == "string" and s or str
  96. end
  97. local function detecttype(str)
  98. local ext = str:lower():match("%.(%a+)$")
  99. return map_type[ext] or "raw"
  100. end
  101. local function checkmodname(str)
  102. check(str:match("^[%w_.%-]+$"), "bad module name")
  103. return str:gsub("[%.%-]", "_")
  104. end
  105. local function detectmodname(str)
  106. if type(str) == "string" then
  107. local tail = str:match("[^/\\]+$")
  108. if tail then str = tail end
  109. local head = str:match("^(.*)%.[^.]*$")
  110. if head then str = head end
  111. str = str:match("^[%w_.%-]+")
  112. else
  113. str = nil
  114. end
  115. check(str, "cannot derive module name, use -n name")
  116. return str:gsub("[%.%-]", "_")
  117. end
  118. ------------------------------------------------------------------------------
  119. local function bcsave_tail(fp, output, s)
  120. local ok, err = fp:write(s)
  121. if ok and output ~= "-" then ok, err = fp:close() end
  122. check(ok, "cannot write ", output, ": ", err)
  123. end
  124. local function bcsave_raw(output, s)
  125. if output == "-" and jit.os == "Windows" then
  126. local ok, ffi = pcall(require, "ffi")
  127. check(ok, "FFI library required to write binary file to stdout")
  128. set_stdout_binary(ffi)
  129. end
  130. local fp = savefile(output, "wb")
  131. bcsave_tail(fp, output, s)
  132. end
  133. local function bcsave_c(ctx, output, s)
  134. local fp = savefile(output, "w")
  135. if ctx.type == "c" then
  136. fp:write(format([[
  137. #ifdef __cplusplus
  138. extern "C"
  139. #endif
  140. #ifdef _WIN32
  141. __declspec(dllexport)
  142. #endif
  143. const unsigned char %s%s[] = {
  144. ]], LJBC_PREFIX, ctx.modname))
  145. else
  146. fp:write(format([[
  147. #define %s%s_SIZE %d
  148. static const unsigned char %s%s[] = {
  149. ]], LJBC_PREFIX, ctx.modname, #s, LJBC_PREFIX, ctx.modname))
  150. end
  151. local t, n, m = {}, 0, 0
  152. for i=1,#s do
  153. local b = tostring(string.byte(s, i))
  154. m = m + #b + 1
  155. if m > 78 then
  156. fp:write(tconcat(t, ",", 1, n), ",\n")
  157. n, m = 0, #b + 1
  158. end
  159. n = n + 1
  160. t[n] = b
  161. end
  162. bcsave_tail(fp, output, tconcat(t, ",", 1, n).."\n};\n")
  163. end
  164. local function bcsave_elfobj(ctx, output, s, ffi)
  165. ffi.cdef[[
  166. typedef struct {
  167. uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7];
  168. uint16_t type, machine;
  169. uint32_t version;
  170. uint32_t entry, phofs, shofs;
  171. uint32_t flags;
  172. uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx;
  173. } ELF32header;
  174. typedef struct {
  175. uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7];
  176. uint16_t type, machine;
  177. uint32_t version;
  178. uint64_t entry, phofs, shofs;
  179. uint32_t flags;
  180. uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx;
  181. } ELF64header;
  182. typedef struct {
  183. uint32_t name, type, flags, addr, ofs, size, link, info, align, entsize;
  184. } ELF32sectheader;
  185. typedef struct {
  186. uint32_t name, type;
  187. uint64_t flags, addr, ofs, size;
  188. uint32_t link, info;
  189. uint64_t align, entsize;
  190. } ELF64sectheader;
  191. typedef struct {
  192. uint32_t name, value, size;
  193. uint8_t info, other;
  194. uint16_t sectidx;
  195. } ELF32symbol;
  196. typedef struct {
  197. uint32_t name;
  198. uint8_t info, other;
  199. uint16_t sectidx;
  200. uint64_t value, size;
  201. } ELF64symbol;
  202. typedef struct {
  203. ELF32header hdr;
  204. ELF32sectheader sect[6];
  205. ELF32symbol sym[2];
  206. uint8_t space[4096];
  207. } ELF32obj;
  208. typedef struct {
  209. ELF64header hdr;
  210. ELF64sectheader sect[6];
  211. ELF64symbol sym[2];
  212. uint8_t space[4096];
  213. } ELF64obj;
  214. ]]
  215. local symname = LJBC_PREFIX..ctx.modname
  216. local ai = assert(map_arch[ctx.arch])
  217. local is64, isbe = ai.b == 64, ai.e == "be"
  218. -- Handle different host/target endianess.
  219. local function f32(x) return x end
  220. local f16, fofs = f32, f32
  221. if ffi.abi("be") ~= isbe then
  222. f32 = bit.bswap
  223. function f16(x) return bit.rshift(bit.bswap(x), 16) end
  224. if is64 then
  225. local two32 = ffi.cast("int64_t", 2^32)
  226. function fofs(x) return bit.bswap(x)*two32 end
  227. else
  228. fofs = f32
  229. end
  230. end
  231. -- Create ELF object and fill in header.
  232. local o = ffi.new(is64 and "ELF64obj" or "ELF32obj")
  233. local hdr = o.hdr
  234. if ctx.os == "bsd" or ctx.os == "other" then -- Determine native hdr.eosabi.
  235. local bf = assert(io.open("/bin/ls", "rb"))
  236. local bs = bf:read(9)
  237. bf:close()
  238. ffi.copy(o, bs, 9)
  239. check(hdr.emagic[0] == 127, "no support for writing native object files")
  240. else
  241. hdr.emagic = "\127ELF"
  242. hdr.eosabi = ({ freebsd=9, netbsd=2, openbsd=12, solaris=6 })[ctx.os] or 0
  243. end
  244. hdr.eclass = is64 and 2 or 1
  245. hdr.eendian = isbe and 2 or 1
  246. hdr.eversion = 1
  247. hdr.type = f16(1)
  248. hdr.machine = f16(ai.m)
  249. hdr.flags = f32(ai.f or 0)
  250. hdr.version = f32(1)
  251. hdr.shofs = fofs(ffi.offsetof(o, "sect"))
  252. hdr.ehsize = f16(ffi.sizeof(hdr))
  253. hdr.shentsize = f16(ffi.sizeof(o.sect[0]))
  254. hdr.shnum = f16(6)
  255. hdr.shstridx = f16(2)
  256. -- Fill in sections and symbols.
  257. local sofs, ofs = ffi.offsetof(o, "space"), 1
  258. for i,name in ipairs{
  259. ".symtab", ".shstrtab", ".strtab", ".rodata", ".note.GNU-stack",
  260. } do
  261. local sect = o.sect[i]
  262. sect.align = fofs(1)
  263. sect.name = f32(ofs)
  264. ffi.copy(o.space+ofs, name)
  265. ofs = ofs + #name+1
  266. end
  267. o.sect[1].type = f32(2) -- .symtab
  268. o.sect[1].link = f32(3)
  269. o.sect[1].info = f32(1)
  270. o.sect[1].align = fofs(8)
  271. o.sect[1].ofs = fofs(ffi.offsetof(o, "sym"))
  272. o.sect[1].entsize = fofs(ffi.sizeof(o.sym[0]))
  273. o.sect[1].size = fofs(ffi.sizeof(o.sym))
  274. o.sym[1].name = f32(1)
  275. o.sym[1].sectidx = f16(4)
  276. o.sym[1].size = fofs(#s)
  277. o.sym[1].info = 17
  278. o.sect[2].type = f32(3) -- .shstrtab
  279. o.sect[2].ofs = fofs(sofs)
  280. o.sect[2].size = fofs(ofs)
  281. o.sect[3].type = f32(3) -- .strtab
  282. o.sect[3].ofs = fofs(sofs + ofs)
  283. o.sect[3].size = fofs(#symname+2)
  284. ffi.copy(o.space+ofs+1, symname)
  285. ofs = ofs + #symname + 2
  286. o.sect[4].type = f32(1) -- .rodata
  287. o.sect[4].flags = fofs(2)
  288. o.sect[4].ofs = fofs(sofs + ofs)
  289. o.sect[4].size = fofs(#s)
  290. o.sect[5].type = f32(1) -- .note.GNU-stack
  291. o.sect[5].ofs = fofs(sofs + ofs + #s)
  292. -- Write ELF object file.
  293. local fp = savefile(output, "wb")
  294. fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs))
  295. bcsave_tail(fp, output, s)
  296. end
  297. local function bcsave_peobj(ctx, output, s, ffi)
  298. ffi.cdef[[
  299. typedef struct {
  300. uint16_t arch, nsects;
  301. uint32_t time, symtabofs, nsyms;
  302. uint16_t opthdrsz, flags;
  303. } PEheader;
  304. typedef struct {
  305. char name[8];
  306. uint32_t vsize, vaddr, size, ofs, relocofs, lineofs;
  307. uint16_t nreloc, nline;
  308. uint32_t flags;
  309. } PEsection;
  310. typedef struct __attribute((packed)) {
  311. union {
  312. char name[8];
  313. uint32_t nameref[2];
  314. };
  315. uint32_t value;
  316. int16_t sect;
  317. uint16_t type;
  318. uint8_t scl, naux;
  319. } PEsym;
  320. typedef struct __attribute((packed)) {
  321. uint32_t size;
  322. uint16_t nreloc, nline;
  323. uint32_t cksum;
  324. uint16_t assoc;
  325. uint8_t comdatsel, unused[3];
  326. } PEsymaux;
  327. typedef struct {
  328. PEheader hdr;
  329. PEsection sect[2];
  330. // Must be an even number of symbol structs.
  331. PEsym sym0;
  332. PEsymaux sym0aux;
  333. PEsym sym1;
  334. PEsymaux sym1aux;
  335. PEsym sym2;
  336. PEsym sym3;
  337. uint32_t strtabsize;
  338. uint8_t space[4096];
  339. } PEobj;
  340. ]]
  341. local symname = LJBC_PREFIX..ctx.modname
  342. local ai = assert(map_arch[ctx.arch])
  343. local is64 = ai.b == 64
  344. local symexport = " /EXPORT:"..symname..",DATA "
  345. -- The file format is always little-endian. Swap if the host is big-endian.
  346. local function f32(x) return x end
  347. local f16 = f32
  348. if ffi.abi("be") then
  349. f32 = bit.bswap
  350. function f16(x) return bit.rshift(bit.bswap(x), 16) end
  351. end
  352. -- Create PE object and fill in header.
  353. local o = ffi.new("PEobj")
  354. local hdr = o.hdr
  355. hdr.arch = f16(assert(ai.p))
  356. hdr.nsects = f16(2)
  357. hdr.symtabofs = f32(ffi.offsetof(o, "sym0"))
  358. hdr.nsyms = f32(6)
  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. -- Write PE object file.
  391. local fp = savefile(output, "wb")
  392. fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs))
  393. bcsave_tail(fp, output, s)
  394. end
  395. local function bcsave_machobj(ctx, output, s, ffi)
  396. ffi.cdef[[
  397. typedef struct
  398. {
  399. uint32_t magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags;
  400. } mach_header;
  401. typedef struct
  402. {
  403. mach_header; uint32_t reserved;
  404. } mach_header_64;
  405. typedef struct {
  406. uint32_t cmd, cmdsize;
  407. char segname[16];
  408. uint32_t vmaddr, vmsize, fileoff, filesize;
  409. uint32_t maxprot, initprot, nsects, flags;
  410. } mach_segment_command;
  411. typedef struct {
  412. uint32_t cmd, cmdsize;
  413. char segname[16];
  414. uint64_t vmaddr, vmsize, fileoff, filesize;
  415. uint32_t maxprot, initprot, nsects, flags;
  416. } mach_segment_command_64;
  417. typedef struct {
  418. char sectname[16], segname[16];
  419. uint32_t addr, size;
  420. uint32_t offset, align, reloff, nreloc, flags;
  421. uint32_t reserved1, reserved2;
  422. } mach_section;
  423. typedef struct {
  424. char sectname[16], segname[16];
  425. uint64_t addr, size;
  426. uint32_t offset, align, reloff, nreloc, flags;
  427. uint32_t reserved1, reserved2, reserved3;
  428. } mach_section_64;
  429. typedef struct {
  430. uint32_t cmd, cmdsize, symoff, nsyms, stroff, strsize;
  431. } mach_symtab_command;
  432. typedef struct {
  433. int32_t strx;
  434. uint8_t type, sect;
  435. int16_t desc;
  436. uint32_t value;
  437. } mach_nlist;
  438. typedef struct {
  439. int32_t strx;
  440. uint8_t type, sect;
  441. uint16_t desc;
  442. uint64_t value;
  443. } mach_nlist_64;
  444. typedef struct
  445. {
  446. int32_t magic, nfat_arch;
  447. } mach_fat_header;
  448. typedef struct
  449. {
  450. int32_t cputype, cpusubtype, offset, size, align;
  451. } mach_fat_arch;
  452. typedef struct {
  453. struct {
  454. mach_header hdr;
  455. mach_segment_command seg;
  456. mach_section sec;
  457. mach_symtab_command sym;
  458. } arch[1];
  459. mach_nlist sym_entry;
  460. uint8_t space[4096];
  461. } mach_obj;
  462. typedef struct {
  463. struct {
  464. mach_header_64 hdr;
  465. mach_segment_command_64 seg;
  466. mach_section_64 sec;
  467. mach_symtab_command sym;
  468. } arch[1];
  469. mach_nlist_64 sym_entry;
  470. uint8_t space[4096];
  471. } mach_obj_64;
  472. typedef struct {
  473. mach_fat_header fat;
  474. mach_fat_arch fat_arch[2];
  475. struct {
  476. mach_header hdr;
  477. mach_segment_command seg;
  478. mach_section sec;
  479. mach_symtab_command sym;
  480. } arch[2];
  481. mach_nlist sym_entry;
  482. uint8_t space[4096];
  483. } mach_fat_obj;
  484. typedef struct {
  485. mach_fat_header fat;
  486. mach_fat_arch fat_arch[2];
  487. struct {
  488. mach_header_64 hdr;
  489. mach_segment_command_64 seg;
  490. mach_section_64 sec;
  491. mach_symtab_command sym;
  492. } arch[2];
  493. mach_nlist_64 sym_entry;
  494. uint8_t space[4096];
  495. } mach_fat_obj_64;
  496. ]]
  497. local symname = '_'..LJBC_PREFIX..ctx.modname
  498. local isfat, is64, align, mobj = false, false, 4, "mach_obj"
  499. if ctx.arch == "x64" then
  500. is64, align, mobj = true, 8, "mach_obj_64"
  501. elseif ctx.arch == "arm" then
  502. isfat, mobj = true, "mach_fat_obj"
  503. elseif ctx.arch == "arm64" then
  504. is64, align, isfat, mobj = true, 8, true, "mach_fat_obj_64"
  505. else
  506. check(ctx.arch == "x86", "unsupported architecture for OSX")
  507. end
  508. local function aligned(v, a) return bit.band(v+a-1, -a) end
  509. local be32 = bit.bswap -- Mach-O FAT is BE, supported archs are LE.
  510. -- Create Mach-O object and fill in header.
  511. local o = ffi.new(mobj)
  512. local mach_size = aligned(ffi.offsetof(o, "space")+#symname+2, align)
  513. local cputype = ({ x86={7}, x64={0x01000007}, arm={7,12}, arm64={0x01000007,0x0100000c} })[ctx.arch]
  514. local cpusubtype = ({ x86={3}, x64={3}, arm={3,9}, arm64={3,0} })[ctx.arch]
  515. if isfat then
  516. o.fat.magic = be32(0xcafebabe)
  517. o.fat.nfat_arch = be32(#cpusubtype)
  518. end
  519. -- Fill in sections and symbols.
  520. for i=0,#cpusubtype-1 do
  521. local ofs = 0
  522. if isfat then
  523. local a = o.fat_arch[i]
  524. a.cputype = be32(cputype[i+1])
  525. a.cpusubtype = be32(cpusubtype[i+1])
  526. -- Subsequent slices overlap each other to share data.
  527. ofs = ffi.offsetof(o, "arch") + i*ffi.sizeof(o.arch[0])
  528. a.offset = be32(ofs)
  529. a.size = be32(mach_size-ofs+#s)
  530. end
  531. local a = o.arch[i]
  532. a.hdr.magic = is64 and 0xfeedfacf or 0xfeedface
  533. a.hdr.cputype = cputype[i+1]
  534. a.hdr.cpusubtype = cpusubtype[i+1]
  535. a.hdr.filetype = 1
  536. a.hdr.ncmds = 2
  537. a.hdr.sizeofcmds = ffi.sizeof(a.seg)+ffi.sizeof(a.sec)+ffi.sizeof(a.sym)
  538. a.seg.cmd = is64 and 0x19 or 0x1
  539. a.seg.cmdsize = ffi.sizeof(a.seg)+ffi.sizeof(a.sec)
  540. a.seg.vmsize = #s
  541. a.seg.fileoff = mach_size-ofs
  542. a.seg.filesize = #s
  543. a.seg.maxprot = 1
  544. a.seg.initprot = 1
  545. a.seg.nsects = 1
  546. ffi.copy(a.sec.sectname, "__data")
  547. ffi.copy(a.sec.segname, "__DATA")
  548. a.sec.size = #s
  549. a.sec.offset = mach_size-ofs
  550. a.sym.cmd = 2
  551. a.sym.cmdsize = ffi.sizeof(a.sym)
  552. a.sym.symoff = ffi.offsetof(o, "sym_entry")-ofs
  553. a.sym.nsyms = 1
  554. a.sym.stroff = ffi.offsetof(o, "sym_entry")+ffi.sizeof(o.sym_entry)-ofs
  555. a.sym.strsize = aligned(#symname+2, align)
  556. end
  557. o.sym_entry.type = 0xf
  558. o.sym_entry.sect = 1
  559. o.sym_entry.strx = 1
  560. ffi.copy(o.space+1, symname)
  561. -- Write Macho-O object file.
  562. local fp = savefile(output, "wb")
  563. fp:write(ffi.string(o, mach_size))
  564. bcsave_tail(fp, output, s)
  565. end
  566. local function bcsave_obj(ctx, output, s)
  567. local ok, ffi = pcall(require, "ffi")
  568. check(ok, "FFI library required to write this file type")
  569. if output == "-" and jit.os == "Windows" then
  570. set_stdout_binary(ffi)
  571. end
  572. if ctx.os == "windows" then
  573. return bcsave_peobj(ctx, output, s, ffi)
  574. elseif ctx.os == "osx" then
  575. return bcsave_machobj(ctx, output, s, ffi)
  576. else
  577. return bcsave_elfobj(ctx, output, s, ffi)
  578. end
  579. end
  580. ------------------------------------------------------------------------------
  581. local function bclist(ctx, input, output)
  582. local f = readfile(ctx, input)
  583. require("jit.bc").dump(f, savefile(output, "w"), true)
  584. end
  585. local function bcsave(ctx, input, output)
  586. local f = readfile(ctx, input)
  587. local s = string.dump(f, ctx.strip)
  588. local t = ctx.type
  589. if not t then
  590. t = detecttype(output)
  591. ctx.type = t
  592. end
  593. if t == "raw" then
  594. bcsave_raw(output, s)
  595. else
  596. if not ctx.modname then ctx.modname = detectmodname(input) end
  597. if t == "obj" then
  598. bcsave_obj(ctx, output, s)
  599. else
  600. bcsave_c(ctx, output, s)
  601. end
  602. end
  603. end
  604. local function docmd(...)
  605. local arg = {...}
  606. local n = 1
  607. local list = false
  608. local ctx = {
  609. strip = true, arch = jit.arch, os = jit.os:lower(),
  610. type = false, modname = false,
  611. }
  612. while n <= #arg do
  613. local a = arg[n]
  614. if type(a) == "string" and a:sub(1, 1) == "-" and a ~= "-" then
  615. tremove(arg, n)
  616. if a == "--" then break end
  617. for m=2,#a do
  618. local opt = a:sub(m, m)
  619. if opt == "l" then
  620. list = true
  621. elseif opt == "s" then
  622. ctx.strip = true
  623. elseif opt == "g" then
  624. ctx.strip = false
  625. else
  626. if arg[n] == nil or m ~= #a then usage() end
  627. if opt == "e" then
  628. if n ~= 1 then usage() end
  629. arg[1] = check(loadstring(arg[1]))
  630. elseif opt == "n" then
  631. ctx.modname = checkmodname(tremove(arg, n))
  632. elseif opt == "t" then
  633. ctx.type = checkarg(tremove(arg, n), map_type, "file type")
  634. elseif opt == "a" then
  635. ctx.arch = checkarg(tremove(arg, n), map_arch, "architecture")
  636. elseif opt == "o" then
  637. ctx.os = checkarg(tremove(arg, n), map_os, "OS name")
  638. elseif opt == "F" then
  639. ctx.filename = "@"..tremove(arg, n)
  640. else
  641. usage()
  642. end
  643. end
  644. end
  645. else
  646. n = n + 1
  647. end
  648. end
  649. if list then
  650. if #arg == 0 or #arg > 2 then usage() end
  651. bclist(ctx, arg[1], arg[2] or "-")
  652. else
  653. if #arg ~= 2 then usage() end
  654. bcsave(ctx, arg[1], arg[2])
  655. end
  656. end
  657. ------------------------------------------------------------------------------
  658. -- Public module functions.
  659. return {
  660. start = docmd -- Process -b command line option.
  661. }