【问题标题】:How to use __func__ with inline assembly如何将 __func__ 与内联汇编一起使用
【发布时间】:2023-03-30 02:21:01
【问题描述】:

我正在尝试通过将字符串存储在特殊部分 (__dlog) 来将元数据添加到 ELF 可执行文件中。当前的方法使用(滥用?)内联汇编来存储字符串并且几乎可以按需要工作。

#include <stdio.h>
#include <stdlib.h>

#define DLOG(proto...) \
        __asm__(".pushsection __dlog, \"S\", @note\n\t" \
                ".asciz \"" __FILE__ ":function_name_here:" #proto "\"\n\t" \
                ".popsection\n\t" )

int
foo(int bar)
{
    int baz = bar / 2;
    DLOG(int baz);
    return baz;
}

int
main(int argc, char *argv[])
{
    foo(argc);
    return EXIT_SUCCESS;
}

但理想情况下,宏应该利用__func__ 标识符自动将函数名称作为字符串的一部分包含在内。最终结果应该是字符串

file.c:foo:int baz\0

在名为__dlog 的部分中。但由于__func__ 不是字符串文字,gcc 会抱怨这段代码

".asciz \"" __FILE__ ":" __func__ ":" #proto "\"\n\t"

有没有办法将__func__ 的内容添加到字符串中?如果解决方案不需要自定义构建选项或后处理步骤,则可以加分。编译器是 gcc 4.4 和 4.5。

【问题讨论】:

    标签: gcc inline-assembly


    【解决方案1】:

    编辑:这似乎有效,它没有给出一个完全未损坏的名称,但函数名称在那里

    #define DLOG( proto...) \
    __asm__(".pushsection __dlog, \"S\", @note\n\t" \
                    ".asciz \"" __FILE__ ":%0:" #proto "\"\n\t" \
                    ".popsection\n\t"  \
     : \
     :  "s" ( __func__ ) )
    
    
    int main(int argc, char*argv[]) {
    DLOG(int argc, char*argv[]);
    
    return 0;
    }
    
    extern "C" void test(int bar) {
    DLOG(bar);
    }
    

    g++-4.4 test.cpp && xxd a.out |少 -p test.cpp

    0001020: 7465 7374 2e63 7070 3a24 5f5a 5a34 6d61  test.cpp:$_ZZ4ma
    0001030: 696e 4538 5f5f 6675 6e63 5f5f 3a69 6e74  inE8__func__:int
    0001040: 2061 7267 632c 2063 6861 722a 6172 6776   argc, char*argv
    0001050: 5b5d 0074 6573 742e 6370 703a 245f 5a5a  [].test.cpp:$_ZZ
    0001060: 3474 6573 7445 385f 5f66 756e 635f 5f3a  4testE8__func__:
    0001070: 6261 7200 4743 433a 2028 5562 756e 7475  bar.GCC: (Ubuntu
    

    原答案:

    在使用 c 模式的 gcc-3.3 中,__func__ 被视为 const char []。如果是 c++ 模式,并且在 gcc > 3.3 中,__func__ 始终是一个变量。

    我猜你可以在 c 模式下使用旧版本的 gcc 来完成此操作。

    查看http://gcc.gnu.org/onlinedocs/gcc/Function-Names.html的最后一段

    【讨论】:

    • 好吧,如果你想要完整的 C++ 名称,你必须使用 __PRETTY_FUNCTION__
    • @user 不起作用。无论如何printf("%s\n",__func__) 打印一个未损坏的名称(因为我的函数是extern "C")。这是汇编程序修改名称。也许如果它是一个 dll(因此必须保留导出的符号)
    • @KitsuneYMG 查看__dlog 部分,使用readelf -x __dlog a.out 之类的内容。在我的系统上,这个解决方案插入“$__func__.2523”而不是实际的函数名。
    • @ctuffli 我专门使用了xxd,因为它除了格式化数据之外什么都不做。 readelfdumpobjnm 都可以为您重新解释数据并错过嵌入的字符串:$_ZZ4mainE8__func__
    • @KitsuneYMG 您的解决方案是正确的,但分析有点偏离。碰巧 g++ 在符号标识符 ($_ZZ4mainE8__func__) 中包含函数名称,但 gcc 没有 ($__func__.2523)。在任何一种情况下,查找符号都会在 .rodata 部分中使用正确的字符串值给出偏移量。再次感谢!
    猜你喜欢
    • 2012-03-20
    • 2018-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-16
    • 1970-01-01
    • 2011-11-12
    相关资源
    最近更新 更多