Я застрял с проблемой, которая иллюстрируется следующим кодом G ++:
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); }
Я делаю эти необычные вещи из пользовательского раздела как способ подражать механизм здесь в ядре Linux (но в пользовательской среде и в C ++).
Моя проблема в том, что создание frob<int>
распознается как слабый символ, и это нормально, и один из двух в конечном итоге удаляется компоновщиком, что тоже хорошо. За исключением того, что компоновщик не беспокоит тот факт, что extra
в разделе есть ссылки на этот символ (через .quad 1b
), и компоновщик хочет разрешить их локально. Я получил:
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
это хорошо, потому что символ не испускается вообще).
Я не знаю, как обойти это.
extra
раздел тоже?возможно, можно было бы обменять местные этикетки на .weak
глобальные ярлыки? Например. как в:
asm(".weak exception_handler_%=\n""exception_handler_%=: nop\n"".pushsection \"extra\",\"a\"\n"".quad exception_handler_%=\n"".popsection\n"::);
Однако я боюсь, что если я пойду таким образом, различные ассемблерные выражения в разных единицах компиляции могут получить один и тот же символ через этот механизм (не так ли?).
Есть ли способ обойти, что я упустил?
g ++ (по крайней мере, 5,6) компилирует встроенную функцию с внешней связью, например
template<> inline int frob<int>(int x)
— при слабом глобальном
символ в [COMDAT] [Функция-раздел] в
своя секция-группа. Увидеть:-
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
...
...
Соответствующие директивы:
.section .text._Z4frobIiET_S0_,"axG",@progbits,_Z4frobIiET_S0_,comdat
.weak _Z4frobIiET_S0_
(Сгенерированный компилятором #APP
а также #NO_APP
разграничить вашу встроенную сборку).
Делайте так, как делает компилятор, делая extra
также раздел COMDAT в
секция-группа:
frob.hpp (исправлено)
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;
}
и ошибка связи будет исправлена:
$ g++ -O0 foo.cpp bar.cpp
$ ./a.out; echo $?
61
Других решений пока нет …