I'm stuck with a problem which is illustrated by the following g++ code:
frob.hpp:
template<typename T> T frob(T x);
template<> inline int frob<int>(int x) {
asm("1: nop\n"
".pushsection \"extra\",\"a\"\n"
".quad 1b\n"
".popsection\n");
return x+1;
}
foo.cpp:
#include "frob.hpp"
extern int bar();
int foo() { return frob(17); }
int main() { return foo() + bar(); }
bar.cpp:
#include "frob.hpp"
int bar() { return frob(42); }
I'm doing these quirky custom section things as a way to mimick the mechanism here in the linux kernel (but in a userland and C++ way).
My problem is that the instantiation of frob<int>
is recognized as a weak symbol, which is fine, and one of the two is eventually elided by the linker, which is fine too. Except that the linker is not disturbed by the fact that the extra
section has references to that symbol (via .quad 1b
), and the linker want to resolve them locally. I get:
localhost /tmp $ g++ -O3 foo.cpp bar.cpp
localhost /tmp $ g++ -O0 foo.cpp bar.cpp
`.text._Z4frobIiET_S0_' referenced in section `extra' of /tmp/ccr5s7Zg.o: defined in discarded section `.text._Z4frobIiET_S0_[_Z4frobIiET_S0_]' of /tmp/ccr5s7Zg.o
collect2: error: ld returned 1 exit status
(-O3
is fine because no symbol is emitted altogether).
I don't know how to work around this.
extra
section too ?perhaps one could trade the local labels for .weak
global labels ? E.g. like in:
asm(".weak exception_handler_%=\n"
"exception_handler_%=: nop\n"
".pushsection \"extra\",\"a\"\n"
".quad exception_handler_%=\n"
".popsection\n"::);
However I fear that if I go this way, distinct asm statements in distinct compilation units may get the same symbol via this mechanism (may they ?).
Is there a way around that I've overlooked ?
g++ (5,6, at least) compiles an inline function with external linkage - such as
template<> inline int frob<int>(int x)
- at a weak global
symbol in a [COMDAT] [function-section] in
its own section-group. See:-
g++ -S -O0 bar.cpp
bar.s
.file "bar.cpp"
.section .text._Z4frobIiET_S0_,"axG",@progbits,_Z4frobIiET_S0_,comdat
.weak _Z4frobIiET_S0_
.type _Z4frobIiET_S0_, @function
_Z4frobIiET_S0_:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl %edi, -4(%rbp)
#APP
# 8 "frob.hpp" 1
1: nop
.pushsection "extra","a"
.quad 1b
.popsection
# 0 "" 2
#NO_APP
movl -4(%rbp), %eax
addl $1, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
...
...
The relevant directives are:
.section .text._Z4frobIiET_S0_,"axG",@progbits,_Z4frobIiET_S0_,comdat
.weak _Z4frobIiET_S0_
(The compiler-generated #APP
and #NO_APP
delimit your inline assembly).
Do as the compiler does by making extra
likewise a COMDAT section in
a section-group:
frob.hpp (fixed)
template<typename T> T frob(T x);
template<> inline int frob<int>(int x) {
asm("1: nop\n"
".pushsection \"extra\", \"axG\", @progbits,extra,comdat" "\n"
".quad 1b\n"
".popsection\n");
return x+1;
}
and the linkage error will be cured:
$ g++ -O0 foo.cpp bar.cpp
$ ./a.out; echo $?
61