mirror of
https://github.com/darlinghq/darling.git
synced 2025-02-21 10:20:32 +00:00
Allow for running 32-bit apps in 32-bit processes
Use this by default instead of 32in64
This commit is contained in:
parent
7d908aa8bf
commit
70a1ac7510
@ -17,6 +17,7 @@ function(wrap_elf name elfname)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/src/dyld)
|
||||
add_darling_library(${name} SHARED ${CMAKE_CURRENT_BINARY_DIR}/${name}.c)
|
||||
target_link_libraries(${name} PRIVATE system)
|
||||
make_fat(${name})
|
||||
install(TARGETS ${name} DESTINATION libexec/darling/usr/lib/native)
|
||||
endfunction(wrap_elf)
|
||||
|
||||
|
@ -11,7 +11,7 @@ enable_language(C ASM)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-Ttext-segment,0x400000 -Wl,-Tbss,0x410000 -Wl,-Tdata,0x420000")
|
||||
#set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-Ttext-segment,0x400000 -Wl,-Tbss,0x410000 -Wl,-Tdata,0x420000")
|
||||
add_definitions(-DINSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}" -D_GNU_SOURCE -DMLDR_BUILD)
|
||||
|
||||
add_executable(darling darling.c)
|
||||
@ -28,10 +28,18 @@ set(mldr_sources
|
||||
add_executable(mldr ${mldr_sources})
|
||||
target_link_libraries(mldr pthread dl)
|
||||
|
||||
add_executable(mldr32 ${mldr_sources})
|
||||
target_link_libraries(mldr32 pthread dl)
|
||||
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 DESTINATION libexec/darling/bin)
|
||||
install(TARGETS mldr mldr32 DESTINATION libexec/darling/bin)
|
||||
install(TARGETS darling DESTINATION bin
|
||||
PERMISSIONS
|
||||
OWNER_READ OWNER_WRITE OWNER_EXECUTE
|
||||
|
@ -42,24 +42,34 @@ void gdb_notifier(enum dyld_image_mode mode, uint32_t infoCount, const struct dy
|
||||
|
||||
struct jump
|
||||
{
|
||||
#ifdef __x86_64__
|
||||
uint16_t mov;
|
||||
void* addr;
|
||||
uint16_t jump;
|
||||
#elif __i386__
|
||||
uint8_t mov;
|
||||
void* addr;
|
||||
uint16_t jump;
|
||||
#endif
|
||||
} __attribute__ ((packed));
|
||||
|
||||
void setup_gdb_notifications(uint64_t slide, uint64_t addr)
|
||||
void setup_gdb_notifications(uintptr_t slide, uintptr_t addr)
|
||||
{
|
||||
orig_dyld_all_image_infos = (struct dyld_all_image_infos*)(addr + slide);
|
||||
|
||||
// dyld will later rebase the address in notification,
|
||||
// but at this point we must add slide manually.
|
||||
struct jump* jump = (struct jump*)(((uint64_t)orig_dyld_all_image_infos->notification) + slide);
|
||||
struct jump* jump = (struct jump*)(((uintptr_t)orig_dyld_all_image_infos->notification) + slide);
|
||||
|
||||
// Rewrite instructions in the notification function to redirect the call to us.
|
||||
#ifdef __x86_64__
|
||||
jump->mov = 0xb948; // movabs imm,%rcx
|
||||
jump->addr = (void*) &dyld_notification_wrapper; // immediate for preceding movabs
|
||||
jump->jump = 0xe1ff; // jmpq *%ecx
|
||||
jump->jump = 0xe1ff; // jmpq *%rcx
|
||||
#elif __i386__
|
||||
jump->mov = 0xb9; // mov imm,%ecx
|
||||
jump->addr = (void*) &dyld_notification_wrapper; // immediate for preceding mov
|
||||
jump->jump = 0xe1ff; // jmpl *%ecx
|
||||
#else
|
||||
# error TODO: Unsupported platform
|
||||
#endif
|
||||
|
@ -26,7 +26,7 @@ along with Darling. If not, see <http://www.gnu.org/licenses/>.
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void setup_gdb_notifications(uint64_t slide, uint64_t addr);
|
||||
void setup_gdb_notifications(uintptr_t slide, uintptr_t addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -24,14 +24,14 @@
|
||||
# error See above
|
||||
#endif
|
||||
|
||||
void FUNCTION_NAME(int fd, uint64_t* entryPoint_out, uint64_t* mh_out)
|
||||
void FUNCTION_NAME(int fd, uintptr_t* entryPoint_out, uintptr_t* mh_out)
|
||||
{
|
||||
struct MACH_HEADER_STRUCT header;
|
||||
uint8_t* cmds;
|
||||
uint64_t entryPoint = 0, entryPointDylinker = 0;
|
||||
uintptr_t entryPoint = 0, entryPointDylinker = 0;
|
||||
struct MACH_HEADER_STRUCT* mappedHeader = NULL;
|
||||
uint64_t slide = 0;
|
||||
uint64_t mmapSize = 0;
|
||||
uintptr_t slide = 0;
|
||||
uintptr_t mmapSize = 0;
|
||||
bool pie = false;
|
||||
uint32_t fat_offset;
|
||||
|
||||
@ -58,7 +58,7 @@ void FUNCTION_NAME(int fd, uint64_t* entryPoint_out, uint64_t* mh_out)
|
||||
|
||||
if ((header.filetype == MH_EXECUTE && header.flags & MH_PIE) || header.filetype == MH_DYLINKER)
|
||||
{
|
||||
uint64_t base = -1;
|
||||
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++)
|
||||
@ -80,8 +80,8 @@ void FUNCTION_NAME(int fd, uint64_t* entryPoint_out, uint64_t* mh_out)
|
||||
p += seg->cmdsize;
|
||||
}
|
||||
|
||||
slide = (uint64_t) mmap((void*) base, mmapSize, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_EXTRA, -1, 0);
|
||||
if (slide == (uint64_t)MAP_FAILED)
|
||||
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);
|
||||
@ -183,7 +183,7 @@ no_slide:
|
||||
|
||||
if (length > sizeof(path)-1)
|
||||
{
|
||||
fprintf(stderr, "Dynamic linker name too long: %lu\n", length);
|
||||
fprintf(stderr, "Dynamic linker name too long: %zu\n", length);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -193,10 +193,10 @@ no_slide:
|
||||
apply_root_path(path);
|
||||
|
||||
#ifdef GEN_64BIT
|
||||
load(path, &entryPointDylinker, NULL, CPU_TYPE_X86_64);
|
||||
load(path, &entryPointDylinker, NULL, CPU_TYPE_X86_64, NULL);
|
||||
#endif
|
||||
#ifdef GEN_32BIT
|
||||
load(path, &entryPointDylinker, NULL, CPU_TYPE_X86);
|
||||
load(path, &entryPointDylinker, NULL, CPU_TYPE_X86, NULL);
|
||||
#endif
|
||||
|
||||
break;
|
||||
@ -218,7 +218,7 @@ no_slide:
|
||||
if (entryPoint_out != NULL)
|
||||
*entryPoint_out = entryPointDylinker ? entryPointDylinker : entryPoint;
|
||||
if (mh_out != NULL)
|
||||
*mh_out = (uint64_t) mappedHeader;
|
||||
*mh_out = (uintptr_t) mappedHeader;
|
||||
}
|
||||
|
||||
|
||||
|
@ -37,6 +37,8 @@ along with Darling. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "commpage.h"
|
||||
#include "32in64.h"
|
||||
|
||||
#define USE_32IN64 0
|
||||
|
||||
#ifndef PAGE_SIZE
|
||||
# define PAGE_SIZE 4096
|
||||
#endif
|
||||
@ -56,21 +58,28 @@ static const char* dyld_path = INSTALL_PREFIX "/libexec/usr/lib/dyld";
|
||||
//
|
||||
// Additionally, mldr providers access to native platforms libdl.so APIs (ELF loader).
|
||||
|
||||
static void load64(int fd, uint64_t* entryPoint_out, uint64_t* mh_out);
|
||||
static void load32(int fd, uint64_t* entryPoint_out, uint64_t* mh_out);
|
||||
static void load(const char* path, uint64_t* entryPoint_out, uint64_t* mh_out, cpu_type_t cpu);
|
||||
#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);
|
||||
|
||||
#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)
|
||||
{
|
||||
uint64_t entryPoint, mh;
|
||||
uintptr_t entryPoint, mh;
|
||||
void** sp;
|
||||
int pushCount = 0;
|
||||
const char* apple[3];
|
||||
@ -91,6 +100,12 @@ int main(int argc, char** argv, char** envp)
|
||||
else
|
||||
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++)
|
||||
@ -104,9 +119,7 @@ int main(int argc, char** argv, char** envp)
|
||||
memset(p, 0, envp[0]-p);
|
||||
argv[--argc] = NULL;
|
||||
|
||||
load(filename, &entryPoint, &mh, CPU_TYPE_ANY);
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
#if __i386__ || __x86_64__
|
||||
if (getenv("BREAK_AFTER_LOAD") != NULL)
|
||||
__asm__("int3");
|
||||
#endif
|
||||
@ -128,7 +141,9 @@ int main(int argc, char** argv, char** envp)
|
||||
apple[1] = elfcalls_make();
|
||||
apple[2] = NULL;
|
||||
|
||||
#if USE_32IN64
|
||||
if (!mode_32in64)
|
||||
#endif
|
||||
{
|
||||
GETSP(sp);
|
||||
sp--;
|
||||
@ -149,6 +164,7 @@ int main(int argc, char** argv, char** envp)
|
||||
|
||||
JUMPX(pushCount, entryPoint);
|
||||
}
|
||||
#if USE_32IN64
|
||||
else
|
||||
{
|
||||
uint32_t size = stack_size ? stack_size : 8*1024*1024;
|
||||
@ -165,7 +181,7 @@ int main(int argc, char** argv, char** envp)
|
||||
|
||||
_64TO32_WITH_STACK(setup_stack32(sp, argc, (const char**) argv, (const char**) envp, apple, mh), entryPoint);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
__builtin_unreachable();
|
||||
}
|
||||
@ -189,7 +205,8 @@ static size_t arraylen(const char** str)
|
||||
return len;
|
||||
}
|
||||
|
||||
void* setup_stack32(void* stack, int argc, const char** argv_in, const char** envp_in, const char** apple_in, uint64_t mh)
|
||||
#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;
|
||||
@ -231,8 +248,9 @@ void* setup_stack32(void* stack, int argc, const char** argv_in, const char** en
|
||||
|
||||
return stack_pointers;
|
||||
}
|
||||
#endif
|
||||
|
||||
void load(const char* path, uint64_t* entryPoint_out, uint64_t* mh_out, cpu_type_t cpu_desired)
|
||||
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;
|
||||
@ -244,7 +262,7 @@ void load(const char* path, uint64_t* entryPoint_out, uint64_t* mh_out, cpu_type
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// TODO: We need to read argv[1] and detect whether it's a 32 or 64-bit application.
|
||||
// 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
|
||||
@ -258,20 +276,30 @@ void load(const char* path, uint64_t* entryPoint_out, uint64_t* mh_out, cpu_type
|
||||
|
||||
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)
|
||||
{
|
||||
@ -349,11 +377,24 @@ void load(const char* path, uint64_t* entryPoint_out, uint64_t* mh_out, cpu_type
|
||||
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
|
||||
@ -365,9 +406,11 @@ void load(const char* path, uint64_t* entryPoint_out, uint64_t* mh_out, cpu_type
|
||||
close(fd);
|
||||
}
|
||||
|
||||
#ifdef __x86_64__
|
||||
#define GEN_64BIT
|
||||
#include "loader.c"
|
||||
#undef GEN_64BIT
|
||||
#endif
|
||||
|
||||
#define GEN_32BIT
|
||||
#include "loader.c"
|
||||
@ -443,3 +486,26 @@ char* apple0_make(const char* filepath)
|
||||
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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user