diff options
author | Jari Vetoniemi <mailroxas@gmail.com> | 2018-11-19 11:34:35 +0200 |
---|---|---|
committer | Jari Vetoniemi <mailroxas@gmail.com> | 2018-11-19 11:34:35 +0200 |
commit | 924f18438f1ff33c4852ef2a266830aa16a4bec8 (patch) | |
tree | 188e4ed4d144d46f467ea04b171bf4f2a05dffbd | |
parent | 092fafe6b85d72ba6a2cf17a6ab01b606616d440 (diff) |
support running bionic binaries more properly
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | src/app.c | 58 | ||||
-rw-r--r-- | src/libc.c | 53 | ||||
-rw-r--r-- | src/linker/linker.c | 18 |
4 files changed, 110 insertions, 21 deletions
@@ -66,7 +66,7 @@ libdl.so: runtime/libdl.so libpthread.so: runtime/libpthread.so ln -s $< $@ -app: private override CFLAGS += -D_DEFAULT_SOURCE +app: private override CPPFLAGS += -D_GNU_SOURCE app: private override LDFLAGS += -L. -Wl,-Y,runtime,-rpath,runtime app: private override LDLIBS += -ldl -lpthread app: private override LDLIBS += -ljvm -ljvm-java -ljvm-android -ljvm-unity @@ -1,16 +1,23 @@ #include <stdio.h> +#include <stdint.h> #include <stdlib.h> #include <libgen.h> #include <dlfcn.h> +#include <elf.h> #include <err.h> #include <limits.h> #include "linker/dlfcn.h" +#include "linker/linker.h" #include "jvm/jvm.h" +#include <link.h> static int run_jni_game(struct jvm *jvm) { // Works only with unity libs for now + // XXX: What this basically is that, we port the Java bits to C + // XXX: This will become unneccessary as we make dalvik interpreter + struct { union { void *ptr; @@ -154,19 +161,38 @@ run_jni_game(struct jvm *jvm) return EXIT_SUCCESS; } +static void +raw_start(void *entry, int argc, const char *argv[]) +{ + // XXX: make this part of the linker when it's rewritten +#if ANDROID_X86_LINKER + __asm__("mov 2*4(%ebp),%eax"); /* entry */ + __asm__("mov 3*4(%ebp),%ecx"); /* original_argc */ + __asm__("mov 4*4(%ebp),%edx"); /* original_argv */ + __asm__("mov %edx,%esp"); /* Trim stack. */ + __asm__("push %edx"); /* New argv */ + __asm__("push %ecx"); /* New argc */ + __asm__("sub %edx,%edx"); /* no rtld_fini function */ + __asm__("jmp *%eax"); /* Goto entry. */ +#else + warnx("raw_start not implemented for this asm platform, can't execute binaries."); +#endif +} + int main(int argc, const char *argv[]) { if (argc < 2) - errx(EXIT_FAILURE, "usage: so-file"); + errx(EXIT_FAILURE, "usage: <elf file or jni library>"); printf("loading module: %s\n", argv[1]); { // FIXME: when bionic linker is rewritten it will just use system search path - char abs[PATH_MAX]; + char abs[PATH_MAX], paths[4096]; realpath(argv[1], abs); - dl_parse_library_path(dirname(abs), ";"); + snprintf(paths, sizeof(paths), "%s:%s", dirname(abs), "runtime-ndk"); + dl_parse_library_path(paths, ":"); } void *handle; @@ -183,10 +209,27 @@ main(int argc, const char *argv[]) union { void *ptr; - int (*fun)(int, const char*[]); - } main; + } start; } entry; + { + union { + char bytes[sizeof(Elf32_Ehdr)]; + Elf32_Ehdr hdr; + } elf; + + FILE *f; + if (!(f = fopen(argv[1], "rb"))) + err(EXIT_FAILURE, "fopen(%s)", argv[1]); + + fread(elf.bytes, 1, sizeof(elf.bytes), f); + fclose(f); + + struct soinfo *si = handle; + if (elf.hdr.e_entry) + entry.start.ptr = (void*)(intptr_t)(si->base + elf.hdr.e_entry); + } + int ret = EXIT_FAILURE; if ((entry.JNI_OnLoad.ptr = bionic_dlsym(handle, "JNI_OnLoad"))) { struct jvm jvm; @@ -194,8 +237,9 @@ main(int argc, const char *argv[]) entry.JNI_OnLoad.fun(&jvm.vm, NULL); ret = run_jni_game(&jvm); jvm_release(&jvm); - } else if ((entry.main.ptr = bionic_dlsym(handle, "main"))) { - ret = entry.main.fun(argc - 1, &argv[1]); + } else if (entry.start.ptr) { + printf("jumping to %p\n", entry.start.ptr); + raw_start(entry.start.ptr, argc - 1, &argv[1]); } else { warnx("no entrypoint found in %s", argv[1]); } @@ -428,6 +428,59 @@ bionic_sysconf(int name) return sysconf(bionic_sysconf_to_glibc_sysconf(name)); } +static void +__libc_fini(int signal, void *array) +{ + void** fini_array = (void**)array; + + if (!array || (size_t)fini_array[0] != (size_t)~0) + return; + + fini_array += 1; + + int count; + for (count = 0; fini_array[count]; ++count); + + for (; count > 0; --count) { + const union { + void *ptr; + void (*fun)(void); + } fini = { .ptr = fini_array[count] }; + + if ((size_t)fini.ptr != (size_t)~0) + fini.fun(); + } +} + +struct bionic_structors { + void (**preinit_array)(void); + void (**init_array)(void); + void (**fini_array)(void); +}; + +__attribute__((noreturn)) void +bionic___libc_init(void *raw_args, void (*onexit)(void), int (*slingshot)(int, char**, char**), struct bionic_structors const *const structors) +{ + // linker has already called the constructors + + union { + struct s { + uintptr_t argc; + char **argv; + } s; + char bytes[sizeof(struct s)]; + } arg; + + memcpy(arg.bytes, raw_args, sizeof(arg.bytes)); + + if (structors->fini_array && on_exit(__libc_fini, structors->fini_array)) { + fprintf(stderr, "__cxa_atexit failed\n"); + abort(); + } + + exit(slingshot(arg.s.argc, arg.s.argv, arg.s.argv + arg.s.argc + 1)); +} + #ifdef VERBOSE_FUNCTIONS # include "libc-verbose.h" #endif diff --git a/src/linker/linker.c b/src/linker/linker.c index 66fc593..2a1df13 100644 --- a/src/linker/linker.c +++ b/src/linker/linker.c @@ -1628,19 +1628,11 @@ void apkenv_call_constructors_recursive(soinfo *si) // out above, the libc constructor will be called again (recursively!). si->constructors_called = 1; - if (si->flags & FLAG_EXE) { - TRACE("[ %5d Calling preinit_array @ 0x%08x [%d] for '%s' ]\n", - apkenv_pid, (unsigned)si->preinit_array, si->preinit_array_count, - si->name); - apkenv_call_array(si->preinit_array, si->preinit_array_count, 0); - TRACE("[ %5d Done calling preinit_array for '%s' ]\n", apkenv_pid, si->name); - } else { - if (si->preinit_array) { - DL_ERR("%5d Shared library '%s' has a preinit_array table @ 0x%08x." - " This is INVALID.", apkenv_pid, si->name, - (unsigned)si->preinit_array); - } - } + TRACE("[ %5d Calling preinit_array @ 0x%08x [%d] for '%s' ]\n", + apkenv_pid, (unsigned)si->preinit_array, si->preinit_array_count, + si->name); + apkenv_call_array(si->preinit_array, si->preinit_array_count, 0); + TRACE("[ %5d Done calling preinit_array for '%s' ]\n", apkenv_pid, si->name); if (si->dynamic) { unsigned *d; |