ARM linker bug when global aliased symbols are called from .mod_init_func code

Originator:jmaebe
Number:rdar://7120987 Date Originated:05-Aug-2009 11:08 PM
Status:Open Resolved:
Product:iPhone SDK Product Version:3.0
Classification:Serious Bug Reproducible:Always
 
05-Aug-2009 11:08 PM Jonas Maebe:
* Summary

If all of the following conditions are true at the same time, the ARM linker assigns a wrong address to the  "_calledfrominit" symbol:
a) there is a .mod_init_term section pointing to a function, e.g. _initfunc
b) this _initfunc calls another function, e.g. _calledfrominit
c) the call from _initfun to _calledfrominit occurs via a symbol stub
d) there is (at least?) one other global symbol with the same address as _calledfrominit

I have however attached a simple, artificial test case that demonstrates this problem.

I don't know how to make GCC generate such code (maybe using C++ with static initialisers in combination with some gcc extension to define symbol aliases), but the Free Pascal Compiler does generate such code (http://www.freepascal.org). If you want to see this bug in a real world example, you can download/install the Free Pascal Compiler for iPhone SDK from http://wiki.freepascal.org/iPhone/iPod_development (note that it always installs globally under /usr/local), create a new Xcode project using the "iPhone (FPC)" -> "OpenGL ES App" template, and build/run it. It will crash in the _start function.


* Steps to reproduce (replace "/iphone3.0" in the commands below with whichever iPhoneSDK version you want to test)
1) tar xjf iphonelinkerbug.tbz
2) cd iphonelinkerbug
3) /iphone3.0/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc-4.0 -arch armv6 -isysroot /iphone3.0/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.1.sdk main.s -o main
4) otool -tV main|less

* Expected result

Something like this:

main:
(__TEXT,__text) section
_calledfrominitfuncalias:
00002000        e92d4080        stmdb   sp!, {r7, lr}
00002004        e28d7000        add     r7, sp, #0      ; 0x0
00002008        e59f300c        ldr     r3, [pc, #12]   ; 0x201c
0000200c        e08f3003        add     r3, pc, r3
00002010        e1a00003        mov     r0, r3
00002014        eb00002d        bl      0x20d0  ; symbol stub for: _printf
00002018        e8bd8080        ldmia   sp!, {r7, pc}
0000201c        000000d4        ldreqd  r0, [r0], -r4
_initfunc:
00002020        e92d4080        stmdb   sp!, {r7, lr}
00002024        e28d7000        add     r7, sp, #0      ; 0x0
00002028        e59f3010        ldr     r3, [pc, #16]   ; 0x2040
0000202c        e08f3003        add     r3, pc, r3
00002030        e1a00003        mov     r0, r3
00002034        eb000028        bl      0x20dc  ; symbol stub for: _puts
00002038        ebfffff0        bl      _calledfrominitfuncalias
0000203c        e8bd8080        ldmia   sp!, {r7, pc}
00002040        000000d0        ldreqd  r0, [r0], -r0
start:
00002044        e59d0000        ldr     r0, [sp]


* Actual result

(__TEXT,__text) section
_calledfrominitfunc:
00002000        e92d4080        stmdb   sp!, {r7, lr}
00002004        e28d7000        add     r7, sp, #0      ; 0x0
00002008        e59f3010        ldr     r3, [pc, #16]   ; 0x2020
0000200c        e08f3003        add     r3, pc, r3
00002010        e1a00003        mov     r0, r3
00002014        eb000030        bl      0x20dc  ; symbol stub for: _puts
00002018        ebfffff8        bl      _calledfrominitfunc
0000201c        e8bd8080        ldmia   sp!, {r7, pc}
00002020        000000f0        streqd  r0, [r0], -r0
start:
00002024        e59d0000        ldr     r0, [sp]
[snip]
_calledfrominitfuncalias:
0000209c        e92d4080        stmdb   sp!, {r7, lr}
000020a0        e28d7000        add     r7, sp, #0      ; 0x0
000020a4        e59f300c        ldr     r3, [pc, #12]   ; 0x20b8
000020a8        e08f3003        add     r3, pc, r3
000020ac        e1a00003        mov     r0, r3
000020b0        eb000006        bl      0x20d0  ; symbol stub for: _printf
000020b4        e8bd8080        ldmia   sp!, {r7, pc}
000020b8        00000038        andeq   r0, r0, r8, lsr r0

otool displays _calledfrominitfunc  as the symbol name for address 00002000, but nm shows that _initfunc also is at that address. So effectively, _calledfrominitfunc has now become an alias for _initfunc rather than for _calledfrominitfuncalias


* Regression

The above works fine with the tools from the iPhone SDK 2.2.1/9m2621a (final).

It is still broken with the tools from the iPhone SDK 3.1 beta 3

(all under Leopartd/10.5.7)


* Notes

The main.c file included in the archive is the C file from which I started. I compiled it with -S and made a few changes to the generated assembler code (marked by "# added").

If you replace the "bl      L_calledfrominitfunc$stub" with "bl      _calledfrominitfunc" in the assembler code  so that the stub is no longer used, then
a) the code for _calledfrominitfunc is properly referenced from _initfunc, but
b) the symbol alias _calledfrominitfuncalias now gets the same address as the "_main" symbol

This, too, is wrong (but causes no immediate problems in our case).


'iphonelinkerbug.tbz' was successfully uploaded

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!