summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJari Vetoniemi <mailroxas@gmail.com>2018-11-19 11:34:35 +0200
committerJari Vetoniemi <mailroxas@gmail.com>2018-11-19 11:34:35 +0200
commit924f18438f1ff33c4852ef2a266830aa16a4bec8 (patch)
tree188e4ed4d144d46f467ea04b171bf4f2a05dffbd
parent092fafe6b85d72ba6a2cf17a6ab01b606616d440 (diff)
support running bionic binaries more properly
-rw-r--r--Makefile2
-rw-r--r--src/app.c58
-rw-r--r--src/libc.c53
-rw-r--r--src/linker/linker.c18
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 <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]);
}
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;