linux-user/elfload: add FDPIC support

Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Signed-off-by: Riku Voipio <riku.voipio@nokia.com>
This commit is contained in:
Mike Frysinger 2011-02-07 01:05:50 -05:00 committed by Riku Voipio
parent 73160d9529
commit 1af02e83c0
3 changed files with 97 additions and 0 deletions

View file

@ -1075,6 +1075,33 @@ static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot)
}
}
#ifdef CONFIG_USE_FDPIC
static abi_ulong loader_build_fdpic_loadmap(struct image_info *info, abi_ulong sp)
{
uint16_t n;
struct elf32_fdpic_loadseg *loadsegs = info->loadsegs;
/* elf32_fdpic_loadseg */
n = info->nsegs;
while (n--) {
sp -= 12;
put_user_u32(loadsegs[n].addr, sp+0);
put_user_u32(loadsegs[n].p_vaddr, sp+4);
put_user_u32(loadsegs[n].p_memsz, sp+8);
}
/* elf32_fdpic_loadmap */
sp -= 4;
put_user_u16(0, sp+0); /* version */
put_user_u16(info->nsegs, sp+2); /* nsegs */
info->personality = PER_LINUX_FDPIC;
info->loadmap_addr = sp;
return sp;
}
#endif
static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
struct elfhdr *exec,
struct image_info *info,
@ -1087,6 +1114,21 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
const int n = sizeof(elf_addr_t);
sp = p;
#ifdef CONFIG_USE_FDPIC
/* Needs to be before we load the env/argc/... */
if (elf_is_fdpic(exec)) {
/* Need 4 byte alignment for these structs */
sp &= ~3;
sp = loader_build_fdpic_loadmap(info, sp);
info->other_info = interp_info;
if (interp_info) {
interp_info->other_info = info;
sp = loader_build_fdpic_loadmap(interp_info, sp);
}
}
#endif
u_platform = 0;
k_platform = ELF_PLATFORM;
if (k_platform) {
@ -1197,6 +1239,11 @@ static void load_elf_image(const char *image_name, int image_fd,
}
bswap_phdr(phdr, ehdr->e_phnum);
#ifdef CONFIG_USE_FDPIC
info->nsegs = 0;
info->pt_dynamic_addr = 0;
#endif
/* Find the maximum size of the image and allocate an appropriate
amount of memory to handle that. */
loaddr = -1, hiaddr = 0;
@ -1210,6 +1257,9 @@ static void load_elf_image(const char *image_name, int image_fd,
if (a > hiaddr) {
hiaddr = a;
}
#ifdef CONFIG_USE_FDPIC
++info->nsegs;
#endif
}
}
@ -1290,6 +1340,27 @@ static void load_elf_image(const char *image_name, int image_fd,
}
load_bias = load_addr - loaddr;
#ifdef CONFIG_USE_FDPIC
{
struct elf32_fdpic_loadseg *loadsegs = info->loadsegs =
qemu_malloc(sizeof(*loadsegs) * info->nsegs);
for (i = 0; i < ehdr->e_phnum; ++i) {
switch (phdr[i].p_type) {
case PT_DYNAMIC:
info->pt_dynamic_addr = phdr[i].p_vaddr + load_bias;
break;
case PT_LOAD:
loadsegs->addr = phdr[i].p_vaddr + load_bias;
loadsegs->p_vaddr = phdr[i].p_vaddr;
loadsegs->p_memsz = phdr[i].p_memsz;
++loadsegs;
break;
}
}
}
#endif
info->load_bias = load_bias;
info->load_addr = load_addr;
info->entry = ehdr->e_entry + load_bias;