aboutsummaryrefslogtreecommitdiff
path: root/libexec/rtld-elf/aarch64/reloc.c
diff options
context:
space:
mode:
authorMichal Meloun <mmel@FreeBSD.org>2018-12-15 10:38:07 +0000
committerMichal Meloun <mmel@FreeBSD.org>2018-12-15 10:38:07 +0000
commit4849c3a57055c77aa3009f5b8cbcdc9d5ba10bd5 (patch)
treec11599d43044ba540ed40e34c5d71afc2fb606b5 /libexec/rtld-elf/aarch64/reloc.c
parentb937183e005002f13e7016e6a013b16398571a39 (diff)
downloadsrc-4849c3a57055c77aa3009f5b8cbcdc9d5ba10bd5.tar.gz
src-4849c3a57055c77aa3009f5b8cbcdc9d5ba10bd5.zip
Notes
Diffstat (limited to 'libexec/rtld-elf/aarch64/reloc.c')
-rw-r--r--libexec/rtld-elf/aarch64/reloc.c126
1 files changed, 62 insertions, 64 deletions
diff --git a/libexec/rtld-elf/aarch64/reloc.c b/libexec/rtld-elf/aarch64/reloc.c
index cd33f3e2a872..f1c66816fcee 100644
--- a/libexec/rtld-elf/aarch64/reloc.c
+++ b/libexec/rtld-elf/aarch64/reloc.c
@@ -49,7 +49,8 @@ __FBSDID("$FreeBSD$");
* This is not the correct prototype, but we only need it for
* a function pointer to a simple asm function.
*/
-void *_rtld_tlsdesc(void *);
+void *_rtld_tlsdesc_static(void *);
+void *_rtld_tlsdesc_undef(void *);
void *_rtld_tlsdesc_dynamic(void *);
void _exit(int);
@@ -122,78 +123,58 @@ do_copy_relocations(Obj_Entry *dstobj)
}
struct tls_data {
- int64_t index;
- Obj_Entry *obj;
- const Elf_Rela *rela;
+ Elf_Addr dtv_gen;
+ int tls_index;
+ Elf_Addr tls_offs;
};
-int64_t rtld_tlsdesc_handle(struct tls_data *tlsdesc, int flags);
-
-static struct tls_data *
-reloc_tlsdesc_alloc(Obj_Entry *obj, const Elf_Rela *rela)
+static Elf_Addr
+reloc_tlsdesc_alloc(int tlsindex, Elf_Addr tlsoffs)
{
struct tls_data *tlsdesc;
tlsdesc = xmalloc(sizeof(struct tls_data));
- tlsdesc->index = -1;
- tlsdesc->obj = obj;
- tlsdesc->rela = rela;
+ tlsdesc->dtv_gen = tls_dtv_generation;
+ tlsdesc->tls_index = tlsindex;
+ tlsdesc->tls_offs = tlsoffs;
- return (tlsdesc);
+ return ((Elf_Addr)tlsdesc);
}
-/*
- * Look up the symbol to find its tls index
- */
-static int64_t
-rtld_tlsdesc_handle_locked(struct tls_data *tlsdesc, int flags,
- RtldLockState *lockstate)
+static void
+reloc_tlsdesc(const Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *where,
+ int flags, RtldLockState *lockstate)
{
- const Elf_Rela *rela;
const Elf_Sym *def;
const Obj_Entry *defobj;
- Obj_Entry *obj;
-
- rela = tlsdesc->rela;
- obj = tlsdesc->obj;
-
- def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, flags, NULL,
- lockstate);
- if (def == NULL)
- rtld_die();
-
- tlsdesc->index = defobj->tlsoffset + def->st_value + rela->r_addend;
-
- return (tlsdesc->index);
-}
-
-int64_t
-rtld_tlsdesc_handle(struct tls_data *tlsdesc, int flags)
-{
- RtldLockState lockstate;
-
- /* We have already found the index, return it */
- if (tlsdesc->index >= 0)
- return (tlsdesc->index);
-
- wlock_acquire(rtld_bind_lock, &lockstate);
- /* tlsdesc->index may have been set by another thread */
- if (tlsdesc->index == -1)
- rtld_tlsdesc_handle_locked(tlsdesc, flags, &lockstate);
- lock_release(rtld_bind_lock, &lockstate);
-
- return (tlsdesc->index);
-}
+ Elf_Addr offs;
+
+
+ offs = 0;
+ if (ELF_R_SYM(rela->r_info) != 0) {
+ def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, flags,
+ NULL, lockstate);
+ if (def == NULL)
+ rtld_die();
+ offs = def->st_value;
+ obj = defobj;
+ if (def->st_shndx == SHN_UNDEF) {
+ /* Weak undefined thread variable */
+ where[0] = (Elf_Addr)_rtld_tlsdesc_undef;
+ where[1] = rela->r_addend;
+ return;
+ }
+ }
+ offs += rela->r_addend;
-static void
-reloc_tlsdesc(Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *where)
-{
- if (ELF_R_SYM(rela->r_info) == 0) {
- where[0] = (Elf_Addr)_rtld_tlsdesc;
- where[1] = obj->tlsoffset + rela->r_addend;
+ if (obj->tlsoffset != 0) {
+ /* Variable is in initialy allocated TLS segment */
+ where[0] = (Elf_Addr)_rtld_tlsdesc_static;
+ where[1] = obj->tlsoffset + offs;
} else {
+ /* TLS offest is unknown at load time, use dynamic resolving */
where[0] = (Elf_Addr)_rtld_tlsdesc_dynamic;
- where[1] = (Elf_Addr)reloc_tlsdesc_alloc(obj, rela);
+ where[1] = reloc_tlsdesc_alloc(obj->tlsindex, offs);
}
}
@@ -201,7 +182,7 @@ reloc_tlsdesc(Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *where)
* Process the PLT relocations.
*/
int
-reloc_plt(Obj_Entry *obj)
+reloc_plt(Obj_Entry *obj, int flags, RtldLockState *lockstate)
{
const Elf_Rela *relalim;
const Elf_Rela *rela;
@@ -218,7 +199,8 @@ reloc_plt(Obj_Entry *obj)
*where += (Elf_Addr)obj->relocbase;
break;
case R_AARCH64_TLSDESC:
- reloc_tlsdesc(obj, rela, where);
+ reloc_tlsdesc(obj, rela, where, SYMLOOK_IN_PLT | flags,
+ lockstate);
break;
case R_AARCH64_IRELATIVE:
obj->irelative = true;
@@ -458,7 +440,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
}
break;
case R_AARCH64_TLSDESC:
- reloc_tlsdesc(obj, rela, where);
+ reloc_tlsdesc(obj, rela, where, flags, lockstate);
break;
case R_AARCH64_TLS_TPREL64:
/*
@@ -478,9 +460,25 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
return (-1);
}
}
-
- *where = def->st_value + rela->r_addend +
- defobj->tlsoffset;
+ /* Test weak undefined thread variable */
+ if (def->st_shndx != SHN_UNDEF) {
+ *where = def->st_value + rela->r_addend +
+ defobj->tlsoffset;
+ } else {
+ /*
+ * XXX We should relocate undefined thread
+ * weak variable address to NULL, but how?
+ * Can we return error in this situation?
+ */
+ rtld_printf("%s: Unable to relocate undefined "
+ "weak TLS variable\n", obj->path);
+#if 0
+ return (-1);
+#else
+ *where = def->st_value + rela->r_addend +
+ defobj->tlsoffset;
+#endif
+ }
break;
/*