为啥在两台略有不同的机器上编译的库的行为略有不同?
Posted
技术标签:
【中文标题】为啥在两台略有不同的机器上编译的库的行为略有不同?【英文标题】:Why does the library compiled on two slightly different machines behaves slightly different?为什么在两台略有不同的机器上编译的库的行为略有不同? 【发布时间】:2010-11-19 01:55:23 【问题描述】:设置如下:
我的同事有一台带有 gcc 4.3.3 交叉编译器(来自 buildroot)的 Fedora x64_86 机器。 我有一台具有相同交叉编译器的 Ubuntu 9.04 x64_86 机器。
我的同事构建了一个可在测试机器上运行的库 + 测试应用程序,我编译了相同的库和 testapp,但它在同一台测试机器上崩溃了。
据我所知,gcc 是针对 buildroot 编译的 ucLibc 构建的,因此,相同的代码,相同的编译器。什么样的主机差异会影响交叉编译?
任何见解都值得赞赏。
更新:为了澄清,编译器是相同的。库和 testapp 的源代码相同。唯一的区别是testapp + lib是在不同的机器上编译的..
【问题讨论】:
如果不能检查机器或代码就很难知道。你能告诉我们坠机的性质吗?这是什么类型的崩溃?它发生在您的代码中还是它所依赖的库中? 如果一切都相同,那么输出文件有什么不同? 怎么样,有没有发现问题? 不幸的是,我没有找到导致崩溃的原因。环境中的某些东西,或源中的错误。我永远不会知道:( 【参考方案1】:如果您的代码崩溃(我假设您获得了 sigsegv),则似乎存在错误。这很可能是某种未定义的行为,例如使用悬空指针或写入缓冲区边界。
未定义行为的不幸之处在于,它可能在某些机器上工作。我想你在这里遇到了这样的事件。试着找出错误,你就会知道会发生什么:-)
【讨论】:
澄清一下,这是相同的代码,它是在两台不同的机器上用相同的编译器编译的。但是它的行为不同。 这与 ebo 所说的并不矛盾。未定义的行为是未定义的,并且绝对可以受到任何东西的影响,例如编译器在不同操作系统上使用的动态库版本略有不同。我敢打赌,这个错误可以追溯到未定义的行为。 这正是未定义行为的样子。 哦。啊。明白了,我认为..原始编译不会崩溃的事实是例外而不是规则。明白了。。【参考方案2】:它以什么方式崩溃?你能更具体一点,提供输出、返回码等...你试过插入一些有用的 printf() 吗?
而且,我认为我们需要更多细节:
testapp 是否链接到库?
库是静态的还是动态的?
库是否在库搜索路径中,或者您是否已将其目录添加到 ld.so.conf?
您是否遵循库和 testapp 的任何安装过程?
这两个库和 testapps 是否逐位兼容?你希望他们是吗?
您是否以与同事相同的用户、相同的环境和权限运行?
【讨论】:
应用程序因段错误而崩溃。我不知道这是否有趣,我更感兴趣的是了解这种差异来自哪里。 1. 是的,应用程序链接到图书馆。 2. 它是一个共享库。 3. 通过 LD_LIBRARY_PATH 找到该库 4. 我编译了该库和 testapp 并将其保留在其原始目录中。 5. 我不确定 bit for bit compatible 是什么意思。它们是为相同的拱门、相同的编译器编译的。 6. 是的,这是一个嵌入式设备,所以我以 root 身份运行。 您是否使用 ldd 来确保两个 testapp 都链接到目标上完全相同的库?我不确定你在pt上的意思。 4. 原始目录是什么?由于这是一个交叉编译的目标,您必须在一台机器上编译并部署到目标(测试机器)。您的部署方式与您的同事完全相同吗? 至于 pt。 5、每个部分(库和测试应用程序)的两个版本之间的二进制差异返回什么,即它们是否完全相同? 为了清楚起见,我并不是建议您使用 testapp 来区分库,而是建议您使用 testapp(同事)来区分 testapp(您的)。图书馆也一样。【参考方案3】:显然,有些不一样。
尝试使用 objdump 及其许多选项,尤其是 -d,来确定有什么不同。
你没有说明这一点,所以我猜测 binutils 是不同的。那是用于构建二进制文件的工具集。它包括ld、as和objdump。
交叉编译器需要它们自己的一组用于目标架构的 binutils。但是,与 GCC 不同,我不相信 binutils 工具会执行双重引导构建和验证步骤,因此可能与原始 x86_64 构建环境存在一些差异。
我会尝试使用 ARM 交叉编译器再次为 ARM 构建 binutils 包。看看会不会有什么不同。
这也是我在常规 x86 Gentoo stage1 安装中看到的情况:在安装和更新引导系统和编译器后,强烈建议 Gentoo 用户使用更新的工具再次重建系统。
【讨论】:
Binutils 在两台机器上是相同的,因为它们是由 buildroot 编译的。关于重新编译工具的有趣说明,谢谢。【参考方案4】:你的目标是什么拱门(测试机器)?
您是否使用发行版提供的编译器?他们通常有相当多的补丁集应用于 gcc,例如在 gentoo 上大约有 20 个补丁,fedora 和 ubuntu 不会有那么不同。不过,并非所有补丁都 100% 好 :-( 所以编译器实际上可能会有所不同。
您可能会在您的发行版中寻找“香草”版本的 gcc,也许它可以解决问题。
【讨论】:
目标拱门是手臂。该代码使用 buildroot 提供的相同编译器进行编译。【参考方案5】:我认识一个在大学里有类似经历的人。基本上,在一个相同机器的实验室中,他的项目在他的开发箱上运行,但在教授箱上可怕地崩溃了。这是两台机器,它们是相同的架构,运行相同版本的操作系统。
归结为某处未初始化的指针。
他的代码看起来像:
if(p == NULL)
p = f();
由于 p 是在堆上分配的类的成员,它的值实际上是随机的,有时实际上是 NULL,使事情正常...问题是 有时 和在 一些 机器上,p 的内存在程序启动时为 NULL,但在 prof 的机器上却不是。修复当然是正确初始化 p tp NULL,一切都很好。
您可能正在经历类似的事情。或者某种类型的未定义行为,这是一种奇特的说法,即“它可能会或可能不会因为任何原因或根本没有原因按预期工作”
【讨论】:
【参考方案6】:作为在黑暗中的刺,我会寻找未初始化的变量。 确保为所有局部和全局变量赋值。 仔细检查构造函数是否具有所有数据成员的初始化程序。
【讨论】:
以上是关于为啥在两台略有不同的机器上编译的库的行为略有不同?的主要内容,如果未能解决你的问题,请参考以下文章
Discord 在我的 GitHub 上编译的 dll 中找到了机器人令牌