---
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