我正在使用Linux(centos7_64)中的sqlite3库编译程序。由于用户的CPU较旧,我在GCC中设置了-march = nehalem标志(-march = nehalem -mtune = nehalem -m64 -O3)。我发现我不能将汇编指令限制为nehalem,最终的二进制文件中仍然存在一些BMI操作。
按照输出步骤,发现问题来自链接器(ld)。
libsqlite3.a:
632c2: 66 41 83 4f 26 01 orw $0x1,0x26(%r15)
632c8: 0f b6 84 24 80 00 00 movzbl 0x80(%rsp),%eax
632cf: 00
632d0: c1 e0 08 shl $0x8,%eax
632d3: 89 c2 mov %eax,%edx
632d5: 0f b6 84 24 81 00 00 movzbl 0x81(%rsp),%eax
632dc: 00
632dd: c1 e0 10 shl $0x10,%eax
632e0: 09 d0 or %edx,%eax
632e2: 8d 90 00 fe ff ff lea -0x200(%rax),%edx
632e8: 41 89 47 30 mov %eax,0x30(%r15)
632ec: 81 fa 00 fe 00 00 cmp $0xfe00,%edx
632f2: 0f 87 d1 05 00 00 ja 638c9 <sqlite3BtreeOpen+0xb29>
632f8: 8d 50 ff lea -0x1(%rax),%edx
632fb: 85 c2 test %eax,%edx
632fd: 0f 85 c6 05 00 00 jne 638c9 <sqlite3BtreeOpen+0xb29>
但是,在最后的二进制文件中:
9499f2: 66 41 83 4f 26 01 orw $0x1,0x26(%r15)
9499f8: 0f b6 84 24 80 00 00 movzbl 0x80(%rsp),%eax
9499ff: 00
949a00: 0f b6 94 24 81 00 00 movzbl 0x81(%rsp),%edx
949a07: 00
949a08: c1 e0 08 shl $0x8,%eax
949a0b: 89 c1 mov %eax,%ecx
949a0d: 89 d0 mov %edx,%eax
949a0f: c1 e0 10 shl $0x10,%eax
949a12: 09 c8 or %ecx,%eax
949a14: 8d 90 00 fe ff ff lea -0x200(%rax),%edx
949a1a: 41 89 47 30 mov %eax,0x30(%r15)
949a1e: 81 fa 00 fe 00 00 cmp $0xfe00,%edx
949a24: 0f 87 cf 05 00 00 ja 949ff9 <sqlite3BtreeOpen+0xb09>
949a2a: c4 e2 78 f3 c8 blsr %eax,%eax
949a2f: 85 c0 test %eax,%eax
949a31: 0f 85 c2 05 00 00 jne 949ff9 <sqlite3BtreeOpen+0xb09>
注意最后几行,链接器将lea更改为blsr,这是意外的。
因此,为什么会这样。链接程序(ld)会进一步优化代码吗?如何限制链接器使用的指令?
非常感谢您的评论。正如彼得·科德斯(Peter Cordes)在评论中所说,我已经找到问题了,我链接到另一套sqlite库。我安装了太多套GCC编译器环境,并且每个编译器在其默认库路径中都有自己的sqlite。我的项目由cmake管理,它记得以前所有的GCC设置...
发现步骤:
向gcc命令添加-v标志。
复制ld命令,并添加标志“ --print-map -Map = demo.map”,再次运行完整的ld命令。
在demo.map中搜索库名称(在此处为sqlite),我清楚地发现另一组sqlite库已链接。意识到我是多么愚蠢...
更新:我有一个新问题:如果library.a是使用高级CPU指令编译的,如何在链接阶段降级,看来那些指令将被复制为二进制而不检查GCC中的-march标志。