LuaJit分析(七)LuaJit -b 命令分析

Luajit -b 命令用于生成字节码文件,通过之前对 -bl命令的分析:

luajit -bl 命令分析

可知,-b系统的命令都通过执行 bcsave.lua脚本来完成, luajit -b命令最终是执行bcsave.lua脚本中的 bcsave函数,bcsave函数代码如下:

local function bcsave(ctx, input, output)
  local f = readfile(input)
  local s = string.dump(f, ctx.strip)
  local t = ctx.type
  if not t then
    t = detecttype(output)
    ctx.type = t
  end
  if t == "raw" then
    bcsave_raw(output, s)
  else
    if not ctx.modname then ctx.modname = detectmodname(input) end
    if t == "obj" then
      bcsave_obj(ctx, output, s)
    else
      bcsave_c(ctx, output, s)
    end
  end
end

这通过关键的两个函数,来完成代码的转换:

local f = readfile(input)
local s = string.dump(f, ctx.strip)

由之前对luajit -b 命令的分析可知,readfile函数最终返回原型数据,如果是字节码文件,返回读取后的原型数据,否则进行源码分析再返回原型数据。接着通过string.dump返回完整的字节码文件,通过ctx.strip决定是否有调试信息,string.dump为库函数,位于lib_string.c中,实现如下:

LJLIB_CF(string_dump)
{
  GCfunc *fn = lj_lib_checkfunc(L, 1);
  int strip = L->base+1 < L->top && tvistruecond(L->base+1);
  SBuf *sb = lj_buf_tmp_(L);  /* Assumes lj_bcwrite() doesn't use tmpbuf. */
  L->top = L->base+1;
  if (!isluafunc(fn) || lj_bcwrite(L, funcproto(fn), writer_buf, sb, strip))
    lj_err_caller(L, LJ_ERR_STRDUMP);
  setstrV(L, L->top-1, lj_buf_str(L, sb));
  lj_gc_check(L);
  return 1;
}

最终是通过lj_bcwrite函数来完成字节码的生成,与lj_bcread对应。Lj_bcwriter位于lj_bcwriter.c文件中,代码如下:

int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer, void *data,
        int strip)
{
  BCWriteCtx ctx;
  int status;
  ctx.pt = pt;
  ctx.wfunc = writer;
  ctx.wdata = data;
  ctx.strip = strip;
  ctx.status = 0;
  lj_buf_init(L, &ctx.sb);
  status = lj_vm_cpcall(L, NULL, &ctx, cpwriter);
  if (status == 0) status = ctx.status;
  lj_buf_free(G(sbufL(&ctx.sb)), &ctx.sb);
  return status;
}

实质是调用 cpwriter函数,实现如下:

/* Protected callback for bytecode writer. */
static TValue *cpwriter(lua_State *L, lua_CFunction dummy, void *ud)
{
  BCWriteCtx *ctx = (BCWriteCtx *)ud;
  UNUSED(L); UNUSED(dummy);
  lj_buf_need(&ctx->sb, 1024);  /* Avoids resize for most prototypes. */
  bcwrite_header(ctx);
  bcwrite_proto(ctx, ctx->pt);
  bcwrite_footer(ctx);
  return NULL;
}

从这里就可以明显的看出,它通过分别生成头部、原型等数据来完成字节码的生成。

Bcsave函数中通过detecttype确定要保存的文件类型,代码如下:

local function detecttype(str)
  local ext = string.match(string.lower(str), "%.(%a+)$")
  return map_type[ext] or "raw"
end
local map_type = {
  raw = "raw", c = "c", h = "h", o = "obj", obj = "obj",
}

这里通过正则表达式匹配了输出文件后缀名,map_type中定义了几种后缀,除非特别指定了如obj等后缀名,否则都是返回raw.即执行bcsave_raw函数,实现如下:

local function bcsave_raw(output, s)
  local fp = savefile(output, "wb")
  bcsave_tail(fp, output, s)
end

这里最终将整个字节码文件写入到指定的文件名中。

总结:luajit -b生成字节码,实际上是调用 bcsave.lua脚本中的bcsave函数,该函数通过readfile函数(最终调用loadfile库函数)来完成lua脚本和字节码统一返回原型数据,并通过string.dump库函数生成完整的字节码文件。

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
luajit-decomp是一个用于反编译LuaJIT代码的工具。LuaJIT是一个高性能的Lua解释器和编译器,而luajit-decomp允许用户将经过编译的LuaJIT代码还原为可读性较高的源代码。 反编译是指将已编译的程序转换回源代码的过程。在软件工程领域,一些开发者可能会遇到这种需要,例如对于某些加密的LuaJIT代码,开发者可能需要了解其实际实现以修复bug或进行优化。 使用luajit-decomp可以帮助开发者更好地理解已编译的LuaJIT二进制代码的工作原理。它可以将字节码指令还原为Lua源代码,并提供了一些额外的信息,比如变量名和注释。 要使用luajit-decomp,用户需要安装LuaJIT并将其添加到系统路径中。然后,用户可以在命令行界面中运行luajit-decomp,并提供已编译的LuaJIT二进制文件作为输入。在执行过程中,luajit-decomp会分析字节码并尝试还原源代码。 然而,需要注意的是,由于反编译的本质,luajit-decomp并不能完全还原原始的Lua源代码。在编译过程中,一些信息可能会丢失,例如变量名和注释等。因此,反编译后的代码可能不是与原始代码完全一致的。 总的来说,luajit-decomp是一个方便的工具,可以帮助开发者更好地理解LuaJIT二进制代码的工作原理,并在某些情况下提供有用的信息。但是,用户应该明白反编译过程的局限性,并谨慎使用反编译后的源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值