diff --git a/lib/liblaunch/CMakeLists.txt b/lib/liblaunch/CMakeLists.txt index bccb93b..6a5ad0a 100644 --- a/lib/liblaunch/CMakeLists.txt +++ b/lib/liblaunch/CMakeLists.txt @@ -18,4 +18,4 @@ sysroot_add_library( HEADER_DIR /usr/include LIB_DIR /usr/lib) -target_link_libraries(liblaunch libmango ulibc) +target_link_libraries(liblaunch librosetta libmango libc-core) diff --git a/lib/liblaunch/elf.c b/lib/liblaunch/elf.c index 1d44c20..0d86766 100644 --- a/lib/liblaunch/elf.c +++ b/lib/liblaunch/elf.c @@ -300,8 +300,14 @@ static enum launch_status map_executable(struct elf_image *image) 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)); + elf_sym_t *sym = (elf_sym_t *)(image->e_local_base + image->e_dynsym + + (index * image->e_dynsym_entsize)); + + if (!sym->st_value) { + return NULL; + } + + return sym; } static enum launch_status do_rela(struct elf_image *image, elf_rela_t *rela) @@ -312,6 +318,10 @@ static enum launch_status do_rela(struct elf_image *image, elf_rela_t *rela) switch (type) { case R_X86_64_JUMP_SLOT: sym = get_dynsym(image, ELF64_R_SYM(rela->r_info)); + if (!sym) { + return LAUNCH_ERR_MISSING_SYMBOL; + } + *(uint64_t *)(image->e_local_base + rela->r_offset) = image->e_remote_base + sym->st_value + rela->r_addend; kern_tracef( @@ -354,7 +364,7 @@ static enum launch_status do_rela_list( rela = (elf_rela_t *)((char *)rela + entsize); } - return LAUNCH_OK; + return status; } static enum launch_status do_rel( diff --git a/lib/liblaunch/include/launch.h b/lib/liblaunch/include/launch.h index 4364b86..1beb86d 100644 --- a/lib/liblaunch/include/launch.h +++ b/lib/liblaunch/include/launch.h @@ -14,6 +14,7 @@ enum launch_status { * version, etc). */ LAUNCH_ERR_UNSUPPORTED_EXECUTABLE, + LAUNCH_ERR_MISSING_SYMBOL, /* a particular dependency of the executable could not be resolved. */ LAUNCH_ERR_CANNOT_RESOLVE_DEPENDENCY, LAUNCH_ERR_MEMORY_MAP_FAILED, @@ -28,6 +29,8 @@ enum launch_flags { }; struct launch_ctx; +struct rosetta_bootstrap_handle; +struct rosetta_bootstrap_channel; typedef enum launch_status (*launch_resolve_library_function)( struct launch_ctx *, @@ -52,6 +55,12 @@ struct launch_parameters { int p_envc; const char **p_envp; + const struct rosetta_bootstrap_handle *p_handles; + size_t p_handle_count; + + const struct rosetta_bootstrap_channel *p_channels; + size_t p_channel_count; + void *p_resolver_arg; }; diff --git a/lib/liblaunch/launch.c b/lib/liblaunch/launch.c index eb81d51..79518a8 100644 --- a/lib/liblaunch/launch.c +++ b/lib/liblaunch/launch.c @@ -1,10 +1,12 @@ #include "elf.h" +#include "stack.h" #include #include #include #include #include +#include #include #include @@ -34,6 +36,58 @@ static kern_handle_t get_library( return result; } +static virt_addr_t write_bootstrap_data( + struct stack_writer *stack, + const struct launch_parameters *params) +{ + virt_addr_t bs_remote; + struct rosetta_bootstrap *bs + = stack_writer_put(stack, NULL, sizeof *bs, &bs_remote); + + memset(bs, 0x0, sizeof *bs); + + bs->bs_argc = params->p_argc; + bs->bs_envc = params->p_envc; + bs->bs_handles_count = params->p_handle_count; + bs->bs_channels_count = params->p_channel_count; + + const char **argv, **envp; + + if (bs->bs_argc > 0) { + virt_addr_t remote_argv; + argv = stack_writer_put( + stack, + NULL, + bs->bs_argc * sizeof(char *), + &remote_argv); + bs->bs_argv = (const char **)remote_argv; + } + + if (bs->bs_envc > 0) { + virt_addr_t remote_envp; + envp = stack_writer_put( + stack, + NULL, + bs->bs_envc * sizeof(char *), + &remote_envp); + bs->bs_envp = (const char **)remote_envp; + } + + for (size_t i = 0; i < params->p_argc; i++) { + virt_addr_t arg_ptr; + stack_writer_put_string(stack, params->p_argv[i], &arg_ptr); + argv[i] = (const char *)arg_ptr; + } + + for (size_t i = 0; i < params->p_envc; i++) { + virt_addr_t env_ptr; + stack_writer_put_string(stack, params->p_envp[i], &env_ptr); + envp[i] = (const char *)env_ptr; + } + + return bs_remote; +} + enum launch_status launch_ctx_execute( struct launch_ctx *ctx, const struct launch_parameters *params, @@ -102,7 +156,7 @@ enum launch_status launch_ctx_execute( return status; } - virt_addr_t stack_buf; + virt_addr_t remote_stack_buf, local_stack_buf; kstatus = vm_region_map_relative( remote_address_space, VM_REGION_ANY_OFFSET, @@ -110,7 +164,15 @@ enum launch_status launch_ctx_execute( 0, STACK_SIZE, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER, - &stack_buf); + &remote_stack_buf); + kstatus = vm_region_map_relative( + params->p_local_address_space, + VM_REGION_ANY_OFFSET, + stack_vmo, + 0, + STACK_SIZE, + VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER, + &local_stack_buf); kern_handle_close(stack_vmo); if (kstatus != KERN_OK) { @@ -120,11 +182,23 @@ enum launch_status launch_ctx_execute( return LAUNCH_ERR_MEMORY_MAP_FAILED; } + struct stack_writer stack; + stack_writer_init( + &stack, + local_stack_buf + STACK_SIZE, + remote_stack_buf + STACK_SIZE); + virt_addr_t bsdata = write_bootstrap_data(&stack, params); + 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); + kstatus = task_create_thread( + remote_task, + ip, + stack.w_remote_sp, + &bsdata, + 1, + &thread); if (kstatus != KERN_OK) { elf_image_cleanup(&image); kern_handle_close(remote_address_space); diff --git a/lib/liblaunch/stack.c b/lib/liblaunch/stack.c new file mode 100644 index 0000000..82f4de6 --- /dev/null +++ b/lib/liblaunch/stack.c @@ -0,0 +1,59 @@ +#include "stack.h" + +#include +#include + +void stack_writer_init( + struct stack_writer *w, + virt_addr_t local_sp, + virt_addr_t remote_sp) +{ + memset(w, 0x0, sizeof *w); + + w->w_local_sp = local_sp; + w->w_remote_sp = remote_sp; +} + +void *stack_writer_put_string( + struct stack_writer *w, + const char *s, + virt_addr_t *out_remote) +{ + size_t len = strlen(s); + + w->w_local_sp -= (len + 1); + w->w_remote_sp -= (len + 1); + + char *local_ptr = (char *)w->w_local_sp; + virt_addr_t remote_ptr = w->w_remote_sp; + + memcpy(local_ptr, s, len); + local_ptr[len] = '\0'; + + if (out_remote) { + *out_remote = remote_ptr; + } + + return local_ptr; +} + +void *stack_writer_put( + struct stack_writer *w, + const void *p, + size_t len, + virt_addr_t *out_remote) +{ + w->w_local_sp -= len; + w->w_remote_sp -= len; + + void *local_ptr = (char *)w->w_local_sp; + virt_addr_t remote_ptr = w->w_remote_sp; + + memset(local_ptr, 0x0, len); + + if (out_remote) { + *out_remote = remote_ptr; + } + + return local_ptr; +} diff --git a/lib/liblaunch/stack.h b/lib/liblaunch/stack.h new file mode 100644 index 0000000..ed0a187 --- /dev/null +++ b/lib/liblaunch/stack.h @@ -0,0 +1,26 @@ +#ifndef LIBLAUNCH_STACK_H_ +#define LIBLAUNCH_STACK_H_ + +#include + +struct stack_writer { + virt_addr_t w_local_sp; + virt_addr_t w_remote_sp; +}; + +extern void stack_writer_init( + struct stack_writer *w, + virt_addr_t local_sp, + virt_addr_t remote_sp); + +extern void *stack_writer_put_string( + struct stack_writer *w, + const char *s, + virt_addr_t *out_remote); +extern void *stack_writer_put( + struct stack_writer *w, + const void *p, + size_t len, + virt_addr_t *out_remote); + +#endif