62

我所做的

在为 Linux 编写共享库时,我倾向于关注重定位、符号可见性、GOT/PLT 等。

如果适用,我会尽量避免在同一个库中的函数相互调用时调用 PLT 存根。例如,假设一个共享对象提供了两个公共函数 -foo()bar()(其中任何一个都可以由用户调用)。bar()但是,该函数也调用foo(). 所以我在这种情况下要做的是:

  1. 定义具有私有可见性的函数_foo()_bar()
  2. 分别为和定义foo()bar()弱别名。_foo()_bar()

这样,共享对象中的代码就不会使用弱符号。它只直接调用本地函数。例如,当_bar()被调用时,它_foo()直接调用。

但用户不了解_*函数,总是使用相应的弱别名。

我是怎么做的

在 Linux 中,这是通过使用以下结构来实现的:

extern __typeof (_NAME) NAME __attribute__(weak, alias("_NAME"));

问题

不幸的是,这不适用于 OS X。我对 OS X 或其二进制格式没有深入的了解,所以我翻了一下,发现了一些弱函数的例子(比如这个),但那些并不完全就像你可以有一个弱符号一样,但不能有一个弱符号,它是 DSO 本地函数的别名。

可能的解决方案...

现在,我刚刚禁用了这个功能(使用宏实现),以便所有符号都是全局的并且具有默认可见性。我现在能想到的唯一方法是让所有_foo函数都具有私有可见性,并具有foo具有默认可见性的相应函数并调用它们的“隐藏”对应项。

更好的方法?

但是,这需要更改大量代码。因此,除非真的没有其他办法,否则我宁愿不去那里。

那么关闭 OS X 替代方案或获得相同语义/行为的最简单方法是什么?

4

1 回答 1

2

在 OS X 上,在库中进行的调用会自动成为直接调用,并且不会通过 dyld 存根。事实的证据是,如果您希望能够注入替代函数来服务调用,则需要使用 interposable 来强制间接访问符号并通过 dyld 存根强制执行调用。否则,默认情况下,本地调用将是直接的,不会产生通过 dyld 运行的开销。

因此,您在 Linux 上的优化已经是默认行为,不需要别名。

尽管如此,如果您只是为了使您的平台兼容代码更简单而这样做,您仍然可以创建别名。您只需要使用“weak_import”或“weak”(如果您想合并)作为您的属性名称。

extern typeof (_NAME) NAME __attribute (weak_import, alias("_NAME"));

Apple 关于弱链接的参考:为弱链接标记符号
Apple 关于 Mach-O 运行时绑定的参考:符号定义的范围和处理

于 2014-06-13T23:13:57.650 回答