bcsave.lua 13 KB

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