6

I try to wrap a template function with the help of GNU's linker wrap option. The code looks like this:

// f.h
template<typename T>
void f(T t) {
}

// bar.h
void bar();

// bar.cpp
#include "bar.h"
#include "f.h"

void bar() {
  f(42);
}

// test.cpp
extern "C" {
  extern void __real__Z1fIiEvT_(int i);
  void __wrap__Z1fIiEvT_(int i) {
    __real__Z1fIiEvT_(i);
  }
}

int main() {
  bar();
}

The code shown above is linked with the following command:

g++ -Xlinker -wrap=_Z1fIiEvT_ -o test test.o bar.o 

Unfortunately, this does not work and always the original function f is called instead of my wrapped version __wrap__Z1fIiEvT_. Do you see any mistakes I've made?

Edited: As advised, I append the output of nm here to make sure that the I haven't done any mistakes with the mangled name of the template function:

$ g++ -c bar.cpp -o bar.o
$ nm bar.o
0000000000000000 W _Z1fIiEvT_
Donald Duck
  • 8,409
  • 22
  • 75
  • 99
Mike
  • 187
  • 2
  • 8
  • 1
    Double check you are calling the correct decorated function by using `nm` or a similar tool. Adding the relevant output from that to the question may be helpful. – uesp Jan 17 '12 at 15:57
  • Shouldn't f(42); be f(42) ? – Francesco Belladonna Jan 20 '12 at 18:34
  • 1
    @Fire-Dragon-DoL - Template functions will infer their argument types from the arguments, and since int is the type of an otherwise undecorated integer literal, this works fine. If f were a class, then the template argument would need to be explicit. – Marc Jan 20 '12 at 18:47

2 Answers2

1

From http://linux.die.net/man/1/ld:

--wrap=symbol
Use a wrapper function for symbol. Any undefined reference to symbol will be resolved to "_wrap symbol ". Any undefined reference to "_real symbol " will be resolved to symbol.

I think the word "undefined" could be the key here. Your symbol of interest is certainly defined in bar.o, and the nm output confirms it, as undefined symbols are marked with "U", not "W".


Update:

I guess it is therefore not possible to wrap template functions?

I think it depends more on where the function is defined (or instantiated), and if this definition is available to the linker. In your case, if you defined a non-template function in bar.cpp where it is used, the result would be the same. Even if you defined the function in bar.cpp but used it in main.cpp, I guess it would be the same, though not completely sure (you may give it a try). And I am sure that if you linked bar.cpp and main.cpp into different modules (a shared library and an executable), then you would be able to wrap a function from bar.cpp used in main.cpp, again no matter whether it's template or not.


Update 2: I was not sure, but Mike confirmed with experiment (see his own answer and the comments there) that wrapping works if the symbol is undefined in an object file, even if that object file is linked together with another object file containing the symbol definition. Great!

Alexey Kukanov
  • 12,479
  • 2
  • 36
  • 55
  • You're right. Because the compiler generates code for the instantiated function template, it is not an undefined symbol anymore and hence the linker will not wrap it to "_wrap_symbol". I guess it is therefore not possible to wrap template functions? – Mike Jan 19 '12 at 08:46
1

The comments were helpful, but I don't think it is necessary to split it into an executable and a (shared) library. The key is to have a forward declaration for the template function in the calling origin and to instantiate the template function with the used type in a separate translation unit. This guarantees that f is undefined in bar.o:

//bar.cpp
#include "bar.h"

template<typename T> void f(T);

void bar() {
 f(42);
}

//f.h
template<typename T>
void f(T t) {
}

//f.cpp
#include "f.h"
template void f(int);


$ nm bar.o
                 U _Z1fIiEvT_
0000000000000000 T _Z3barv
Mike
  • 187
  • 2
  • 8
  • But, is it still considered undefined when bar.o is linked together with f.o to create an executable file? I admit I do not have practical experience with `-wrap` to say for sure what it will do. – Alexey Kukanov Jan 24 '12 at 12:41
  • Apparently yes, otherwise the linker would not wrap the symbol with the `_wrap` prefix, or am I wrong? The example given above works when used with the mangled wrapped name (`_Z1fIiEvT_`) as shown in the code at the beginning of this post. – Mike Jan 24 '12 at 14:14
  • Then, of course, yes. I will modify my answer and refer to your investigation. Thanks! – Alexey Kukanov Jan 24 '12 at 15:04