从gcc / clang(C ++)中的函数范围中获取标签地址

问题描述 投票:5回答:1

我正在做某种解释器,由于本地标签地址,我正在计算一个静态const跳转表。你知道该怎么做,static const int JUMP_TABLE[] = { &&case0 - &&case0, &&case1 - &&case0等。由于各种原因(主要是性能),我想在初始化期间将表复制/压缩到对象中。我伤脑筋了,因为我想不通如何逃避函数的词法作用域!我怎样才能从另一个函数引用&& case0?有人为此有一个好把戏吗?在此先感谢

c++ c gcc goto jump-table
1个回答
1
投票

我不知道在纯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;
}

现在您可以编译,从.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;

内联汇编

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

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;
}

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

© www.soinside.com 2019 - 2024. All rights reserved.