多年来一直在Mac OS X通用二进制应用程序中使用Lua 5.0。 Lua脚本使用luac编译,编译后的脚本与app捆绑在一起。他们在Tiger和Leopard,Intel或PPC中都能正常工作。
为了避免当时的库问题,我只是将Lua src树添加到我的Xcode项目中并按原样编译,没有任何问题。
是时候更新到更现代版本的Lua了,所以我用5.1.4替换了我的源代码树。我使用 make macosx (机器在Intel上运行Leopard)重建了luac。
未编译的脚本一如既往地在Tiger和Leopard,Intel和PPC中正常运行。
但是,现在已编译的脚本无法在PPC计算机上加载。
所以我用'ansi'标志重建了luac,并重新编译了我的脚本。同样的错误。同样,'generic'的构建标志也没有产生任何乐趣。
有人可以告诉我接下来可以做些什么吗?
答案 0 :(得分:13)
Lua的编译脚本几乎是在短标题之后转储的原始字节码。头文件记录了用于编译字节码的平台的一些属性,但加载器仅验证当前平台具有相同的属性。
不幸的是,这会在加载在另一个平台上编译的字节码时产生问题,即使是由相同版本的Lua编译也是如此。当然,不能期望由不同版本的Lua编译的脚本工作,并且由于Lua的版本号包含在字节码头中,因此加载它们的尝试被内核捕获。
简单的答案是不编译脚本。如果Lua编译脚本本身,您只需要担心应用程序的各种版本中的Lua核心之间可能存在版本不匹配,这并不难解决。
实际上,支持已编译字节码的完全交叉兼容性为not easy。在该电子邮件中,Mike Pall确定了以下问题:
Endianess:根据需要交换输出。
sizeof(size_t)
会影响巨大的字符串常量:检查溢出时间 降级。
sizeof(int)
,影响MAXARG_Bx
和MAXARG_sBx
:检查溢出时间 降级。- 醇>
typeof(lua_Number)
:在C中很容易,但仅限于主机和目标 遵循相同的FP标准;精确 升级时丢失(罕见情况); 警告有关非整数的时候 降级为int32
。
从我在邮件列表中看到的有关此问题的所有讨论中,我看到两种可行的方法,假设您不愿意考虑只发送未编译的Lua脚本。
第一个是在加载编译脚本时修复字节顺序。事实证明这比你期望的更容易,因为它可以通过替换读取脚本文件的低级函数而不重新编译核心本身来完成。实际上,它甚至可以在纯Lua中完成,方法是将chunk reader函数提供给lua_load()。只要您的平台上唯一的兼容性问题是字节顺序,这应该可以工作。
第二种方法是修补核心本身,以便在所有平台上使用编译脚本的通用表示。 Luiz Henrique de Figueiredo已将此描述为可能:
.... 我相信最好的路线 字节顺序或交叉编译是 第三方转储/转储对。该 文件ldump.c和lundump.c是 完全可以替换;他们出口了 单一的,定义明确的切入点。该 预编译块的格式不是 神圣的;你可以使用任何格式, 只要ldump.c和lundump.c同意 关于它。 (例如,Rici Lake就是 考虑为...编写文本格式 预编译的块。) ....
就个人而言,我建议认真考虑不预先编译脚本,从而完全避免平台可移植性问题。
编辑:由于lhf的评论,我已经更新了我对字节码标题的描述。我还没有读过Lua源代码的这一部分,我可能应该先检查它,然后对标题中是否存在哪些信息非常自信。
这是来自lundump.c
的片段,它形成与运行平台匹配的标头副本,用于与正在加载的字节码进行比较。只需将memcmp()
与文件中的标题完全匹配进行比较,因此任何不匹配都会导致库存加载程序(luaU_undump()
)拒绝该文件。
/*
* make header
*/
void luaU_header (char* h)
{
int x=1;
memcpy(h,LUA_SIGNATURE,sizeof(LUA_SIGNATURE)-1);
h+=sizeof(LUA_SIGNATURE)-1;
*h++=(char)LUAC_VERSION;
*h++=(char)LUAC_FORMAT;
*h++=(char)*(char*)&x; /* endianness */
*h++=(char)sizeof(int);
*h++=(char)sizeof(size_t);
*h++=(char)sizeof(Instruction);
*h++=(char)sizeof(lua_Number);
*h++=(char)(((lua_Number)0.5)==0); /* is lua_Number integral? */
}
可以看出,标头长度为12个字节,包含一个签名(4个字节,“<esc>Lua
”),版本和格式代码,字节序的字节字节,类型的大小{{1} },int
,size_t
和Instruction
,以及一个标志,指示lua_Number
是否为整数类型。
这允许捕获大多数平台区别,但不会尝试捕获平台可以区别的各种方式。
我仍然支持上面提出的建议:首先,发布可编辑的来源;或者第二,自定义lua_Number
和ldump.c
以存储和加载通用格式,另外注意任何自定义格式应重新定义标题的LUAC_FORMAT字节,以免与库存字节码格式混淆
答案 1 :(得分:3)
您可能希望使用支持不同字节序的修补字节码加载器。 请参阅this。
答案 2 :(得分:3)
我会对RBerteig的帖子发表评论,但我显然还没有足够的声誉能够做到这一点。在努力使LuaRPC与Lua 5.1.x保持同步并使其与嵌入式目标一起工作时,我一直在修改ldump.c和lundump.c源代码以使它们更加灵活。嵌入式Lua项目(eLua)已经有了一些你可以在Lua列表中找到的补丁,但我添加了一些更多内容,使lundump对在不同体系结构上编译的脚本更加友好。还提供了交叉编译支持,以便您可以构建与主机系统不同的目标(请参阅下面链接所在目录中的luac.c.)
如果您有兴趣查看修改,可以在eLua源代码库中找到它们: http://svn.berlios.de/wsvn/elua/trunk/src/lua/lundump.c http://svn.berlios.de/wsvn/elua/trunk/src/lua/lundump.h http://svn.berlios.de/wsvn/elua/trunk/src/lua/ldump.c
标准免责声明: 我并未声称修改是完美的或适用于所有情况。如果您使用它并发现任何损坏,我很高兴听到它可以修复它。
答案 3 :(得分:1)
Lua字节码不可移植。您应该随应用程序一起提供源脚本。
如果担心下载大小,它们通常比字节码形式短。
如果知识产权是一个问题,你可以使用代码混淆器,并记住反汇编Lua字节码是困难的。
如果需要考虑加载时间,可以在安装脚本中本地预编译源代码。
答案 4 :(得分:0)
我猜想你在英特尔盒子上编译了脚本。
编译的脚本非常难以移植。如果您真的想要预编译脚本,则需要包含每个编译脚本的两个版本:一个用于Intel,另一个用于PPC。您的应用程序必须询问正在运行的程序并使用正确的编译脚本。
答案 5 :(得分:0)
我没有足够的声誉来评论,所以我必须提供这个作为答案,即使它不是一个问题的适当答案。遗憾。
这里有一个Lua Obfuscator:
http://www.capprime.com/CapprimeLuaObfuscator/CapprimeLuaObfuscator.aspx
完全披露:我是混淆器的作者,我知道它并不完美。欢迎并鼓励反馈(上页提供了反馈页面)。