diff options
Diffstat (limited to 'ldso/ldso/cris/dl-sysdep.h')
-rw-r--r-- | ldso/ldso/cris/dl-sysdep.h | 24 |
1 files changed, 24 insertions, 0 deletions
diff --git a/ldso/ldso/cris/dl-sysdep.h b/ldso/ldso/cris/dl-sysdep.h index b58f5e0a3..b5fa89035 100644 --- a/ldso/ldso/cris/dl-sysdep.h +++ b/ldso/ldso/cris/dl-sysdep.h @@ -68,8 +68,32 @@ elf_machine_load_address(void) { Elf32_Addr gotaddr_diff; +#ifdef __arch_v32 + extern char ___CRISv32_dummy[] __asm__ ("_dl_start"); + + __asm__ ("addo.w _dl_start:GOT16,$r0,$acr\n\t" + "lapc _dl_start,%0\n\t" + "sub.d [$acr],%0" + /* For v32, we need to force GCC to have R0 loaded with + _GLOBAL_OFFSET_TABLE_ at this point, which might not + otherwise have happened in the caller. (For v10, it's + loaded for non-global variables too, so we don't need + anything special there.) We accomplish this by faking the + address of a global variable (as seen by GCC) as input to + the asm; that address calculation goes through the GOT. + Use of this function happens before we've filled in the + GOT, so the address itself will not be correctly + calculated, therefore we don't use any symbol whose + address may be re-used later on. Let's just reuse the + _dl_start symbol, faking it as a global by renaming it as + another variable through an asm. */ + : "=r" (gotaddr_diff) + : "g" (___CRISv32_dummy) + : "acr"); +#else __asm__ ("sub.d [$r0+_dl_start:GOT16],$r0,%0\n\t" "add.d _dl_start:GOTOFF,%0" : "=r" (gotaddr_diff)); +#endif return gotaddr_diff; } |