从 gcc/clang (C++) 中的函数作用域中获取标签地址

Tra*_*boi 6 c c++ gcc goto jump-table


我正在制作某种解释器,并且由于本地标签地址,我正在计算一个静态常量跳转表。
你知道演习, static const int JUMP_TABLE[] = { &&case0 - &&case0, &&case1 - &&case0等等。
出于各种原因,主要是性能,我想在初始化期间在对象中复制/压缩此表。
我的头撞在墙上,因为我不知道如何逃避函数的词汇范围!

我怎样才能以某种方式从另一个函数引用 &&case0 ?

有人对此有什么好技巧吗?
提前致谢

yug*_*ugr 4

我不知道在纯 GNU C 中实现此目的的方法,因此下面的方法使用其他机制。

双编译

您可以编译目标文件两次,在第一次运行时收集偏移量并在第二次运行时使用它们。例如

int foo(int x) {
#ifdef GENERATE_ADDRESSES
    static __attribute__((section(".foo_offsets"))) unsigned offsets[] = { &&case0 - &&case0, &&case1 - &&case0 };
#endif
    switch (x) {
case0:
        case 0:
            return 1;
case1:
        case 1:
            return 2;
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

现在您可以编译,从.foo_offsets部分中提取字节并在第二次运行时将它们嵌入到您的应用程序中

$ gcc tmp.c -c -DGENERATE_ADDRESSES
$ objcopy -j .foo_offsets -O binary tmp.o
$ xxd -i tmp.o | tee offsets.inc
unsigned char tmp_o[] = {
  0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00
};
unsigned int tmp_o_len = 8;
Run Code Online (Sandbox Code Playgroud)

内联装配

您可以使用内联汇编来全球化标签:

extern char foo_case0[];
extern char foo_case1[];
const void *foo_addresses[] = { &foo_case0[0], &foo_case1[0] };

int foo(int x) {
    switch (x) {
        case 0:
asm("foo_case0:");
            return 1;
        case 1:
asm("foo_case1:");
            return 2;
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,在这种情况下,您只能收集地址(而不是偏移量),因此您需要在启动时手动计算偏移量。