use compat memory layout
[ginge.git] / loader / loader.c
index 28bdf8e..84758c1 100644 (file)
@@ -1,12 +1,24 @@
-// 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 <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <elf.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
 #include <sys/mman.h>
 
 #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) { \
@@ -55,7 +67,7 @@ extern char **environ;
 
 int main(int argc, char *argv[])
 {
-  void *lowest_segment = (void *)-1;
+  void *lowest_segments[2] = { NULL, NULL };
   Elf32_Ehdr hdr;
   Elf32_Phdr *phdr;
   FILE *fi;
@@ -63,12 +75,23 @@ int main(int argc, char *argv[])
   int map_cnt;
   int i, ret, envc, sfp;
   long *stack_frame;
+  struct stat st;
+  char buf[64];
+  long lret;
 
   if (argc < 2) {
     fprintf(stderr, "usage: %s <program> [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");
 
@@ -125,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;
@@ -145,11 +168,24 @@ int main(int argc, char *argv[])
         do_patches((char *)ptr + align, phdr[i].p_filesz);
     }
 
-    if (map_ptr < lowest_segment)
-      lowest_segment = map_ptr;
+    if (lowest_segments[0] == NULL || map_ptr < lowest_segments[0])
+      lowest_segments[0] = map_ptr;
   }
 
-  emu_init(lowest_segment);
+  // 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;
+
+  fclose(fi);
+
+  emu_init(lowest_segments, 0);
 
   // generate stack frame: argc, argv[], NULL, env[], NULL
   for (envc = 0; environ[envc] != NULL; envc++)
@@ -161,6 +197,9 @@ int main(int argc, char *argv[])
     return 1;
   }
 
+  // update the environment
+  setenv("_", bin_path, 1);
+
   sfp = 0;
   stack_frame[sfp++] = argc - 1;
   for (i = 1; i < argc; i++)
@@ -170,10 +209,11 @@ int main(int argc, char *argv[])
     stack_frame[sfp++] = (long)environ[i];
   stack_frame[sfp++] = 0;
 
-  printf("entering %08x, %d stack entries\n", hdr.e_entry, sfp);
+  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