diff --git a/Makefile b/Makefile index 0ab0bfd..d5a64fc 100644 --- a/Makefile +++ b/Makefile @@ -125,7 +125,7 @@ $(foreach s,$(wildcard src/*/$(ARCH)*/*.s),$(eval $(call mkasmdep,$(s)))) lib/libc.so: $(LOBJS) $(CC) $(CFLAGS_ALL_SHARED) $(LDFLAGS) -nostdlib -shared \ - -Wl,-e,_start -Wl,-Bsymbolic-functions \ + -Wl,-e,_dlstart -Wl,-Bsymbolic-functions \ -o $@ $(LOBJS) $(LIBCC) lib/libc.a: $(OBJS) diff --git a/arch/arm/reloc.h b/arch/arm/reloc.h index 264b7ab..ee39b7f 100644 --- a/arch/arm/reloc.h +++ b/arch/arm/reloc.h @@ -16,41 +16,29 @@ #define LDSO_ARCH "arm" ENDIAN_SUFFIX FP_SUFFIX -#define IS_COPY(x) ((x)==R_ARM_COPY) -#define IS_PLT(x) ((x)==R_ARM_JUMP_SLOT) +#define NO_LEGACY_INITFINI + +#define TPOFF_K 8 -static inline void do_single_reloc( - struct dso *self, unsigned char *base_addr, - size_t *reloc_addr, int type, size_t addend, - Sym *sym, size_t sym_size, - struct symdef def, size_t sym_val) +static int remap_rel(int type) { switch(type) { case R_ARM_ABS32: - *reloc_addr += sym_val; - break; + return REL_SYMBOLIC; case R_ARM_GLOB_DAT: + return REL_GOT; case R_ARM_JUMP_SLOT: - *reloc_addr = sym_val; - break; + return REL_PLT; case R_ARM_RELATIVE: - *reloc_addr += (size_t)base_addr; - break; + return REL_RELATIVE; case R_ARM_COPY: - memcpy(reloc_addr, (void *)sym_val, sym_size); - break; + return REL_COPY; case R_ARM_TLS_DTPMOD32: - *reloc_addr = def.dso ? def.dso->tls_id : self->tls_id; - break; + return REL_DTPMOD; case R_ARM_TLS_DTPOFF32: - *reloc_addr += def.sym->st_value; - break; + return REL_DTPOFF; case R_ARM_TLS_TPOFF32: - *reloc_addr += def.sym - ? def.sym->st_value + def.dso->tls_offset + 8 - : self->tls_offset + 8; - break; + return REL_TPOFF; } + return 0; } - -#define NO_LEGACY_INITFINI diff --git a/arch/i386/reloc.h b/arch/i386/reloc.h index 3923b54..eaf5aae 100644 --- a/arch/i386/reloc.h +++ b/arch/i386/reloc.h @@ -3,47 +3,31 @@ #define LDSO_ARCH "i386" -#define IS_COPY(x) ((x)==R_386_COPY) -#define IS_PLT(x) ((x)==R_386_JMP_SLOT) - -static inline void do_single_reloc( - struct dso *self, unsigned char *base_addr, - size_t *reloc_addr, int type, size_t addend, - Sym *sym, size_t sym_size, - struct symdef def, size_t sym_val) +static int remap_rel(int type) { switch(type) { case R_386_32: - *reloc_addr += sym_val; - break; + return REL_SYMBOLIC; case R_386_PC32: - *reloc_addr += sym_val - (size_t)reloc_addr; - break; + return REL_OFFSET; case R_386_GLOB_DAT: + return REL_GOT; case R_386_JMP_SLOT: - *reloc_addr = sym_val; - break; + return REL_PLT; case R_386_RELATIVE: - *reloc_addr += (size_t)base_addr; - break; + return REL_RELATIVE; case R_386_COPY: - memcpy(reloc_addr, (void *)sym_val, sym_size); - break; + return REL_COPY; case R_386_TLS_DTPMOD32: - *reloc_addr = def.dso ? def.dso->tls_id : self->tls_id; - break; + return REL_DTPMOD; case R_386_TLS_DTPOFF32: - *reloc_addr = def.sym->st_value; - break; + return REL_DTPOFF; case R_386_TLS_TPOFF: - *reloc_addr += def.sym - ? def.sym->st_value - def.dso->tls_offset - : 0 - self->tls_offset; - break; + return REL_TPOFF; case R_386_TLS_TPOFF32: - *reloc_addr += def.sym - ? def.dso->tls_offset - def.sym->st_value - : self->tls_offset; - break; + return REL_TPOFF_NEG; + case R_386_TLS_DESC: + return REL_TLSDESC; } + return 0; } diff --git a/arch/microblaze/reloc.h b/arch/microblaze/reloc.h index 7bf3a5b..71a6219 100644 --- a/arch/microblaze/reloc.h +++ b/arch/microblaze/reloc.h @@ -10,34 +10,27 @@ #define LDSO_ARCH "microblaze" ENDIAN_SUFFIX -#define IS_COPY(x) ((x)==R_MICROBLAZE_COPY) -#define IS_PLT(x) ((x)==R_MICROBLAZE_JUMP_SLOT) +#define TPOFF_K 0 -static inline void do_single_reloc( - struct dso *self, unsigned char *base_addr, - size_t *reloc_addr, int type, size_t addend, - Sym *sym, size_t sym_size, - struct symdef def, size_t sym_val) +static int remap_rel(int type) { switch(type) { case R_MICROBLAZE_32: + return REL_SYMBOLIC; case R_MICROBLAZE_GLOB_DAT: + return REL_GOT; case R_MICROBLAZE_JUMP_SLOT: - *reloc_addr = sym_val + addend; - break; + return REL_PLT; case R_MICROBLAZE_REL: - *reloc_addr = (size_t)base_addr + addend; - break; + return REL_RELATIVE; case R_MICROBLAZE_COPY: - memcpy(reloc_addr, (void *)sym_val, sym_size); - break; + return REL_COPY; case R_MICROBLAZE_TLSDTPMOD32: - *reloc_addr = def.dso ? def.dso->tls_id : self->tls_id; - break; + return REL_DTPMOD; case R_MICROBLAZE_TLSDTPREL32: - *reloc_addr = def.sym->st_value + addend; - break; + return REL_DTPOFF; } + return 0; } #include "syscall.h" diff --git a/arch/mips/reloc.h b/arch/mips/reloc.h index 4ca8125..91fa097 100644 --- a/arch/mips/reloc.h +++ b/arch/mips/reloc.h @@ -16,38 +16,25 @@ #define LDSO_ARCH "mips" ENDIAN_SUFFIX FP_SUFFIX -#define IS_COPY(x) ((x)==R_MIPS_COPY) -#define IS_PLT(x) 1 +#define TPOFF_K (-0x7000) -static inline void do_single_reloc( - struct dso *self, unsigned char *base_addr, - size_t *reloc_addr, int type, size_t addend, - Sym *sym, size_t sym_size, - struct symdef def, size_t sym_val) +static int remap_rel(int type) { switch(type) { - case R_MIPS_JUMP_SLOT: - *reloc_addr = sym_val; - break; case R_MIPS_REL32: - if (sym_val) *reloc_addr += sym_val; - else *reloc_addr += (size_t)base_addr; - break; + return REL_SYM_OR_REL; + case R_MIPS_JUMP_SLOT: + return REL_PLT; case R_MIPS_COPY: - memcpy(reloc_addr, (void *)sym_val, sym_size); - break; + return REL_COPY; case R_MIPS_TLS_DTPMOD32: - *reloc_addr = def.dso ? def.dso->tls_id : self->tls_id; - break; + return REL_DTPMOD; case R_MIPS_TLS_DTPREL32: - *reloc_addr += def.sym->st_value; - break; + return REL_DTPOFF; case R_MIPS_TLS_TPREL32: - *reloc_addr += def.sym - ? def.sym->st_value + def.dso->tls_offset - 0x7000 - : self->tls_offset - 0x7000; - break; + return REL_TPOFF; } + return 0; } void __reloc_self(int c, size_t *a, size_t *dynv, size_t *got) diff --git a/arch/powerpc/reloc.h b/arch/powerpc/reloc.h index 38034c5..73c583b 100644 --- a/arch/powerpc/reloc.h +++ b/arch/powerpc/reloc.h @@ -3,40 +3,29 @@ #define LDSO_ARCH "powerpc" -#define IS_COPY(x) ((x)==R_PPC_COPY) -#define IS_PLT(x) ((x)==R_PPC_JMP_SLOT) +#define TPOFF_K (-0x7000) -// see linux' arch/powerpc/include/asm/elf.h -static inline void do_single_reloc( - struct dso *self, unsigned char *base_addr, - size_t *reloc_addr, int type, size_t addend, - Sym *sym, size_t sym_size, - struct symdef def, size_t sym_val) +static int remap_rel(int type) { switch(type) { + case R_PPC_ADDR32: + return REL_SYMBOLIC; case R_PPC_GLOB_DAT: + return REL_GOT; case R_PPC_JMP_SLOT: - case R_PPC_ADDR32: - *reloc_addr = sym_val + addend; - break; - case R_PPC_COPY: - memcpy(reloc_addr, (void *)sym_val, sym_size); - break; + return REL_PLT; case R_PPC_RELATIVE: - *reloc_addr = (size_t)base_addr + addend; - break; + return REL_RELATIVE; + case R_PPC_COPY: + return REL_COPY; case R_PPC_DTPMOD32: - *reloc_addr = def.dso ? def.dso->tls_id : self->tls_id; - break; + return REL_DTPMOD; case R_PPC_DTPREL32: - *reloc_addr = def.sym->st_value + addend; - break; + return REL_DTPOFF; case R_PPC_TPREL32: - *reloc_addr += def.sym - ? def.sym->st_value + def.dso->tls_offset - 0x7000 - : self->tls_offset - 0x7000; - break; + return REL_TPOFF; } + return 0; } void __reloc_self(int c, size_t *a, size_t *dynv) diff --git a/arch/sh/reloc.h b/arch/sh/reloc.h index db3de08..aeb02d0 100644 --- a/arch/sh/reloc.h +++ b/arch/sh/reloc.h @@ -6,42 +6,29 @@ #define LDSO_ARCH "sh" ENDIAN_SUFFIX -#define IS_COPY(x) ((x) == R_SH_COPY) -#define IS_PLT(x) ((x) == R_SH_JMP_SLOT) +#define TPOFF_K 8 -static inline void do_single_reloc( - struct dso *self, unsigned char *base_addr, - size_t *reloc_addr, int type, size_t addend, - Sym *sym, size_t sym_size, - struct symdef def, size_t sym_val) +static int remap_rel(int type) { switch(type) { + case R_SH_DIR32: + return REL_SYMBOLIC; + case R_SH_REL32: + return REL_OFFSET; case R_SH_GLOB_DAT: + return REL_GOT; case R_SH_JMP_SLOT: - *reloc_addr = sym_val; - break; + return REL_PLT; case R_SH_RELATIVE: - *reloc_addr = (size_t)base_addr + addend; - break; - case R_SH_DIR32: - *reloc_addr = sym_val + addend; - break; - case R_SH_REL32: - *reloc_addr = sym_val + addend - (size_t)reloc_addr + (size_t)base_addr; - break; + return REL_RELATIVE; case R_SH_COPY: - memcpy(reloc_addr, (void *)sym_val, sym_size); - break; + return REL_COPY; case R_SH_TLS_DTPMOD32: - *reloc_addr += def.dso ? def.dso->tls_id : self->tls_id; - break; + return REL_DTPMOD; case R_SH_TLS_DTPOFF32: - *reloc_addr += def.sym->st_value; - break; + return REL_DTPOFF; case R_SH_TLS_TPOFF32: - *reloc_addr += def.sym - ? def.sym->st_value + def.dso->tls_offset + 8 - : self->tls_offset + 8; - break; + return REL_TPOFF; } + return 0; } diff --git a/arch/x32/reloc.h b/arch/x32/reloc.h index f294eec..fcfbf99 100644 --- a/arch/x32/reloc.h +++ b/arch/x32/reloc.h @@ -4,43 +4,37 @@ #define LDSO_ARCH "x32" -#define IS_COPY(x) ((x)==R_X86_64_COPY) -#define IS_PLT(x) ((x)==R_X86_64_JUMP_SLOT) +/* FIXME: x32 is very strange in its use of 64-bit relocation types in + * a 32-bit environment. As long as the memory at reloc_addr is + * zero-filled prior to relocations, just treating 64-bit relocations + * as operating on 32-bit slots should be fine, but this should be + * checked. In particular, R_X86_64_64, R_X86_64_DTPOFF64, and + * R_X86_64_TPOFF64 may need checking. */ -static inline void do_single_reloc( - struct dso *self, unsigned char *base_addr, - size_t *reloc_addr, int type, size_t addend, - Sym *sym, size_t sym_size, - struct symdef def, size_t sym_val) +static int remap_rel(int type) { switch(type) { - case R_X86_64_GLOB_DAT: - case R_X86_64_JUMP_SLOT: case R_X86_64_64: - *reloc_addr = sym_val + addend; - break; case R_X86_64_32: - *(uint32_t *)reloc_addr = sym_val + addend; - break; + return REL_SYMBOLIC; case R_X86_64_PC32: - *reloc_addr = sym_val + addend - (size_t)reloc_addr + (size_t)base_addr; - break; + return REL_OFFSET; + case R_X86_64_GLOB_DAT: + return REL_GOT; + case R_X86_64_JUMP_SLOT: + return REL_PLT; case R_X86_64_RELATIVE: - *reloc_addr = (size_t)base_addr + addend; - break; + return REL_RELATIVE; case R_X86_64_COPY: - memcpy(reloc_addr, (void *)sym_val, sym_size); - break; + return REL_COPY; case R_X86_64_DTPMOD64: - *reloc_addr = def.dso ? def.dso->tls_id : self->tls_id; - break; + return REL_DTPMOD; case R_X86_64_DTPOFF64: - *reloc_addr = def.sym->st_value + addend; - break; + case R_X86_64_DTPOFF32: + return REL_DTPOFF; case R_X86_64_TPOFF64: - *reloc_addr = (def.sym - ? def.sym->st_value - def.dso->tls_offset - : 0 - self->tls_offset) + addend; - break; + case R_X86_64_TPOFF32: + return REL_TPOFF; } + return 0; } diff --git a/arch/x86_64/reloc.h b/arch/x86_64/reloc.h index 28cf7cc..9bc5849 100644 --- a/arch/x86_64/reloc.h +++ b/arch/x86_64/reloc.h @@ -4,43 +4,29 @@ #define LDSO_ARCH "x86_64" -#define IS_COPY(x) ((x)==R_X86_64_COPY) -#define IS_PLT(x) ((x)==R_X86_64_JUMP_SLOT) - -static inline void do_single_reloc( - struct dso *self, unsigned char *base_addr, - size_t *reloc_addr, int type, size_t addend, - Sym *sym, size_t sym_size, - struct symdef def, size_t sym_val) +static int remap_rel(int type) { switch(type) { - case R_X86_64_GLOB_DAT: - case R_X86_64_JUMP_SLOT: case R_X86_64_64: - *reloc_addr = sym_val + addend; - break; - case R_X86_64_32: - *(uint32_t *)reloc_addr = sym_val + addend; - break; + return REL_SYMBOLIC; case R_X86_64_PC32: - *reloc_addr = sym_val + addend - (size_t)reloc_addr + (size_t)base_addr; - break; + return REL_OFFSET32; + case R_X86_64_GLOB_DAT: + return REL_GOT; + case R_X86_64_JUMP_SLOT: + return REL_PLT; case R_X86_64_RELATIVE: - *reloc_addr = (size_t)base_addr + addend; - break; + return REL_RELATIVE; case R_X86_64_COPY: - memcpy(reloc_addr, (void *)sym_val, sym_size); - break; + return REL_COPY; case R_X86_64_DTPMOD64: - *reloc_addr = def.dso ? def.dso->tls_id : self->tls_id; - break; + return REL_DTPMOD; case R_X86_64_DTPOFF64: - *reloc_addr = def.sym->st_value + addend; - break; + return REL_DTPOFF; case R_X86_64_TPOFF64: - *reloc_addr = (def.sym - ? def.sym->st_value - def.dso->tls_offset - : 0 - self->tls_offset) + addend; - break; + return REL_TPOFF; + case R_X86_64_TLSDESC: + return REL_TLSDESC; } + return 0; } diff --git a/include/sys/socket.h b/include/sys/socket.h index d752791..b911d6e 100644 --- a/include/sys/socket.h +++ b/include/sys/socket.h @@ -26,6 +26,17 @@ struct ucred uid_t uid; gid_t gid; }; + +struct mmsghdr +{ + struct msghdr msg_hdr; + unsigned int msg_len; +}; + +struct timespec; + +int sendmmsg (int, struct mmsghdr *, unsigned int, unsigned int); +int recvmmsg (int, struct mmsghdr *, unsigned int, unsigned int, struct timespec *); #endif struct linger diff --git a/src/env/__init_tls.c b/src/env/__init_tls.c index f7eab8d..13cf2ee 100644 --- a/src/env/__init_tls.c +++ b/src/env/__init_tls.c @@ -53,11 +53,6 @@ void *__copy_tls(unsigned char *mem) return td; } -void *__tls_get_addr(size_t *v) -{ - return (char *)__pthread_self()->dtv[1]+v[1]; -} - #if ULONG_MAX == 0xffffffff typedef Elf32_Phdr Phdr; #else diff --git a/src/ldso/arm/start.s b/src/ldso/arm/start.s index dfa3657..5dd93b5 100644 --- a/src/ldso/arm/start.s +++ b/src/ldso/arm/start.s @@ -1,6 +1,6 @@ .text -.global _start -_start: +.global _dlstart +_dlstart: ldr r0,[sp] add r1,sp,#4 bl __dynlink diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c index 1cb3fb4..bc4f2f6 100644 --- a/src/ldso/dynlink.c +++ b/src/ldso/dynlink.c @@ -1,6 +1,8 @@ #define _GNU_SOURCE #include #include +#include +#include #include #include #include @@ -48,6 +50,11 @@ struct debug { void *base; }; +struct td_index { + size_t args[2]; + struct td_index *next; +}; + struct dso { unsigned char *base; char *name; @@ -79,6 +86,7 @@ struct dso { void **new_dtv; unsigned char *new_tls; int new_dtv_idx, new_tls_idx; + struct td_index *td_index; struct dso *fini_next; char *shortname; char buf[]; @@ -89,6 +97,24 @@ struct symdef { struct dso *dso; }; +enum { + REL_ERR, + REL_SYMBOLIC, + REL_GOT, + REL_PLT, + REL_RELATIVE, + REL_OFFSET, + REL_OFFSET32, + REL_COPY, + REL_SYM_OR_REL, + REL_TLS, /* everything past here is TLS */ + REL_DTPMOD, + REL_DTPOFF, + REL_TPOFF, + REL_TPOFF_NEG, + REL_TLSDESC, +}; + #include "reloc.h" int __init_tp(void *); @@ -107,6 +133,7 @@ static jmp_buf *rtld_fail; static pthread_rwlock_t lock; static struct debug debug; static size_t tls_cnt, tls_offset, tls_align = 4*sizeof(size_t); +static size_t static_tls_cnt; static pthread_mutex_t init_fini_lock = { ._m_type = PTHREAD_MUTEX_RECURSIVE }; static long long builtin_tls[(sizeof(struct pthread) + 64)/sizeof(long long)]; @@ -132,6 +159,17 @@ static int search_vec(size_t *v, size_t *r, size_t key) return 1; } +static void error(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vsnprintf(errbuf, sizeof errbuf, fmt, ap); + va_end(ap); + if (runtime) longjmp(*rtld_fail, 1); + dprintf(2, "%s\n", errbuf); + ldso_fail = 1; +} + static uint32_t sysv_hash(const char *s0) { const unsigned char *s = (void *)s0; @@ -227,6 +265,10 @@ static struct symdef find_sym(struct dso *dso, const char *s, int need_def) return def; } +#define NO_INLINE_ADDEND (1<base; @@ -235,36 +277,116 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri Sym *sym; const char *name; void *ctx; - int type; + int astype, type; int sym_index; struct symdef def; + size_t *reloc_addr; + size_t sym_val; + size_t tls_val; + size_t addend; for (; rel_size; rel+=stride, rel_size-=stride*sizeof(size_t)) { - type = R_TYPE(rel[1]); + astype = R_TYPE(rel[1]); + if (!astype) continue; + type = remap_rel(astype); + if (!type) { + error(errbuf, sizeof errbuf, + "Error relocating %s: unsupported relocation type %d", + dso->name, astype); + continue; + } sym_index = R_SYM(rel[1]); + reloc_addr = (void *)(base + rel[0]); if (sym_index) { sym = syms + sym_index; name = strings + sym->st_name; - ctx = IS_COPY(type) ? head->next : head; - def = find_sym(ctx, name, IS_PLT(type)); + ctx = type==REL_COPY ? head->next : head; + def = find_sym(ctx, name, type==REL_PLT); if (!def.sym && (sym->st_shndx != SHN_UNDEF || sym->st_info>>4 != STB_WEAK)) { - snprintf(errbuf, sizeof errbuf, + error(errbuf, sizeof errbuf, "Error relocating %s: %s: symbol not found", dso->name, name); - if (runtime) longjmp(*rtld_fail, 1); - dprintf(2, "%s\n", errbuf); - ldso_fail = 1; continue; } } else { sym = 0; def.sym = 0; - def.dso = 0; + def.dso = dso; + } + + addend = stride>2 ? rel[2] + : (1<base+def.sym->st_value : 0; + tls_val = def.sym ? def.sym->st_value : 0; + + switch(type) { + case REL_OFFSET: + addend -= (size_t)reloc_addr; + case REL_SYMBOLIC: + case REL_GOT: + case REL_PLT: + *reloc_addr = sym_val + addend; + break; + case REL_RELATIVE: + *reloc_addr = (size_t)base + addend; + break; + case REL_SYM_OR_REL: + if (sym) *reloc_addr = sym_val + addend; + else *reloc_addr = (size_t)base + addend; + break; + case REL_COPY: + memcpy(reloc_addr, (void *)sym_val, sym->st_size); + break; + case REL_OFFSET32: + *(uint32_t *)reloc_addr = sym_val + addend + - (size_t)reloc_addr; + break; + case REL_DTPMOD: + *reloc_addr = def.dso->tls_id; + break; + case REL_DTPOFF: + *reloc_addr = tls_val + addend; + break; +#ifdef TLS_ABOVE_TP + case REL_TPOFF: + *reloc_addr = tls_val + def.dso->tls_offset + TPOFF_K + addend; + break; +#else + case REL_TPOFF: + *reloc_addr = tls_val - def.dso->tls_offset + addend; + break; + case REL_TPOFF_NEG: + *reloc_addr = def.dso->tls_offset - tls_val + addend; + break; +#endif + case REL_TLSDESC: + if (stride<3) addend = reloc_addr[1]; + if (runtime && def.dso->tls_id >= static_tls_cnt) { + struct td_index *new = malloc(sizeof *new); + if (!new) error(errbuf, sizeof errbuf, + "Error relocating %s: cannot allocate TLSDESC for %s", + dso->name, sym ? name : "(local)" ); + new->next = dso->td_index; + dso->td_index = new; + new->args[0] = def.dso->tls_id; + new->args[1] = tls_val + addend; + reloc_addr[0] = (size_t)__tlsdesc_dynamic; + reloc_addr[1] = (size_t)new; + } else { + reloc_addr[0] = (size_t)__tlsdesc_static; +#ifdef TLS_ABOVE_TP + reloc_addr[1] = tls_val + def.dso->tls_offset + + TPOFF_K + addend; +#else + reloc_addr[1] = tls_val - def.dso->tls_offset + + addend; +#endif + } + break; } - do_single_reloc(dso, base, (void *)(base + rel[0]), type, - stride>2 ? rel[2] : 0, sym, sym?sym->st_size:0, def, - def.sym?(size_t)(def.dso->base+def.sym->st_value):0); } } @@ -717,12 +839,9 @@ static void load_deps(struct dso *p) if (p->dynv[i] != DT_NEEDED) continue; dep = load_library(p->strings + p->dynv[i+1], p); if (!dep) { - snprintf(errbuf, sizeof errbuf, + error(errbuf, sizeof errbuf, "Error loading shared library %s: %m (needed by %s)", p->strings + p->dynv[i+1], p->name); - if (runtime) longjmp(*rtld_fail, 1); - dprintf(2, "%s\n", errbuf); - ldso_fail = 1; continue; } if (runtime) { @@ -771,12 +890,9 @@ static void reloc_all(struct dso *p) if (p->relro_start != p->relro_end && mprotect(p->base+p->relro_start, p->relro_end-p->relro_start, PROT_READ) < 0) { - snprintf(errbuf, sizeof errbuf, + error(errbuf, sizeof errbuf, "Error relocating %s: RELRO protection failed: %m", p->name); - if (runtime) longjmp(*rtld_fail, 1); - dprintf(2, "%s\n", errbuf); - ldso_fail = 1; } p->relocated = 1; @@ -915,17 +1031,15 @@ void *__copy_tls(unsigned char *mem) return td; } -void *__tls_get_addr(size_t *v) +void *__tls_get_new(size_t *v) { pthread_t self = __pthread_self(); - if (v[0]<=(size_t)self->dtv[0] && self->dtv[v[0]]) - return (char *)self->dtv[v[0]]+v[1]; /* Block signals to make accessing new TLS async-signal-safe */ sigset_t set; - pthread_sigmask(SIG_BLOCK, SIGALL_SET, &set); - if (v[0]<=(size_t)self->dtv[0] && self->dtv[v[0]]) { - pthread_sigmask(SIG_SETMASK, &set, 0); + __block_all_sigs(&set); + if (v[0]<=(size_t)self->dtv[0]) { + __restore_sigs(&set); return (char *)self->dtv[v[0]]+v[1]; } @@ -946,13 +1060,19 @@ void *__tls_get_addr(size_t *v) self->dtv = newdtv; } - /* Get new TLS memory from new DSO */ - unsigned char *mem = p->new_tls + - (p->tls_size + p->tls_align) * a_fetch_add(&p->new_tls_idx,1); - mem += ((uintptr_t)p->tls_image - (uintptr_t)mem) & (p->tls_align-1); - self->dtv[v[0]] = mem; - memcpy(mem, p->tls_image, p->tls_len); - pthread_sigmask(SIG_SETMASK, &set, 0); + /* Get new TLS memory from all new DSOs up to the requested one */ + unsigned char *mem; + for (p=head; ; p=p->next) { + if (!p->tls_id || self->dtv[p->tls_id]) continue; + mem = p->new_tls + (p->tls_size + p->tls_align) + * a_fetch_add(&p->new_tls_idx,1); + mem += ((uintptr_t)p->tls_image - (uintptr_t)mem) + & (p->tls_align-1); + self->dtv[p->tls_id] = mem; + memcpy(mem, p->tls_image, p->tls_len); + if (p->tls_id == v[0]) break; + } + __restore_sigs(&set); return mem + v[1]; } @@ -1196,6 +1316,7 @@ void *__dynlink(int argc, char **argv) dprintf(2, "%s: Thread-local storage not supported by kernel.\n", argv[0]); _exit(127); } + static_tls_cnt = tls_cnt; if (ldso_fail) _exit(127); if (ldd_mode) _exit(0); @@ -1251,6 +1372,11 @@ void *dlopen(const char *file, int mode) for (p=orig_tail->next; p; p=next) { next = p->next; munmap(p->map, p->map_len); + while (p->td_index) { + void *tmp = p->td_index->next; + free(p->td_index); + p->td_index = tmp; + } free(p->deps); free(p); } @@ -1314,6 +1440,8 @@ static int invalid_dso_handle(void *h) return 1; } +void *__tls_get_addr(size_t *); + static void *do_dlsym(struct dso *p, const char *s, void *ra) { size_t i; diff --git a/src/ldso/i386/start.s b/src/ldso/i386/start.s index b16f8af..c37a1fa 100644 --- a/src/ldso/i386/start.s +++ b/src/ldso/i386/start.s @@ -1,6 +1,6 @@ .text -.global _start -_start: +.global _dlstart +_dlstart: xor %ebp,%ebp pop %edi mov %esp,%esi diff --git a/src/ldso/i386/tlsdesc.s b/src/ldso/i386/tlsdesc.s new file mode 100644 index 0000000..3ac6129 --- /dev/null +++ b/src/ldso/i386/tlsdesc.s @@ -0,0 +1,27 @@ +.text +.global __tlsdesc_static +.type __tlsdesc_static,@function +__tlsdesc_static: + mov 4(%eax),%eax + ret + +.global __tlsdesc_dynamic +.type __tlsdesc_dynamic,@function +__tlsdesc_dynamic: + mov 4(%eax),%eax + push %edx + mov %gs:4,%edx + push %ecx + mov (%eax),%ecx + cmp %ecx,(%edx) + jc 1f + mov 4(%eax),%eax + add (%edx,%ecx,4),%eax +2: pop %ecx + sub %gs:0,%eax + pop %edx + ret +1: push %eax + call __tls_get_addr + pop %ecx + jmp 2b diff --git a/src/ldso/microblaze/start.s b/src/ldso/microblaze/start.s index 4e0a0e5..067e861 100644 --- a/src/ldso/microblaze/start.s +++ b/src/ldso/microblaze/start.s @@ -1,6 +1,6 @@ # FIXME: clearing argv entries -.global _start -_start: +.global _dlstart +_dlstart: add r19, r0, r0 lw r5, r0, r1 diff --git a/src/ldso/mips/start.s b/src/ldso/mips/start.s index 2e98529..0cadbf8 100644 --- a/src/ldso/mips/start.s +++ b/src/ldso/mips/start.s @@ -2,9 +2,9 @@ .hidden __reloc_self .set noreorder .set nomacro -.global _start -.type _start,@function -_start: +.global _dlstart +.type _dlstart,@function +_dlstart: move $fp, $0 bgezal $0, 1f diff --git a/src/ldso/powerpc/start.s b/src/ldso/powerpc/start.s index 6c499e8..6548d58 100644 --- a/src/ldso/powerpc/start.s +++ b/src/ldso/powerpc/start.s @@ -1,6 +1,6 @@ - .global _start - .type _start,@function -_start: + .global _dlstart + .type _dlstart,@function +_dlstart: bl 1f 2: .long _DYNAMIC-2b 1: mflr 5 diff --git a/src/ldso/sh/start.s b/src/ldso/sh/start.s index ca6b7fc..0d2d913 100644 --- a/src/ldso/sh/start.s +++ b/src/ldso/sh/start.s @@ -1,7 +1,7 @@ .text -.global _start -.type _start, @function -_start: +.global _dlstart +.type _dlstart, @function +_dlstart: mov.l @r15, r4 mov r15, r5 mov.l L1, r0 diff --git a/src/ldso/tlsdesc.c b/src/ldso/tlsdesc.c new file mode 100644 index 0000000..031b5b8 --- /dev/null +++ b/src/ldso/tlsdesc.c @@ -0,0 +1,13 @@ +#ifdef SHARED + +#include +#include "libc.h" + +ptrdiff_t __tlsdesc_static() +{ + return 0; +} + +weak_alias(__tlsdesc_static, __tlsdesc_dynamic); + +#endif diff --git a/src/ldso/x32/start.s b/src/ldso/x32/start.s index 0fcf46d..3c3800a 100644 --- a/src/ldso/x32/start.s +++ b/src/ldso/x32/start.s @@ -1,6 +1,6 @@ .text -.global _start -_start: +.global _dlstart +_dlstart: mov (%rsp),%rdi /* move argc into 1st argument slot */ lea 4(%rsp),%rsi /* move argv into 2nd argument slot */ call __dynlink diff --git a/src/ldso/x86_64/start.s b/src/ldso/x86_64/start.s index 80c1d08..1c5598a 100644 --- a/src/ldso/x86_64/start.s +++ b/src/ldso/x86_64/start.s @@ -1,6 +1,6 @@ .text -.global _start -_start: +.global _dlstart +_dlstart: mov (%rsp),%rdi lea 8(%rsp),%rsi call __dynlink diff --git a/src/ldso/x86_64/tlsdesc.s b/src/ldso/x86_64/tlsdesc.s new file mode 100644 index 0000000..57b78e0 --- /dev/null +++ b/src/ldso/x86_64/tlsdesc.s @@ -0,0 +1,40 @@ +.text +.global __tlsdesc_static +.type __tlsdesc_static,@function +__tlsdesc_static: + mov 8(%rax),%rax + ret + +.global __tlsdesc_dynamic +.type __tlsdesc_dynamic,@function +__tlsdesc_dynamic: + mov 8(%rax),%rax + push %rdx + mov %fs:8,%rdx + push %rcx + mov (%rax),%rcx + cmp %rcx,(%rdx) + jc 1f + mov 8(%rax),%rax + add (%rdx,%rcx,8),%rax +2: pop %rcx + sub %fs:0,%rax + pop %rdx + ret +1: push %rdi + push %rdi + push %rsi + push %r8 + push %r9 + push %r10 + push %r11 + mov %rax,%rdi + call __tls_get_addr + pop %r11 + pop %r10 + pop %r9 + pop %r8 + pop %rsi + pop %rdi + pop %rdi + jmp 2b diff --git a/src/linux/fanotify.c b/src/linux/fanotify.c index 1f4ef93..c6211af 100644 --- a/src/linux/fanotify.c +++ b/src/linux/fanotify.c @@ -9,6 +9,6 @@ int fanotify_init(unsigned flags, unsigned event_f_flags) int fanotify_mark(int fanotify_fd, unsigned flags, unsigned long long mask, int dfd, const char *pathname) { - return syscall(SYS_fanotify_mark, flags, __SYSCALL_LL_O(mask), dfd, pathname); + return syscall(SYS_fanotify_mark, fanotify_fd, flags, __SYSCALL_LL_E(mask), dfd, pathname); } diff --git a/src/network/recvmmsg.c b/src/network/recvmmsg.c new file mode 100644 index 0000000..58b1b2f --- /dev/null +++ b/src/network/recvmmsg.c @@ -0,0 +1,15 @@ +#define _GNU_SOURCE +#include +#include +#include "syscall.h" + +int recvmmsg(int fd, struct mmsghdr *msgvec, unsigned int vlen, unsigned int flags, struct timespec *timeout) +{ +#if LONG_MAX > INT_MAX + struct mmsghdr *mh = msgvec; + unsigned int i; + for (i = vlen; i; i--, mh++) + mh->msg_hdr.__pad1 = mh->msg_hdr.__pad2 = 0; +#endif + return syscall_cp(SYS_recvmmsg, fd, msgvec, vlen, flags, timeout); +} diff --git a/src/network/sendmmsg.c b/src/network/sendmmsg.c new file mode 100644 index 0000000..ff9f861 --- /dev/null +++ b/src/network/sendmmsg.c @@ -0,0 +1,29 @@ +#define _GNU_SOURCE +#include +#include +#include +#include "syscall.h" + +int sendmmsg(int fd, struct mmsghdr *msgvec, unsigned int vlen, unsigned int flags) +{ +#if LONG_MAX > INT_MAX + /* Can't use the syscall directly because the kernel has the wrong + * idea for the types of msg_iovlen, msg_controllen, and cmsg_len, + * and the cmsg blocks cannot be modified in-place. */ + int i; + if (vlen > IOV_MAX) vlen = IOV_MAX; /* This matches the kernel. */ + for (i=0; i +#include "pthread_impl.h" +#include "libc.h" + +void *__tls_get_new(size_t *) ATTR_LIBC_VISIBILITY; + +void *__tls_get_addr(size_t *v) +{ + pthread_t self = __pthread_self(); +#ifdef SHARED + if (v[0]<=(size_t)self->dtv[0]) + return (char *)self->dtv[v[0]]+v[1]; + return __tls_get_new(v); +#else + return (char *)self->dtv[1]+v[1]; +#endif +} diff --git a/src/thread/i386/tls.s b/src/thread/i386/tls.s index e1f2262..6e01adf 100644 --- a/src/thread/i386/tls.s +++ b/src/thread/i386/tls.s @@ -2,7 +2,14 @@ .global ___tls_get_addr .type ___tls_get_addr,@function ___tls_get_addr: - push %eax + mov %gs:4,%edx + mov (%eax),%ecx + cmp %ecx,(%edx) + jc 1f + mov 4(%eax),%eax + add (%edx,%ecx,4),%eax + ret +1: push %eax call __tls_get_addr pop %edx ret