lib: add liblaunch elf loader library
This commit is contained in:
21
lib/liblaunch/CMakeLists.txt
Normal file
21
lib/liblaunch/CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
file(GLOB sources
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/*.c)
|
||||||
|
file(GLOB headers
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include/launch.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/*.h)
|
||||||
|
|
||||||
|
set(public_include_dirs
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
|
|
||||||
|
rosetta_add_library(
|
||||||
|
NAME liblaunch STATIC
|
||||||
|
PUBLIC_INCLUDE_DIRS ${public_include_dirs}
|
||||||
|
SOURCES ${sources}
|
||||||
|
HEADERS ${headers})
|
||||||
|
|
||||||
|
sysroot_add_library(
|
||||||
|
NAME liblaunch
|
||||||
|
HEADER_DIR /usr/include
|
||||||
|
LIB_DIR /usr/lib)
|
||||||
|
|
||||||
|
target_link_libraries(liblaunch libmango ulibc)
|
||||||
547
lib/liblaunch/elf.c
Normal file
547
lib/liblaunch/elf.c
Normal file
@@ -0,0 +1,547 @@
|
|||||||
|
#include "elf.h"
|
||||||
|
|
||||||
|
#include <mango/config.h>
|
||||||
|
#include <mango/handle.h>
|
||||||
|
#include <mango/log.h>
|
||||||
|
#include <mango/vm.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define MAX(x, y) ((x) > (y) ? (x) : (y))
|
||||||
|
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||||
|
|
||||||
|
#define NEEDS_NOTHING 0
|
||||||
|
#define NEEDS_VDSO 1
|
||||||
|
#define NEEDS_MORE 2
|
||||||
|
|
||||||
|
#define ACL (PF_R | PF_W | PF_X)
|
||||||
|
#define ACCESS(x) ((x) & ACL)
|
||||||
|
|
||||||
|
/* TODO in case we ever support ELF32 images */
|
||||||
|
#define elf_class_bits(x) (64)
|
||||||
|
|
||||||
|
#define PAGE_SIZE (page_size())
|
||||||
|
#define PAGE_MASK (page_size() - 1)
|
||||||
|
#define PAGE_OFFSET(v) ((v) & (PAGE_SIZE - 1))
|
||||||
|
#define PAGE_ALIGN_DOWN(v) (v) &= ~(PAGE_SIZE - 1)
|
||||||
|
#define PAGE_ALIGN_UP(v) \
|
||||||
|
do { \
|
||||||
|
if ((v) & (PAGE_SIZE - 1)) { \
|
||||||
|
v &= ~(PAGE_SIZE - 1); \
|
||||||
|
v += PAGE_SIZE; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#undef DEBUG_LOG
|
||||||
|
|
||||||
|
static size_t page_size(void)
|
||||||
|
{
|
||||||
|
static size_t pagesz = 0;
|
||||||
|
if (pagesz == 0) {
|
||||||
|
kern_config_get(KERN_CFG_PAGE_SIZE, &pagesz, sizeof pagesz);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pagesz;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum launch_status elf_validate_ehdr(elf_ehdr_t *hdr)
|
||||||
|
{
|
||||||
|
if (hdr->e_ident[EI_MAG0] != ELF_MAG0) {
|
||||||
|
return LAUNCH_ERR_INVALID_EXECUTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr->e_ident[EI_MAG1] != ELF_MAG1) {
|
||||||
|
return LAUNCH_ERR_INVALID_EXECUTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr->e_ident[EI_MAG2] != ELF_MAG2) {
|
||||||
|
return LAUNCH_ERR_INVALID_EXECUTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr->e_ident[EI_MAG3] != ELF_MAG3) {
|
||||||
|
return LAUNCH_ERR_INVALID_EXECUTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr->e_ident[EI_CLASS] != ELFCLASS64) {
|
||||||
|
return LAUNCH_ERR_UNSUPPORTED_EXECUTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr->e_machine != EM_X86_64) {
|
||||||
|
return LAUNCH_ERR_UNSUPPORTED_EXECUTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr->e_ident[EI_DATA] != ELFDATA2LSB) {
|
||||||
|
return LAUNCH_ERR_UNSUPPORTED_EXECUTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr->e_ident[EI_VERSION] != EV_CURRENT) {
|
||||||
|
return LAUNCH_ERR_UNSUPPORTED_EXECUTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LAUNCH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum launch_status read_header(struct elf_image *image)
|
||||||
|
{
|
||||||
|
size_t nr_read = 0;
|
||||||
|
vm_object_read(
|
||||||
|
image->e_image,
|
||||||
|
&image->e_hdr,
|
||||||
|
0,
|
||||||
|
sizeof image->e_hdr,
|
||||||
|
&nr_read);
|
||||||
|
if (nr_read != sizeof image->e_hdr) {
|
||||||
|
return LAUNCH_ERR_INVALID_EXECUTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return elf_validate_ehdr(&image->e_hdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum launch_status parse_phdr(struct elf_image *image)
|
||||||
|
{
|
||||||
|
elf_phdr_t phdr;
|
||||||
|
size_t r = 0;
|
||||||
|
image->e_total_size = 0;
|
||||||
|
image->e_data_size = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < image->e_hdr.e_phnum; i++) {
|
||||||
|
off_t offset
|
||||||
|
= image->e_hdr.e_phoff + (i * image->e_hdr.e_phentsize);
|
||||||
|
kern_status_t status = vm_object_read(
|
||||||
|
image->e_image,
|
||||||
|
&phdr,
|
||||||
|
offset,
|
||||||
|
sizeof phdr,
|
||||||
|
&r);
|
||||||
|
|
||||||
|
if (status != KERN_OK || r != sizeof phdr) {
|
||||||
|
return LAUNCH_ERR_INVALID_EXECUTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (phdr.p_type) {
|
||||||
|
case PT_DYNAMIC:
|
||||||
|
image->e_dynamic = phdr;
|
||||||
|
break;
|
||||||
|
case PT_LOAD:
|
||||||
|
if (phdr.p_vaddr & (PAGE_SIZE - 1)) {
|
||||||
|
phdr.p_vaddr &= (PAGE_SIZE - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (phdr.p_memsz & (PAGE_SIZE - 1)) {
|
||||||
|
phdr.p_memsz &= (PAGE_SIZE - 1);
|
||||||
|
phdr.p_memsz += PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
image->e_total_size
|
||||||
|
= MAX(image->e_total_size,
|
||||||
|
phdr.p_vaddr + phdr.p_memsz);
|
||||||
|
break;
|
||||||
|
case PT_INTERP: {
|
||||||
|
size_t r = 0;
|
||||||
|
vm_object_read(
|
||||||
|
image->e_image,
|
||||||
|
image->e_interp,
|
||||||
|
phdr.p_offset,
|
||||||
|
MIN(sizeof image->e_interp - 1, phdr.p_filesz),
|
||||||
|
&r);
|
||||||
|
image->e_interp[r] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (phdr.p_flags & PF_W) {
|
||||||
|
image->e_data_size
|
||||||
|
= MAX(image->e_data_size,
|
||||||
|
phdr.p_vaddr + phdr.p_memsz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return LAUNCH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static kern_status_t create_exec_regions(struct elf_image *image)
|
||||||
|
{
|
||||||
|
kern_status_t status = KERN_OK;
|
||||||
|
if (image->e_local_space != KERN_HANDLE_INVALID) {
|
||||||
|
status = vm_region_create(
|
||||||
|
image->e_local_space,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
VM_REGION_ANY_OFFSET,
|
||||||
|
image->e_total_size,
|
||||||
|
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXEC
|
||||||
|
| VM_PROT_USER,
|
||||||
|
&image->e_local_exec,
|
||||||
|
&image->e_local_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image->e_remote_space != KERN_HANDLE_INVALID) {
|
||||||
|
status = vm_region_create(
|
||||||
|
image->e_remote_space,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
VM_REGION_ANY_OFFSET,
|
||||||
|
image->e_total_size,
|
||||||
|
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXEC
|
||||||
|
| VM_PROT_USER,
|
||||||
|
&image->e_remote_exec,
|
||||||
|
&image->e_remote_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
/* TODO cleanup e_local_exec */
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return KERN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum launch_status map_executable(struct elf_image *image)
|
||||||
|
{
|
||||||
|
elf_phdr_t phdr;
|
||||||
|
size_t r = 0;
|
||||||
|
image->e_total_size = 0;
|
||||||
|
image->e_data_size = 0;
|
||||||
|
|
||||||
|
size_t data_offset = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < image->e_hdr.e_phnum; i++) {
|
||||||
|
off_t phdr_offset
|
||||||
|
= image->e_hdr.e_phoff + (i * image->e_hdr.e_phentsize);
|
||||||
|
kern_status_t status = vm_object_read(
|
||||||
|
image->e_image,
|
||||||
|
&phdr,
|
||||||
|
phdr_offset,
|
||||||
|
sizeof phdr,
|
||||||
|
&r);
|
||||||
|
|
||||||
|
if (status != KERN_OK || r != sizeof phdr) {
|
||||||
|
return LAUNCH_ERR_INVALID_EXECUTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (phdr.p_type != PT_LOAD) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_handle_t vmo = image->e_image;
|
||||||
|
vm_prot_t prot = VM_PROT_USER;
|
||||||
|
size_t offset = phdr.p_offset;
|
||||||
|
|
||||||
|
phdr.p_flags &PF_R && (prot |= VM_PROT_READ);
|
||||||
|
phdr.p_flags &PF_W && (prot |= VM_PROT_WRITE);
|
||||||
|
phdr.p_flags &PF_X && (prot |= VM_PROT_EXEC);
|
||||||
|
if (phdr.p_flags & PF_W) {
|
||||||
|
vmo = image->e_data;
|
||||||
|
offset = data_offset;
|
||||||
|
|
||||||
|
status = vm_object_copy(
|
||||||
|
image->e_data,
|
||||||
|
data_offset + (phdr.p_offset & PAGE_MASK),
|
||||||
|
image->e_image,
|
||||||
|
phdr.p_offset,
|
||||||
|
phdr.p_filesz,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
return LAUNCH_ERR_IMAGE_DATA_LOAD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image->e_local_exec != KERN_HANDLE_INVALID) {
|
||||||
|
status = vm_region_map_relative(
|
||||||
|
image->e_local_exec,
|
||||||
|
phdr.p_vaddr,
|
||||||
|
vmo,
|
||||||
|
offset,
|
||||||
|
phdr.p_memsz,
|
||||||
|
prot,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
return LAUNCH_ERR_MEMORY_MAP_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image->e_remote_exec != KERN_HANDLE_INVALID) {
|
||||||
|
status = vm_region_map_relative(
|
||||||
|
image->e_remote_exec,
|
||||||
|
phdr.p_vaddr,
|
||||||
|
vmo,
|
||||||
|
offset,
|
||||||
|
phdr.p_memsz,
|
||||||
|
prot,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
return LAUNCH_ERR_MEMORY_MAP_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (phdr.p_flags & PF_W) {
|
||||||
|
data_offset += phdr.p_memsz;
|
||||||
|
if (data_offset & (PAGE_SIZE - 1)) {
|
||||||
|
data_offset &= (PAGE_SIZE - 1);
|
||||||
|
data_offset += PAGE_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return LAUNCH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static elf_sym_t *get_dynsym(struct elf_image *image, size_t index)
|
||||||
|
{
|
||||||
|
return (elf_sym_t *)(image->e_local_base + image->e_dynsym
|
||||||
|
+ (index * image->e_dynsym_entsize));
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum launch_status do_rela(struct elf_image *image, elf_rela_t *rela)
|
||||||
|
{
|
||||||
|
int type = ELF64_R_TYPE(rela->r_info);
|
||||||
|
elf_sym_t *sym = NULL;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case R_X86_64_JUMP_SLOT:
|
||||||
|
sym = get_dynsym(image, ELF64_R_SYM(rela->r_info));
|
||||||
|
*(uint64_t *)(image->e_local_base + rela->r_offset)
|
||||||
|
= image->e_remote_base + sym->st_value + rela->r_addend;
|
||||||
|
kern_tracef(
|
||||||
|
"JUMP_SLOT: offset=%zx, symbol=%zu, addend=%zx",
|
||||||
|
rela->r_offset,
|
||||||
|
ELF64_R_SYM(rela->r_info),
|
||||||
|
rela->r_addend);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
kern_trace("Unknown relocation type");
|
||||||
|
return LAUNCH_ERR_UNSUPPORTED_EXECUTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LAUNCH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum launch_status do_rela_list(
|
||||||
|
struct elf_image *image,
|
||||||
|
off_t offset,
|
||||||
|
size_t size,
|
||||||
|
size_t entsize)
|
||||||
|
{
|
||||||
|
kern_tracef(
|
||||||
|
"do_rela_list(%p, %d, %d, %d)",
|
||||||
|
image,
|
||||||
|
offset,
|
||||||
|
size,
|
||||||
|
entsize);
|
||||||
|
size_t entries = size / entsize;
|
||||||
|
elf_rela_t *rela = (elf_rela_t *)(image->e_local_base + offset);
|
||||||
|
enum launch_status status = LAUNCH_OK;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < entries; i++) {
|
||||||
|
status = do_rela(image, rela);
|
||||||
|
|
||||||
|
if (status != LAUNCH_OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rela = (elf_rela_t *)((char *)rela + entsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
return LAUNCH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum launch_status do_rel(
|
||||||
|
struct elf_image *image,
|
||||||
|
off_t offset,
|
||||||
|
size_t size,
|
||||||
|
size_t entsize)
|
||||||
|
|
||||||
|
{
|
||||||
|
return LAUNCH_ERR_UNSUPPORTED_EXECUTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum launch_status relocate(struct elf_image *image)
|
||||||
|
{
|
||||||
|
elf_dyn_t *dyn
|
||||||
|
= (elf_dyn_t *)(image->e_local_base + image->e_dynamic.p_vaddr);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
RT_REL,
|
||||||
|
RT_RELA,
|
||||||
|
RT_PLTREL,
|
||||||
|
RT_COUNT,
|
||||||
|
};
|
||||||
|
|
||||||
|
int pltrel_type = DT_NULL;
|
||||||
|
off_t offsets[RT_COUNT] = {0};
|
||||||
|
size_t sizes[RT_COUNT] = {0}, entsizes[RT_COUNT] = {0};
|
||||||
|
|
||||||
|
size_t nr_dyn = image->e_dynamic.p_filesz / sizeof *dyn;
|
||||||
|
for (size_t i = 0; i < nr_dyn; i++) {
|
||||||
|
switch (dyn[i].d_tag) {
|
||||||
|
case DT_SYMTAB:
|
||||||
|
image->e_dynsym = dyn[i].d_un.d_ptr;
|
||||||
|
break;
|
||||||
|
case DT_SYMENT:
|
||||||
|
image->e_dynsym_entsize = dyn[i].d_un.d_val;
|
||||||
|
break;
|
||||||
|
case DT_REL:
|
||||||
|
offsets[RT_REL] = dyn[i].d_un.d_ptr;
|
||||||
|
break;
|
||||||
|
case DT_RELSZ:
|
||||||
|
sizes[RT_REL] = dyn[i].d_un.d_val;
|
||||||
|
break;
|
||||||
|
case DT_RELENT:
|
||||||
|
entsizes[RT_REL] = dyn[i].d_un.d_val;
|
||||||
|
break;
|
||||||
|
case DT_RELA:
|
||||||
|
offsets[RT_RELA] = dyn[i].d_un.d_ptr;
|
||||||
|
break;
|
||||||
|
case DT_RELASZ:
|
||||||
|
sizes[RT_RELA] = dyn[i].d_un.d_val;
|
||||||
|
break;
|
||||||
|
case DT_RELAENT:
|
||||||
|
entsizes[RT_RELA] = dyn[i].d_un.d_val;
|
||||||
|
break;
|
||||||
|
case DT_PLTREL:
|
||||||
|
pltrel_type = dyn[i].d_un.d_val;
|
||||||
|
switch (pltrel_type) {
|
||||||
|
case DT_REL:
|
||||||
|
entsizes[RT_PLTREL] = 0;
|
||||||
|
break;
|
||||||
|
case DT_RELA:
|
||||||
|
entsizes[RT_PLTREL] = sizeof(elf_rela_t);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DT_JMPREL:
|
||||||
|
offsets[RT_PLTREL] = dyn[i].d_un.d_ptr;
|
||||||
|
break;
|
||||||
|
case DT_PLTRELSZ:
|
||||||
|
sizes[RT_PLTREL] = dyn[i].d_un.d_val;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dyn[i].d_tag == DT_NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum launch_status status = LAUNCH_OK;
|
||||||
|
if (offsets[RT_RELA] && sizes[RT_RELA] && entsizes[RT_RELA]) {
|
||||||
|
kern_trace("RELA");
|
||||||
|
status = do_rela_list(
|
||||||
|
image,
|
||||||
|
offsets[RT_RELA],
|
||||||
|
sizes[RT_RELA],
|
||||||
|
entsizes[RT_RELA]);
|
||||||
|
|
||||||
|
if (status != LAUNCH_OK) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offsets[RT_PLTREL] && entsizes[RT_PLTREL]) {
|
||||||
|
kern_trace("PLTREL");
|
||||||
|
if (pltrel_type == DT_REL) {
|
||||||
|
status = do_rel(
|
||||||
|
image,
|
||||||
|
offsets[RT_PLTREL],
|
||||||
|
sizes[RT_PLTREL],
|
||||||
|
entsizes[RT_PLTREL]);
|
||||||
|
} else {
|
||||||
|
status = do_rela_list(
|
||||||
|
image,
|
||||||
|
offsets[RT_PLTREL],
|
||||||
|
sizes[RT_PLTREL],
|
||||||
|
entsizes[RT_PLTREL]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != LAUNCH_OK) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return LAUNCH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void elf_image_init(struct elf_image *out)
|
||||||
|
{
|
||||||
|
memset(out, 0x0, sizeof(*out));
|
||||||
|
|
||||||
|
out->e_image = KERN_HANDLE_INVALID;
|
||||||
|
out->e_data = KERN_HANDLE_INVALID;
|
||||||
|
out->e_local_space = KERN_HANDLE_INVALID;
|
||||||
|
out->e_remote_space = KERN_HANDLE_INVALID;
|
||||||
|
out->e_local_exec = KERN_HANDLE_INVALID;
|
||||||
|
out->e_remote_exec = KERN_HANDLE_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum launch_status elf_image_load(
|
||||||
|
struct elf_image *image,
|
||||||
|
kern_handle_t exec_object,
|
||||||
|
kern_handle_t local_space,
|
||||||
|
kern_handle_t remote_space)
|
||||||
|
{
|
||||||
|
image->e_image = exec_object;
|
||||||
|
image->e_local_space = local_space;
|
||||||
|
image->e_remote_space = remote_space;
|
||||||
|
|
||||||
|
enum launch_status status = read_header(image);
|
||||||
|
if (status != LAUNCH_OK) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = parse_phdr(image);
|
||||||
|
if (status != LAUNCH_OK) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image->e_interp[0] != 0) {
|
||||||
|
return LAUNCH_ERR_INTERPRETER_REQUIRED;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t kstatus = vm_object_create(
|
||||||
|
".data",
|
||||||
|
5,
|
||||||
|
image->e_data_size,
|
||||||
|
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
|
||||||
|
&image->e_data);
|
||||||
|
if (kstatus != KERN_OK) {
|
||||||
|
return LAUNCH_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = create_exec_regions(image);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
return LAUNCH_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = map_executable(image);
|
||||||
|
if (status != LAUNCH_OK) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = relocate(image);
|
||||||
|
if (status != LAUNCH_OK) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LAUNCH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void elf_image_cleanup(struct elf_image *image)
|
||||||
|
{
|
||||||
|
vm_region_unmap_relative(image->e_local_exec, 0, image->e_total_size);
|
||||||
|
kern_handle_close(image->e_data);
|
||||||
|
kern_handle_close(image->e_local_exec);
|
||||||
|
kern_handle_close(image->e_remote_exec);
|
||||||
|
}
|
||||||
314
lib/liblaunch/elf.h
Normal file
314
lib/liblaunch/elf.h
Normal file
@@ -0,0 +1,314 @@
|
|||||||
|
#ifndef USERBOOT_ELF_H_
|
||||||
|
#define USERBOOT_ELF_H_
|
||||||
|
|
||||||
|
#include <launch.h>
|
||||||
|
#include <mango/types.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define ELF_LOAD_ERR -1
|
||||||
|
#define ELF_LOADED_EXEC 0
|
||||||
|
#define ELF_LOADED_INTERP 1
|
||||||
|
|
||||||
|
#define ELF_MAG0 0x7f
|
||||||
|
#define ELF_MAG1 'E'
|
||||||
|
#define ELF_MAG2 'L'
|
||||||
|
#define ELF_MAG3 'F'
|
||||||
|
#define ELF_NIDENT 16
|
||||||
|
|
||||||
|
#define SHT_NONE 0
|
||||||
|
#define SHT_PROGBITS 1
|
||||||
|
#define SHT_SYMTAB 2
|
||||||
|
#define SHT_STRTAB 3
|
||||||
|
#define SHT_RELA 4
|
||||||
|
#define SHT_DYNAMIC 6
|
||||||
|
#define SHT_NOBITS 8
|
||||||
|
#define SHT_REL 9
|
||||||
|
#define SHT_DYNSYM 11
|
||||||
|
|
||||||
|
/** Little endian. */
|
||||||
|
#define ELFDATA2LSB (1)
|
||||||
|
|
||||||
|
/** 64-bit. */
|
||||||
|
#define ELFCLASS64 (2)
|
||||||
|
|
||||||
|
/** x86_64 machine type. */
|
||||||
|
#define EM_X86_64 (62)
|
||||||
|
|
||||||
|
/** ELF current version. */
|
||||||
|
#define EV_CURRENT (1)
|
||||||
|
|
||||||
|
/** Dynamic section tags. */
|
||||||
|
#define DT_NULL 0
|
||||||
|
#define DT_NEEDED 1
|
||||||
|
#define DT_PLTRELSZ 2
|
||||||
|
#define DT_PLTGOT 3
|
||||||
|
#define DT_HASH 4
|
||||||
|
#define DT_STRTAB 5
|
||||||
|
#define DT_SYMTAB 6
|
||||||
|
#define DT_RELA 7
|
||||||
|
#define DT_RELASZ 8
|
||||||
|
#define DT_RELAENT 9
|
||||||
|
#define DT_STRSZ 10
|
||||||
|
#define DT_SYMENT 11
|
||||||
|
#define DT_INIT 12
|
||||||
|
#define DT_FINI 13
|
||||||
|
#define DT_REL 17
|
||||||
|
#define DT_RELSZ 18
|
||||||
|
#define DT_RELENT 19
|
||||||
|
#define DT_PLTREL 20
|
||||||
|
#define DT_JMPREL 23
|
||||||
|
#define DT_GNU_HASH 0x6ffffef5
|
||||||
|
#define DT_AUXILIARY 0x7ffffffd
|
||||||
|
|
||||||
|
#define R_386_32 1
|
||||||
|
#define R_386_PC32 2
|
||||||
|
#define R_386_GOT32 3
|
||||||
|
#define R_386_PLT32 4
|
||||||
|
#define R_386_GOTOFF 9
|
||||||
|
#define R_386_GOTPC 10
|
||||||
|
#define R_386_GOT32X 43
|
||||||
|
|
||||||
|
#define R_X86_64_64 1
|
||||||
|
#define R_X86_64_PC32 2
|
||||||
|
#define R_X86_64_GOT32 3
|
||||||
|
#define R_X86_64_PLT32 4
|
||||||
|
#define R_X86_64_COPY 5
|
||||||
|
#define R_X86_64_GLOB_DAT 6
|
||||||
|
#define R_X86_64_JUMP_SLOT 7
|
||||||
|
#define R_X86_64_RELATIVE 8
|
||||||
|
#define R_X86_64_GOTPCREL 9
|
||||||
|
#define R_X86_64_32 10
|
||||||
|
|
||||||
|
#define STT_NOTYPE 0
|
||||||
|
#define STT_OBJECT 1
|
||||||
|
#define STT_FUNC 2
|
||||||
|
#define STT_SECTION 3
|
||||||
|
#define STT_FILE 4
|
||||||
|
#define STT_LOPROC 13
|
||||||
|
#define STT_HIPROC 15
|
||||||
|
|
||||||
|
/* Section flags */
|
||||||
|
#define SHF_WRITE 0x1
|
||||||
|
#define SHF_ALLOC 0x2
|
||||||
|
#define SHF_EXECINSTR 0x4
|
||||||
|
|
||||||
|
#define SHN_UNDEF 0
|
||||||
|
|
||||||
|
#define ELF64_R_SYM(i) ((i) >> 32)
|
||||||
|
#define ELF64_R_TYPE(i) ((elf_word_t)(i))
|
||||||
|
#define ELF64_ST_BIND(i) ((i) >> 4)
|
||||||
|
#define ELF64_ST_TYPE(i) ((i) & 0xf)
|
||||||
|
|
||||||
|
#define STB_LOCAL 0
|
||||||
|
#define STB_GLOBAL 1
|
||||||
|
#define STB_WEAK 2
|
||||||
|
#define STB_NUM 3
|
||||||
|
|
||||||
|
typedef uint64_t elf_addr_t;
|
||||||
|
typedef uint64_t elf_off_t;
|
||||||
|
typedef uint16_t elf_half_t;
|
||||||
|
typedef uint32_t elf_word_t;
|
||||||
|
typedef int32_t elf_sword_t;
|
||||||
|
typedef uint64_t elf_xword_t;
|
||||||
|
typedef int64_t elf_sxword_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ELF file header.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint8_t e_ident[ELF_NIDENT];
|
||||||
|
elf_half_t e_type;
|
||||||
|
elf_half_t e_machine;
|
||||||
|
elf_word_t e_version;
|
||||||
|
elf_addr_t e_entry;
|
||||||
|
elf_off_t e_phoff;
|
||||||
|
elf_off_t e_shoff;
|
||||||
|
elf_word_t e_flags;
|
||||||
|
elf_half_t e_ehsize;
|
||||||
|
elf_half_t e_phentsize;
|
||||||
|
elf_half_t e_phnum;
|
||||||
|
elf_half_t e_shentsize;
|
||||||
|
elf_half_t e_shnum;
|
||||||
|
elf_half_t e_shstrndx;
|
||||||
|
} elf_ehdr_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ELF section header.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
elf_word_t sh_name;
|
||||||
|
elf_word_t sh_type;
|
||||||
|
elf_xword_t sh_flags;
|
||||||
|
elf_addr_t sh_addr;
|
||||||
|
elf_off_t sh_offset;
|
||||||
|
elf_xword_t sh_size;
|
||||||
|
elf_word_t sh_link;
|
||||||
|
elf_word_t sh_info;
|
||||||
|
elf_xword_t sh_addralign;
|
||||||
|
elf_xword_t sh_entsize;
|
||||||
|
} elf_shdr_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ELF symbol.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
elf_word_t st_name;
|
||||||
|
unsigned char st_info;
|
||||||
|
unsigned char st_other;
|
||||||
|
elf_half_t st_shndx;
|
||||||
|
elf_addr_t st_value;
|
||||||
|
elf_xword_t st_size;
|
||||||
|
} elf_sym_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ELF program header.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
elf_word_t p_type;
|
||||||
|
elf_word_t p_flags;
|
||||||
|
elf_off_t p_offset;
|
||||||
|
elf_addr_t p_vaddr;
|
||||||
|
elf_addr_t p_paddr;
|
||||||
|
elf_xword_t p_filesz;
|
||||||
|
elf_xword_t p_memsz;
|
||||||
|
elf_xword_t p_align;
|
||||||
|
} elf_phdr_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extended ELF relocation information.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
elf_addr_t r_offset;
|
||||||
|
elf_xword_t r_info;
|
||||||
|
elf_sxword_t r_addend;
|
||||||
|
} elf_rela_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dynamic section entries
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
elf_sxword_t d_tag;
|
||||||
|
union {
|
||||||
|
elf_xword_t d_val;
|
||||||
|
elf_addr_t d_ptr;
|
||||||
|
} d_un;
|
||||||
|
} elf_dyn_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Section header types.
|
||||||
|
*/
|
||||||
|
enum elf_stype {
|
||||||
|
ST_NONE = 0,
|
||||||
|
ST_PROGBITS = 1,
|
||||||
|
ST_SYMTAB = 2,
|
||||||
|
ST_STRTAB = 3,
|
||||||
|
ST_NOBITS = 8,
|
||||||
|
ST_REL = 9
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Program header types.
|
||||||
|
*/
|
||||||
|
enum elf_ptype {
|
||||||
|
PT_NULL = 0,
|
||||||
|
PT_LOAD = 1,
|
||||||
|
PT_DYNAMIC = 2,
|
||||||
|
PT_INTERP = 3,
|
||||||
|
PT_NOTE = 4,
|
||||||
|
PT_SHLIB = 5,
|
||||||
|
PT_PHDR = 6
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PF_X 0x1
|
||||||
|
#define PF_W 0x2
|
||||||
|
#define PF_R 0x4
|
||||||
|
|
||||||
|
#define PT_LOPROC 0x70000000
|
||||||
|
#define PT_HIPROC 0x7FFFFFFF
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ELF identification byte locations.
|
||||||
|
*/
|
||||||
|
enum elf_ident {
|
||||||
|
EI_MAG0 = 0,
|
||||||
|
EI_MAG1 = 1,
|
||||||
|
EI_MAG2 = 2,
|
||||||
|
EI_MAG3 = 3,
|
||||||
|
EI_CLASS = 4,
|
||||||
|
EI_DATA = 5,
|
||||||
|
EI_VERSION = 6,
|
||||||
|
EI_OSABI = 7,
|
||||||
|
EI_ABIVERSION = 8,
|
||||||
|
EI_PAD = 9
|
||||||
|
};
|
||||||
|
|
||||||
|
enum elf_type {
|
||||||
|
ET_NONE = 0,
|
||||||
|
ET_REL = 1,
|
||||||
|
ET_EXEC = 2,
|
||||||
|
ET_DYN = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define AT_NULL 0
|
||||||
|
#define AT_IGNORE 1
|
||||||
|
#define AT_EXECFD 2
|
||||||
|
#define AT_PHDR 3
|
||||||
|
#define AT_PHENT 4
|
||||||
|
#define AT_PHNUM 5
|
||||||
|
#define AT_PAGESZ 6
|
||||||
|
#define AT_BASE 7
|
||||||
|
#define AT_FLAGS 8
|
||||||
|
#define AT_ENTRY 9
|
||||||
|
#define AT_NOTELF 10
|
||||||
|
#define AT_UID 11
|
||||||
|
#define AT_EUID 12
|
||||||
|
#define AT_GID 13
|
||||||
|
#define AT_EGID 14
|
||||||
|
#define AT_CLKTCK 17
|
||||||
|
#define AT_PLATFORM 15
|
||||||
|
#define AT_HWCAP 16
|
||||||
|
#define AT_FPUCW 18
|
||||||
|
#define AT_DCACHEBSIZE 19
|
||||||
|
#define AT_ICACHEBSIZE 20
|
||||||
|
#define AT_UCACHEBSIZE 21
|
||||||
|
#define AT_IGNOREPPC 22
|
||||||
|
#define AT_SECURE 23
|
||||||
|
#define AT_BASE_PLATFORM 24
|
||||||
|
#define AT_RANDOM 25
|
||||||
|
#define AT_HWCAP2 26
|
||||||
|
#define AT_EXECFN 31
|
||||||
|
#define AT_SYSINFO 32
|
||||||
|
#define AT_SYSINFO_EHDR 33
|
||||||
|
#define AT_L1I_CACHESHAPE 34
|
||||||
|
#define AT_L1D_CACHESHAPE 35
|
||||||
|
#define AT_L2_CACHESHAPE 36
|
||||||
|
#define AT_L3_CACHESHAPE 37
|
||||||
|
#define AT_ENTRY_COUNT 38
|
||||||
|
|
||||||
|
struct bootdata;
|
||||||
|
struct bootfs_file;
|
||||||
|
|
||||||
|
struct elf_image {
|
||||||
|
kern_handle_t e_image, e_data;
|
||||||
|
kern_handle_t e_local_space, e_remote_space;
|
||||||
|
kern_handle_t e_local_exec, e_remote_exec;
|
||||||
|
virt_addr_t e_local_base, e_remote_base;
|
||||||
|
elf_ehdr_t e_hdr;
|
||||||
|
elf_phdr_t e_dynamic;
|
||||||
|
off_t e_dynsym;
|
||||||
|
size_t e_dynsym_entsize;
|
||||||
|
|
||||||
|
char e_interp[256];
|
||||||
|
size_t e_total_size, e_data_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void elf_image_init(struct elf_image *out);
|
||||||
|
extern enum launch_status elf_image_load(
|
||||||
|
struct elf_image *image,
|
||||||
|
kern_handle_t exec_object,
|
||||||
|
kern_handle_t local_space,
|
||||||
|
kern_handle_t remote_space);
|
||||||
|
|
||||||
|
extern void elf_image_cleanup(struct elf_image *image);
|
||||||
|
|
||||||
|
#endif
|
||||||
73
lib/liblaunch/include/launch.h
Normal file
73
lib/liblaunch/include/launch.h
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
#ifndef LAUNCH_H_
|
||||||
|
#define LAUNCH_H_
|
||||||
|
|
||||||
|
#include <mango/types.h>
|
||||||
|
|
||||||
|
enum launch_status {
|
||||||
|
LAUNCH_OK,
|
||||||
|
/* a memory allocation failed */
|
||||||
|
LAUNCH_ERR_NO_MEMORY,
|
||||||
|
/* executable file is corrupt or of an unrecognised format. */
|
||||||
|
LAUNCH_ERR_INVALID_EXECUTABLE,
|
||||||
|
/* executable file IS valid and IS of a recognised format, but is
|
||||||
|
* not supported by this machine (different class, architecture,
|
||||||
|
* version, etc).
|
||||||
|
*/
|
||||||
|
LAUNCH_ERR_UNSUPPORTED_EXECUTABLE,
|
||||||
|
/* a particular dependency of the executable could not be resolved. */
|
||||||
|
LAUNCH_ERR_CANNOT_RESOLVE_DEPENDENCY,
|
||||||
|
LAUNCH_ERR_MEMORY_MAP_FAILED,
|
||||||
|
LAUNCH_ERR_IMAGE_DATA_LOAD_FAILED,
|
||||||
|
LAUNCH_ERR_INTERPRETER_REQUIRED,
|
||||||
|
LAUNCH_ERR_TASK_CREATION_FAILED,
|
||||||
|
LAUNCH_ERR_THREAD_CREATION_FAILED,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum launch_flags {
|
||||||
|
LAUNCH_F_NONE = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct launch_ctx;
|
||||||
|
|
||||||
|
typedef enum launch_status (*launch_resolve_library_function)(
|
||||||
|
struct launch_ctx *,
|
||||||
|
const char *,
|
||||||
|
kern_handle_t *,
|
||||||
|
void *);
|
||||||
|
|
||||||
|
struct launch_ctx {
|
||||||
|
launch_resolve_library_function ctx_resolve_library;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct launch_parameters {
|
||||||
|
kern_handle_t p_parent_task;
|
||||||
|
kern_handle_t p_local_address_space;
|
||||||
|
kern_handle_t p_executable;
|
||||||
|
|
||||||
|
const char *p_task_name;
|
||||||
|
|
||||||
|
int p_argc;
|
||||||
|
const char **p_argv;
|
||||||
|
|
||||||
|
int p_envc;
|
||||||
|
const char **p_envp;
|
||||||
|
|
||||||
|
void *p_resolver_arg;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct launch_result {
|
||||||
|
kern_handle_t r_task;
|
||||||
|
kern_handle_t r_thread;
|
||||||
|
kern_handle_t r_address_space;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern enum launch_status launch_ctx_init(struct launch_ctx *ctx);
|
||||||
|
extern void launch_ctx_cleanup(struct launch_ctx *ctx);
|
||||||
|
|
||||||
|
extern enum launch_status launch_ctx_execute(
|
||||||
|
struct launch_ctx *ctx,
|
||||||
|
const struct launch_parameters *params,
|
||||||
|
enum launch_flags flags,
|
||||||
|
struct launch_result *result);
|
||||||
|
|
||||||
|
#endif
|
||||||
141
lib/liblaunch/launch.c
Normal file
141
lib/liblaunch/launch.c
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
#include "elf.h"
|
||||||
|
|
||||||
|
#include <launch.h>
|
||||||
|
#include <mango/handle.h>
|
||||||
|
#include <mango/log.h>
|
||||||
|
#include <mango/task.h>
|
||||||
|
#include <mango/vm.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define STACK_SIZE 0x10000
|
||||||
|
|
||||||
|
enum launch_status launch_ctx_init(struct launch_ctx *ctx)
|
||||||
|
{
|
||||||
|
memset(ctx, 0x0, sizeof *ctx);
|
||||||
|
return LAUNCH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void launch_ctx_cleanup(struct launch_ctx *ctx)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static kern_handle_t get_library(
|
||||||
|
struct launch_ctx *ctx,
|
||||||
|
const char *name,
|
||||||
|
void *arg)
|
||||||
|
{
|
||||||
|
enum launch_status status = LAUNCH_ERR_CANNOT_RESOLVE_DEPENDENCY;
|
||||||
|
kern_handle_t result = KERN_HANDLE_INVALID;
|
||||||
|
if (ctx->ctx_resolve_library) {
|
||||||
|
status = ctx->ctx_resolve_library(ctx, name, &result, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum launch_status launch_ctx_execute(
|
||||||
|
struct launch_ctx *ctx,
|
||||||
|
const struct launch_parameters *params,
|
||||||
|
enum launch_flags flags,
|
||||||
|
struct launch_result *result)
|
||||||
|
{
|
||||||
|
kern_status_t kstatus;
|
||||||
|
kern_handle_t stack_vmo;
|
||||||
|
|
||||||
|
kstatus = vm_object_create(
|
||||||
|
"stack",
|
||||||
|
5,
|
||||||
|
STACK_SIZE,
|
||||||
|
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
|
||||||
|
&stack_vmo);
|
||||||
|
|
||||||
|
size_t name_len = params->p_task_name ? strlen(params->p_task_name) : 0;
|
||||||
|
kern_handle_t remote_task = KERN_HANDLE_INVALID,
|
||||||
|
remote_address_space = KERN_HANDLE_INVALID;
|
||||||
|
kstatus = task_create(
|
||||||
|
params->p_parent_task,
|
||||||
|
params->p_task_name,
|
||||||
|
name_len,
|
||||||
|
&remote_task,
|
||||||
|
&remote_address_space);
|
||||||
|
if (kstatus != KERN_OK) {
|
||||||
|
kern_handle_close(stack_vmo);
|
||||||
|
return LAUNCH_ERR_TASK_CREATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct elf_image image;
|
||||||
|
elf_image_init(&image);
|
||||||
|
|
||||||
|
enum launch_status status = elf_image_load(
|
||||||
|
&image,
|
||||||
|
params->p_executable,
|
||||||
|
params->p_local_address_space,
|
||||||
|
remote_address_space);
|
||||||
|
|
||||||
|
if (status == LAUNCH_ERR_INTERPRETER_REQUIRED) {
|
||||||
|
kern_handle_t interp = get_library(
|
||||||
|
ctx,
|
||||||
|
image.e_interp,
|
||||||
|
params->p_resolver_arg);
|
||||||
|
if (interp == KERN_HANDLE_INVALID) {
|
||||||
|
elf_image_cleanup(&image);
|
||||||
|
kern_handle_close(stack_vmo);
|
||||||
|
kern_handle_close(remote_address_space);
|
||||||
|
kern_handle_close(remote_task);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
elf_image_init(&image);
|
||||||
|
status = elf_image_load(
|
||||||
|
&image,
|
||||||
|
interp,
|
||||||
|
params->p_local_address_space,
|
||||||
|
remote_address_space);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != LAUNCH_OK) {
|
||||||
|
elf_image_cleanup(&image);
|
||||||
|
kern_handle_close(stack_vmo);
|
||||||
|
kern_handle_close(remote_address_space);
|
||||||
|
kern_handle_close(remote_task);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
virt_addr_t stack_buf;
|
||||||
|
kstatus = vm_region_map_relative(
|
||||||
|
remote_address_space,
|
||||||
|
VM_REGION_ANY_OFFSET,
|
||||||
|
stack_vmo,
|
||||||
|
0,
|
||||||
|
STACK_SIZE,
|
||||||
|
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
|
||||||
|
&stack_buf);
|
||||||
|
kern_handle_close(stack_vmo);
|
||||||
|
|
||||||
|
if (kstatus != KERN_OK) {
|
||||||
|
elf_image_cleanup(&image);
|
||||||
|
kern_handle_close(remote_address_space);
|
||||||
|
kern_handle_close(remote_task);
|
||||||
|
return LAUNCH_ERR_MEMORY_MAP_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
virt_addr_t ip = image.e_hdr.e_entry + image.e_remote_base;
|
||||||
|
virt_addr_t sp = stack_buf + STACK_SIZE;
|
||||||
|
|
||||||
|
kern_handle_t thread;
|
||||||
|
kstatus = task_create_thread(remote_task, ip, sp, NULL, 0, &thread);
|
||||||
|
if (kstatus != KERN_OK) {
|
||||||
|
elf_image_cleanup(&image);
|
||||||
|
kern_handle_close(remote_address_space);
|
||||||
|
kern_handle_close(remote_task);
|
||||||
|
return LAUNCH_ERR_THREAD_CREATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_start(thread);
|
||||||
|
|
||||||
|
kern_handle_close(thread);
|
||||||
|
elf_image_cleanup(&image);
|
||||||
|
|
||||||
|
return LAUNCH_OK;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user