c - COFF 对象文件中大于 64K 的未初始化数组的意外符号值
问题描述
编辑:我在使用 clang 编译器进行测试时犯了一个错误。这与 clang 一样有效。Visual Studio 2015 产生了意想不到的结果。我的结论是 Visual Studio 2015 有一些可疑之处。
我做了一个观察,我无法解释表示 Visual Studio 2015 生成的 COFF 对象文件中未初始化 C 数组的对象文件符号的值。该值应该以字节为单位表示数组的大小,但这不是我的观察。我希望有人可以解释这里发生了什么。
考虑源文件 testdata_works.c
char testb[0x10002];
考虑源文件 testdata_fails.c:
char testa[0x10001];
char testb[0x10002];
现在编译:
cl -c testdata_works.c
cl -c testdata_fails.c
现在在两个目标文件上运行“dumpbin /symbols”,并注意符号“testb”的值在两个目标文件之间有何不同(!)有关血腥细节,请参见下文。
dumpbin /symbols testdata_works.obj
006 00010002 UNDEF notype External | testb
现在为 testdata_fails.obj
dumpbin /symbols testdata_fails.obj
006 00010001 UNDEF notype External | testa
007 00010041 UNDEF notype External | testb
我们注意到符号 testb 在 testdata_works.obj 中具有预期值 0x10002,但在 testdata_fails.obj 中具有意外值 0x10041。
我把真正奇怪的部分留到最后,这可能会在那些精通 COFF 目标文件格式的人中触发众所周知的“啊哈”:
将 testdata_fails.c 中的数组大小减小到 0x10000 以下,例如:
char testa[0x0001];
char testb[0x0002];
并编译
cl -c testdata_fails.c
dumpbin 命令现在为符号 testa 和 testb 生成预期的结果:
006 00000001 UNDEF notype External | testa
007 00000002 UNDEF notype External | testb
关于这里发生了什么以及如何修复它以便它为大于 64K 的符号值产生预期结果的任何建议?
最后的评论:
我已经使用 clang/llvm-nm 7.0.1 而不是 Visual Studio 2015/dumpbin 复制了这个,所以它可能与 COFF 格式有关?
你可能会问我是如何偶然发现这一点的。我正在研究 BSD 内核 genassym.sh 脚本,并决定编写一个小型 C++ STL 程序,该程序可以从 LLVM 库可以读取的任何目标文件格式中实现相同的任务。我已经构建了这个程序,但它不能正常工作,因为目标文件中的数据不符合预期。
解决方案
COFF 不保留数组大小。与数组符号关联的值是它的起始地址。要推断数组的大小,dumpbin
必须使用一些启发式方法,例如通过查看相邻符号、部分结尾等。显然,启发式方法失败了。只有编译器知道为什么 BSS 比预期的要大。
推荐阅读
- elasticsearch - 索引 Elasticsearch 索引中的每个字段是否有缺点?
- python - 将 pandas 数据框写入 Excel 命名范围
- docker - 如何在 Dockerfile 的 RUN 中设置环境变量?
- c# - FindElement() 通过 C# 使用 Selenium 引发 System.ArgumentException
- javascript - 获取 React Native bottomTabNavigator 高度
- html - IE 浏览器控件不显示 CSS 框阴影
- android - 我想显示用法和免责声明,所以我编写了以下代码,但我的应用程序挂起
- encryption - 为大数据系统设计数据供应策略?
- python - 如何在不出现 ModuleNotFoundError 的情况下运行我的脚本?
- android - 有没有办法从 ACTION_GET_CONTENT 获取文件?