在C函数中定义唯一且全局的程序集标签/符号

时间:2018-10-09 22:07:12

标签: c gcc assembly

我想用某种汇编标签/符号标记特定的C行,这些标签不会在二进制文件中占据任何空间,但是通过检查链接器输出映射文件,我将知道所有此类生成的标签以及最终出现的C这样“标记”的代码。因此,我希望能够定义此类标签,并使它们成为全局标签,并使用,这样链接程序就不会将其丢弃 我还需要一些宏魔术,以便每次对C代码进行预处理时,这些标签都具有唯一的名称(以确保该函数的每个内联实例都有其自己的标签-否则,我想我将有重复的符号)

示例:

// my build system will pass -DMYFILE_ID for each file, here I am trying to create a unique literal for each inline instance of the function
#define UN(X) #X
#define UNIQUE(X,Y) UN(X##Y)

void my_func(void)
{
    _asm("GLOBAL_LABEL_"UNIQUE(MYFILE_ID,__LINE__)":\n\t")
    my_c_code_I_want_to_track();
}

最后,我想在链接输出符号映射文件中找到类似的内容

0xsome_address GLOBAL_LABEL_12_1
0xdifferent_address GLOBAL_LABEL_12_2
0xyeanotheraddress GLOBAL_LABEL_13_1

从根本上应该让我知道my_c_code_i_want_to_track的实例化地址

整个想法是受汇编中的标签实际上是具有位置的“符号”启发的,因此可以检查其地址,但实际上并没有占用其自身的空间。

问题: 1.是否有可能像这样定义装配标签 2.如何使这些标签停留并出现在输出符号映射文件中 3. UNIQUE宏出了点问题,因为在尝试编译时会得到“标签重新定义”

2 个答案:

答案 0 :(得分:2)

您可以在Extended-asm template内使用%=(例如label%=:)来使编译器生成一个唯一的编号,以避免在多次内联包含inline-asm的函数时发生名称冲突在一个编译单元中。

#define STRINGIFY(x) #x
#define STR(x) STRINGIFY(x)
int foo(int x) {
    asm("marker" __FILE__ "_line" STR(__LINE__)  "_uniqueid%=:" :::);
    return x+1;
}


int caller1(int x) {
    return foo(x);
}

int caller2(int x) {
    return foo(x);
}

使用gcc -O3on Godbolt)编译为以下asm:

foo(int):
        marker/tmp/compiler-explorer-compiler11899-55-1ki0cth.pehm/example.cpp_line4_uniqueid7:
        lea     eax, [rdi+1]
        ret
caller1(int):
        marker/tmp/compiler-explorer-compiler11899-55-1ki0cth.pehm/example.cpp_line4_uniqueid22:
        lea     eax, [rdi+1]
        ret
caller2(int):
        marker/tmp/compiler-explorer-compiler11899-55-1ki0cth.pehm/example.cpp_line4_uniqueid41:
        lea     eax, [rdi+3]
        ret

这当然不会组合,因为/在GAS中不是有效的标签字符。

使用MYFILE_ID,其中仅包含可以出现在符号名称中的字符,这样可以很好地进行汇编,并且您应该能够在marker输出中看到所有的nm标签。 / p>

答案 1 :(得分:0)

一个问题是,由于内联,您可能会获得同一标签的多个副本。将以下属性添加到包含这些标签的函数中:

__attribute__((noinline))

还请注意,您需要将符号标记为全局符号。让我们将其提取到宏中,以便我们可以很好地格式化而不更改__LINE__的值:

#define MAKE_LABEL \
    __asm__( \
        "GLOBAL_LABEL_" UNIQUE(MYFILE_ID, __LINE__) ":" \
        "\n\t.global GLOBAL_LABEL_" UNIQUE(MYFILE_ID, __LINE__) \
    )

但是宏扩展已关闭。不幸的是,我无法向您解释为什么这样做。但这是正确的宏定义:

#define UN(X) #X
#define UNIQUE2(X,Y) UN(X##Y)
#define UNIQUE(X,Y) UNIQUE2(X,Y)

否则,您将获得__LINE__而不是23。