for (; rel_size; rel+=stride, rel_size-=stride*sizeof(size_t)) {
if (skip_relative && IS_RELATIVE(rel[1])) continue;
type = R_TYPE(rel[1]);
+ if (type == REL_NONE) continue;
sym_index = R_SYM(rel[1]);
reloc_addr = (void *)(base + rel[0]);
if (sym_index) {
}
}
+static void *mmap_fixed(void *p, size_t n, int prot, int flags, int fd, off_t off)
+{
+ char *q = mmap(p, n, prot, flags, fd, off);
+ if (q != MAP_FAILED || errno != EINVAL) return q;
+ /* Fallbacks for MAP_FIXED failure on NOMMU kernels. */
+ if (flags & MAP_ANONYMOUS) {
+ memset(p, 0, n);
+ return p;
+ }
+ ssize_t r;
+ 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) {
+ memset(q, 0, n);
+ break;
+ }
+ }
+ return p;
+}
+
static void *map_library(int fd, struct dso *dso)
{
Ehdr buf[(896+sizeof(Ehdr))/sizeof(Ehdr)];
prot = (((ph->p_flags&PF_R) ? PROT_READ : 0) |
((ph->p_flags&PF_W) ? PROT_WRITE: 0) |
((ph->p_flags&PF_X) ? PROT_EXEC : 0));
- if (mmap(base+this_min, this_max-this_min, prot, MAP_PRIVATE|MAP_FIXED, fd, off_start) == MAP_FAILED)
+ if (mmap_fixed(base+this_min, this_max-this_min, prot, MAP_PRIVATE|MAP_FIXED, fd, off_start) == MAP_FAILED)
goto error;
if (ph->p_memsz > ph->p_filesz) {
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((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 && mmap_fixed((void *)pgbrk, (size_t)base+this_max-pgbrk, prot, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) == MAP_FAILED)
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) < 0)
+ if (mprotect(map, map_len, PROT_READ|PROT_WRITE|PROT_EXEC)
+ && errno != ENOSYS)
goto error;
break;
}
do_relocs(p, (void *)(p->base+dyn[DT_RELA]), dyn[DT_RELASZ], 3);
if (head != &ldso && p->relro_start != p->relro_end &&
- mprotect(p->base+p->relro_start, p->relro_end-p->relro_start, PROT_READ) < 0) {
+ mprotect(p->base+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);
char **argv_orig = argv;
char **envp = argv+argc+1;
+ /* Find aux vector just past environ[] and use it to initialize
+ * global data that may be needed before we can make syscalls. */
+ __environ = envp;
+ for (i=argc+1; argv[i]; i++);
+ libc.auxv = auxv = (void *)(argv+i+1);
+ decode_vec(auxv, aux, AUX_CNT);
+ __hwcap = aux[AT_HWCAP];
+ libc.page_size = aux[AT_PAGESZ];
+ libc.secure = ((aux[0]&0x7800)!=0x7800 || aux[AT_UID]!=aux[AT_EUID]
+ || aux[AT_GID]!=aux[AT_EGID] || aux[AT_SECURE]);
+
/* Setup early thread pointer in builtin_tls for ldso/libc itself to
* use during dynamic linking. If possible it will also serve as the
* thread pointer at runtime. */
a_crash();
}
- /* Find aux vector just past environ[] */
- for (i=argc+1; argv[i]; i++)
- if (!memcmp(argv[i], "LD_LIBRARY_PATH=", 16))
- env_path = argv[i]+16;
- else if (!memcmp(argv[i], "LD_PRELOAD=", 11))
- env_preload = argv[i]+11;
- auxv = (void *)(argv+i+1);
-
- decode_vec(auxv, aux, AUX_CNT);
-
/* Only trust user/env if kernel says we're not suid/sgid */
- if ((aux[0]&0x7800)!=0x7800 || aux[AT_UID]!=aux[AT_EUID]
- || aux[AT_GID]!=aux[AT_EGID] || aux[AT_SECURE]) {
- env_path = 0;
- env_preload = 0;
- libc.secure = 1;
+ if (!libc.secure) {
+ env_path = getenv("LD_LIBRARY_PATH");
+ env_preload = getenv("LD_PRELOAD");
}
- libc.page_size = aux[AT_PAGESZ];
- libc.auxv = auxv;
/* If the main program was already loaded by the kernel,
* AT_PHDR will point to some location other than the dynamic