Hi,
John Rigby wrote:
288: e59f0148 ldr r0, [pc, #328] ; 3d8 <i2c_init+0x1a4> 28c: e1a01083 lsl r1, r3, #1 290: ebfffffe bl 0 <__aeabi_idiv> 294: e2507006 subs r7, r0, #6 298: 4a000001 bmi 2a4 <i2c_init+0x70>
I believe such calls are getting resolved via a veneer because of a combination the thumb2-ness of libgcc and the toolchain being used.
In principle, the linker can know that it is linking for >= ARMv5T due to the way it was configured and the way the input objects were built, but GNU ld is conservative and doesn't do this automatically. As a result, it has to generate a veneer, reached via a normal non-interworking branch. ld has no way the veneer needs to be PIC and use the GOT, so it isn't and doesn't.
ld.info says:
The `--use-blx' switch enables the linker to use ARM/Thumb BLX instructions (available on ARMv5t and above) in various situations. Currently it is used to perform calls via the PLT from Thumb code using BLX rather than using BX and a mode-switching stub before each PLT entry. This should lead to such calls executing slightly faster.
...so you might explicitly want to enable this whenever building for ARMv5 or later.
Wolfgang, can you foresee any reason not to do that? As far as I can see it will be safe so long as we don't use it when building for architectured <ARMv5 (where the BLX instruction isn't supported).
Otherwise, the only straightforward workaround is to build with cc -fPIC and ld -shared, to guarantee that every absolute address is resolved via the GOT instead of hard-coded veneers, then let U-Boot patch it all up. This causes non-relative branches to jump a veneer in .plt instead. If extra trampolines are needed to reach .plt, those will be generated as PIC code in this case too. Of course, we don't want the linker to resolve symbols using actual shared libraries, so we need -nostdlib and explicit references to .a files if there might be ambiguity about library selection. Since U-Boot is bare-metal, I'm guessing these requirements are either met or nearly met already... but there might be gotchas such as if the fixup code in U-Boot ends up with fixups inside itself.
Alternatively, using ld --emit-relocs and then embedding the relocation information in the image so that U-Boot can use it could help to solve the problem. I'm guessing that isn't set up at present, though.
[...]
- u-boot has its own private libgcc and if I use it the problem goes away.
Hopefully not necessary--- I agree with Wolfgang's concerns on relying on this.
- is there an option for the toolchain to use an arm libgcc instead of thumb?
You'd need to rebuild the toolchain (or at least libgcc). I believe that no ARM libgcc is built at present for the linaro/Ubuntu tools. I don't think the GCC packages currently support this kind of thing well. --use-blx is probably the better workaround.
- is there a way to find the veneers at runtime and fix them up?
No. Even if you can find the veneers, you would need to make assumptions about their structure which may break when the toolchain gets upgraded... unless you write the veneers by hand in the first place (bad...)
So the options are to avoid the veneers using --use-blx; to post-processing the relocations output from ld --emit-relocs; or to do a fully PIC link with ld -shared. The latter options feel like overkill, unless U-Boot already supports this, or evolves a general need for it in the future.
Cheers ---Dave