早就听闻LuaJIT字节码有很好的代码保护措施,而且还可以加快代码的加载速度,趁着项目中期不太忙的时候,抽空做看了一下LuaJIT如何使用字节码。
顺便吐槽一下,公司之前那么多cocos项目,居然一个使用字节码的都没有,很好奇他们的项目是怎么做的客户端加密,哈哈。
我们项目是Unity3d项目,使用的xLua做热更方案。不过字节码这一块跟使用什么框架没有关系,官方文档说,字节码(bytecode)和源码(sourcecode)在使用上是没有区别的。所以不考虑32位移动平台的话,在框架和业务层面无需改动任何东西。
HOW
LuaJIT支持交叉编译,即在mac osx上编译出ios或android上系统可执行的字节码,如此,我们只需要针对32和64位的LuaJIT解释器分别编译一次,然后在打包过程中使用LuaJIT解释器将项目中的Lua源码编译成字节码即可。
LuaJIT字节码有平台兼容性的问题,如果需要兼容iphone 5s及以下32位平台的用户,则需要针对32位/64位各生成一套字节码。
如下给出一套在桌面平台生成移动平台上可用的字节码的流程。
1. 重新编译LuaJIT解释器
LuaJIT默认生成的字节码是32位的,如果在64位的ios机器上直接读取的话,会一个报错。针对这个种情况,而作者在2015年8月对LuaJIT做了一个更新,增加了LJ_GC64模式,这样我们可以重新编译LuaJIT解释器来生成64位的字节码。
过程很简单,只需要在 make 命令后加上一个参数即可。如下是mac os上编译LuaJIT解释器的命令。
1 | // 控制台定位到LuaJIT解释器所在目录 |
2. 生成32/64位字节码
有了32/64位的LuaJIT解释器之后,我们就可以按照官方流程来生成LuaJIT来生成平台兼容的字节码了。
1 | // 控制台定位到LuaJIT解释器所在目录 |
mac osx平台
1 | // 生成字节码 |
windows平台
1 | // 生成字节码 |
3. 读取字节码
移动平台在加载Lua代码时,在Lua的加载器中根据当前手机的CPU架构来加载对应位数的字节码。
Android读取32位字节码,ios根据cpu来读取32/64位字节码即可。
##
官方文档搬运:LuaJIT编译生成字节码的方式
LuaJIT只有一个单独的可执行文件,POSIX系统上是luajit,Window平台上是luajit.exe,它可以使用命令行来执行Lua Statements 或者整个lua应用程序,也有交互模式(?)
LuaJIT命令行选项 -b[options] input output
-b 这个选项用于保存和列出字节码, 并且可以接受以下一些叠加选项
-1 — Only list bytecode. -s — Strip debug info (this is the default). -g — Keep debug info. -n name — Set module name (default: auto-detect from input name) -t type — Set output file type (default: auto-detect from output name). -a arch — Override architecture for object files (default: native). -o os — Override OS for object files (default: native). -e chunk — Use chunk string as input. - (a single minus sign) — Use stdin as input and/or stdout as output.
输出文件类型是从输出文件名的拓展类型中自动得到的
c — C source file, exported bytecode data.
h — C header file, static bytecode data.
obj or o — Object file, exported bytecode data (OS- and architecture-specific).
raw or any other extension — Raw bytecode file (portable). Notes:
- 请参阅string.dump()来获取字节码的可移植性和兼容性的信息。
- 一个raw bytecode格式的文件是自动获取的,然后可以被像Lua源代码一样被加载。举例来说类似于直接使用命令行或者使用loadfile(),dofile。
- 为了在应用程序中静态地嵌入模块的字节码,生成一个object文件并将其与您的应用程序连接起来。
- 在大多数基于elf的系统(如Linux)上,您需要在连接应用程序时显式地导出全局符号,例如:-wl-e
- require()尝试从导出的符号中加载嵌入的字节码数据(从 *.exe或Windows平台上上的lua5.1.dll)和来自package.cpath的共享库。
string.dump(f [,strip]) 生成轻便的字节码
string.dump()中加入了一个额外的参数,如果被设置为true, 将会生成没有调试信息的‘剥离式’字节码,这将会加速字节码的加载和减少内存用量。请参阅 -b 命令行选项。
产生出来的字节码是轻便的而且可以被任意LuaJIT支持的架构加载,独立的字长和字节序,但是字节码的兼容版本号必须匹配。字节码版本在小版本之间保持兼容(x.y.0 -> x.y.1), 但是可能会在major或者minor版本或任意beta版本之间改变。外部字节码(例如 来自于lua 5.1 )是不兼容且不能被加载的。
参考链接:
Luajit-2.1.0-beta1的发布和生成arm64用bytecode的解脱
64位lua引擎如何支持32位luac编译出来的二进制字节码?
【最新】LuaJIT 32/64 位字节码,从编译到使用全纪录
