有没有办法,在标准 C 中或使用 gcc/gas/binutils/etc 失败时,使用在函数定义体的语法范围内编写的代码(可能是宏)来定义全局符号?

如果没有 ,是否需要为出现在函数体外部的每个此类符号单独设置宏?

为此,如果我必须明确指定 ELF 部分来放置生成的符号,那很好,如果我必须使用 .pushsection.popsection 等 asm 功能(如果它们可以提供帮助?) .

我想做这件疯狂事情的​​原因是,跟踪点声明(必须出现在函数体中)可以自动生成跟踪工具可以查找的关联元数据。无需单独预先声明跟踪点,即使其尽可能干燥。

伪代码

void foo(void)
{
    normal_app_code();
    MAGICALLY_DEFINE_A_GLOBAL_VARIABLE_SYMBOL(symboltype, symbolname);
    more_normal_app_code();
}

这样编译的结果就像上面写的一样:
symboltype symbolname;

void foo(void)
{
    normal_app_code();
    some_library_function_that_uses(symbolname);
    more_normal_app_code();
}

语境

我正在研究增强 systemtap/dtrace 跟踪 API 以支持记录探测参数的数据类型和名称的想法。

我目前的设计要求应用程序作者在顶级(全局)范围内插入额外的宏来定义 stap 运行时将用来发现探测器的名称和 arg 类型的符号,例如人为的:
STAP_PROBE2_ARGNAMES(myprovider, myprobe, foo, bar);
STAP_PROBE2_ARGTYPES(myprovider, myprobe, const char *, MyDataType*);

void something(const char *foo)
{
    MyDataType *bar = get_bar();
    STAP_PROBE2(myprovider, myprobe, foo, bar);
}

这很不方便,而且容易出错。特别是如果应用程序想要自动生成 STAP_PROBEn(..) 探测点作为它自己的宏的一部分。

我宁愿在同一站点的跟踪点旁边声明 arg 类型和名称信息,使用预处理器字符串化来捕获 arg 名称(当它们是简单的变量名称标记时)和 __typeof__ 运算符来捕获它们的类型名称,例如:
void something(const char *foo)
{
    MyDataType *bar = get_bar();
    STAP_PROBE2_ARGINFO(myprovider, myprobe, foo, bar);
}

或者对于非简单 token 表达式参数,例如:
void something(void)
{
    MyDataTypeHolder *barholder = get_barholder();
    STAP_PROBE2_ARGNAMES(myprovider, myprobe,
        something_global->foo, "foo",
        barholder->bar, "bar");
}
STAP_PROBE2_ARGINFO 的宏扩展负责使用适当的字符串化和 _typeof_ 运算符,例如,在全局符号表中为 char-array-array 生成一对单独的符号。伪ish-c:
#define STAP_PROBE2_ARGINFO(myprovider, myprobe, arg1, arg2) \
    STAP_PROBE2(myprovider, myprobe, (arg1), (arg2)) \
    STAP_PROBE2_ARGTYPES(myprovider, myprobe, (arg1), (arg2))
    STAP_PROBE2_ARGNAMES(myprovider, myprobe, (arg1), (arg2))

#define STAP_PROBE2_ARGTYPES(myprovider, myprobe, argname1, argname2) \
    const char _stapargtypes_#myprovider#_#myprobe[2][] = {#argname1, #argname2};

#define STAP_PROBE2_ARGTYPES(myprovider, myprobe, arg1, arg2) \
    const char _stapargtypes_#myprovider#_#myprobe[2][] = {__typeof__((arg1)), __typeof__((arg2))};

...以及类似 STAP_PROBE2_ARGNAMES 的东西,它分别提取和存储显式提供的 arg 名称。

目标是结果类似于以下的全局声明:
const char _stapargnames_myprovider_myprobe[2][] = {"foo", "bar"};
const char _stapargtypes_myprovider_myprobe[2][] = {"const char *", "MyDataType*"};

并且还在 STAP_PROBE2_ARGINFO(...) 出现的调用站点上为探测点本身发出通常的 asm,就好像它是一个普通的 STAP_PROBE2(...) 一样。

疯狂的?

可能的?

最佳答案

我不明白为什么你不能用 __asm__.pushsection 做到这一点。为 C 中的变量创建一个 extern 声明,它在块范围内有效,以便它可以从 C 访问,并将其大小作为整数文字操作数传递给 __asm__ 。在 __asm__ 内部,您可以定义符号,如果您愿意(或不愿意),可以将其设为 .global,并根据传入的大小为其预留空间。

关于c - 临时转义函数范围以在 C 中定义全局符号? (海合会),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/59402666/

10-17 00:23