|
Message-Id: <1585441168-23444-4-git-send-email-rcombs@rcombs.me> Date: Sat, 28 Mar 2020 19:19:28 -0500 From: rcombs <rcombs@...mbs.me> To: musl@...ts.openwall.com Subject: [PATCH 4/4] crt: add dcrt1, with support for locating the dynamic loader at runtime --- Makefile | 10 +- crt/dcrt1.c | 372 ++++++++++++++++++++++++++++++++++++++++++++++++ ldso/dlstart.c | 59 +++++--- ldso/dynlink.c | 13 ++ ldso/map_library.h | 59 ++++---- tools/ld.musl-clang.in | 17 ++- tools/musl-clang.in | 8 ++ tools/musl-gcc.specs.sh | 4 +- 8 files changed, 490 insertions(+), 52 deletions(-) create mode 100644 crt/dcrt1.c diff --git a/Makefile b/Makefile index bd8f5c3..348ffd0 100644 --- a/Makefile +++ b/Makefile @@ -106,13 +106,15 @@ obj/src/internal/version.h: $(wildcard $(srcdir)/VERSION $(srcdir)/.git) obj/src/internal/version.o obj/src/internal/version.lo: obj/src/internal/version.h -obj/crt/rcrt1.o obj/ldso/dlstart.lo obj/ldso/dynlink.lo: $(srcdir)/src/internal/dynlink.h $(srcdir)/arch/$(ARCH)/reloc.h +obj/crt/rcrt1.o obj/crt/dcrt1.o obj/ldso/dlstart.lo obj/ldso/dynlink.lo: $(srcdir)/src/internal/dynlink.h $(srcdir)/arch/$(ARCH)/reloc.h -obj/crt/crt1.o obj/crt/scrt1.o obj/crt/rcrt1.o obj/ldso/dlstart.lo: $(srcdir)/arch/$(ARCH)/crt_arch.h +obj/crt/crt1.o obj/crt/scrt1.o obj/crt/rcrt1.o obj/crt/dcrt1.o obj/ldso/dlstart.lo: $(srcdir)/arch/$(ARCH)/crt_arch.h -obj/crt/rcrt1.o: $(srcdir)/ldso/dlstart.c +obj/crt/rcrt1.o obj/crt/dcrt1.o: $(srcdir)/ldso/dlstart.c -obj/crt/Scrt1.o obj/crt/rcrt1.o: CFLAGS_ALL += -fPIC +obj/crt/Scrt1.o obj/crt/rcrt1.o obj/crt/dcrt1.o: CFLAGS_ALL += -fPIC + +obj/crt/dcrt1.o: CFLAGS_ALL += -DLDSO_PATHNAME=\"$(LDSO_PATHNAME)\" OPTIMIZE_SRCS = $(wildcard $(OPTIMIZE_GLOBS:%=$(srcdir)/src/%)) $(OPTIMIZE_SRCS:$(srcdir)/%.c=obj/%.o) $(OPTIMIZE_SRCS:$(srcdir)/%.c=obj/%.lo): CFLAGS += -O3 diff --git a/crt/dcrt1.c b/crt/dcrt1.c new file mode 100644 index 0000000..d58a606 --- /dev/null +++ b/crt/dcrt1.c @@ -0,0 +1,372 @@ +#define SYSCALL_NO_TLS 1 + +#include <elf.h> +#include <errno.h> +#include <fcntl.h> +#include <features.h> +#include <libgen.h> +#include <sys/mman.h> +#include <string.h> +#include <unistd.h> +#include "atomic.h" +#include "dynlink.h" +#include "syscall.h" + +extern weak hidden const size_t _DYNAMIC[]; + +int main(); +weak void _init(); +weak void _fini(); +weak _Noreturn int __libc_start_main(int (*)(), int, char **, + void (*)(), void(*)(), void(*)()); + +#define START "_start" +#define _dlstart_c _start_c +#define DL_DNI +#include "../ldso/dlstart.c" + +struct dso { + unsigned char *base; + struct fdpic_loadmap *loadmap; + size_t *dynv; + Phdr *phdr; + int phnum; + size_t phentsize; + unsigned char *map; + size_t map_len; +}; + +#ifndef PAGESIZE +#ifdef PAGE_SIZE +#undef PAGE_SIZE // We don't want to use libc.page_size here +#endif +static size_t page_size; +#define PAGE_SIZE page_size +#endif + +#ifdef SYS_mmap2 +#define mmap(start, len, prot, flags, fd, off) (void*)__syscall(SYS_mmap2, start, len, prot, flags, fd, off/SYSCALL_MMAP2_UNIT) +#else +#define mmap(start, len, prot, flags, fd, off) (void*)__syscall(SYS_mmap, start, len, prot, flags, fd, off) +#endif + +#define munmap(ptr, len) __syscall(SYS_munmap, ptr, len) + +static inline int crt_mprotect(void *addr, size_t len, int prot) +{ + size_t start, end; + start = (size_t)addr & -PAGE_SIZE; + end = (size_t)((char *)addr + len + PAGE_SIZE-1) & -PAGE_SIZE; + return __syscall(SYS_mprotect, start, end-start, prot); +} +#define mprotect crt_mprotect + +#define read(fd, buf, size) __syscall(SYS_read, fd, buf, size) +#define pread(fd, buf, size, ofs) __syscall(SYS_pread, fd, buf, size, __SYSCALL_LL_PRW(ofs)) + +static inline off_t crt_lseek(int fd, off_t offset, int whence) +{ +#ifdef SYS__llseek + off_t result; + return __syscall(SYS__llseek, fd, offset>>32, offset, &result, whence) ? -1 : result; +#else + return __syscall(SYS_lseek, fd, offset, whence); +#endif +} +#define lseek crt_lseek + +static inline void *map_library_allocz(size_t *size) +{ + void *ret; + *size = (*size + SYSCALL_MMAP2_UNIT - 1) & -SYSCALL_MMAP2_UNIT; + ret = mmap(0, *size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (ret == MAP_FAILED) + return NULL; + return ret; +} + +static inline void map_library_free(void *ptr, size_t size) +{ + if (ptr) + munmap(ptr, size); +} + +#define map_library_failed(val) ((unsigned long)val > -4096UL) +#define map_library_error(ret) (-(long)ret) + +#ifdef SYS_readlink +#define readlink(path, buf, bufsize) __syscall(SYS_readlink, path, buf, bufsize) +#else +#define readlink(path, buf, bufsize) __syscall(SYS_readlinkat, AT_FDCWD, path, buf, bufsize) +#endif + +#ifdef SYS_access +#define access(filename, amode) __syscall(SYS_access, filename, amode) +#else +#define access(filename, amode) __syscall(SYS_faccessat, AT_FDCWD, filename, amode, 0) +#endif + +static void *crt_memcpy(void *restrict dest, const void *restrict src, size_t n) +{ + unsigned char *d = dest; + const unsigned char *s = src; + for (; n; n--) *d++ = *s++; + return dest; +} + +static void *crt_memset(void *dest, int c, size_t n) +{ + unsigned char *s = dest; + for (; n; n--, s++) *s = c; + return dest; +} +#define memset crt_memset + +static size_t crt_strlen(const char *s) +{ + const char *a = s; + for (; *s; s++); + return s-a; +} + +static char *crt_strchrnul(const char *s, int c) +{ + c = (unsigned char)c; + if (!c) return (char *)s + crt_strlen(s); + for (; *s && *(unsigned char *)s != c; s++); + return (char *)s; +} + +static int crt_strncmp(const char *_l, const char *_r, size_t n) +{ + const unsigned char *l=(void *)_l, *r=(void *)_r; + if (!n--) return 0; + for (; *l && *r && n && *l == *r ; l++, r++, n--); + return *l - *r; +} + +static char *crt_getenv(const char *name, char **environ) +{ + size_t l = crt_strchrnul(name, '=') - name; + if (l && !name[l] && environ) + for (char **e = environ; *e; e++) + if (!crt_strncmp(name, *e, l) && l[*e] == '=') + return *e + l+1; + return 0; +} + +#define LD_CRT +#include "../ldso/map_library.h" + +static void decode_vec(const size_t *v, size_t *a, size_t cnt) +{ + size_t i; + for (i=0; i<cnt; i++) a[i] = 0; + for (; v[0]; v+=2) if (v[0]-1<cnt-1) { + a[0] |= 1UL<<v[0]; + a[v[0]] = v[1]; + } +} + +static void get_rpath(const char **runpath, const size_t *dyn, unsigned char *base) +{ + /* DT_STRTAB is pre-relocated for us by dlstart */ + const char *strings = (char*)base + dyn[DT_STRTAB]; + + *runpath = NULL; + + if (dyn[0] & (1 << DT_RPATH)) + *runpath = strings + dyn[DT_RPATH]; + if (dyn[0] & (1 << DT_RUNPATH)) + *runpath = strings + dyn[DT_RUNPATH]; +} + +static size_t find_linker(char *outbuf, size_t bufsize, const char *this_path, size_t thisl, const size_t *dyn, unsigned char *base, char **environ, int secure) +{ + const char *paths[2]; // envpath, rpath/runpath + size_t i; + int fd; + + // In the suid/secure case, skip everything and use the fixed path + if (secure) + goto default_path; + + // Strip filename + if (thisl) + thisl--; + while (thisl > 1 && this_path[thisl] == '/') + thisl--; + while (thisl > 0 && this_path[thisl] != '/') + thisl--; + + const char *envpath = crt_getenv("LD_LOADER_PATH", environ); + if (envpath) { + size_t envlen = crt_strlen(envpath); + if (envlen < bufsize) { + crt_memcpy(outbuf, envpath, envlen + 1); + return envlen + 1; + } + } + + get_rpath(&paths[1], dyn, base); + + paths[0] = crt_getenv("LD_LIBRARY_PATH", environ); + + for (i = 0; i < 2; i++) { + const char *p = paths[i]; + char *o = outbuf; + if (!p) + continue; + for (;;) { + if (!crt_strncmp(p, "$ORIGIN", 7) || + !crt_strncmp(p, "${ORIGIN}", 9)) { + if (o + thisl + 1 < outbuf + bufsize) { + crt_memcpy(o, this_path, thisl); + o += thisl; + } else { + o = outbuf + bufsize - 1; + } + p += (p[1] == '{' ? 9 : 7); + } else if (*p == ':' || !*p) { +#define LDSO_FILENAME "ld-musl-" LDSO_ARCH ".so.1" + if (o + sizeof(LDSO_FILENAME) + 1 < outbuf + bufsize) { + *o++ = '/'; + crt_memcpy(o, LDSO_FILENAME, sizeof(LDSO_FILENAME)); + if (!access(outbuf, R_OK | X_OK)) + return (o + sizeof(LDSO_FILENAME)) - outbuf; + } + if (!*p) + break; + o = outbuf; + p++; + } else { + if (o < outbuf + bufsize) + *o++ = *p; + p++; + } + } + } + + default_path: + // Didn't find a usable loader anywhere (or in secure mode), so try the default + crt_memcpy(outbuf, LDSO_PATHNAME, sizeof(LDSO_PATHNAME)); + return sizeof(LDSO_PATHNAME); +} + +hidden _Noreturn void __dls2(unsigned char *base, size_t *p) +{ + int argc = p[0]; + char **argv = (void *)(p+1); + int fd; + int secure; + int prot = PROT_READ; + struct dso loader; + Ehdr *loader_hdr; + Phdr *new_hdr; + void *entry; + char this_path[PATH_MAX]; + size_t thisl; + char linker_path[PATH_MAX]; + size_t linker_len; + size_t i; + size_t aux[AUX_CNT]; + size_t *auxv; + size_t dyn[DYN_CNT]; + char **environ = argv + argc + 1; + + // We're already finished here; just run main. + if (__libc_start_main) + __libc_start_main(main, argc, argv, _init, _fini, 0); + + /* Find aux vector just past environ[] and use it to initialize + * global data that may be needed before we can make syscalls. */ + for (i = argc + 1; argv[i]; i++); + auxv = (void *)(argv + i + 1); + decode_vec(auxv, aux, AUX_CNT); + secure = ((aux[0] & 0x7800) != 0x7800 || aux[AT_UID] != aux[AT_EUID] + || aux[AT_GID] != aux[AT_EGID] || aux[AT_SECURE]); + +#ifndef PAGESIZE + page_size = aux[AT_PAGESZ]; +#endif + + decode_vec(_DYNAMIC, dyn, DYN_CNT); + + thisl = readlink("/proc/self/exe", this_path, sizeof this_path); + linker_len = find_linker(linker_path, sizeof linker_path, this_path, thisl, dyn, base, environ, secure); + + fd = __sys_open2(, linker_path, O_RDONLY); + if (fd < 0) + goto error; + + loader_hdr = map_library(fd, &loader); + if (!loader_hdr) + goto error; + + __syscall(SYS_close, fd); + + // Copy the program headers into an anonymous mapping + new_hdr = mmap(0, (aux[AT_PHENT] * (aux[AT_PHNUM] + 2) + linker_len + PAGE_SIZE - 1) & -PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (map_library_failed(new_hdr)) + goto error; + + // Point it back at the original kernel-provided base + new_hdr->p_type = PT_PHDR; + new_hdr->p_vaddr = (size_t)new_hdr - (size_t)base; + + ((Phdr*)((char*)new_hdr + aux[AT_PHENT]))->p_type = PT_INTERP; + ((Phdr*)((char*)new_hdr + aux[AT_PHENT]))->p_vaddr = new_hdr->p_vaddr + aux[AT_PHENT] * (aux[AT_PHNUM] + 2); + + crt_memcpy((char*)new_hdr + aux[AT_PHENT] * (aux[AT_PHNUM] + 2), linker_path, linker_len); + + for (i = 0; i < aux[AT_PHNUM]; i++) { + Phdr *hdr = (void*)((char*)aux[AT_PHDR] + aux[AT_PHENT] * i); + Phdr *dst = (void*)((char*)new_hdr + aux[AT_PHENT] * (i + 2)); + if (hdr->p_type == PT_PHDR || hdr->p_type == PT_INTERP) { + // Can't have a duplicate + dst->p_type = PT_NULL; + } else { + crt_memcpy(dst, hdr, aux[AT_PHENT]); + } + } + + if (mprotect(new_hdr, aux[AT_PHENT] * (aux[AT_PHNUM] + 2) + linker_len, PROT_READ)) + goto error; + + for (i=0; auxv[i]; i+=2) { + if (auxv[i] == AT_BASE) + auxv[i + 1] = (size_t)loader_hdr; + if (auxv[i] == AT_PHDR) + auxv[i + 1] = (size_t)new_hdr; + if (auxv[i] == AT_PHNUM) + auxv[i + 1] += 2; + } + + entry = laddr(&loader, loader_hdr->e_entry); + +#ifndef LD_FDPIC + /* Undo the relocations performed by dlstart */ + + if (NEED_MIPS_GOT_RELOCS) { + const size_t *dynv = _DYNAMIC; + size_t local_cnt = 0; + size_t *got = (void *)(base + dyn[DT_PLTGOT]); + for (i=0; dynv[i]; i+=2) if (dynv[i]==DT_MIPS_LOCAL_GOTNO) + local_cnt = dynv[i+1]; + for (i=0; i<local_cnt; i++) got[i] -= (size_t)base; + } + + size_t *rel = (void *)((size_t)base+dyn[DT_REL]); + size_t rel_size = dyn[DT_RELSZ]; + for (; rel_size; rel+=2, rel_size-=2*sizeof(size_t)) { + if (!IS_RELATIVE(rel[1], 0)) continue; + size_t *rel_addr = (void *)((size_t)base + rel[0]); + *rel_addr -= (size_t)base; + } +#endif + + CRTJMP(entry, argv - 1); + +error: + for(;;) a_crash(); +} diff --git a/ldso/dlstart.c b/ldso/dlstart.c index 20d50f2..49e6a99 100644 --- a/ldso/dlstart.c +++ b/ldso/dlstart.c @@ -21,7 +21,7 @@ hidden void _dlstart_c(size_t *sp, size_t *dynv) { size_t i, aux[AUX_CNT], dyn[DYN_CNT]; - size_t *rel, rel_size, base; + size_t *rel, rel_size, base, loader_phdr; int argc = *sp; char **argv = (void *)(sp+1); @@ -41,6 +41,13 @@ hidden void _dlstart_c(size_t *sp, size_t *dynv) * space and moving the extra fdpic arguments to the stack * vector where they are easily accessible from C. */ segs = ((struct fdpic_loadmap *)(sp[-1] ? sp[-1] : sp[-2]))->segs; + if (aux[AT_BASE]) { + Ehdr *eh = (void*)aux[AT_BASE]; + for (i = 0; eh->e_phoff - segs[i].p_vaddr >= segs[i].p_memsz; i++); + loader_phdr = (eh->e_phoff - segs[i].p_vaddr + segs[i].addr); + } else { + loader_phdr = aux[AT_PHDR]; + } } else { /* If dynv is null, the entry point was started from loader * that is not fdpic-aware. We can assume normal fixed- @@ -55,6 +62,7 @@ hidden void _dlstart_c(size_t *sp, size_t *dynv) segs[0].p_memsz = -1; Ehdr *eh = (void *)base; Phdr *ph = (void *)(base + eh->e_phoff); + loader_phdr = (size_t)ph; size_t phnum = eh->e_phnum; size_t phent = eh->e_phentsize; while (phnum-- && ph->p_type != PT_DYNAMIC) @@ -69,13 +77,42 @@ hidden void _dlstart_c(size_t *sp, size_t *dynv) #if DL_FDPIC for (i=0; i<DYN_CNT; i++) { - if (i==DT_RELASZ || i==DT_RELSZ) continue; + if (i==DT_RELASZ || i==DT_RELSZ || i==DT_RPATH || i==DT_RUNPATH) continue; if (!dyn[i]) continue; for (j=0; dyn[i]-segs[j].p_vaddr >= segs[j].p_memsz; j++); dyn[i] += segs[j].addr - segs[j].p_vaddr; } base = 0; +#else + /* If the dynamic linker is invoked as a command, its load + * address is not available in the aux vector. Instead, compute + * the load address as the difference between &_DYNAMIC and the + * virtual address in the PT_DYNAMIC program header. */ + base = aux[AT_BASE]; + if (!base) { + size_t phnum = aux[AT_PHNUM]; + size_t phentsize = aux[AT_PHENT]; + Phdr *ph = (void *)aux[AT_PHDR]; + for (i=phnum; i--; ph = (void *)((char *)ph + phentsize)) { + if (ph->p_type == PT_DYNAMIC) { + base = (size_t)dynv - ph->p_vaddr; + break; + } + } + } + loader_phdr = base + ((Ehdr*)base)->e_phoff; +#endif +#ifdef DL_DNI + /* If AT_PHDR doesn't match the PHDR in AT_BASE, then we've been loaded as a + * dynamic executable and ld.so has already been run, either by the kernel, + * or by dcrt. This means relocs are already finished (and doing them again + * would break DT_RELs), so we can just skip to the stage-2 jump. */ + if (aux[AT_PHDR] != loader_phdr) + goto skip_relocs; +#endif + +#if DL_FDPIC const Sym *syms = (void *)dyn[DT_SYMTAB]; rel = (void *)dyn[DT_RELA]; @@ -97,23 +134,6 @@ hidden void _dlstart_c(size_t *sp, size_t *dynv) } } #else - /* If the dynamic linker is invoked as a command, its load - * address is not available in the aux vector. Instead, compute - * the load address as the difference between &_DYNAMIC and the - * virtual address in the PT_DYNAMIC program header. */ - base = aux[AT_BASE]; - if (!base) { - size_t phnum = aux[AT_PHNUM]; - size_t phentsize = aux[AT_PHENT]; - Phdr *ph = (void *)aux[AT_PHDR]; - for (i=phnum; i--; ph = (void *)((char *)ph + phentsize)) { - if (ph->p_type == PT_DYNAMIC) { - base = (size_t)dynv - ph->p_vaddr; - break; - } - } - } - /* MIPS uses an ugly packed form for GOT relocations. Since we * can't make function calls yet and the code is tiny anyway, * it's simply inlined here. */ @@ -143,6 +163,7 @@ hidden void _dlstart_c(size_t *sp, size_t *dynv) #endif stage2_func dls2; +skip_relocs: GETFUNCSYM(&dls2, __dls2, base+dyn[DT_PLTGOT]); dls2((void *)base, sp); } diff --git a/ldso/dynlink.c b/ldso/dynlink.c index 0e557b1..329a9e7 100644 --- a/ldso/dynlink.c +++ b/ldso/dynlink.c @@ -154,6 +154,19 @@ extern hidden void (*const __init_array_end)(void), (*const __fini_array_end)(vo weak_alias(__init_array_start, __init_array_end); weak_alias(__fini_array_start, __fini_array_end); +static inline void *map_library_allocz(size_t *size) +{ + return calloc(1, *size); +} + +static inline void map_library_free(void *ptr, size_t size) +{ + return free(ptr); +} + +#define map_library_failed(ptr) (ptr == MAP_FAILED) +#define map_library_error(val) (errno) + #include "map_library.h" static int dl_strcmp(const char *l, const char *r) diff --git a/ldso/map_library.h b/ldso/map_library.h index d685471..2b3faee 100644 --- a/ldso/map_library.h +++ b/ldso/map_library.h @@ -1,11 +1,3 @@ -#include <errno.h> -#include <features.h> -#include <string.h> -#include <sys/mman.h> -#include <unistd.h> -#include "dynlink.h" -#include "pthread_impl.h" - /* Compute load address for a virtual address in a given dso. */ #if DL_FDPIC static inline void *laddr(const struct dso *p, size_t v) @@ -50,7 +42,7 @@ static void *mmap_fixed(void *p, size_t n, int prot, int flags, int fd, off_t of char *q; if (!no_map_fixed) { q = mmap(p, n, prot, flags|MAP_FIXED, fd, off); - if (!DL_NOMMU_SUPPORT || q != MAP_FAILED || errno != EINVAL) + if (!DL_NOMMU_SUPPORT || !map_library_failed(q) || map_library_error(q) != EINVAL) return q; no_map_fixed = 1; } @@ -63,7 +55,7 @@ static void *mmap_fixed(void *p, size_t n, int prot, int flags, int fd, off_t of if (lseek(fd, off, SEEK_SET) < 0) return MAP_FAILED; for (q=p; n; q+=r, off+=r, n-=r) { r = read(fd, q, n); - if (r < 0 && errno != EINTR) return MAP_FAILED; + if (r < 0 && map_library_error(r) != EINTR) return MAP_FAILED; if (!r) { memset(q, 0, n); break; @@ -72,6 +64,11 @@ static void *mmap_fixed(void *p, size_t n, int prot, int flags, int fd, off_t of return p; } +static inline int map_library_error_check(int ret, int expected) +{ + return ret && map_library_error(ret) != expected; +} + static inline void unmap_library(struct dso *dso) { if (dso->loadmap) { @@ -82,7 +79,7 @@ static inline void unmap_library(struct dso *dso) munmap((void *)dso->loadmap->segs[i].addr, dso->loadmap->segs[i].p_memsz); } - free(dso->loadmap); + map_library_free(dso->loadmap, dso->map_len); } else if (dso->map && dso->map_len) { munmap(dso->map, dso->map_len); } @@ -92,8 +89,8 @@ static inline void *map_library(int fd, struct dso *dso) { Ehdr buf[(896+sizeof(Ehdr))/sizeof(Ehdr)]; void *allocated_buf=0; + size_t allocated_buf_size; size_t phsize; - size_t ph_allocated_size; size_t addr_min=SIZE_MAX, addr_max=0, map_len; size_t this_min, this_max; size_t nsegs = 0; @@ -104,7 +101,9 @@ static inline void *map_library(int fd, struct dso *dso) unsigned char *map=MAP_FAILED, *base; size_t dyn=0; size_t i; +#ifndef LD_CRT size_t tls_image=0; +#endif ssize_t l = read(fd, buf, sizeof buf); eh = buf; @@ -113,7 +112,8 @@ static inline void *map_library(int fd, struct dso *dso) goto noexec; phsize = eh->e_phentsize * eh->e_phnum; if (phsize > sizeof buf - sizeof *eh) { - allocated_buf = malloc(phsize); + allocated_buf_size = phsize; + allocated_buf = map_library_allocz(&allocated_buf_size); if (!allocated_buf) return 0; l = pread(fd, allocated_buf, phsize, eh->e_phoff); if (l < 0) goto error; @@ -130,6 +130,7 @@ static inline void *map_library(int fd, struct dso *dso) for (i=eh->e_phnum; i; i--, ph=(void *)((char *)ph+eh->e_phentsize)) { if (ph->p_type == PT_DYNAMIC) { dyn = ph->p_vaddr; +#ifndef LD_CRT } else if (ph->p_type == PT_TLS) { tls_image = ph->p_vaddr; dso->tls.align = ph->p_align; @@ -144,6 +145,7 @@ static inline void *map_library(int fd, struct dso *dso) ph->p_memsz < DEFAULT_STACK_MAX ? ph->p_memsz : DEFAULT_STACK_MAX; } +#endif } if (ph->p_type != PT_LOAD) continue; nsegs++; @@ -160,8 +162,8 @@ static inline void *map_library(int fd, struct dso *dso) } if (!dyn) goto noexec; if (DL_FDPIC && !(eh->e_flags & FDPIC_CONSTDISP_FLAG)) { - dso->loadmap = calloc(1, sizeof *dso->loadmap - + nsegs * sizeof *dso->loadmap->segs); + dso->map_len = sizeof *dso->loadmap + nsegs * sizeof *dso->loadmap->segs; + dso->loadmap = map_library_allocz(&dso->map_len); if (!dso->loadmap) goto error; dso->loadmap->nsegs = nsegs; for (ph=ph0, i=0; i<nsegs; ph=(void *)((char *)ph+eh->e_phentsize)) { @@ -172,7 +174,7 @@ static inline void *map_library(int fd, struct dso *dso) map = mmap(0, ph->p_memsz + (ph->p_vaddr & PAGE_SIZE-1), prot, MAP_PRIVATE, fd, ph->p_offset & -PAGE_SIZE); - if (map == MAP_FAILED) { + if (map_library_failed(map)) { unmap_library(dso); goto error; } @@ -187,10 +189,10 @@ static inline void *map_library(int fd, struct dso *dso) size_t pgbrk = brk + PAGE_SIZE-1 & -PAGE_SIZE; size_t pgend = brk + ph->p_memsz - ph->p_filesz + PAGE_SIZE-1 & -PAGE_SIZE; - if (pgend > pgbrk && mmap_fixed(map+pgbrk, + if (pgend > pgbrk && !map_library_failed(mmap_fixed(map+pgbrk, pgend-pgbrk, prot, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, - -1, off_start) == MAP_FAILED) + -1, off_start))) goto error; memset(map + brk, 0, pgbrk-brk); } @@ -213,13 +215,15 @@ static inline void *map_library(int fd, struct dso *dso) MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) : mmap((void *)addr_min, map_len, prot, MAP_PRIVATE, fd, off_start); - if (map==MAP_FAILED) goto error; + if (map_library_failed(map)) goto error; dso->map = map; dso->map_len = map_len; /* If the loaded file is not relocatable and the requested address is * not available, then the load operation must fail. */ if (eh->e_type != ET_DYN && addr_min && map!=(void *)addr_min) { +#ifndef LD_CRT errno = EBUSY; +#endif goto error; } base = map - addr_min; @@ -244,33 +248,36 @@ static inline void *map_library(int fd, struct dso *dso) ((ph->p_flags&PF_X) ? PROT_EXEC : 0)); /* Reuse the existing mapping for the lowest-address LOAD */ if ((ph->p_vaddr & -PAGE_SIZE) != addr_min || DL_NOMMU_SUPPORT) - if (mmap_fixed(base+this_min, this_max-this_min, prot, MAP_PRIVATE|MAP_FIXED, fd, off_start) == MAP_FAILED) + if (map_library_failed(mmap_fixed(base+this_min, this_max-this_min, prot, MAP_PRIVATE|MAP_FIXED, fd, off_start))) goto error; if (ph->p_memsz > ph->p_filesz && (ph->p_flags&PF_W)) { size_t brk = (size_t)base+ph->p_vaddr+ph->p_filesz; size_t pgbrk = brk+PAGE_SIZE-1 & -PAGE_SIZE; memset((void *)brk, 0, pgbrk-brk & PAGE_SIZE-1); - if (pgbrk-(size_t)base < this_max && mmap_fixed((void *)pgbrk, (size_t)base+this_max-pgbrk, prot, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) == MAP_FAILED) + if (pgbrk-(size_t)base < this_max && map_library_failed(mmap_fixed((void *)pgbrk, (size_t)base+this_max-pgbrk, prot, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0))) goto error; } } for (i=0; ((size_t *)(base+dyn))[i]; i+=2) if (((size_t *)(base+dyn))[i]==DT_TEXTREL) { - if (mprotect(map, map_len, PROT_READ|PROT_WRITE|PROT_EXEC) - && errno != ENOSYS) + if (map_library_error_check(mprotect(map, map_len, PROT_READ|PROT_WRITE|PROT_EXEC), ENOSYS)) goto error; break; } done_mapping: dso->base = base; dso->dynv = laddr(dso, dyn); +#ifndef LD_CRT if (dso->tls.size) dso->tls.image = laddr(dso, tls_image); - free(allocated_buf); +#endif + map_library_free(allocated_buf, allocated_buf_size); return map; noexec: +#ifndef LD_CRT errno = ENOEXEC; +#endif error: - if (map!=MAP_FAILED) unmap_library(dso); - free(allocated_buf); + if (!map_library_failed(map)) unmap_library(dso); + map_library_free(allocated_buf, allocated_buf_size); return 0; } diff --git a/tools/ld.musl-clang.in b/tools/ld.musl-clang.in index 93763d6..02d9893 100644 --- a/tools/ld.musl-clang.in +++ b/tools/ld.musl-clang.in @@ -7,6 +7,18 @@ shared= userlinkdir= userlink= +Scrt="$libc_lib/Scrt1.o" +dynamic_linker_args="-dynamic-linker \"$ldso\"" + +for x ; do + case "$x" in + -l-dni) + dynamic_linker_args="-no-dynamic-linker" + Scrt="$libc_lib/dcrt1.o" + ;; + esac +done + for x ; do test "$cleared" || set -- ; cleared=1 @@ -42,10 +54,13 @@ for x ; do ;; -sysroot=*|--sysroot=*) ;; + $libc_lib/Scrt1.o) + set -- "$@" $Scrt + ;; *) set -- "$@" "$x" ;; esac done -exec $($cc -print-prog-name=ld) -nostdlib "$@" -lc -dynamic-linker "$ldso" +exec $($cc -print-prog-name=ld) -nostdlib "$@" -lc "$dynamic_linker_args" diff --git a/tools/musl-clang.in b/tools/musl-clang.in index 623de6f..49cba1b 100644 --- a/tools/musl-clang.in +++ b/tools/musl-clang.in @@ -5,14 +5,21 @@ libc_inc="@INCDIR@" libc_lib="@LIBDIR@" thisdir="`cd "$(dirname "$0")"; pwd`" +cleared= + # prevent clang from running the linker (and erroring) on no input. sflags= eflags= +dniflags= for x ; do + test "$cleared" || set -- ; cleared=1 + case "$x" in + --dni) dniflags=-l-dni; continue ;; -l*) input=1 ;; *) input= ;; esac + set -- "$@" "$x" if test "$input" ; then sflags="-l-user-start" eflags="-l-user-end" @@ -29,6 +36,7 @@ exec $cc \ -isystem "$libc_inc" \ -L-user-start \ $sflags \ + $dniflags \ "$@" \ $eflags \ -L"$libc_lib" \ diff --git a/tools/musl-gcc.specs.sh b/tools/musl-gcc.specs.sh index 3049257..86374f1 100644 --- a/tools/musl-gcc.specs.sh +++ b/tools/musl-gcc.specs.sh @@ -17,13 +17,13 @@ cat <<EOF libgcc.a%s %:if-exists(libgcc_eh.a%s) *startfile: -%{!shared: $libdir/Scrt1.o} $libdir/crti.o crtbeginS.o%s +%{!shared: %{-dni:$libdir/dcrt1.o;:$libdir/Scrt1.o}} $libdir/crti.o crtbeginS.o%s *endfile: crtendS.o%s $libdir/crtn.o *link: --dynamic-linker $ldso -nostdlib %{shared:-shared} %{static:-static} %{rdynamic:-export-dynamic} +%{-dni:-no-dynamic-linker;:--dynamic-linker $ldso} -nostdlib %{shared:-shared} %{static:-static} %{rdynamic:-export-dynamic} *esp_link: -- 2.7.4
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.