diff --git a/src/kernel/emulation/linux/process/execve.c b/src/kernel/emulation/linux/process/execve.c
index 1c843c25a..a613a96fc 100644
--- a/src/kernel/emulation/linux/process/execve.c
+++ b/src/kernel/emulation/linux/process/execve.c
@@ -34,121 +34,7 @@ static inline bool isspace(char c)
long sys_execve(char* fname, char** argvp, char** envp)
{
- int ret, fd, len;
- char mldr_path[256];
- union
- {
- uint32_t magic;
- char magic_array[256];
- } m;
-
- // Ideally, if everybody used binfmt_misc to allow direct
- // execution of Mach-O binaries under Darling, this wouldn't
- // be necessary. But we cannot rely on that.
-
- fd = sys_open(fname, BSD_O_RDONLY, 0);
- if (fd < 0)
- return fd;
-
- ret = sys_read(fd, m.magic_array, sizeof(m.magic_array));
- sys_close(fd);
-
- if (ret < 4)
- return -ENOEXEC;
-
- len = LINUX_SYSCALL(__NR_readlink, "/proc/self/exe", mldr_path, sizeof(mldr_path)-1);
- if (len < 0)
- return -ENOEXEC;
- mldr_path[len] = '\0';
-
- if (m.magic == MH_MAGIC || m.magic == MH_CIGAM
- || m.magic == MH_MAGIC_64 || m.magic == MH_CIGAM_64
- || m.magic == FAT_MAGIC || m.magic == FAT_CIGAM)
- {
- // It is a Mach-O file
- int i;
- char** modargvp;
- char *buf;
-
- // Prepend mldr path
- len = 0;
-
- // Count arguments
- while (argvp[len++]);
-
- // Allocate a new argvp, execute mldr_path
- modargvp = (char**) __builtin_alloca(sizeof(void*) * (len+1));
- buf = __builtin_alloca(strlen(mldr_path) + 2 + strlen(fname));
-
- strcpy(buf, mldr_path);
- strcat(buf, "!");
- strcat(buf, fname);
- modargvp[0] = buf;
-
- for (i = 1; i < len+1; i++)
- modargvp[i] = argvp[i-1];
-
- argvp = modargvp;
- fname = mldr_path;
- }
- // Shebang support
- else if (m.magic_array[0] == '#' && m.magic_array[1] == '!')
- {
- char *nl, *interp, *arg;
- char** modargvp;
- int i, j;
-
- nl = memchr(m.magic_array, '\n', sizeof(m.magic_array));
- if (nl == NULL)
- return -ENOEXEC;
-
- *nl = '\0';
-
- for (i = 2; isspace(m.magic_array[i]); i++);
-
- interp = &m.magic_array[i];
-
- for (i = 0; !isspace(interp[i]) && interp[i]; i++);
-
- if (interp[i] == '\0')
- arg = NULL;
- else
- arg = &interp[i];
-
- if (arg != NULL)
- {
- *arg = '\0'; // terminate interp
- arg++;
-
- while (isspace(*arg))
- arg++;
- if (*arg == '\0')
- arg = NULL; // no argument, just whitespace
- }
-
- // Count original arguments
- while (argvp[len++]);
-
- // Allocate a new argvp
- modargvp = (char**) __builtin_alloca(sizeof(void*) * (len+3));
-
- i = 0;
-
- modargvp[i++] = mldr_path;
- modargvp[i++] = interp;
- if (arg != NULL)
- modargvp[i++] = arg;
- modargvp[i] = fname;
-
- // Append original arguments
- for (j = 1; j < len+1; j++)
- modargvp[i+j] = argvp[j];
-
- argvp = modargvp;
- fname = mldr_path;
- }
-
- // otherwise, it's a native Linux executable (ELF)
+ int ret;
linux_sigset_t set;
set = (1ull << (SIGNAL_SIGEXC_TOGGLE-1));
diff --git a/src/lkm b/src/lkm
index 9f3be3190..9648becf4 160000
--- a/src/lkm
+++ b/src/lkm
@@ -1 +1 @@
-Subproject commit 9f3be31908437c6292709364224f5d9cae872d5b
+Subproject commit 9648becf4a32ffb0208c401c1ebce26f7dfc2ee9
diff --git a/src/startup/CMakeLists.txt b/src/startup/CMakeLists.txt
index 774a26322..0bac7a418 100644
--- a/src/startup/CMakeLists.txt
+++ b/src/startup/CMakeLists.txt
@@ -20,28 +20,9 @@ target_link_libraries(darling -lutil)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
-set(mldr_sources
- mldr.c
- threads.c
- gdb.c
- commpage.c
- elfcalls.c
-)
-add_executable(mldr ${mldr_sources})
-target_link_libraries(mldr pthread dl rt)
-
-add_executable(mldr32 ${mldr_sources})
-target_link_libraries(mldr32 pthread dl rt)
-set_target_properties(mldr32
- PROPERTIES
- COMPILE_FLAGS "-m32"
- LINK_FLAGS "-m32"
-)
-
add_executable(wrapgen wrapgen/wrapgen.cpp)
target_link_libraries(wrapgen dl)
-install(TARGETS mldr mldr32 DESTINATION libexec/darling/bin)
install(TARGETS darling DESTINATION bin
PERMISSIONS
OWNER_READ OWNER_WRITE OWNER_EXECUTE
@@ -49,9 +30,6 @@ install(TARGETS darling DESTINATION bin
WORLD_READ WORLD_EXECUTE
SETUID)
-include(setcap)
-setcap(libexec/darling/bin/mldr cap_sys_rawio,cap_sys_ptrace+ep)
-setcap(libexec/darling/bin/mldr32 cap_sys_rawio,cap_sys_ptrace+ep)
# This tool is useful for packaging to detect ELF dependencies inside Mach-O libraries,
# which standard distro tools cannot do.
diff --git a/src/startup/darling.c b/src/startup/darling.c
index a613ccd03..475dc5e7d 100644
--- a/src/startup/darling.c
+++ b/src/startup/darling.c
@@ -47,8 +47,6 @@ along with Darling. If not, see .
#include "darling.h"
#include "darling-config.h"
-#define MLDR_PATH "/bin/mldr"
-
// Between Linux 4.9 and 4.11, a strange bug has been introduced
// which prevents connecting to Unix sockets if the socket was
// created in a different mount namespace or under overlayfs
@@ -866,7 +864,7 @@ void spawnLaunchd(void)
puts("Bootstrapping the container with launchd...");
// putenv("KQUEUE_DEBUG=1");
- execl(MLDR_PATH, "mldr!/sbin/launchd", "launchd", NULL);
+ execl("/sbin/launchd", "launchd", NULL);
fprintf(stderr, "Failed to exec launchd: %s\n", strerror(errno));
abort();
@@ -1093,7 +1091,7 @@ pid_t getInitProcess()
}
fclose(fp);
- if (strcmp(exeBuf, "mldr") != 0)
+ if (strcmp(exeBuf, "launchd") != 0)
{
unlink(pidPath);
return 0;
diff --git a/src/startup/loader.c b/src/startup/loader.c
deleted file mode 100644
index 85b561590..000000000
--- a/src/startup/loader.c
+++ /dev/null
@@ -1,242 +0,0 @@
-
-// Definitions:
-// FUNCTION_NAME (load32/load64)
-// SEGMENT_STRUCT (segment_command/SEGMENT_STRUCT)
-// SEGMENT_COMMAND (LC_SEGMENT/SEGMENT_COMMAND)
-// MACH_HEADER_STRUCT (mach_header/MACH_HEADER_STRUCT)
-// SECTION_STRUCT (section/SECTION_STRUCT)
-
-#if defined(GEN_64BIT)
-# define FUNCTION_NAME load64
-# define SEGMENT_STRUCT segment_command_64
-# define SEGMENT_COMMAND LC_SEGMENT_64
-# define MACH_HEADER_STRUCT mach_header_64
-# define SECTION_STRUCT section_64
-# define MAP_EXTRA 0
-#elif defined(GEN_32BIT)
-# define FUNCTION_NAME load32
-# define SEGMENT_STRUCT segment_command
-# define SEGMENT_COMMAND LC_SEGMENT
-# define MACH_HEADER_STRUCT mach_header
-# define SECTION_STRUCT section
-# define MAP_EXTRA MAP_32BIT
-#else
-# error See above
-#endif
-
-void FUNCTION_NAME(int fd, uintptr_t* entryPoint_out, uintptr_t* mh_out)
-{
- struct MACH_HEADER_STRUCT header;
- uint8_t* cmds;
- uintptr_t entryPoint = 0, entryPointDylinker = 0;
- struct MACH_HEADER_STRUCT* mappedHeader = NULL;
- uintptr_t slide = 0;
- uintptr_t mmapSize = 0;
- bool pie = false;
- uint32_t fat_offset;
-
- fat_offset = lseek(fd, 0, SEEK_CUR);
-
- if (read(fd, &header, sizeof(header)) != sizeof(header))
- {
- fprintf(stderr, "Cannot read the mach header.\n");
- exit(1);
- }
-
- cmds = (uint8_t*) malloc(header.sizeofcmds);
- if (!cmds)
- {
- fprintf(stderr, "Cannot allocate %u bytes for loader commands.\n", header.sizeofcmds);
- exit(1);
- }
-
- if (read(fd, cmds, header.sizeofcmds) != header.sizeofcmds)
- {
- fprintf(stderr, "Cannot read loader commands.\n");
- exit(1);
- }
-
- if ((header.filetype == MH_EXECUTE && header.flags & MH_PIE) || header.filetype == MH_DYLINKER)
- {
- uintptr_t base = -1;
-
- // Go through all SEGMENT_COMMAND commands to get the total continuous range required.
- for (uint32_t i = 0, p = 0; i < header.ncmds; i++)
- {
- struct SEGMENT_STRUCT* seg = (struct SEGMENT_STRUCT*) &cmds[p];
-
- // Load commands are always sorted, so this will get us the maximum address.
- if (seg->cmd == SEGMENT_COMMAND)
- {
- if (base == -1)
- {
- base = seg->vmaddr;
- if (base != 0 && header.filetype == MH_DYLINKER)
- goto no_slide;
- }
- mmapSize = seg->vmaddr + seg->vmsize - base;
- }
-
- p += seg->cmdsize;
- }
-
- slide = (uintptr_t) mmap((void*) base, mmapSize, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_EXTRA, -1, 0);
- if (slide == (uintptr_t)MAP_FAILED)
- {
- fprintf(stderr, "Cannot mmap anonymous memory range: %s", strerror(errno));
- exit(1);
- }
-
- pie = true;
- }
-no_slide:
-
- for (uint32_t i = 0, p = 0; i < header.ncmds; i++)
- {
- struct load_command* lc;
-
- lc = (struct load_command*) &cmds[p];
-
- switch (lc->cmd)
- {
- case SEGMENT_COMMAND:
- {
- struct SEGMENT_STRUCT* seg = (struct SEGMENT_STRUCT*) lc;
- void* rv;
-
- if (memcmp(SEG_PAGEZERO, seg->segname, sizeof(SEG_PAGEZERO)) == 0)
- {
- // Let's skip pagezero and map a single page at address 0 elsewhere.
- p += lc->cmdsize;
- continue;
- }
-
- if (seg->filesize < seg->vmsize)
- {
- if (slide != 0)
- {
- // Some segments' filesize != vmsize, thus this mprotect().
- if (mprotect((void*) (seg->vmaddr + slide), seg->vmsize, native_prot(seg->maxprot)) != 0)
- {
- fprintf(stderr, "Cannot mprotect for segment %s: %s\n", seg->segname, strerror(errno));
- exit(1);
- }
- }
- else
- {
- size_t size = seg->vmsize - seg->filesize;
- rv = mmap((void*) PAGE_ALIGN(seg->vmaddr + seg->vmsize - size), PAGE_ROUNDUP(size), native_prot(seg->maxprot),
- MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
- }
- }
-
- if (seg->filesize > 0)
- {
- rv = mmap((void*) (seg->vmaddr + slide), seg->filesize, native_prot(seg->maxprot),
- MAP_FIXED | MAP_PRIVATE, fd, seg->fileoff + fat_offset);
- if (rv == (void*)MAP_FAILED)
- {
- fprintf(stderr, "Cannot mmap segment %s at %p: %s\n", seg->segname, (void*)(uintptr_t)seg->vmaddr, strerror(errno));
- exit(1);
- }
-
- if (seg->fileoff == 0)
- mappedHeader = (struct MACH_HEADER_STRUCT*) (seg->vmaddr + slide);
- }
-
- if (strcmp(SEG_DATA, seg->segname) == 0)
- {
- // Look for section named __all_image_info for GDB integration
- struct SECTION_STRUCT* sect = (struct SECTION_STRUCT*) (seg+1);
- struct SECTION_STRUCT* end = (struct SECTION_STRUCT*) (&cmds[p + lc->cmdsize]);
-
- while (sect < end)
- {
- if (strncmp(sect->sectname, "__all_image_info", 16) == 0)
- {
- dyld_all_image_location = slide + sect->addr;
- dyld_all_image_size = sect->size;
-#ifdef GEN_64BIT
- setup_gdb_notifications(slide, sect->addr);
-#endif
- break;
- }
- sect++;
- }
- }
- break;
- }
- case LC_UNIXTHREAD:
- {
-#ifdef GEN_64BIT
- entryPoint = ((uint64_t*) lc)[18];
-#endif
-#ifdef GEN_32BIT
- entryPoint = ((uint32_t*) lc)[14];
-#endif
- entryPoint += slide;
- break;
- }
- case LC_LOAD_DYLINKER:
- {
- struct dylinker_command* dy = (struct dylinker_command*) lc;
- char path[4096];
- size_t length = dy->cmdsize - dy->name.offset;
-
- if (length > sizeof(path)-1)
- {
- fprintf(stderr, "Dynamic linker name too long: %zu\n", length);
- exit(1);
- }
-
- memcpy(path, ((char*) dy) + dy->name.offset, length);
- path[length] = '\0';
-
- apply_root_path(path);
-
-#ifdef GEN_64BIT
- load(path, &entryPointDylinker, NULL, CPU_TYPE_X86_64, NULL);
-#endif
-#ifdef GEN_32BIT
- load(path, &entryPointDylinker, NULL, CPU_TYPE_X86, NULL);
-#endif
-
- break;
- }
- case LC_MAIN:
- {
- struct entry_point_command* ee = (struct entry_point_command*) lc;
- if (ee->stacksize > stack_size)
- stack_size = ee->stacksize;
- break;
- }
- case LC_UUID:
- {
- if (header.filetype == MH_EXECUTE)
- {
- struct uuid_command* ue = (struct uuid_command*) lc;
- memcpy(exe_uuid, ue->uuid, sizeof(exe_uuid));
- }
- break;
- }
- }
-
- p += lc->cmdsize;
- }
-
- free(cmds);
-
- if (entryPoint_out != NULL)
- *entryPoint_out = entryPointDylinker ? entryPointDylinker : entryPoint;
- if (mh_out != NULL)
- *mh_out = (uintptr_t) mappedHeader;
-}
-
-
-#undef FUNCTION_NAME
-#undef SEGMENT_STRUCT
-#undef SEGMENT_COMMAND
-#undef MACH_HEADER_STRUCT
-#undef SECTION_STRUCT
-#undef MAP_EXTRA
-
diff --git a/src/startup/mldr.c b/src/startup/mldr.c
deleted file mode 100644
index 854f56d4b..000000000
--- a/src/startup/mldr.c
+++ /dev/null
@@ -1,570 +0,0 @@
-/*
-This file is part of Darling.
-
-Copyright (C) 2017 Lubos Dolezel
-
-Darling is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-Darling is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Darling. If not, see .
-*/
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include "elfcalls.h"
-#include "gdb.h"
-#include "commpage.h"
-#include "32in64.h"
-
-#define USE_32IN64 0
-
-#ifndef PAGE_SIZE
-# define PAGE_SIZE 4096
-#endif
-#define PAGE_ALIGN(x) (x & ~(PAGE_SIZE-1))
-#define PAGE_ROUNDUP(x) (((((x)-1) / PAGE_SIZE)+1) * PAGE_SIZE)
-
-#define CPU_ARCH_ABI64 0x01000000
-#define CPU_TYPE_ANY ((cpu_type_t) -1)
-#define CPU_TYPE_X86 ((cpu_type_t) 7)
-#define CPU_TYPE_X86_64 (CPU_TYPE_X86 | CPU_ARCH_ABI64)
-
-static const char* dyld_path = INSTALL_PREFIX "/libexec/usr/lib/dyld";
-
-// The idea of mldr is to load dyld_path into memory and set up the stack
-// as described in dyldStartup.S.
-// After that, we pass control over to dyld.
-//
-// Additionally, mldr providers access to native platforms libdl.so APIs (ELF loader).
-
-#ifdef __x86_64__
-static void load64(int fd, uintptr_t* entryPoint_out, uintptr_t* mh_out);
-static void reexec32(char** argv);
-#endif
-static void load32(int fd, uintptr_t* entryPoint_out, uintptr_t* mh_out);
-static void load(const char* path, uintptr_t* entryPoint_out, uintptr_t* mh_out, cpu_type_t cpu, char** argv);
-static int native_prot(int prot);
-static void apply_root_path(char* path);
-char* elfcalls_make(void);
-static char* apple0_make(const char* filepath);
-static void map_pagezero(void);
-
-// UUID of the main executable
-uint8_t exe_uuid[16];
-
-// Data for TASK_DYLD_INFO
-uintptr_t dyld_all_image_location;
-size_t dyld_all_image_size;
-
-#if USE_32IN64
-static void* setup_stack32(void* stack, int argc, const char** argv, const char** envp, const char** apple, uint64_t mh);
-
-static bool mode_32in64 = false;
-#endif
-
-static uint32_t stack_size = 0;
-
-int main(int argc, char** argv, char** envp)
-{
- uintptr_t entryPoint, mh;
- void** sp;
- int pushCount = 0;
- const char* apple[3];
- char *filename, *p = NULL;
- // sys_execve() passes the original file path appended to the mldr path in argv[0].
- if (argc > 0)
- p = strchr(argv[0], '!');
-
- if (argc <= 1)
- {
- if (p == NULL) {
- fprintf(stderr, "mldr is part of Darling. It is not to be executed directly.\n");
- return 1;
- }
- else
- {
- fprintf(stderr, "mldr: warning: Executing with no argv[0]. Continuing anyway, but this is probably a bug.\n");
- }
- }
-
- if (p != NULL)
- {
- filename = (char*) __builtin_alloca(strlen(argv[0])+1);
- strcpy(filename, p + 1);
- }
- else
- {
- filename = (char*) __builtin_alloca(strlen(argv[1])+1);
- strcpy(filename, argv[1]);
- }
-
-#ifdef __i386__
- load(filename, &entryPoint, &mh, CPU_TYPE_X86, argv); // accept i386 only
-#else
- load(filename, &entryPoint, &mh, CPU_TYPE_ANY, argv);
-#endif
-
- p = argv[0];
- // Update process name in ps output
- for (int i = 1; i < argc; i++)
- {
- size_t len = strlen(argv[i]);
- memmove(p, argv[i], len+1);
-
- argv[i-1] = p;
- p += len+1;
- }
-
- if (envp[0] != NULL)
- memset(p, 0, envp[0]-p);
- else
- {
- while (*p)
- *p++ = '\0';
- }
- argv[--argc] = NULL;
-
-#if __i386__ || __x86_64__
- if (getenv("BREAK_AFTER_LOAD") != NULL)
- __asm__("int3");
-#endif
-
-#ifdef __x86_64__
-# define GETSP(ptr) __asm__ volatile("movq %%rsp, %0" : "=r"(ptr) ::)
-# define JUMPX(pushCount, addr) __asm__ volatile("sub %1, %%rsp; jmpq *%0" :: "m"(addr), "r"(pushCount * sizeof(void*)) :)
-#elif defined(__i386__)
-# define GETSP(ptr) __asm__ volatile("movl %%esp, %0" : "=m"(ptr) ::)
-# define JUMPX(pushCount, addr) __asm__ volatile("sub %1, %%esp; jmp *%0" :: "m"(addr), "r"(pushCount * sizeof(void*)) :)
-#elif defined(__arm__)
-# define GETSP(ptr) __asm__ volatile("mov %0, sp" : "=r"(ptr) ::)
-# define JUMPX(pushCount, addr) __asm__ volatile("sub sp, %1; bx %0" :: "r"(addr), "r"(pushCount * sizeof(void*)) :)
-#else
-# error Unsupported platform!
-#endif
-
- apple[0] = apple0_make(filename);
- apple[1] = elfcalls_make();
- apple[2] = NULL;
-
- map_pagezero();
-
-#if USE_32IN64
- if (!mode_32in64)
-#endif
- {
- GETSP(sp);
- sp--;
-
- for (int i = sizeof(apple)/sizeof(apple[0])-1; i >= 0; i--)
- *(sp-(pushCount++)) = (void*) apple[i];
-
- *(sp-(pushCount++)) = NULL;
- for (int i = 0; environ[i] != NULL; i++)
- *(sp-(pushCount++)) = environ[i];
-
- *(sp-(pushCount++)) = NULL;
- for (int i = argc-1; i >= 0; i--)
- *(sp-(pushCount++)) = (void*) argv[i];
-
- *(sp-(pushCount++)) = (void*) (uintptr_t)(argc);
- *(sp-(pushCount++)) = (void*) mh;
-
- JUMPX(pushCount, entryPoint);
- }
-#if USE_32IN64
- else
- {
- uint32_t size = stack_size ? stack_size : 8*1024*1024;
- size &= ~3u;
-
- sp = mmap(NULL, size,
- PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_32BIT | MAP_ANONYMOUS,
- -1, 0);
- // stack guard page
- mprotect(sp, PAGE_SIZE, PROT_NONE);
-
- // move to the top of the stack
- sp += size/sizeof(void*) - 1;
-
- _64TO32_WITH_STACK(setup_stack32(sp, argc, (const char**) argv, (const char**) envp, apple, mh), entryPoint);
- }
-#endif
-
- __builtin_unreachable();
-}
-
-static char* copystring(void* stack, const char* str)
-{
- size_t len = strlen(str);
- char* pos = (char*) stack;
-
- pos -= len+1;
- strcpy(pos, str);
-
- return pos;
-}
-
-static size_t arraylen(const char** str)
-{
- size_t len = 0;
- while (str[len] != NULL)
- len++;
- return len;
-}
-
-#if USE_32IN64
-void* setup_stack32(void* stack, int argc, const char** argv_in, const char** envp_in, const char** apple_in, uintptr_t mh)
-{
- char **argv_new, **envp_new, **apple_new;
- size_t size, apple_size;
- uint32_t* stack_pointers;
-
- argv_new = (char**) __builtin_alloca((arraylen(argv_in) + 1) * sizeof(char*));
- for (int i = argc-1; i >= 0; i--)
- stack = argv_new[i] = copystring(stack, argv_in[i]);
- argv_new[argc] = NULL;
-
- size = arraylen(envp_in);
- envp_new = (char**) __builtin_alloca((size + 1) * sizeof(char*));
- for (int i = size-1; i >= 0; i--)
- stack = envp_new[i] = copystring(stack, envp_in[i]);
- envp_new[size] = NULL;
-
- apple_size = arraylen(apple_in);
- apple_new = (char**) __builtin_alloca((apple_size + 1) * sizeof(char*));
- for (int i = apple_size-1; i >= 0; i--)
- stack = apple_new[i] = copystring(stack, apple_in[i]);
-
- stack_pointers = (uint32_t*) stack;
- stack_pointers--;
-
- *stack_pointers-- = 0;
- for (int i = apple_size-1; i >= 0; i--)
- *stack_pointers-- = (uint32_t) apple_new[i];
-
- *stack_pointers-- = 0;
- for (int i = 0; envp_new[i] != NULL; i++)
- *stack_pointers-- = (uint32_t) envp_new[i];
-
- *stack_pointers-- = 0;
- for (int i = argc-1; i >= 0; i--)
- *stack_pointers-- = (uint32_t) argv_new[i];
-
- *stack_pointers-- = argc;
- *stack_pointers = (uint32_t) mh;
-
- return stack_pointers;
-}
-#endif
-
-static void parse_binprefs(uint32_t bprefs[4])
-{
- const char* bprefs_str;
-
- bprefs[0] = bprefs[1] = bprefs[2] = bprefs[3] = 0;
- bprefs_str = getenv("__mldr_bprefs");
-
- if (bprefs_str != NULL)
- {
- sscanf(bprefs_str, "%x,%x,%x,%x", &bprefs[0], &bprefs[1], &bprefs[2], &bprefs[3]);
- unsetenv("__mldr_bprefs");
- }
-}
-
-void load(const char* path, uintptr_t* entryPoint_out, uintptr_t* mh_out, cpu_type_t cpu_desired, char** argv)
-{
- int fd;
- uint32_t magic;
- uint32_t bprefs[4];
-
- fd = open(path, O_RDONLY);
- if (fd == -1)
- {
- fprintf(stderr, "Cannot open %s: %s\n", path, strerror(errno));
- exit(1);
- }
-
- // We need to read argv[1] and detect whether it's a 32 or 64-bit application.
- // Then load the appropriate version of dyld from the fat file.
- // In case the to-be-executed executable contains both, we prefer the 64-bit version,
- // unless a special property has been passed to sys_posix_spawn() to force the 32-bit
- // version. See posix_spawnattr_setbinpref_np().
- parse_binprefs(bprefs);
-
- if (read(fd, &magic, sizeof(magic)) != sizeof(magic))
- {
- fprintf(stderr, "Cannot read the file header of %s.\n", path);
- exit(1);
- }
-
- if (magic == MH_MAGIC_64 || magic == MH_CIGAM_64)
- {
-#ifndef __i386__
- if (mh_out)
- commpage_setup(true);
-
- lseek(fd, 0, SEEK_SET);
- load64(fd, entryPoint_out, mh_out);
-#else
- abort();
-#endif
- }
- else if (magic == MH_MAGIC || magic == MH_CIGAM)
- {
-#if !__x86_64__ || USE_32IN64
- if (mh_out)
- commpage_setup(false);
-#if __x86_64__
- mode_32in64 = true;
-#endif
- lseek(fd, 0, SEEK_SET);
- load32(fd, entryPoint_out, mh_out);
-#else
- // Re-run self as mldr32
- reexec32(argv);
-#endif
- }
- else if (magic == FAT_MAGIC || magic == FAT_CIGAM)
- {
- struct fat_header fhdr;
- struct fat_arch best_arch;
- const bool swap = magic == FAT_CIGAM;
-
- best_arch.cputype = CPU_TYPE_ANY;
-
- if (read(fd, &fhdr.nfat_arch, sizeof(fhdr.nfat_arch)) != sizeof(fhdr.nfat_arch))
- {
- fprintf(stderr, "Cannot read the file header of %s.\n", path);
- exit(1);
- }
-
-#define SWAP32(x) x = __bswap_32(x)
-
- if (swap)
- SWAP32(fhdr.nfat_arch);
-
- for (uint32_t i = 0; i < fhdr.nfat_arch; i++)
- {
- struct fat_arch arch;
-
- if (read(fd, &arch, sizeof(arch)) != sizeof(arch))
- {
- fprintf(stderr, "Cannot read fat_arch header of %s.\n", path);
- exit(1);
- }
-
- if (swap)
- {
- SWAP32(arch.cputype);
- SWAP32(arch.cpusubtype);
- SWAP32(arch.offset);
- SWAP32(arch.size);
- SWAP32(arch.align);
- }
-
- if (cpu_desired == CPU_TYPE_ANY)
- {
- // Find the best arch
-#ifdef __x86_64__
- // Analyze binprefs used with posix_spawn()
- for (int i = 0; i < sizeof(bprefs) / sizeof(bprefs[0]) && bprefs[i] != 0; i++)
- {
- if (arch.cputype == bprefs[i])
- {
- memcpy(&best_arch, &arch, sizeof(arch));
- break;
- }
- }
-
- // Hope for x86-64, but also accept i386
- // TODO: x86_64h (Haswell)
- if (arch.cputype == CPU_TYPE_X86_64)
- {
- memcpy(&best_arch, &arch, sizeof(arch));
- break;
- }
- else if (arch.cputype == CPU_TYPE_X86)
- memcpy(&best_arch, &arch, sizeof(arch));
-#endif
- }
- else if (arch.cputype == cpu_desired)
- {
- memcpy(&best_arch, &arch, sizeof(arch));
- break;
- }
- }
-
- if (best_arch.cputype == CPU_TYPE_ANY)
- {
- fprintf(stderr, "No supported architecture found in fat %s.\n", path);
- exit(1);
- }
- if (lseek(fd, best_arch.offset, SEEK_SET) == -1)
- {
- fprintf(stderr, "Cannot seek to selected arch in fat %s.\n", path);
- exit(1);
- }
-
-
- if (mh_out)
- commpage_setup(best_arch.cputype & CPU_ARCH_ABI64);
-
- if (best_arch.cputype & CPU_ARCH_ABI64)
- {
-#if !__i386__
- load64(fd, entryPoint_out, mh_out);
-#else
- abort();
-#endif
- }
- else
- {
-#if USE_32IN64 && __x86_64__
- mode_32in64 = true;
-#endif
-#if !USE_32IN64 && __x86_64__
- // Re-execute self as mldr32
- reexec32(argv);
-#else
- load32(fd, entryPoint_out, mh_out);
-#endif
- }
- }
- else
- {
- fprintf(stderr, "Unknown file format: %s.\n", path);
- exit(1);
- }
-
- close(fd);
-}
-
-#ifdef __x86_64__
-#define GEN_64BIT
-#include "loader.c"
-#undef GEN_64BIT
-#endif
-
-#define GEN_32BIT
-#include "loader.c"
-#undef GEN_32BIT
-
-int native_prot(int prot)
-{
- int protOut = 0;
-
- if (prot & VM_PROT_READ)
- protOut |= PROT_READ;
- if (prot & VM_PROT_WRITE)
- protOut |= PROT_WRITE;
- if (prot & VM_PROT_EXECUTE)
- protOut |= PROT_EXEC;
-
- return protOut;
-}
-
-// Enable the use of DYLD_ROOT_PATH also for dyld itself.
-// This is mainly used for testing.
-void apply_root_path(char* path)
-{
- const char* roots = getenv("DYLD_ROOT_PATH");
- char my_path[4096];
- const char *p, *next;
-
- if (!roots)
- return;
-
- p = roots;
-
- do
- {
- next = strchr(p, ':');
-
- if (next != NULL)
- {
- strncpy(my_path, p, next-p);
- my_path[next-p] = '\0';
- next++;
- }
- else
- {
- strcpy(my_path, p);
- }
-
- strcat(my_path, path);
-
- if (access(my_path, R_OK) == 0)
- {
- // We've found the desired path in one of the roots, switch to it
- strcpy(path, my_path);
- break;
- }
- }
- while (next != NULL);
-}
-
-char* apple0_make(const char* filepath)
-{
- static char apple0[4096] = "executable_path=";
-
- if (filepath[0] == '/')
- strcat(apple0, filepath);
- else
- {
- char* path = realpath(filepath, NULL);
- strcat(apple0, path);
- free(path);
- }
-
- return apple0;
-}
-
-#ifdef __x86_64__
-static void reexec32(char** argv)
-{
- char selfpath[1024];
- ssize_t len;
-
- len = readlink("/proc/self/exe", selfpath, sizeof(selfpath)-3);
- if (len == -1)
- {
- perror("Cannot readlink /proc/self/exe");
- abort();
- }
-
- selfpath[len] = '\0';
- strcat(selfpath, "32");
-
- execv(selfpath, argv);
-
- perror("Cannot re-execute as 32-bit process");
- abort();
-}
-#endif
-
-static void map_pagezero(void)
-{
- if (mmap(NULL, 4096, PROT_READ | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0) == MAP_FAILED)
- fprintf(stderr, "Cannot mmap page zero, some apps may crash because of this (%s)\n", strerror(errno));
-}