I'm making some kind of interpreter and I'm computing a static const jump table thanks to local label addresses.
You know the drill,
static const int JUMP_TABLE[] = { &&case0 - &&case0, &&case1 - &&case0
and so on.
For various reasons, mostly performance, I'd like to copy/compress this table in an object during init.
I'm hurting my head against the wall because I can't figure how to escape the lexical scoping of the function !
How can I somehow reference &&case0 from another function ?
Does somebody have a good trick for this ?
Thanks in advance
I'm not aware of ways to achieve this within pure GNU C so approaches below use other mechanisms.
You can compile your object file twice, collecting offsets on the first run and using them on the second. For example
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;
}
Now you can compile, extract bytes from .foo_offsets
section and embed them to you app on second run
$ 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;
You can use inline assembly to globalize labels:
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;
}
Unfortunately in this case you can only collect addresses (not offsets) so you'll need to manually compute offsets at startup.