In linux-gcc you write:
>I'm using C as the back end for a compiler. One of the things this
>compiler generates is a jump table consisting of an array of x86 `jmp'
>instructions. Machine-generated C code calls through this table like
>this:
> extern const char jump_table[];
> typedef void (*func_ptr)(void);
> ....
> ((func_ptr)&jump_table[256])();
>This works fine unless I both optimize and compile with -fPIC. When I
>compile that way (with both the call and the jump table are in the
>same file, FWIW), the above code compiles to this:
> call 256+jump_table@PLT
>That looks plausible, although I don't know what @PLT does.
jump_table@PLT gets resolved by the linker to point to the Procedure
Linkage Table entry for the 'procedure' jump_table. I'm not sure exactly
why the compiler got fooled into thinking there is a PLT entry for
jump_table, as jump_table is not declared as a function ...
As 'jump_table' is really a data symble, you need to look up its absolute
address in the GOT (Global Offset Table) instead, and use this as a jump
target; with inline assembly something like this should work:
__asm__( "movl jump_table@GOT(%%ebx), %%eax\n"
"addl $256, %%eax\n"
"jmp *%%eax\n" );
(This assumes that the %ebx register does indeed contain the GOT address,
as it usually does within gcc generated PIC x86 code ...)
Actually, I'd have assumed that gcc would generate exactly this code
for the code fragment given above, but it appears to get confused.
(Sure, it's undefined behaviour according to the standard, but this
would have been IMHO the logical choice of what to do :-/)
I've experimented using an intermediate variable, like this:
char *ptr = jump_table + 256;
((func_ptr)ptr)();
and *that* does generate exactly the assembly code given above ...
(gcc-2.7.2.3 with -O2 -fPIC)
Of course, the code you are jumping to needs to be aware as well
that it might get loaded at different addresses ... ;-)
--
Ulrich Weigand,
IMMD 1, Universitaet Erlangen-Nuernberg,
Martensstr. 3, D-91058 Erlangen, Phone: +49 9131 85-7688