summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@ens-lyon.org>2016-08-26 02:55:39 +0200
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2016-08-26 02:55:39 +0200
commit12576ff7afd71799d9cc6fe6af065932540ff0ea (patch)
tree352670843d1bc9389193f7b947f08b51f91689ac
parentca5b01f538c122dc1f0e989f5703c75b8cf8ca3a (diff)
Fix loading small pic programs
It happens that the link script for ld.so contains a hole, which might thus leave an empty page between the text and the data. When loading a small pic program, its text would then fit in there, and loading the data right after it would fail. We here rather force all pic loads to be mapped contiguously, starting from the place that was allocated for the first pic load. * exec/exec.c (load_section): Return the address of the end of the section. (load): Take the address to be used for loading pic objects as parameter, force pic objects there if it is not zero, and compute and return the address to be used for the next pic object. (do_exec): Pass addresses for pic loads between calls to load().
-rw-r--r--exec/exec.c57
1 files changed, 42 insertions, 15 deletions
diff --git a/exec/exec.c b/exec/exec.c
index 3b63b7f6..ea352fa8 100644
--- a/exec/exec.c
+++ b/exec/exec.c
@@ -47,11 +47,12 @@ pthread_rwlock_t std_lock = PTHREAD_RWLOCK_INITIALIZER;
#include <hurd/sigpreempt.h>
-/* Load or allocate a section. */
-static void
+/* Load or allocate a section.
+ Returns the address of the end of the section. */
+static vm_address_t
load_section (void *section, struct execdata *u)
{
- vm_address_t addr = 0;
+ vm_address_t addr = 0, end = 0;
vm_offset_t filepos = 0;
vm_size_t filesz = 0, memsz = 0;
vm_prot_t vm_prot;
@@ -60,7 +61,7 @@ load_section (void *section, struct execdata *u)
const ElfW(Phdr) *const ph = section;
if (u->error)
- return;
+ return 0;
vm_prot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
@@ -97,9 +98,11 @@ load_section (void *section, struct execdata *u)
if (anywhere && addr < vm_page_size)
addr = vm_page_size;
+ end = addr + memsz;
+
if (memsz == 0)
/* This section is empty; ignore it. */
- return;
+ return 0;
if (filesz != 0)
{
@@ -173,7 +176,7 @@ load_section (void *section, struct execdata *u)
write_to_task (mapstart, size, vm_prot, (vm_address_t) buf);
}
if (u->error)
- return;
+ return 0;
if (anywhere)
{
@@ -230,7 +233,7 @@ load_section (void *section, struct execdata *u)
{
maplose:
vm_deallocate (u->task, mapstart, filesz);
- return;
+ return 0;
}
}
@@ -294,7 +297,7 @@ load_section (void *section, struct execdata *u)
mask, anywhere, MACH_PORT_NULL, 0, 1,
vm_prot, VM_PROT_ALL, VM_INHERIT_COPY);
if (u->error)
- return;
+ return 0;
}
if (anywhere)
@@ -319,7 +322,7 @@ load_section (void *section, struct execdata *u)
if (u->error)
{
vm_deallocate (u->task, mapstart, memsz);
- return;
+ return 0;
}
u->error = hurd_safe_memset (
(void *) (ourpage + (addr - overlap_page)),
@@ -335,6 +338,7 @@ load_section (void *section, struct execdata *u)
munmap ((caddr_t) ourpage, size);
}
}
+ return end;
}
/* XXX all accesses of the mapped data need to use fault handling
@@ -717,18 +721,37 @@ set_name (task_t task, const char *exec_name, pid_t pid)
free (name);
}
-/* Load the file. */
-static void
-load (task_t usertask, struct execdata *e)
+/* Load the file. Returns the address of the end of the load. */
+static vm_offset_t
+load (task_t usertask, struct execdata *e, vm_offset_t anywhere_start)
{
+ int anywhere = e->info.elf.anywhere;
+ vm_offset_t end;
e->task = usertask;
if (! e->error)
{
ElfW(Word) i;
+
+ if (anywhere && anywhere_start)
+ {
+ /* Make sure this anywhere-load will go at the end of the previous
+ anywhere-load. */
+ /* TODO: Rather compute how much contiguous room is needed, allocate
+ the area from the kernel, and then map memory sections. */
+ /* TODO: Possibly implement Adresse Space Layout Randomization. */
+ e->info.elf.loadbase = anywhere_start;
+ e->info.elf.anywhere = 0;
+ }
+
for (i = 0; i < e->info.elf.phnum; ++i)
if (e->info.elf.phdr[i].p_type == PT_LOAD)
- load_section (&e->info.elf.phdr[i], e);
+ {
+ end = load_section (&e->info.elf.phdr[i], e);
+ if (anywhere && end > anywhere_start)
+ /* This section pushes the next anywhere-load further */
+ anywhere_start = end;
+ }
/* The entry point address is relative to wherever we loaded the
program text. */
@@ -737,6 +760,9 @@ load (task_t usertask, struct execdata *e)
/* Release the conch for the file. */
finish_mapping (e);
+
+ /* Return potentially-new start for anywhere-loads. */
+ return round_page (anywhere_start);
}
@@ -783,6 +809,7 @@ do_exec (file_t file,
mach_msg_type_number_t i;
int intarray_dealloc = 0; /* Dealloc INTARRAY before returning? */
int oldtask_trashed = 0; /* Have we trashed the old task? */
+ vm_address_t anywhere_start = 0;
/* Prime E for executing FILE and check its validity. This must be an
inline function because it stores pointers into alloca'd storage in E
@@ -1156,7 +1183,7 @@ do_exec (file_t file,
if (interp.file != MACH_PORT_NULL)
{
/* Load the interpreter file. */
- load (newtask, &interp);
+ anywhere_start = load (newtask, &interp, anywhere_start);
if (interp.error)
{
e.error = interp.error;
@@ -1167,7 +1194,7 @@ do_exec (file_t file,
/* Load the file into the task. */
- load (newtask, &e);
+ anywhere_start = load (newtask, &e, anywhere_start);
if (e.error)
goto out;