LuaJit分析(五)LuaJit filename分析

LuaJit执行文件过程分析

通过之前对luajit -b命令的分析可知,在luajit.c文件的runargs函数中,用于手机参数,对相应的参数调用对应的函数,若返回LUA_OK则执行handle_script函数,该函数用于执行一个lua脚本文件,该函数如下:

cpp 复制代码
static int handle_script(lua_State *L, char **argx)
{
  int status;
  const char *fname = argx[0];
  if (strcmp(fname, "-") == 0 && strcmp(argx[-1], "--") != 0)
    fname = NULL;  /* stdin */
  status = luaL_loadfile(L, fname);
  if (status == LUA_OK) {
    /* Fetch args from arg table. LUA_INIT or -e might have changed them. */
    int narg = 0;
    lua_getglobal(L, "arg");
    if (lua_istable(L, -1)) {
      do {
  narg++;
  lua_rawgeti(L, -narg, narg);
      } while (!lua_isnil(L, -1));
      lua_pop(L, 1);
      lua_remove(L, -narg);
      narg--;
    } else {
      lua_pop(L, 1);
    }
    status = docall(L, narg, 0);
  }
  return report(L, status);
}

参数argx包含了执行的lua脚本文件名,luaL_loadfile加载了一个lua脚本,通过之前的分析可知,luaL_loadfile会加载一个字节码文件或者转换一个源码文件,最终都会得到转换好的原型结构。在进行一些参数设置后,调用docall函数,执行字节码,该函数如下:

cpp 复制代码
static int docall(lua_State *L, int narg, int clear)
{
  int status;
  int base = lua_gettop(L) - narg;  /* function index */
  lua_pushcfunction(L, traceback);  /* push traceback function */
  lua_insert(L, base);  /* put it under chunk and args */
#if !LJ_TARGET_CONSOLE
  signal(SIGINT, laction);
#endif
  status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base);
#if !LJ_TARGET_CONSOLE
  signal(SIGINT, SIG_DFL);
#endif
  lua_remove(L, base);  /* remove traceback function */
  /* force a complete garbage collection in case of errors */
  if (status != LUA_OK) lua_gc(L, LUA_GCCOLLECT, 0);
  return status;
}

Docall函数继续调用lua_pcall函数,该函数在lua_api.c中如下:

cpp 复制代码
LUA_API int lua_pcall(lua_State *L, int nargs, int nresults, int errfunc)
{
  global_State *g = G(L);
  uint8_t oldh = hook_save(g);
  ptrdiff_t ef;
  int status;
  api_check(L, L->status == LUA_OK || L->status == LUA_ERRERR);
  api_checknelems(L, nargs+1);
  if (errfunc == 0) {
    ef = 0;
  } else {
    cTValue *o = stkindex2adr(L, errfunc);
    api_checkvalidindex(L, o);
    ef = savestack(L, o);
  }
  status = lj_vm_pcall(L, api_call_base(L, nargs), nresults+1, ef);
  if (status) hook_restore(g, oldh);
  return status;
}

在进行一些安全性的检查和处理后,调用lj_vm_pcall执行函数,lj_vm_pcall使用汇编实现,头文件如下:

cpp 复制代码
LJ_ASMF int lj_vm_pcall(lua_State *L, TValue *base, int nres1, ptrdiff_t ef);

X86版本的调用入口简化后如下:

Lua 复制代码
|->vm_pcall:                           // Setup protected C frame and enter VM.
|  // (lua_State *L, TValue *base, int nres1, ptrdiff_t ef)
|  saveregs
|  mov PC, FRAME_CP
|  jmp >1
|1:  // Entry point for vm_pcall above (PC = ftype).
|  mov L:RB, SAVE_L
|  mov RA, INARG_BASE                // Caveat: overlaps SAVE_CFRAME!
|  mov DISPATCH, L:RB->glref             // Setup pointer to dispatch table.
|  mov KBASEa, L:RB->cframe              // Add our C frame to cframe chain.
|  mov SAVE_CFRAME, KBASEa
|  mov SAVE_PC, L:RB                   // Any value outside of bytecode is ok.
|  add DISPATCH, GG_G2DISP
|  mov L:RB->cframe, esp
|2:  // Entry point for vm_resume/vm_cpcall (RA = base, RB = L, PC = ftype).
|  mov [DISPATCH+DISPATCH_GL(cur_L)], L:RB
|  set_vmstate INTERP
|  mov BASE, L:RB->base              // BASE = old base (used in vmeta_call).
|  add PC, RA
|  sub PC, BASE              // PC = frame delta + frame type
|  mov RD, L:RB->top
|  sub RD, RA
|  shr NARGS:RD, 3
|  add NARGS:RD, 1               // RD = nargs+1
|->vm_call_dispatch:
|  mov LFUNC:RB, [RA-8]
|  cmp dword [RA-4], LJ_TFUNC
|  jne ->vmeta_call                // Ensure KBASE defined and != BASE.
|->vm_call_dispatch_f:
|  mov BASE, RA
|  ins_call
|  // BASE = new base, RB = func, RD = nargs+1, PC = caller PC

在还原指针和参数栈后,ins_call开始执行解释器的call指令

相关推荐
众乐乐_20081 分钟前
Maven中的(五种常用依赖范围)
java·maven
凌叁儿2 分钟前
Python 的 datetime 模块使用详解
开发语言·python
谁家有个大人3 分钟前
Python数据清洗笔记(上)
开发语言·笔记·python·数据分析
橘猫云计算机设计4 分钟前
springboot-基于Web企业短信息发送系统(源码+lw+部署文档+讲解),源码可白嫖!
java·前端·数据库·spring boot·后端·小程序·毕业设计
程序猿chen15 分钟前
JVM考古现场(二十五):逆熵者·时间晶体的永恒之战(进阶篇)
java·jvm·git·后端·程序人生·java-ee·改行学it
CopyLower22 分钟前
Spring Boot的优点:赋能现代Java开发的利器
java·linux·spring boot
细心的莽夫25 分钟前
Elasticsearch复习笔记
java·大数据·spring boot·笔记·后端·elasticsearch·docker
程序员阿鹏35 分钟前
实现SpringBoot底层机制【Tomcat启动分析+Spring容器初始化+Tomcat 如何关联 Spring容器】
java·spring boot·后端·spring·docker·tomcat·intellij-idea
大叔比较胖1 小时前
VSCode 用于JAVA开发的环境配置,JDK为1.8版本时的配置
java·ide·vscode·jdk·1.8
MurphyStar1 小时前
UV: Python包和项目管理器(从入门到不放弃教程)
开发语言·python·uv