From Prakash Prabhu: #include<stdio.h> #include<stdlib.h> void test(); void (*funcPtr)(); int main(int argc, char **argv) { funcPtr = test; test(); } void test() { if(funcPtr == test) { printf("OK!\n"); } else { fprintf(stderr, "Bad!\n"); exit(1); } } $ llvm-gcc -emit-llvm -o FPtrEqTest.bc -c FPtrEqTest.c $ llc -f FPtrEqTest.bc $ gcc -o FPtrEqTest FPtrEqTest.s $ ./FPtrEqTest OK! $ lli FPtrEqTest.bc Bad!
Hrm. This has to do with lazy compilation. The generated assembly looks like this with -relocation-model=pic: _main: ... leal _test-"L1$pb"(%eax), %ecx movl L_funcPtr$non_lazy_ptr-"L1$pb"(%eax), %eax movl %ecx, (%eax) call _test _test: ... leal _test-"L2$pb"(%eax), %ecx movl L_funcPtr$non_lazy_ptr-"L2$pb"(%eax), %edx cmpl %ecx, (%edx) jne LBB2_3 ## bb1 Looking at -debug-only=jit dump with -relocation-model=pic JIT: Stub emitted at [0x207fff8] for function 'test' JIT: Map 'funcPtr' to [0x2080044] JIT: Initializing 0x2080044 void () * null JIT: Indirect symbol emitted at [0x207fff4] for GV 'funcPtr' JIT: Finished CodeGen of [0x2080010] Function: main: 56 bytes of text, 3 relocations ... JIT: Lazily resolving function 'test' In stub ptr = 0x2080038 actual ptr = 0x2080038 JIT: Starting CodeGen of Function test The disassembled code looks like this: 0x02080050: sub $0x1c,%esp ... 0x02080059: lea -0x8(%eax),%ecx 0x0208005f: mov -0x64(%eax),%edx 0x02080065: cmp %ecx,(%edx) 0x02080067: jne 0x208007f After the lea, %ecx contains 0x02080050 which is the address of test. After the load, %edx is 0x2080044. However, the value in 0x2080044 is 0x0207fff8 which is the address of test's stub.
The problem is at the time the address of "test" is taken, it has not been compiled. So it stored the address of its stub instead.
I think the current solution would be something like this: 1. When code emitter sees a function address, emit it as a relocation and remember the function. 2. After the function has been emitted, compile and emit all functions whose addresses are taken. 3. Relocate all references to function addresses.
Alternatively, you could emit all function pointers as pointers to the function's stub. The disadvantage of compiling a function whenever its address is taken is that in a C++ program all the entries all vtable would have to be compiled before execution began. Some C programs also contain statically initialized lists of functions that may or may not be called at runtime. The disadvantage of emitting function pointers as pointers to stubs is that it increases the overhead per function call.
Right. That's an acceptable solution for now. Thanks. Fixed here: http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20081110/069830.html
(In reply to comment #5) > Right. That's an acceptable solution for now. Thanks. > Fixed here: > http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20081110/069830.html > Thanks!