【问题标题】:weak symbols and custom sections in inline assembly内联汇编中的弱符号和自定义部分
【发布时间】:2017-06-21 17:37:02
【问题描述】:

我遇到了一个问题,下面的 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); }

我正在做这些古怪的自定义部分以模仿the mechanism here in the linux kernel(但以用户态和 C++ 方式)。

我的问题是frob&lt;int&gt; 的实例化被识别为弱符号,这很好,并且两者之一最终被链接器省略,这也很好。除了链接器不受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 语句可能会通过这种机制获得相同的符号(可能吗?)。

有没有我忽略的方法?

【问题讨论】:

    标签: c++ gcc linker custom-sections


    【解决方案1】:

    g++(至少 5,6)编译带有外部链接的内联函数 - 例如 template&lt;&gt; inline int frob&lt;int&gt;(int x) - 全球疲软 [COMDAT] [function-section] 中的符号 它自己的部分组。见:-

    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 设置为 一个部分组:

    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
    

    【讨论】:

    • 谢谢!事实上,这是一种丢弃对被丢弃部分的引用的有效方法。除了简洁的 binutils 文档之外,我找不到适合气体部分组的语义。我不清楚合并何时发生或不发生,以及我是否可以完全控制它。
    猜你喜欢
    • 1970-01-01
    • 2014-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-15
    • 1970-01-01
    • 2018-02-03
    • 1970-01-01
    相关资源
    最近更新 更多