summaryrefslogtreecommitdiff
path: root/ldso/dynlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'ldso/dynlink.c')
-rw-r--r--ldso/dynlink.c47
1 files changed, 30 insertions, 17 deletions
diff --git a/ldso/dynlink.c b/ldso/dynlink.c
index 7b47b163..715948f4 100644
--- a/ldso/dynlink.c
+++ b/ldso/dynlink.c
@@ -24,6 +24,14 @@
#include "libc.h"
#include "dynlink.h"
+static size_t ldso_page_size;
+/* libc.h may have defined a macro for dynamic PAGE_SIZE already, but
+ * PAGESIZE is only defined if it's constant for the arch. */
+#ifndef PAGESIZE
+#undef PAGE_SIZE
+#define PAGE_SIZE ldso_page_size
+#endif
+
#define malloc __libc_malloc
#define calloc __libc_calloc
#define realloc __libc_realloc
@@ -151,6 +159,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;
@@ -339,7 +349,8 @@ static struct symdef find_sym(struct dso *dso, const char *s, int need_def)
static struct symdef get_lfs64(const char *name)
{
- static const char *p, lfs64_list[] =
+ 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"
@@ -351,19 +362,14 @@ static struct symdef get_lfs64(const char *name)
"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')
+ size_t l = strnlen(name, 18);
+ if (l<2 || name[l-2]!='6' || name[l-1]!='4' || name[l])
goto nomatch;
- buf[l-=2] = 0;
for (p=lfs64_list; *p; p++) {
- if (!strcmp(buf, p)) return find_sym(&ldso, buf, 1);
+ if (!strncmp(name, p, l-2) && !p[l-2])
+ return find_sym(&ldso, p, 1);
while (*p) p++;
}
nomatch:
@@ -508,7 +514,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) {
@@ -533,13 +539,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",
@@ -552,6 +558,7 @@ 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))
@@ -609,6 +616,7 @@ static void reclaim_gaps(struct dso *dso)
for (; phcnt--; ph=(void *)((char *)ph+dso->phentsize)) {
if (ph->p_type!=PT_LOAD) continue;
if ((ph->p_flags&(PF_R|PF_W))!=(PF_R|PF_W)) continue;
+ if (ph->p_memsz == 0) continue;
reclaim(dso, ph->p_vaddr & -PAGE_SIZE, ph->p_vaddr);
reclaim(dso, ph->p_vaddr+ph->p_memsz,
ph->p_vaddr+ph->p_memsz+PAGE_SIZE-1 & -PAGE_SIZE);
@@ -1717,11 +1725,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);
@@ -1984,6 +1993,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