X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ldso%2Fdynlink.c;h=7b47b1635944432159a22f3fb02d27516910cc1c;hb=25e6fee27f4a293728dd15b659170e7b9c7db9bc;hp=502e52c51a852436e6cd57e247b859aba4a4c202;hpb=c1e5d243b7e39b2fbfb17144608ce045575d8e95;p=musl diff --git a/ldso/dynlink.c b/ldso/dynlink.c index 502e52c5..7b47b163 100644 --- a/ldso/dynlink.c +++ b/ldso/dynlink.c @@ -20,10 +20,18 @@ #include #include #include "pthread_impl.h" +#include "fork_impl.h" #include "libc.h" #include "dynlink.h" -static void error(const char *, ...); +#define malloc __libc_malloc +#define calloc __libc_calloc +#define realloc __libc_realloc +#define free __libc_free + +static void error_impl(const char *, ...); +static void error_noop(const char *, ...); +static void (*error)(const char *, ...) = error_noop; #define MAXP2(a,b) (-(-(a)&-(b))) #define ALIGN(x,y) ((x)+(y)-1 & -(y)) @@ -202,7 +210,8 @@ static void decode_vec(size_t *v, size_t *a, size_t cnt) size_t i; for (i=0; i= sizeof buf) goto nomatch; + buf[l] = name[l]; + } + if (!strcmp(name, "readdir64_r")) + return find_sym(&ldso, "readdir_r", 1); + if (l<2 || name[l-2]!='6' || name[l-1]!='4') + goto nomatch; + buf[l-=2] = 0; + for (p=lfs64_list; *p; p++) { + if (!strcmp(buf, p)) return find_sym(&ldso, buf, 1); + while (*p) p++; + } +nomatch: + return (struct symdef){ 0 }; +} + static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stride) { unsigned char *base = dso->base; @@ -381,6 +423,7 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri def = (sym->st_info>>4) == STB_LOCAL ? (struct symdef){ .dso = dso, .sym = sym } : find_sym(ctx, name, type==REL_PLT); + if (!def.sym) def = get_lfs64(name); if (!def.sym && (sym->st_shndx != SHN_UNDEF || sym->st_info>>4 != STB_WEAK)) { if (dso->lazy && (type==REL_PLT || type==REL_GOT)) { @@ -507,6 +550,23 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri } } +static void do_relr_relocs(struct dso *dso, size_t *relr, size_t relr_size) +{ + unsigned char *base = dso->base; + size_t *reloc_addr; + for (; relr_size; relr++, relr_size-=sizeof(size_t)) + if ((relr[0]&1) == 0) { + reloc_addr = laddr(dso, relr[0]); + *reloc_addr++ += (size_t)base; + } else { + int i = 0; + for (size_t bitmap=relr[0]; (bitmap>>=1); i++) + if (bitmap&1) + reloc_addr[i] += (size_t)base; + reloc_addr += 8*sizeof(size_t)-1; + } +} + static void redo_lazy_relocs() { struct dso *p = lazy_head, *next; @@ -573,6 +633,7 @@ static void *mmap_fixed(void *p, size_t n, int prot, int flags, int fd, off_t of { static int no_map_fixed; char *q; + if (!n) return p; if (!no_map_fixed) { q = mmap(p, n, prot, flags|MAP_FIXED, fd, off); if (!DL_NOMMU_SUPPORT || q != MAP_FAILED || errno != EINVAL) @@ -859,7 +920,7 @@ static int fixup_rpath(struct dso *p, char *buf, size_t buf_size) case ENOENT: case ENOTDIR: case EACCES: - break; + return 0; default: return -1; } @@ -1348,13 +1409,17 @@ static void reloc_all(struct dso *p) 2+(dyn[DT_PLTREL]==DT_RELA)); do_relocs(p, laddr(p, dyn[DT_REL]), dyn[DT_RELSZ], 2); do_relocs(p, laddr(p, dyn[DT_RELA]), dyn[DT_RELASZ], 3); - - if (head != &ldso && p->relro_start != p->relro_end && - mprotect(laddr(p, p->relro_start), p->relro_end-p->relro_start, PROT_READ) - && errno != ENOSYS) { - error("Error relocating %s: RELRO protection failed: %m", - p->name); - if (runtime) longjmp(*rtld_fail, 1); + if (!DL_FDPIC) + do_relr_relocs(p, laddr(p, dyn[DT_RELR]), dyn[DT_RELRSZ]); + + if (head != &ldso && p->relro_start != p->relro_end) { + long ret = __syscall(SYS_mprotect, laddr(p, p->relro_start), + p->relro_end-p->relro_start, PROT_READ); + if (ret != 0 && ret != -ENOSYS) { + error("Error relocating %s: RELRO protection failed: %m", + p->name); + if (runtime) longjmp(*rtld_fail, 1); + } } p->relocated = 1; @@ -1421,6 +1486,17 @@ void __libc_exit_fini() } } +void __ldso_atfork(int who) +{ + if (who<0) { + pthread_rwlock_wrlock(&lock); + pthread_mutex_lock(&init_fini_lock); + } else { + pthread_mutex_unlock(&init_fini_lock); + pthread_rwlock_unlock(&lock); + } +} + static struct dso **queue_ctors(struct dso *dso) { size_t cnt, qpos, spos, i; @@ -1479,6 +1555,13 @@ static struct dso **queue_ctors(struct dso *dso) } queue[qpos] = 0; for (i=0; imark = 0; + for (i=0; ictor_visitor && queue[i]->ctor_visitor->tid < 0) { + error("State of %s is inconsistent due to multithreaded fork\n", + queue[i]->name); + free(queue); + if (runtime) longjmp(*rtld_fail, 1); + } return queue; } @@ -1731,6 +1814,9 @@ void __dls3(size_t *sp, size_t *auxv) env_preload = getenv("LD_PRELOAD"); } + /* Activate error handler function */ + error = error_impl; + /* If the main program was already loaded by the kernel, * AT_PHDR will point to some location other than the dynamic * linker's program headers. */ @@ -1806,7 +1892,7 @@ void __dls3(size_t *sp, size_t *auxv) dprintf(2, "%s: cannot load %s: %s\n", ldname, argv[0], strerror(errno)); _exit(1); } - Ehdr *ehdr = (void *)map_library(fd, &app); + Ehdr *ehdr = map_library(fd, &app); if (!ehdr) { dprintf(2, "%s: %s: Not a valid dynamic program\n", ldname, argv[0]); _exit(1); @@ -2306,7 +2392,8 @@ int dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size_t size, void info.dlpi_adds = gencnt; info.dlpi_subs = 0; info.dlpi_tls_modid = current->tls_id; - info.dlpi_tls_data = current->tls.image; + info.dlpi_tls_data = !current->tls_id ? 0 : + __tls_get_addr((tls_mod_off_t[]){current->tls_id,0}); ret = (callback)(&info, sizeof (info), data); @@ -2319,7 +2406,7 @@ int dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size_t size, void return ret; } -static void error(const char *fmt, ...) +static void error_impl(const char *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -2333,3 +2420,7 @@ static void error(const char *fmt, ...) __dl_vseterr(fmt, ap); va_end(ap); } + +static void error_noop(const char *fmt, ...) +{ +}