mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 11:25:21 +01:00
i386 rtld: implement support for TLSDESC relocation
Discussed with: jrtc27 Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D59269
This commit is contained in:
1 parent
fb63a60d6e
commit
d45d7aea61
4 files changed
+183
-4
No files matched your search
@@ -171,4 +171,29 @@ rtld_dynamic_addr:
|
||||
.cfi_endproc
|
||||
.size rtld_dynamic_addr, . - rtld_dynamic_addr
|
||||
|
||||
rtld_tlsdesc_static:
|
||||
.globl rtld_tlsdesc_static
|
||||
.type rtld_tlsdesc_static,@function
|
||||
.cfi_startproc
|
||||
movq 8(%rax), %rax
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size rtld_tlsdesc_static, . - rtld_tlsdesc_static
|
||||
|
||||
rtld_tlsdesc_undef:
|
||||
.globl rtld_tlsdesc_undef
|
||||
.type rtld_tlsdesc_undef,@function
|
||||
.cfi_startproc
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size rtld_tlsdesc_undef, . - rtld_tlsdesc_undef
|
||||
|
||||
rtld_tlsdesc_dynamic:
|
||||
.globl rtld_tlsdesc_static
|
||||
.type rtld_tlsdesc_dynamic,@function
|
||||
.cfi_startproc
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size rtld_tlsdesc_dynamic, . - rtld_tlsdesc_dynamic
|
||||
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
@@ -51,6 +51,22 @@
|
||||
#include "rtld.h"
|
||||
#include "rtld_tls.h"
|
||||
|
||||
void
|
||||
md_obj_entry_init(Obj_Entry *obj)
|
||||
{
|
||||
STAILQ_INIT(&obj->tlsdesc_dynargs);
|
||||
}
|
||||
|
||||
void
|
||||
md_obj_entry_fini(Obj_Entry *obj)
|
||||
{
|
||||
struct tlsdesc_dynarg *tda, *t;
|
||||
|
||||
STAILQ_FOREACH_SAFE(tda, &obj->tlsdesc_dynargs, link, t) {
|
||||
free(tda);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Process the special R_386_COPY relocations in the main program. These
|
||||
* copy data from a shared object into a region in the main program's BSS
|
||||
@@ -125,6 +141,60 @@ init_pltgot(Obj_Entry *obj)
|
||||
}
|
||||
}
|
||||
|
||||
static struct tlsdesc_dynarg *
|
||||
reloc_tlsdesc_alloc(Obj_Entry *obj, Elf_Addr tlsoffs)
|
||||
{
|
||||
struct tlsdesc_dynarg *tda;
|
||||
|
||||
tda = xmalloc(sizeof(struct tlsdesc_dynarg));
|
||||
tda->tlsinfo.ti_module = obj->tlsindex;
|
||||
tda->tlsinfo.ti_offset = tlsoffs;
|
||||
STAILQ_INSERT_TAIL(&obj->tlsdesc_dynargs, tda, link);
|
||||
return (tda);
|
||||
}
|
||||
|
||||
static void
|
||||
reloc_tlsdesc(const Obj_Entry *obj, const Elf_Rel *rel,
|
||||
struct tlsdesc *where, int flags, RtldLockState *lockstate)
|
||||
{
|
||||
const Elf_Sym *def;
|
||||
const Obj_Entry *defobj;
|
||||
Elf_Addr offs;
|
||||
|
||||
dbg("reloc_tlsdesc obj %s rel %p where %p", obj->path, rel, where);
|
||||
offs = 0;
|
||||
if (ELF_R_SYM(rel->r_info) != 0) {
|
||||
def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, flags,
|
||||
NULL, lockstate);
|
||||
if (def == NULL)
|
||||
rtld_die();
|
||||
if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
|
||||
_rtld_error("%s: IFUNC for TLSDESC reloc",
|
||||
obj->path);
|
||||
rtld_die();
|
||||
}
|
||||
offs = def->st_value;
|
||||
obj = defobj;
|
||||
if (def->st_shndx == SHN_UNDEF) {
|
||||
/* Weak undefined thread variable */
|
||||
where->entry = rtld_tlsdesc_undef;
|
||||
return;
|
||||
}
|
||||
}
|
||||
offs += where->offset;
|
||||
|
||||
if (obj->tlsoffset != 0) {
|
||||
/* Variable is in initialy allocated TLS segment */
|
||||
where->entry = rtld_tlsdesc_static;
|
||||
where->offset = offs - obj->tlsoffset;
|
||||
} else {
|
||||
/* TLS offest is unknown at load time, use dynamic resolving */
|
||||
where->entry = rtld_tlsdesc_dynamic;
|
||||
where->arg = reloc_tlsdesc_alloc(__DECONST(Obj_Entry *, obj),
|
||||
offs);
|
||||
}
|
||||
}
|
||||
|
||||
/* Process the non-PLT relocations. */
|
||||
int
|
||||
reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
|
||||
@@ -271,6 +341,10 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
|
||||
case R_386_IRELATIVE:
|
||||
obj->irelative_nonplt = true;
|
||||
break;
|
||||
case R_386_TLS_DESC:
|
||||
reloc_tlsdesc(obj, rel, (struct tlsdesc *)where,
|
||||
flags, lockstate);
|
||||
break;
|
||||
default:
|
||||
_rtld_error(
|
||||
"%s: Unsupported relocation type %d in non-PLT relocations",
|
||||
@@ -295,10 +369,10 @@ reloc_plt(Obj_Entry *obj, int flags __unused, RtldLockState *lockstate __unused)
|
||||
for (rel = obj->pltrel; rel < rellim; rel++) {
|
||||
Elf_Addr *where;
|
||||
|
||||
where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
|
||||
switch (ELF_R_TYPE(rel->r_info)) {
|
||||
case R_386_JMP_SLOT:
|
||||
/* Relocate the GOT slot pointing into the PLT. */
|
||||
where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
|
||||
*where += (Elf_Addr)obj->relocbase;
|
||||
break;
|
||||
|
||||
@@ -306,6 +380,11 @@ reloc_plt(Obj_Entry *obj, int flags __unused, RtldLockState *lockstate __unused)
|
||||
obj->irelative = true;
|
||||
break;
|
||||
|
||||
case R_386_TLS_DESC:
|
||||
reloc_tlsdesc(obj, rel, (struct tlsdesc *)where,
|
||||
SYMLOOK_IN_PLT | flags, lockstate);
|
||||
break;
|
||||
|
||||
default:
|
||||
_rtld_error("Unknown relocation type %x in PLT",
|
||||
ELF_R_TYPE(rel->r_info));
|
||||
@@ -552,3 +631,17 @@ calculate_first_tls_offset(size_t size, size_t align, size_t offset)
|
||||
{
|
||||
return (calculate_tls_offset(0, 0, size, align, offset));
|
||||
}
|
||||
|
||||
__GNU_ABI ptrdiff_t
|
||||
rtld_tlsdesc_dynamic_impl(struct tlsdesc *tdp)
|
||||
{
|
||||
struct tlsdesc_dynarg *tda;
|
||||
struct tcb *tcb;
|
||||
tls_index *ti;
|
||||
|
||||
tda = tdp->arg;
|
||||
ti = &tda->tlsinfo;
|
||||
tcb = _tcb_get();
|
||||
return ((ptrdiff_t)tls_get_addr_common(tcb, ti->ti_module,
|
||||
ti->ti_offset) - (ptrdiff_t)tcb);
|
||||
}
|
||||
@@ -35,10 +35,14 @@
|
||||
|
||||
struct Struct_Obj_Entry;
|
||||
|
||||
#define MD_OBJ_ENTRY
|
||||
#define MD_OBJ_ENTRY \
|
||||
STAILQ_HEAD(, tlsdesc_dynarg) tlsdesc_dynargs;
|
||||
|
||||
#define MD_OBJ_ENTRY_INIT(obj)
|
||||
#define MD_OBJ_ENTRY_FINI(obj)
|
||||
#define MD_OBJ_ENTRY_INIT(obj) md_obj_entry_init(obj)
|
||||
#define MD_OBJ_ENTRY_FINI(obj) md_obj_entry_fini(obj)
|
||||
|
||||
void md_obj_entry_init(struct Struct_Obj_Entry *obj);
|
||||
void md_obj_entry_fini(struct Struct_Obj_Entry *obj);
|
||||
|
||||
/* Return the address of the .dynamic section in the dynamic linker. */
|
||||
#define rtld_dynamic(obj) \
|
||||
@@ -83,10 +87,31 @@ typedef struct {
|
||||
void *___tls_get_addr(tls_index *ti) __GNU_ABI __exported;
|
||||
void *__tls_get_addr(tls_index *ti) __exported;
|
||||
|
||||
struct tlsdesc_dynarg
|
||||
{
|
||||
tls_index tlsinfo;
|
||||
STAILQ_ENTRY(tlsdesc_dynarg) link;
|
||||
};
|
||||
|
||||
struct tlsdesc
|
||||
{
|
||||
ptrdiff_t (*entry)(struct tlsdesc *) __GNU_ABI;
|
||||
union {
|
||||
Elf_Size offset;
|
||||
struct tlsdesc_dynarg *arg;
|
||||
};
|
||||
};
|
||||
|
||||
#define md_abi_variant_hook(x)
|
||||
|
||||
size_t calculate_first_tls_offset(size_t size, size_t align, size_t offset);
|
||||
size_t calculate_tls_offset(size_t prev_offset, size_t prev_size, size_t size,
|
||||
size_t align, size_t offset);
|
||||
|
||||
ptrdiff_t rtld_tlsdesc_dynamic_impl(struct tlsdesc *tdp) __GNU_ABI;
|
||||
|
||||
ptrdiff_t rtld_tlsdesc_static(struct tlsdesc *) __GNU_ABI;
|
||||
ptrdiff_t rtld_tlsdesc_undef(struct tlsdesc *) __GNU_ABI;
|
||||
ptrdiff_t rtld_tlsdesc_dynamic(struct tlsdesc *) __GNU_ABI;
|
||||
|
||||
#endif
|
||||
@@ -95,4 +95,40 @@ _rtld_bind_start:
|
||||
leal 4(%esp),%esp # Discard reloff, do not change eflags
|
||||
ret # "Return" to target address
|
||||
|
||||
rtld_tlsdesc_static:
|
||||
.globl rtld_tlsdesc_static
|
||||
.type rtld_tlsdesc_static,@function
|
||||
.cfi_startproc
|
||||
movl 4(%eax), %eax
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size rtld_tlsdesc_static, . - rtld_tlsdesc_static
|
||||
|
||||
rtld_tlsdesc_undef:
|
||||
.globl rtld_tlsdesc_undef
|
||||
.type rtld_tlsdesc_undef,@function
|
||||
.cfi_startproc
|
||||
movl 4(%eax), %eax
|
||||
subl %gs:0, %eax
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size rtld_tlsdesc_undef, . - rtld_tlsdesc_undef
|
||||
|
||||
rtld_tlsdesc_dynamic:
|
||||
.globl rtld_tlsdesc_dynamic
|
||||
.type rtld_tlsdesc_dynamic,@function
|
||||
.cfi_startproc
|
||||
pushl %ebp
|
||||
/* XXXKIB cfi */
|
||||
movl %esp, %ebp
|
||||
pushl %edx
|
||||
pushl %ecx
|
||||
call rtld_tlsdesc_dynamic_impl
|
||||
popl %ecx
|
||||
popl %edx
|
||||
popl %ebp
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size rtld_tlsdesc_dynamic, . - rtld_tlsdesc_dynamic
|
||||
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
Reference in new issue
Block a user