Weak symbol aliases on OS X similar to those on Linux, or a closest equivalent?
What I do
When writing shared libraries for Linux, I tend to pay attention to relocations, symbol visibility, GOT/PLT etc.
When applicable, I am trying to avoid calling PLT stubs when functions from the same library call each other. For example, let's say a shared object provides two public functions - foo()
and bar()
(either of those can be called by user). The bar()
function, however, also calls foo()
. So what I do in this case is this:
- Define
_foo()
and_bar()
functions that have private visibility. - Define
foo()
andbar()
weak aliases for_foo()
and_bar()
respectively.
That way, the code in shared object never uses weak symbols. It only invokes local functions, directly. For example, when _bar()
is invoked, it calls _foo()
directly.
But users are not aware of _*
functions and always use corresponding weak aliases.
How I do it
In Linux, this is achieved by using the following construct:
extern __typeof (_NAME) NAME __attribute__(weak, alias("_NAME"));
The problem
Unfortunately, this does not work for OS X. I have no deep knowledge of OS X or its binary formats, so I poked around a bit and found a few examples of weak functions (like this one), but those don't quite do the same as you can have a weak symbol, but not a weak symbol that is an alias for DSO's local function.
Possible solution...
For now, I have just disabled this feature (that is implemented using macros) so that all symbols are global and have default visibility. The only way I can think of to achieve the same for now is to have all _foo
functions with private visibility and have corresponding foo
functions with default visibility and calling their "hidden" counterparts.
A better way?
That, however, requires a good chunk of code to be changed. Therefore I would prefer not to go there unless there is really no other way.
So what is the closes OS X alternative or the easiest way to get the same semantics/behavior?
Solution 1:
On OS X, calls made within the library are automatically direct calls and do not go through the dyld stub. The evidence to the fact is that if you want to be able to inject alternative functions to service a call, you'll need to use interposable to force indirect access to the symbols and force execution of the call through the dyld stubs. Otherwise, by default, local calls will be direct and will not incur the overhead of running through dyld.
Thus, your optimization on Linux is already the default behavior and the alias is not needed.
Still, if you want to do this just to make your platform compatible code simpler, you can still make the aliases. You just need to use "weak_import" or "weak" (if you want coalesced) as your attribute name.
extern typeof (_NAME) NAME __attribute(weak_import, alias("_NAME"));
Apple reference on Weak Linking: Marking Symbols for Weak Linking
Apple reference on Mach-O runtime binding : Scope and Treatment of Symbol Definitions