diff options
| -rw-r--r-- | libexec/rtld-elf/amd64/rtld_start.S | 25 | ||||
| -rw-r--r-- | libexec/rtld-elf/i386/reloc.c | 95 | ||||
| -rw-r--r-- | libexec/rtld-elf/i386/rtld_machdep.h | 31 | ||||
| -rw-r--r-- | libexec/rtld-elf/i386/rtld_start.S | 36 |
4 files changed, 183 insertions, 4 deletions
diff --git a/libexec/rtld-elf/amd64/rtld_start.S b/libexec/rtld-elf/amd64/rtld_start.S index 7f85a9f94d5c..dcc168a33c57 100644 --- a/libexec/rtld-elf/amd64/rtld_start.S +++ b/libexec/rtld-elf/amd64/rtld_start.S @@ -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 diff --git a/libexec/rtld-elf/i386/reloc.c b/libexec/rtld-elf/i386/reloc.c index 060b3cb147e3..5dd495f2056c 100644 --- a/libexec/rtld-elf/i386/reloc.c +++ b/libexec/rtld-elf/i386/reloc.c @@ -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); +} diff --git a/libexec/rtld-elf/i386/rtld_machdep.h b/libexec/rtld-elf/i386/rtld_machdep.h index 574eafe432db..50c2a1bef94e 100644 --- a/libexec/rtld-elf/i386/rtld_machdep.h +++ b/libexec/rtld-elf/i386/rtld_machdep.h @@ -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 diff --git a/libexec/rtld-elf/i386/rtld_start.S b/libexec/rtld-elf/i386/rtld_start.S index 9dbe32d27628..d81f2d17fff4 100644 --- a/libexec/rtld-elf/i386/rtld_start.S +++ b/libexec/rtld-elf/i386/rtld_start.S @@ -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 |
