2

次の 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(); }

バー.cpp:

#include "frob.hpp"
int bar() { return frob(42); }

ここでLinuxカーネルのメカニズムを模倣する方法として、これらの風変わりなカスタムセクションのことを行っています(ただし、ユーザーランドとC++の方法で)。

私の問題は、のインスタンス化がfrob<int>弱いシンボルとして認識されることです。これは問題ありません。2 つのうちの 1 つが最終的にリンカーによって省略されますが、これも問題ありません。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"::);
    

    ただし、この方法を使用すると、異なるコンパイル単位の異なる asm ステートメントがこのメカニズムを介して同じシンボルを取得する可能性があるのではないかと心配しています (そうでしょうか?)。

私が見落とした回避策はありますか?

4

1 に答える 1

1

g++ (少なくとも 5、6) は、独自のセクション グループの[COMDAT] [関数セクション]template<> inline int frob<int>(int x)の弱いグローバル シンボルで、外部リンケージ (など) を使用してインライン関数をコンパイルします。見る:-

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
于 2017-06-22T18:52:57.690 に答える