summaryrefslogtreecommitdiff
path: root/ldso
diff options
context:
space:
mode:
Diffstat (limited to 'ldso')
-rw-r--r--ldso/dlstart.c15
-rw-r--r--ldso/dynlink.c123
2 files changed, 117 insertions, 21 deletions
diff --git a/ldso/dlstart.c b/ldso/dlstart.c
index 20d50f2c..259f5e18 100644
--- a/ldso/dlstart.c
+++ b/ldso/dlstart.c
@@ -140,6 +140,21 @@ hidden void _dlstart_c(size_t *sp, size_t *dynv)
size_t *rel_addr = (void *)(base + rel[0]);
*rel_addr = base + rel[2];
}
+
+ rel = (void *)(base+dyn[DT_RELR]);
+ rel_size = dyn[DT_RELRSZ];
+ size_t *relr_addr = 0;
+ for (; rel_size; rel++, rel_size-=sizeof(size_t)) {
+ if ((rel[0]&1) == 0) {
+ relr_addr = (void *)(base + rel[0]);
+ *relr_addr++ += base;
+ } else {
+ for (size_t i=0, bitmap=rel[0]; bitmap>>=1; i++)
+ if (bitmap&1)
+ relr_addr[i] += base;
+ relr_addr += 8*sizeof(size_t)-1;
+ }
+ }
#endif
stage2_func dls2;
diff --git a/ldso/dynlink.c b/ldso/dynlink.c
index b66ad537..324aa859 100644
--- a/ldso/dynlink.c
+++ b/ldso/dynlink.c
@@ -21,15 +21,23 @@
#include <sys/membarrier.h>
#include "pthread_impl.h"
#include "fork_impl.h"
-#include "libc.h"
#include "dynlink.h"
+static size_t ldso_page_size;
+#ifndef PAGE_SIZE
+#define PAGE_SIZE ldso_page_size
+#endif
+
+#include "libc.h"
+
#define malloc __libc_malloc
#define calloc __libc_calloc
#define realloc __libc_realloc
#define free __libc_free
-static void error(const char *, ...);
+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))
@@ -149,6 +157,8 @@ static struct fdpic_dummy_loadmap app_dummy_loadmap;
struct debug *_dl_debug_addr = &debug;
+extern weak hidden char __ehdr_start[];
+
extern hidden int __malloc_replaced;
hidden void (*const __init_array_start)(void)=0, (*const __fini_array_start)(void)=0;
@@ -208,7 +218,8 @@ static void decode_vec(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];
+ if (v[0] < 8*sizeof(long))
+ a[0] |= 1UL<<v[0];
a[v[0]] = v[1];
}
}
@@ -334,6 +345,40 @@ static struct symdef find_sym(struct dso *dso, const char *s, int need_def)
return find_sym2(dso, s, need_def, 0);
}
+static struct symdef get_lfs64(const char *name)
+{
+ const char *p;
+ static const char lfs64_list[] =
+ "aio_cancel\0aio_error\0aio_fsync\0aio_read\0aio_return\0"
+ "aio_suspend\0aio_write\0alphasort\0creat\0fallocate\0"
+ "fgetpos\0fopen\0freopen\0fseeko\0fsetpos\0fstat\0"
+ "fstatat\0fstatfs\0fstatvfs\0ftello\0ftruncate\0ftw\0"
+ "getdents\0getrlimit\0glob\0globfree\0lio_listio\0"
+ "lockf\0lseek\0lstat\0mkostemp\0mkostemps\0mkstemp\0"
+ "mkstemps\0mmap\0nftw\0open\0openat\0posix_fadvise\0"
+ "posix_fallocate\0pread\0preadv\0prlimit\0pwrite\0"
+ "pwritev\0readdir\0scandir\0sendfile\0setrlimit\0"
+ "stat\0statfs\0statvfs\0tmpfile\0truncate\0versionsort\0"
+ "__fxstat\0__fxstatat\0__lxstat\0__xstat\0";
+ size_t l;
+ char buf[16];
+ for (l=0; name[l]; l++) {
+ if (l >= 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;
@@ -387,6 +432,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)) {
@@ -471,7 +517,7 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri
break;
#endif
case REL_TLSDESC:
- if (stride<3) addend = reloc_addr[1];
+ if (stride<3) addend = reloc_addr[!TLSDESC_BACKWARDS];
if (def.dso->tls_id > static_tls_cnt) {
struct td_index *new = malloc(sizeof *new);
if (!new) {
@@ -496,13 +542,13 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri
+ addend;
#endif
}
-#ifdef TLSDESC_BACKWARDS
/* Some archs (32-bit ARM at least) invert the order of
* the descriptor members. Fix them up here. */
- size_t tmp = reloc_addr[0];
- reloc_addr[0] = reloc_addr[1];
- reloc_addr[1] = tmp;
-#endif
+ if (TLSDESC_BACKWARDS) {
+ size_t tmp = reloc_addr[0];
+ reloc_addr[0] = reloc_addr[1];
+ reloc_addr[1] = tmp;
+ }
break;
default:
error("Error relocating %s: unsupported relocation type %d",
@@ -513,6 +559,24 @@ 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)
+{
+ if (dso == &ldso) return; /* self-relocation was done in _dlstart */
+ 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;
@@ -866,7 +930,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;
}
@@ -1355,13 +1419,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;
@@ -1659,11 +1727,12 @@ hidden void __dls2(unsigned char *base, size_t *sp)
} else {
ldso.base = base;
}
- Ehdr *ehdr = (void *)ldso.base;
+ Ehdr *ehdr = __ehdr_start ? (void *)__ehdr_start : (void *)ldso.base;
ldso.name = ldso.shortname = "libc.so";
ldso.phnum = ehdr->e_phnum;
ldso.phdr = laddr(&ldso, ehdr->e_phoff);
ldso.phentsize = ehdr->e_phentsize;
+ search_vec(auxv, &ldso_page_size, AT_PAGESZ);
kernel_mapped_dso(&ldso);
decode_dyn(&ldso);
@@ -1756,6 +1825,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. */
@@ -1831,7 +1903,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);
@@ -1923,6 +1995,10 @@ void __dls3(size_t *sp, size_t *auxv)
size_t *ptr = (size_t *) app.dynv[i+1];
*ptr = (size_t)&debug;
}
+ if (app.dynv[i]==DT_DEBUG_INDIRECT_REL) {
+ size_t *ptr = (size_t *)((size_t)&app.dynv[i] + app.dynv[i+1]);
+ *ptr = (size_t)&debug;
+ }
}
/* This must be done before final relocations, since it calls
@@ -2331,7 +2407,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 = __tls_get_addr((tls_mod_off_t[]){current->tls_id,0});
+ 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);
@@ -2344,7 +2421,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);
@@ -2358,3 +2435,7 @@ static void error(const char *fmt, ...)
__dl_vseterr(fmt, ap);
va_end(ap);
}
+
+static void error_noop(const char *fmt, ...)
+{
+}