Overrides symbols on linking

environment: Apple clang version 14.0.3 (clang-1403.0.22.14.1)

I am trying to override c++ symbols at linking time for the purpose of inserting measurement code into an existing library.

Perhaps typical linkers would search for symbols in specifing order of library and adopt the first hit. Xcode's ld apparently does this in units of a object file. If you create one object file to override one function and link it first, but call another function in the same object file contained in the original library, that one will be adopted. As a result, you cannot override function. To override a function, the function to be overridden must be moved to a new cpp file and separated from the object file.

Here is a sample program to test this. https://onedrive.live.com/redir?resid=DD46698E2D493F32!395&authkey=!AJqfiva7CXIDI_Y&e=OaFlSr

As you can see in main.cpp, func() and bar() are called from main(). func() and bar() are implemented in func.cpp and bar.cpp, respectively. They are linked to libTest.lib. To override func(), link libTest2.lib implementing func2() in func2.cpp, before libTest.lib. If you run make and look at the code with objdump -d a.out, you can see the override. Because the content of func2() is return i+1, __Z4funci contains leal 1(%rdi), %eax.

Then, build with make clean and make CONCAT=1, func() and bar() are concatenated into one cpp file and compiled. The generated a.out is checked in the same way, you will see movl %edi, %eax at same position which means return i; which is the content of func().

This sample is small in scale, but in a larger project, it can be quite a hassle to isolate the functions you want to override.

Is there any easier way to override the function? Since the original function name cannot be changed, it is our policy not to use -alias symbol_name alternate_symbol_name.

Thanks.

  • The variable ret was not initialized in main.cpp. If you do not fix it as follows, the result of executing a.out, echo $? will be undefined.

    int main(void) { int ret = 0; ret = func(ret);

Add a Comment

Accepted Reply

Before we start, I want to point you at An Apple Library Primer, which explains a lot of backstory.

Xcode's ld apparently does this in units of a object file.

Yep. That’s pretty standard for Unix-y toolchains in my experience. One of our recent WWDC sessions (links in An Apple Library Primer) describes the process in great detail.

I’m not sure if there’s any way to achieve your goal. This limitation is pretty fundamental to how object files work. But perhaps someone else will chime in with something I’ve missed.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Replies

Before we start, I want to point you at An Apple Library Primer, which explains a lot of backstory.

Xcode's ld apparently does this in units of a object file.

Yep. That’s pretty standard for Unix-y toolchains in my experience. One of our recent WWDC sessions (links in An Apple Library Primer) describes the process in great detail.

I’m not sure if there’s any way to achieve your goal. This limitation is pretty fundamental to how object files work. But perhaps someone else will chime in with something I’ve missed.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I spent some time digging into this yesterday. My initial impression was that the Apple linker was unable to break up a .o file at all. That’s not true. The linker’s dead code stripping is able to do this. It breaks the code within the .o file up into atoms [1] and can dead strip those atoms independently.

However, I’m not sure that helps you with your situation. I haven’t found a way to convince the linker to split apart a .o for the purposes of symbol resolution. I’m still zenning on this though.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] This is a term used within the linker and AFAIK isn’t exposed externally.

Thank you for the related article and for your efforts. Considering that the Xcode linker (BSD linker?) does not allow symbols to be referenced across objects, I guess the only way is to overwrite the entire object file. Fortunately, one object file is generated from one .cpp file, so it is possible to create an object file with partially different functionality by compiling it with another preprocessor macros. Of course, function override-like things can be realized. Conversely, unfortunately, in non-Makefile Xcode builds, the list of object files (.LinkFileList) is specified before the library flag -l is specified. This is not a problem in many cases, since the overwriting library can be specified before the target library.

Thanks.

Considering that the Xcode linker (BSD linker?)

The linker is an Apple specific thing. I’m not familiar with its very early history, but I believe that it split from BSD during the Mach project [1]. NeXT significantly enhanced it before the merger, and then Apple fully rewrote it to make ld64, and then significantly rewrote it to make ld_prime [2].

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] See here and here.

[2] These terms are defined in An Apple Library Primer.

I've gone off on a tangent with an unnecessary post, but it's safe to say that it's resolved for now. Thank you very much.

I've gone off on a tangent with an unnecessary post

Hey, I love tangents (-:

Earlier I wrote:

I haven’t found a way to convince the linker to split apart a .o for the purposes of symbol resolution. I’m still zenning on this though.

That didn’t pan out. At this point I’m pretty sure there’s no way to get the linker to split apart a .o for the purposes of symbol resolution.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"