summaryrefslogtreecommitdiffstats
path: root/libexec/rtld-elf/powerpc
diff options
context:
space:
mode:
authorssouhlal <ssouhlal@FreeBSD.org>2004-11-02 09:47:01 +0000
committerssouhlal <ssouhlal@FreeBSD.org>2004-11-02 09:47:01 +0000
commit7cf9959da0f98b746de33e1a543163787a4809e2 (patch)
treefab93880b96f37b37d99185e61373e2001ba638f /libexec/rtld-elf/powerpc
parentd6dc36dcc0920420394e02e5b7c7f81c949b1c22 (diff)
downloadFreeBSD-src-7cf9959da0f98b746de33e1a543163787a4809e2.zip
FreeBSD-src-7cf9959da0f98b746de33e1a543163787a4809e2.tar.gz
Implement TLS relocations for powerpc.
Approved by: grehan (mentor)
Diffstat (limited to 'libexec/rtld-elf/powerpc')
-rw-r--r--libexec/rtld-elf/powerpc/reloc.c68
-rw-r--r--libexec/rtld-elf/powerpc/rtld_machdep.h8
2 files changed, 73 insertions, 3 deletions
diff --git a/libexec/rtld-elf/powerpc/reloc.c b/libexec/rtld-elf/powerpc/reloc.c
index 1f9f05a..b65e026 100644
--- a/libexec/rtld-elf/powerpc/reloc.c
+++ b/libexec/rtld-elf/powerpc/reloc.c
@@ -206,6 +206,58 @@ reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
*/
break;
+ case R_PPC_DTPMOD32:
+ def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
+ false, cache);
+
+ if (def == NULL)
+ return (-1);
+
+ *where = (Elf_Addr) defobj->tlsindex;
+
+ break;
+
+ case R_PPC_TPREL32:
+ def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
+ false, cache);
+
+ if (def == NULL)
+ return (-1);
+
+ /*
+ * We lazily allocate offsets for static TLS as we
+ * see the first relocation that references the
+ * TLS block. This allows us to support (small
+ * amounts of) static TLS in dynamically loaded
+ * modules. If we run out of space, we generate an
+ * error.
+ */
+ if (!defobj->tls_done) {
+ if (!allocate_tls_offset((Obj_Entry*) defobj)) {
+ _rtld_error("%s: No space available for static "
+ "Thread Local Storage", obj->path);
+ return (-1);
+ }
+ }
+
+ *(Elf_Addr **)where = *where * sizeof(Elf_Addr)
+ + (Elf_Addr *)(def->st_value + rela->r_addend
+ + defobj->tlsoffset - TLS_TP_OFFSET - TLS_TCB_SIZE);
+
+ break;
+
+ case R_PPC_DTPREL32:
+ def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
+ false, cache);
+
+ if (def == NULL)
+ return (-1);
+
+ *where += (Elf_Addr)(def->st_value + rela->r_addend
+ - TLS_DTV_OFFSET);
+
+ break;
+
default:
_rtld_error("%s: Unsupported relocation type %d"
" in non-PLT relocations\n", obj->path,
@@ -494,6 +546,7 @@ void
allocate_initial_tls(Obj_Entry *list)
{
register Elf_Addr **tp __asm__("r2");
+ Elf_Addr **_tp;
/*
* Fix the size of the static TLS block by using the maximum
@@ -503,7 +556,14 @@ allocate_initial_tls(Obj_Entry *list)
tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA;
- tp = (Elf_Addr **) ((char *) allocate_tls(list, 0, 8, 8) + 0x7008);
+ _tp = (Elf_Addr **) ((char *) allocate_tls(list, 0, 8, 8)
+ + TLS_TP_OFFSET + TLS_TCB_SIZE);
+
+ /*
+ * XXX gcc seems to ignore 'tp = _tp;'
+ */
+
+ __asm __volatile("mr %0,%1" : "=r"(tp) : "r"(_tp));
}
void*
@@ -512,6 +572,8 @@ __tls_get_addr(tls_index* ti)
register Elf_Addr **tp __asm__("r2");
char *p;
- p = tls_get_addr_common(tp, ti->ti_module, ti->ti_offset);
- return p + 0x8000;
+ p = tls_get_addr_common((Elf_Addr**)((Elf_Addr)tp - TLS_TP_OFFSET
+ - TLS_TCB_SIZE), ti->ti_module, ti->ti_offset);
+
+ return (p + TLS_DTV_OFFSET);
}
diff --git a/libexec/rtld-elf/powerpc/rtld_machdep.h b/libexec/rtld-elf/powerpc/rtld_machdep.h
index 534882b..38e105d 100644
--- a/libexec/rtld-elf/powerpc/rtld_machdep.h
+++ b/libexec/rtld-elf/powerpc/rtld_machdep.h
@@ -62,6 +62,14 @@ void _rtld_bind_start(void);
void _rtld_powerpc_pltresolve(void);
void _rtld_powerpc_pltcall(void);
+/*
+ * TLS
+ */
+
+#define TLS_TP_OFFSET 0x7000
+#define TLS_DTV_OFFSET 0x8000
+#define TLS_TCB_SIZE 8
+
#define round(size, align) \
(((size) + (align) - 1) & ~((align) - 1))
#define calculate_first_tls_offset(size, align) \
OpenPOWER on IntegriCloud