Add support for thread local storage on arm64 to the runtime linker. The
ABI specifies that, for R_AARCH64_TLSDESC relocations, we use the symbol value, addend, and object tls offset to calculate the offset from the tls base. We then cache this value for future reference. Differential Revision: https://reviews.freebsd.org/D2183 Reviewed by: kib Sponsored by: The FreeBSD Foundation
This commit is contained in:
parent
96f6ece580
commit
a97120d61e
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=281014
@ -50,6 +50,8 @@ __FBSDID("$FreeBSD$");
|
||||
* a function pointer to a simple asm function.
|
||||
*/
|
||||
void *_rtld_tlsdesc(void *);
|
||||
void *_rtld_tlsdesc_dynamic(void *);
|
||||
|
||||
void _exit(int);
|
||||
|
||||
void
|
||||
@ -120,6 +122,68 @@ do_copy_relocations(Obj_Entry *dstobj)
|
||||
return (0);
|
||||
}
|
||||
|
||||
struct tls_data {
|
||||
int64_t index;
|
||||
Obj_Entry *obj;
|
||||
const Elf_Rela *rela;
|
||||
};
|
||||
|
||||
static struct tls_data *
|
||||
reloc_tlsdesc_alloc(Obj_Entry *obj, const Elf_Rela *rela)
|
||||
{
|
||||
struct tls_data *tlsdesc;
|
||||
|
||||
tlsdesc = xmalloc(sizeof(struct tls_data));
|
||||
tlsdesc->index = -1;
|
||||
tlsdesc->obj = obj;
|
||||
tlsdesc->rela = rela;
|
||||
|
||||
return (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)
|
||||
{
|
||||
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->tlsindex + 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process the PLT relocations.
|
||||
*/
|
||||
@ -142,11 +206,11 @@ reloc_plt(Obj_Entry *obj)
|
||||
case R_AARCH64_TLSDESC:
|
||||
if (ELF_R_SYM(rela->r_info) == 0) {
|
||||
where[0] = (Elf_Addr)_rtld_tlsdesc;
|
||||
where[1] = rela->r_addend;
|
||||
where[1] = obj->tlsindex + rela->r_addend;
|
||||
} else {
|
||||
_rtld_error("Unable to handle "
|
||||
"R_AARCH64_TLSDESC with a symbol set");
|
||||
return (-1);
|
||||
where[0] = (Elf_Addr)_rtld_tlsdesc_dynamic;
|
||||
where[1] = (Elf_Addr)reloc_tlsdesc_alloc(obj,
|
||||
rela);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -169,14 +233,15 @@ reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
|
||||
const Elf_Rela *relalim;
|
||||
const Elf_Rela *rela;
|
||||
const Elf_Sym *def;
|
||||
struct tls_data *tlsdesc;
|
||||
|
||||
relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize);
|
||||
for (rela = obj->pltrela; rela < relalim; rela++) {
|
||||
Elf_Addr *where;
|
||||
|
||||
where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
|
||||
switch(ELF_R_TYPE(rela->r_info)) {
|
||||
case R_AARCH64_JUMP_SLOT:
|
||||
where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
|
||||
def = find_symdef(ELF_R_SYM(rela->r_info), obj,
|
||||
&defobj, SYMLOOK_IN_PLT | flags, NULL, lockstate);
|
||||
if (def == NULL) {
|
||||
@ -187,6 +252,12 @@ reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
|
||||
*where = (Elf_Addr)(defobj->relocbase + def->st_value);
|
||||
break;
|
||||
case R_AARCH64_TLSDESC:
|
||||
if (ELF_R_SYM(rela->r_info) != 0) {
|
||||
tlsdesc = (struct tls_data *)where[1];
|
||||
if (tlsdesc->index == -1)
|
||||
rtld_tlsdesc_handle_locked(tlsdesc,
|
||||
SYMLOOK_IN_PLT | flags, lockstate);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
_rtld_error("Unknown relocation type %x in jmpslot",
|
||||
@ -285,6 +356,32 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
case R_AARCH64_TLS_TPREL64:
|
||||
def = find_symdef(symnum, obj, &defobj, flags, cache,
|
||||
lockstate);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
*where = def->st_value + rela->r_addend +
|
||||
defobj->tlsoffset - TLS_TCB_SIZE;
|
||||
break;
|
||||
case R_AARCH64_RELATIVE:
|
||||
*where = (Elf_Addr)(obj->relocbase + rela->r_addend);
|
||||
break;
|
||||
|
@ -109,5 +109,44 @@ END(_rtld_bind_start)
|
||||
*/
|
||||
ENTRY(_rtld_tlsdesc)
|
||||
ldr x0, [x0, #8]
|
||||
RET
|
||||
ret
|
||||
END(_rtld_tlsdesc)
|
||||
|
||||
/*
|
||||
* uint64_t _rtld_tlsdesc_dynamic(struct tlsdesc *);
|
||||
*
|
||||
* TODO: We could lookup the saved index here to skip saving the entire stack.
|
||||
*/
|
||||
ENTRY(_rtld_tlsdesc_dynamic)
|
||||
/* Store any registers we may use in rtld_tlsdesc_handle */
|
||||
stp x29, x30, [sp, #-(10 * 16)]!
|
||||
mov x29, sp
|
||||
stp x1, x2, [sp, #(1 * 16)]
|
||||
stp x3, x4, [sp, #(2 * 16)]
|
||||
stp x5, x6, [sp, #(3 * 16)]
|
||||
stp x7, x8, [sp, #(4 * 16)]
|
||||
stp x9, x10, [sp, #(5 * 16)]
|
||||
stp x11, x12, [sp, #(6 * 16)]
|
||||
stp x13, x14, [sp, #(7 * 16)]
|
||||
stp x15, x16, [sp, #(8 * 16)]
|
||||
stp x17, x18, [sp, #(9 * 16)]
|
||||
|
||||
/* Find the tls offset */
|
||||
ldr x0, [x0, #8]
|
||||
mov x1, #1
|
||||
bl rtld_tlsdesc_handle
|
||||
|
||||
/* Restore the registers */
|
||||
ldp x17, x18, [sp, #(9 * 16)]
|
||||
ldp x15, x16, [sp, #(8 * 16)]
|
||||
ldp x13, x14, [sp, #(7 * 16)]
|
||||
ldp x11, x12, [sp, #(6 * 16)]
|
||||
ldp x9, x10, [sp, #(5 * 16)]
|
||||
ldp x7, x8, [sp, #(4 * 16)]
|
||||
ldp x5, x6, [sp, #(3 * 16)]
|
||||
ldp x3, x4, [sp, #(2 * 16)]
|
||||
ldp x1, x2, [sp, #(1 * 16)]
|
||||
ldp x29, x30, [sp], #(10 * 16)
|
||||
|
||||
ret
|
||||
END(_rtld_tlsdesc_dynamic)
|
||||
|
Loading…
Reference in New Issue
Block a user