4

多年来一直在 Mac OS X 通用二进制应用程序中使用 Lua 5.0。Lua 脚本使用 luac 编译,编译后的脚本与应用程序捆绑在一起。他们已经在 Tiger and Leopard、Intel 或 PPC 中正常工作。

当时为了避免库问题,我只是将 Lua src 树添加到我的 Xcode 项目中并按原样编译,没有任何问题。

是时候更新到更现代的 Lua 版本了,所以我用 5.1.4 替换了我的源代码树。我使用make macosx重建了 luac (机器在 Intel 上运行 Leopard)。

未编译的脚本一如既往地在 Tiger 和 Leopard、Intel 和 PPC 中正常工作。

但是,现在编译的脚本无法在 PPC 机器上加载。

所以我用'ansi'标志重建了luac,并重新编译了我的脚本。同样的错误。同样,“通用”的构建标志也没有产生任何乐趣。

谁能告诉我下一步我能做什么?

4

6 回答 6

13

Lua 的编译脚本几乎是在一个简短的标头之后转储出来的原始字节码。头文件记录了用于编译字节码的平台的一些属性,但加载器仅验证当前平台是否具有相同的属性。

不幸的是,这在加载在另一个平台上编译的字节码时会产生问题,即使是由相同版本的 Lua 编译。当然,不同版本的 Lua 编译的脚本不能正常工作,而且由于 Lua 的版本号包含在字节码头中,因此加载它们的尝试被内核捕获。

简单的答案是不编译脚本。如果 Lua 自己编译脚本,您只需要担心应用程序的各种构建中 Lua 内核之间可能存在的版本不匹配,这并不难处理。

实际上支持编译字节码的完全交叉兼容性并不容易。在该电子邮件中,Mike Pall 指出了以下问题:

  1. Endianess:根据需要交换输出。

  2. sizeof(size_t), 影响巨大的字符串常量:降级时检查溢出。

  3. sizeof(int), 影响MAXARG_BxMAXARG_sBx: 降级时检查溢出。

  4. typeof(lua_Number):在C语言中很容易,但只有当主机和目标遵循相同的FP标准时;升级时的精度损失(罕见情况);降级到时警告非整数数字 int32

从我在邮件列表上看到的关于这个问题的所有讨论中,我看到了两种可能的可行方法,假设您不愿意考虑只发送未编译的 Lua 脚本。

第一个是在加载编译脚本时修复字节顺序。事实证明,这比您预期的要容易,因为可以通过替换读取脚本文件的低级函数来完成,而无需重新编译内核本身。事实上,它甚至可以在纯 Lua 中完成,方法是向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”)、版本和格式代码、字节顺序的标志字节、类型的大小intsize_tInstructionlua_Number,以及指示是否lua_Number为积分型。

这允许捕获大多数平台差异,但不会尝试捕获平台可能不同的所有方式。

我仍然坚持上面提出的建议:首先,发布可编译的源;或者第二,自定义ldump.clundump.c存储和加载通用格式,另外注意任何自定义格式都应重新定义标头的 LUAC_FORMAT 字节,以免与库存字节码格式混淆。

于 2009-06-26T08:24:12.597 回答
3

您可能想要使用支持不同字节序的修补字节码加载器。看到这个

于 2009-06-26T13:25:08.823 回答
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

标准免责声明:我不声称修改是完美的或在任何情况下都有效。如果您使用它并发现任何损坏的东西,我会很高兴听到它以便修复它。

于 2009-06-27T00:23:40.840 回答
1

Lua 字节码不可移植。您应该随应用程序一起提供源脚本。

如果下载大小是一个问题,它们通常比字节码形式短。

如果知识产权是一个问题,您可以使用代码混淆器,并记住反汇编 Lua 字节码绝非难事。

如果加载时间是一个问题,您可以在安装脚本中本地预编译源代码。

于 2009-06-26T08:46:47.480 回答
0

我猜你是在 Intel 机器上编译的脚本。

编译后的脚本非常不可移植。如果您真的想预编译脚本,则需要包含每个已编译脚本的两个版本:一个用于 Intel,一个用于 PPC。您的应用程序将不得不询问它正在运行的程序并使用正确的编译脚本。

于 2009-06-26T23:54:59.757 回答
0

我没有足够的声誉来发表评论,所以我必须提供这个作为答案,即使它不是对所提问题的适当答案。对不起。

这里有一个 Lua 混淆器:

http://www.capprime.com/CapprimeLuaObfuscator/CapprimeLuaObfuscator.aspx

完全披露:我是混淆器的作者,我知道它并不完美。欢迎并鼓励提供反馈(上面的页面有一个反馈页面)。

于 2009-06-28T11:33:59.953 回答