X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=ginge.git;a=blobdiff_plain;f=loader%2Floader.c;h=84758c1ac8f31393ace15883ceb4150f9df3655f;hp=6a829ff28186a212ff61f8fb7ac564463b0a92c9;hb=df608af11ff903836b8a2be235719511df03b025;hpb=55fe8e70a19187ba960fdca6b48f276cf1cd41f4 diff --git a/loader/loader.c b/loader/loader.c index 6a829ff..84758c1 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -1,10 +1,25 @@ -// vim:shiftwidth=2:expandtab +/* + * GINGE - GINGE Is Not Gp2x Emulator + * (C) notaz, 2010-2011 + * + * This work is licensed under the MAME license, see COPYING file for details. + */ #include #include #include #include +#include +#include +#include #include +#include "header.h" +#include "realfuncs.h" +#include "syscalls.h" + +char *bin_path; +char **g_argv; + #define CHECK_(val, fail_operator, expect, err_msg) \ if (val fail_operator expect) { \ fprintf(stderr, err_msg ", exiting (%d)\n", (int)(long)val); \ @@ -28,8 +43,6 @@ return 1; \ } -#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) - typedef struct { unsigned long start; unsigned long end; @@ -51,29 +64,40 @@ static int is_range_used(maps_range *maps, int map_cnt, unsigned long start, uns } extern char **environ; -extern void do_entry(Elf32_Addr entry, void *stack_frame, int stack_frame_size, void *exitf); int main(int argc, char *argv[]) { + void *lowest_segments[2] = { NULL, NULL }; Elf32_Ehdr hdr; Elf32_Phdr *phdr; FILE *fi; maps_range maps[16]; int map_cnt; - int i, ret; - long stack_frame[5]; - - if (argc != 2) { - fprintf(stderr, "usage: %s \n", argv[0]); + int i, ret, envc, sfp; + long *stack_frame; + struct stat st; + char buf[64]; + long lret; + + if (argc < 2) { + fprintf(stderr, "usage: %s [args]\n", argv[0]); return 1; } + g_argv = argv; + + lret = g_personality(-1); + if (g_syscall_error(lret) != -1) { + lret |= 0x0240000; // ADDR_COMPAT_LAYOUT | ADDR_NO_RANDOMIZE + g_personality(lret); + } + fi = fopen("/proc/self/maps", "r"); CHECK_NE(fi, NULL, "fopen maps"); for (i = 0; i < ARRAY_SIZE(maps); i++) { ret = fscanf(fi, "%lx-%lx %*s %*s %*s %*s %*s\n", &maps[i].start, &maps[i].end); - if (ret == 0) + if (ret <= 0) break; CHECK_EQ(ret, 2, "maps parse error"); } @@ -95,7 +119,7 @@ int main(int argc, char *argv[]) } HDR_CHECK_EQ(e_type, ET_EXEC, "not executable"); -// HDR_CHECK_EQ(e_machine, EM_ARM, "not ARM"); + HDR_CHECK_EQ(e_machine, EM_ARM, "not ARM"); HDR_CHECK_EQ(e_phentsize, sizeof(Elf32_Phdr), "bad PH entry size"); HDR_CHECK_NE(e_phnum, 0, "no PH entries"); @@ -124,7 +148,7 @@ int main(int argc, char *argv[]) return 1; } - printf("load %d %08x-%08x from %08x\n", phdr[i].p_type, + log("load %d %08x-%08x from %08x\n", phdr[i].p_type, phdr[i].p_vaddr, end_addr, phdr[i].p_offset); align = phdr[i].p_vaddr & 0xfff; @@ -139,18 +163,57 @@ int main(int argc, char *argv[]) FAIL_PERROR("fseek"); if (fread((char *)ptr + align, 1, phdr[i].p_filesz, fi) != phdr[i].p_filesz) FAIL_PERROR("too small or"); + + if (phdr[i].p_flags & PF_X) + do_patches((char *)ptr + align, phdr[i].p_filesz); } + + if (lowest_segments[0] == NULL || map_ptr < lowest_segments[0]) + lowest_segments[0] = map_ptr; } - stack_frame[0] = 1; // argc - stack_frame[1] = (long)argv[1]; - stack_frame[2] = 0; - stack_frame[3] = (long)environ; - stack_frame[4] = 0; + // build self bin path + snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fileno(fi)); + if (lstat(buf, &st) != 0) + FAIL_PERROR("lstat bin_path"); + bin_path = malloc(st.st_size + 1); + CHECK_NE(bin_path, NULL, "bin_path"); + ret = readlink(buf, bin_path, st.st_size); + if (ret < 0) + FAIL_PERROR("readlink"); + bin_path[ret] = 0; - printf("entering %08x\n", hdr.e_entry); - do_entry(hdr.e_entry, stack_frame, 5, NULL); + fclose(fi); - return 0; + emu_init(lowest_segments, 0); + + // generate stack frame: argc, argv[], NULL, env[], NULL + for (envc = 0; environ[envc] != NULL; envc++) + ; + + stack_frame = calloc(argc + envc + 3, sizeof(stack_frame[0])); + if (stack_frame == NULL) { + fprintf(stderr, "stack_frame OOM\n"); + return 1; + } + + // update the environment + setenv("_", bin_path, 1); + + sfp = 0; + stack_frame[sfp++] = argc - 1; + for (i = 1; i < argc; i++) + stack_frame[sfp++] = (long)argv[i]; + stack_frame[sfp++] = 0; + for (i = 0; i < envc; i++) + stack_frame[sfp++] = (long)environ[i]; + stack_frame[sfp++] = 0; + + log("entering %08x, %d stack entries\n", hdr.e_entry, sfp); + do_entry(hdr.e_entry, stack_frame, sfp, NULL); + + fprintf(stderr, "do_entry failed!\n"); + return 1; } +// vim:shiftwidth=2:expandtab