title: Jump to entry point of ELF from loader
body: <p>Thanks to the help in <a href="https://stackoverflow.com/questions/55552126/memset-memcpy-on-mmap-region-fails">this</a> question, the loader can now map a statically compiled hello world into memory and jump somewhere in that memory region. The problem I'm facing now is I seem not to jump to the right address or I'm calling the function in the wrong way (or wrong function?).</p>
  
  <p>Below is the code to try; I can't find in glibc where the loader calls the entry point of the program to verify I'm doing the right thing. I tried:</p>
  
  <ul>
  <li>Calling _start(void)</li>
  <li>Calling _start(int, char**, char**)</li>
  <li>Calling __libc_start_main with the last parameters set to NULL (found <a href="http://dbp-consulting.com/tutorials/debugging/linuxProgramStartup.html" rel="nofollow noreferrer">here</a>)</li>
  <li>Calling directly main</li>
  <li>Calling some addresses in  (found with gdb in rdi: 400B4D, r8: 4018E0, rcx: 401840)</li>
  </ul>
  
  <p>The entry point is 0x400a30, some instructions below __libc_start_main. With some of them it SIGSEGV, SIGABRT or prints:</p>
  
  <pre><code>hello, world! haswell xeon_phi ../csu/libc-start.c FATAL: kernel too old
     __ehdr_start.e_phentsize == sizeof *GL(dl_phdr) unexpected reloc type in static binary  FATAL: cannot determine kernel version
   __libc_start_main /dev/full /dev/null   cannot set %fs base address for thread-local storage :  %s%s%s:%u: %s%sAssertion `%s' failed.
  %n        Unexpected error.
  </code></pre>
  
  <p>and some hundred of junk lines.</p>
  
  <pre><code>int main(int argc, char* argv[argc+1]) {
      FILE *fp = fopen(argv[1], "r");
      if (!fp) {
          fprintf(stderr, "cannot open file %s", argv[1]);
          return 1;
      }
  
      fseek(fp, 0L, SEEK_END);
      size_t sz = ftell(fp) + 1;
      rewind(fp);
  
      char *region = mmap(NULL, sz, PROT_READ, MAP_PRIVATE, fileno(fp), 0);
      if (region == MAP_FAILED) {
          fprintf(stderr, "could not mmap");
          return 1;
      }
  
      Elf64_Ehdr elf64Ehdr;
      memmove(&amp;elf64Ehdr, region, sizeof(elf64Ehdr));
  
      size_t offset;
      Elf64_Phdr elf64Phdr;
      for (uint16_t i = 0; i != elf64Ehdr.e_phnum; ++i) {
          offset = elf64Ehdr.e_phoff + i * elf64Ehdr.e_phentsize;
          memmove(&amp;elf64Phdr, region + offset, sizeof(elf64Phdr));
          switch (elf64Phdr.p_type) {
              case PT_NULL:
                  break;
              case PT_LOAD:
                  if (load(&amp;elf64Phdr, region + elf64Phdr.p_offset)) {
                      exit(EXIT_FAILURE);
                  }
                  break;
              default:
                  break;
          }
      }
      printf("jumping to: 0x%x\n", elf64Ehdr.e_entry);
  
      char *argv1[] = {"", NULL};
  
      int ret = ((int (*)(int, char **, char **)) elf64Ehdr.e_entry)(1, argv1, argv1);
      return ret;
  }
  
  int load(const Elf64_Phdr *phdr, const void *elf_bytes_for_phdr) {
      const size_t pagesize = getpagesize();
      const size_t unaligned_bytes = phdr-&gt;p_vaddr % pagesize;
  
      void *base_addr = phdr-&gt;p_vaddr - unaligned_bytes;
      size_t total_bytes = phdr-&gt;p_memsz + unaligned_bytes;
  
      void *region = mmap(base_addr, total_bytes,
              phdr-&gt;p_flags | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
      if (region != MAP_FAILED) {
          memset(region, 0, unaligned_bytes);
          return memcpy(region + unaligned_bytes, elf_bytes_for_phdr, phdr-&gt;p_filesz) != region + unaligned_bytes &amp;&amp; 
          ! mprotect(region, total_bytes, phdr-&gt;p_flags);
      }
      return 1;
  }
  </code></pre>