【发布时间】:2020-02-14 07:44:13
【问题描述】:
我正在使用 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)会进一步优化代码吗?如何限制链接器使用的指令?
【问题讨论】:
-
您确定没有使用
-flto启用链接时优化/代码生成吗?通常允许跨文件内联是一件好事,但您也需要为此设置正确的拱形和优化选项。显然,对于生成最终代码的任何内容,您都设置了基线以外的其他内容。 (或者你链接了一些不同的目标文件......) -
另外,我认为 GCC 正在为那些 2 字节负载编写非常低效的代码。看起来
movzwl 0x80(%rsp), %eax/shl $8, %eax会起作用。您是否有可以重现错过的优化的资源?还是只有某些旧的 GCC 版本才会出现这种情况? -
我真的不确定,但也许是因为一些放松。我的意思是想象一个架构,它有一个
JUMP指令,它只能跳转到256字节之外。你调用了一个在这个范围内的foo函数,所以会生成像JUMP foo这样的东西。现在这在该编译单元中可能有效,但是当您将其与其他代码链接时,foo可能会超出该256字节范围,因此必须将其替换为能够进行更长跳转的类似指令。所以没有必要进行优化,可能只需要使代码有效。 -
请创建一个minimal reproducible example,包括确切的编译器版本和您键入以生成错误二进制文件的确切命令。有多种可能的问题,并且至少不知道编译器和链接器是如何被调用的,很难说问题可能是什么。
-
感谢所有有用的 cmets。我发现了问题。请参阅我自己发布的答案。请不要投票。很抱歉问了一个不完整且愚蠢的问题。
标签: gcc assembly optimization linker ld