From 924f18438f1ff33c4852ef2a266830aa16a4bec8 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Mon, 19 Nov 2018 11:34:35 +0200 Subject: support running bionic binaries more properly --- Makefile | 2 +- src/app.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++------- src/libc.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ src/linker/linker.c | 18 +++++------------ 4 files changed, 110 insertions(+), 21 deletions(-) diff --git a/Makefile b/Makefile index e3343fd..d2d9058 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/src/app.c b/src/app.c index 879de20..326fd3a 100644 --- a/src/app.c +++ b/src/app.c @@ -1,16 +1,23 @@ #include +#include #include #include #include +#include #include #include #include "linker/dlfcn.h" +#include "linker/linker.h" #include "jvm/jvm.h" +#include 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: "); 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]); } diff --git a/src/libc.c b/src/libc.c index 6430c1b..154e89c 100644 --- a/src/libc.c +++ b/src/libc.c @@ -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; -- cgit v1.2.3