gcc链接器选项会改变编译后二进制文件中的汇编指令吗?

6
我想知道gcc链接器选项(例如:-Wl,options)是否会改变编译后的可执行文件中的汇编指令,就像使用某些gcc优化选项一样会发生的那样?当您比较编译后的二进制文件(例如比较签名)时,使用链接器选项和不使用之间的差异是否可以看到?
更新:
更准确地说,我想弄清楚在编译过程中使用某些链接选项是否会更改FLIRT签名。这些签名仅使用库函数来创建签名。

1
请参见例如 --wrap - Phillip
@Phillip,你能更精确地解释一下吗? - Maximilian
手册中详细介绍了该选项;它可以用于覆盖符号,对于C对象文件而言,这也可能会改变函数的签名。 - Phillip
1
你的问题不太有意义。链接器可以在可执行文件中生成不同的汇编指令,这与链接器选项无关,并且GCC优化选项通常会对最终的汇编指令产生巨大的影响。 - Ross Ridge
1
你是在询问整个二进制文件的哈希值会因为什么改变,还是只有实际的机器代码?(即是否排除目标文件元数据,如节头?)我相当确定你包括跳转中不同的rel32偏移量等内容,所以顺序很重要。如果你只关心不同的指令操作码,那只会发生在链接时优化,其中代码生成在链接时完成/重新完成。 - Peter Cordes
2个回答

5

对于某些连接器选项,可以在生成的二进制文件中看到变化,例如:

  • 去除/保留调试符号的选项(--strip-all--strip-debug--discard-all
  • 去除/保留未使用部分的选项,例如包含一个从未被其他部分引用的函数的部分。这些部分可以很容易地被删除。或者保留重定位部分/内容的选项(--as-needed--emit-relocs
  • 包括一个静态库或另一个兼容的静态库的选项(例如库版本x.0与版本x.1)
  • 对象和静态库在命令行上放置的顺序。例如ld -o foo a.obj b.obj c.objld -o foo a.obj c.obj b.obj如果解析了从a到c中的函数调用,则 可能 会产生不同的二进制文件(来自c.obj的代码偏移量以及c中函数的地址将 可能 不同)

但即使在链接后,二进制文件的签名也可能会发生变化。例如在Linux中,当您通过运行prelink来优化二进制文件的启动时间时。


实际上,我只对二进制函数级别的更改感兴趣。如果特定的调试符号被修改,这不会改变函数的汇编代码。您能想象使用链接器选项更改函数基础上的汇编代码的情况吗? - Maximilian
3
是的,对其他对象的调用可能会根据它们的顺序或静态库的顺序或不同版本的库而解析到不同的偏移量/地址。 - Elijan9
但是静态库中的函数不会受到影响,对吧? - Maximilian
2
@PeterFox 不会,它们通常会因为其在可执行文件中的位置以及其他它们所引用的内容所在的位置而有所不同。 - Ross Ridge

2

是的,如果使用不同的链接器选项链接两个二进制文件,你将会看到不同的校验和——除非该选项没有产生影响,例如当你指定默认选项或者一个不改变二进制文件的选项(-print-map)时。

你想要弄清楚什么?听起来你在指定某些链接器选项时遇到了问题,想要找出原因。告诉我们更多细节,也许我们能够提供更好的帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接