слабые символы и пользовательские разделы в встроенной сборке

Я застрял с проблемой, которая иллюстрируется следующим кодом 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 это хорошо, потому что символ не испускается вообще).

Я не знаю, как обойти это.

  1. будет ли способ сказать компоновщику также обратить внимание на разрешение символов в extra раздел тоже?
  2. возможно, можно было бы обменять местные этикетки на .weak глобальные ярлыки? Например. как в:

    asm(".weak exception_handler_%=\n""exception_handler_%=: nop\n"".pushsection \"extra\",\"a\"\n"".quad exception_handler_%=\n"".popsection\n"::);
    

    Однако я боюсь, что если я пойду таким образом, различные ассемблерные выражения в разных единицах компиляции могут получить один и тот же символ через этот механизм (не так ли?).

Есть ли способ обойти, что я упустил?

2

Решение

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
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]