about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2024-08-17 15:59:09 +0200
committerptitSeb <sebastien.chev@gmail.com>2024-08-17 15:59:09 +0200
commitc845d0cf81a259e0d21be46841dc41a0f0ba5b0e (patch)
tree4c34964f41a1e28c1c833266463b55c4ff7c1a3c /src
parentd47b1b0e5679652e6b5fb5fd4cee52b775229a63 (diff)
downloadbox64-c845d0cf81a259e0d21be46841dc41a0f0ba5b0e.tar.gz
box64-c845d0cf81a259e0d21be46841dc41a0f0ba5b0e.zip
[BOX32] Added 32bits elf alloc and load
Diffstat (limited to 'src')
-rw-r--r--src/core.c4
-rw-r--r--src/custommem.c26
-rw-r--r--src/custommmap.c3
-rw-r--r--src/elfs/elfloader.c7
-rw-r--r--src/elfs/elfloader32.c249
-rw-r--r--src/include/custommem.h3
-rw-r--r--src/librarian/library.c4
7 files changed, 288 insertions, 8 deletions
diff --git a/src/core.c b/src/core.c
index bfba08f8..eae05d67 100644
--- a/src/core.c
+++ b/src/core.c
@@ -2087,8 +2087,10 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
     }
     #ifdef BOX32
     box64_is32bits = FileIsX86ELF(my_context->fullpath);
-    if(box64_is32bits)
+    if(box64_is32bits) {
         printf_log(LOG_INFO, "BOX64: Using Box32 to load 32bits elf\n");
+        reserveHighMem();
+    }
     #endif
     elfheader_t *elf_header = LoadAndCheckElfHeader(f, my_context->fullpath, 1);
     if(!elf_header) {
diff --git a/src/custommem.c b/src/custommem.c
index da11885f..06b48328 100644
--- a/src/custommem.c
+++ b/src/custommem.c
@@ -1438,6 +1438,21 @@ void* find47bitBlockElf(size_t size, int mainbin, uintptr_t mask)
     return ret;
 }
 
+void* find31bitBlockElf(size_t size, int mainbin, uintptr_t mask)
+{
+    static void* startingpoint = NULL;
+    if(!startingpoint) {
+        startingpoint = (void*)WINE_LOWEST;
+    }
+    void* mainaddr = (void*)0x1000000;
+    void* ret = find31bitBlockNearHint(MEDIUM, size, mask);
+    if(!ret)
+        ret = find31bitBlockNearHint(LOWEST, size, mask);
+    if(!mainbin)
+        startingpoint = (void*)(((uintptr_t)startingpoint+size+0x1000000)&~0xffffff);
+    return ret;
+}
+
 int isBlockFree(void* hint, size_t size)
 {
     uint32_t prot;
@@ -1510,10 +1525,10 @@ static void atfork_child_custommem(void)
 void my_reserveHighMem()
 {
     static int reserved = 0;
-    if(reserved || !have48bits)
+    if(reserved || (!have48bits && !box64_is32bits))
         return;
     reserved = 1;
-    uintptr_t cur = 1ULL<<47;
+    uintptr_t cur = box64_is32bits?(1ULL<<32):(1ULL<<47);
     uintptr_t bend = 0;
     uint32_t prot;
     while (bend!=0xffffffffffffffffLL) {
@@ -1533,12 +1548,13 @@ void my_reserveHighMem()
 void reserveHighMem()
 {
     char* p = getenv("BOX64_RESERVE_HIGH");
+    if(!box64_is32bits)
     #if 0//def ADLINK
-    if(p && p[0]=='0')
+        if(p && p[0]=='0')
     #else
-    if(!p || p[0]=='0')
+        if(!p || p[0]=='0')
     #endif
-        return; // don't reserve by default
+            return; // don't reserve by default
     my_reserveHighMem();
 }
 
diff --git a/src/custommmap.c b/src/custommmap.c
index 93173098..7ad26b7d 100644
--- a/src/custommmap.c
+++ b/src/custommmap.c
@@ -15,6 +15,7 @@
 
 typedef void x64emu_t;
 extern void* mapallmem;
+extern int box64_is32bits;
 void setProtection(uintptr_t addr, size_t size, uint32_t prot);
 void freeProtection(uintptr_t addr, size_t size);
 void* internal_mmap(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset);
@@ -28,7 +29,7 @@ extern int box64_mmap32;
 EXPORT void* mmap64(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset)
 {
     void* ret;
-    if(!addr && ((running32bits && box64_mmap32) || (flags&0x40)))
+    if(!addr && ((running32bits && box64_mmap32) || (flags&0x40) || box64_is32bits))
         ret = my_mmap64(NULL, addr, length, prot, flags | 0x40, fd, offset);
     else
         ret = internal_mmap(addr, length, prot, flags, fd, offset);
diff --git a/src/elfs/elfloader.c b/src/elfs/elfloader.c
index beeacbfb..e206fcc6 100644
--- a/src/elfs/elfloader.c
+++ b/src/elfs/elfloader.c
@@ -202,7 +202,12 @@ const char* ElfPath(elfheader_t* head)
     return head->path;
 }
 
-int AllocLoadElfMemory32(box64context_t* context, elfheader_t* head, int mainbin) { /*TODO*/ return 1; }
+int AllocLoadElfMemory32(box64context_t* context, elfheader_t* head, int mainbin)
+#ifndef BOX32
+{ return 1; }
+#else
+ ;
+#endif
 int AllocLoadElfMemory(box64context_t* context, elfheader_t* head, int mainbin)
 {
     if(box64_is32bits)
diff --git a/src/elfs/elfloader32.c b/src/elfs/elfloader32.c
new file mode 100644
index 00000000..1da3fc3b
--- /dev/null
+++ b/src/elfs/elfloader32.c
@@ -0,0 +1,249 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <elf.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <sys/types.h>
+#include <link.h>
+#include <unistd.h>
+#include <errno.h>
+#ifndef _DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include "custommem.h"
+#include "box64version.h"
+#include "elfloader.h"
+#include "debug.h"
+#include "elfload_dump.h"
+#include "elfloader_private.h"
+#include "librarian.h"
+#include "x64run.h"
+#include "bridge.h"
+#include "wrapper.h"
+#include "box64context.h"
+#include "library.h"
+#include "x64emu.h"
+#include "box64stack.h"
+#include "callback.h"
+#include "box64stack.h"
+#include "wine_tools.h"
+#include "dictionnary.h"
+#include "symbols.h"
+#ifdef DYNAREC
+#include "dynablock.h"
+#endif
+#include "../emu/x64emu_private.h"
+#include "../emu/x64run_private.h"
+#include "../tools/bridge_private.h"
+#include "x64tls.h"
+#include "box32.h"
+
+int AllocLoadElfMemory32(box64context_t* context, elfheader_t* head, int mainbin)
+{
+    ptr_t offs = 0;
+    loadProtectionFromMap();
+    int log_level = box64_load_addr?LOG_INFO:LOG_DEBUG;
+
+    head->multiblock_n = 0; // count PHEntrie with LOAD
+    uintptr_t max_align = (box64_pagesize-1);
+    for (size_t i=0; i<head->numPHEntries; ++i) 
+        if(head->PHEntries._32[i].p_type == PT_LOAD && head->PHEntries._32[i].p_flags) {
+            ++head->multiblock_n;
+        }
+
+    if(!head->vaddr && box64_load_addr) {
+        offs = to_ptrv(find31bitBlockNearHint((void*)box64_load_addr, head->memsz, max_align));
+        box64_load_addr = offs + head->memsz;
+        box64_load_addr = (box64_load_addr+0x10ffffff)&~0xffffff;
+    }
+    if(!offs && !head->vaddr)
+        offs = (uintptr_t)find31bitBlockElf(head->memsz, mainbin, max_align);
+    // prereserve the whole elf image, without populating
+    size_t sz = head->memsz;
+    void* raw = NULL;
+    void* image = NULL;
+    if(!head->vaddr) {
+        sz += head->align;
+        raw = mmap64(from_ptrv(offs), sz, 0, MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
+        image = (void*)(((uintptr_t)raw+max_align)&~max_align);
+    } else {
+        image = raw = mmap64(from_ptrv(head->vaddr), sz, 0, MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
+    }
+    if(image!=MAP_FAILED && !head->vaddr && image!=from_ptrv(offs)) {
+        printf_log(LOG_INFO, "%s: Mmap64 for (@%p 0x%zx) for elf \"%s\" returned %p(%p/0x%zx) instead\n", (((uintptr_t)image)&max_align)?"Error":"Warning", from_ptrv(head->vaddr?head->vaddr:offs), head->memsz, head->name, image, raw, head->align);
+        offs = to_ptrv(image);
+        if(((uintptr_t)image)&max_align) {
+            munmap(raw, sz);
+            return 1;   // that's an error, alocated memory is not aligned properly
+        }
+    }
+    if(image==MAP_FAILED || image!=from_ptrv(head->vaddr?head->vaddr:offs)) {
+        printf_log(LOG_NONE, "%s cannot create memory map (@%p 0x%zx) for elf \"%s\"", (image==MAP_FAILED)?"Error:":"Warning:", from_ptrv(head->vaddr?head->vaddr:offs), head->memsz, head->name);
+        if(image==MAP_FAILED) {
+            printf_log(LOG_NONE, " error=%d/%s\n", errno, strerror(errno));
+        } else {
+            printf_log(LOG_NONE, " got %p\n", image);
+        }
+        if(image==MAP_FAILED)
+            return 1;
+        offs = to_ptrv(image)-head->vaddr;
+    }
+    printf_dump(log_level, "Pre-allocated 0x%zx byte at %p for %s\n", head->memsz, image, head->name);
+    head->delta = offs;
+    printf_dump(log_level, "Delta of %p (vaddr=%p) for Elf \"%s\"\n", from_ptrv(offs), from_ptrv(head->vaddr), head->name);
+
+    head->image = image;
+    head->raw = raw;
+    head->raw_size = sz;
+    setProtection_elf((uintptr_t)raw, sz, 0);
+
+    head->multiblocks = (multiblock_t*)box_calloc(head->multiblock_n, sizeof(multiblock_t));
+    head->tlsbase = AddTLSPartition(context, head->tlssize);
+    // and now, create all individual blocks
+    head->memory = (char*)0xffffffff;
+    int n = 0;
+    for (size_t i=0; i<head->numPHEntries; ++i) {
+        if(head->PHEntries._32[i].p_type == PT_LOAD && head->PHEntries._32[i].p_flags) {
+            Elf32_Phdr * e = &head->PHEntries._32[i];
+
+            head->multiblocks[n].flags = e->p_flags;
+            head->multiblocks[n].offs = e->p_offset;
+            head->multiblocks[n].paddr = e->p_paddr + offs;
+            head->multiblocks[n].size = e->p_filesz;
+            head->multiblocks[n].align = e->p_align;
+            uint8_t prot = PROT_READ|PROT_WRITE|((e->p_flags & PF_X)?PROT_EXEC:0);
+            // check if alignment is correct
+            uintptr_t balign = head->multiblocks[n].align-1;
+            if(balign<4095) balign = 4095;
+            head->multiblocks[n].asize = (e->p_memsz+(e->p_paddr&balign)+4095)&~4095;
+            int try_mmap = 1;
+            if(e->p_paddr&balign)
+                try_mmap = 0;
+            if(e->p_offset&(box64_pagesize-1))
+                try_mmap = 0;
+            if(ALIGN(e->p_memsz)!=ALIGN(e->p_filesz))
+                try_mmap = 0;
+            if(!e->p_filesz)
+                try_mmap = 0;
+            if(e->p_align<box64_pagesize)
+                try_mmap = 0;
+            if(try_mmap) {
+                printf_dump(log_level, "Mmaping 0x%lx(0x%lx) bytes @%p for Elf \"%s\"\n", head->multiblocks[n].size, head->multiblocks[n].asize, (void*)head->multiblocks[n].paddr, head->name);
+                void* p = mmap64(
+                    (void*)head->multiblocks[n].paddr, 
+                    head->multiblocks[n].size, 
+                    prot,
+                    MAP_PRIVATE|MAP_FIXED, //((prot&PROT_WRITE)?MAP_SHARED:MAP_PRIVATE)|MAP_FIXED,
+                    head->fileno,
+                    e->p_offset
+                );
+                if(p==MAP_FAILED || p!=(void*)head->multiblocks[n].paddr) {
+                    try_mmap = 0;
+                    printf_dump(log_level, "Mapping failed, using regular mmap+read");
+                } else {
+                    if(e->p_memsz>e->p_filesz && (prot&PROT_WRITE))
+                        memset((void*)((uintptr_t)p + e->p_filesz), 0, e->p_memsz-e->p_filesz);
+                    setProtection_elf((uintptr_t)p, head->multiblocks[n].asize, prot);
+                    head->multiblocks[n].p = p;
+
+                }
+            }
+            if(!try_mmap) {
+                uintptr_t paddr = head->multiblocks[n].paddr&~balign;
+                size_t asize = head->multiblocks[n].asize;
+                void* p = MAP_FAILED;
+                if(paddr==(paddr&~(box64_pagesize-1)) && (asize==ALIGN(asize))) {
+                    printf_dump(log_level, "Allocating 0x%zx (0x%zx) bytes @%p, will read 0x%zx @%p for Elf \"%s\"\n", asize, e->p_memsz, (void*)paddr, e->p_filesz, (void*)head->multiblocks[n].paddr, head->name);
+                    p = mmap64(
+                        (void*)paddr,
+                        asize,
+                        prot|PROT_WRITE,
+                        MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED,
+                        -1,
+                        0
+                    );
+                } else {
+                    // difference in pagesize, so need to mmap only what needed to be...
+                    //check startint point
+                    uintptr_t new_addr = paddr;
+                    ssize_t new_size = asize;
+                    while(getProtection(new_addr) && (new_size>0)) {
+                        new_size -= ALIGN(new_addr) - new_addr;
+                        new_addr = ALIGN(new_addr);
+                    }
+                    if(new_size>0) {
+                        printf_dump(log_level, "Allocating 0x%zx (0x%zx) bytes @%p, will read 0x%zx @%p for Elf \"%s\"\n", ALIGN(new_size), e->p_memsz, (void*)new_addr, e->p_filesz, (void*)head->multiblocks[n].paddr, head->name);
+                        p = mmap64(
+                            (void*)new_addr,
+                            ALIGN(new_size),
+                            prot|PROT_WRITE,
+                            MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED,
+                            -1,
+                            0
+                        );
+                        if(p==(void*)new_addr)
+                            p = (void*)paddr;
+                    } else {
+                        p = (void*)paddr;
+                        printf_dump(log_level, "Will read 0x%zx @%p for Elf \"%s\"\n", e->p_filesz, (void*)head->multiblocks[n].paddr, head->name);    
+                    }
+                }
+                if(p==MAP_FAILED || p!=(void*)paddr) {
+                    printf_log(LOG_NONE, "Cannot create memory map (@%p 0x%zx/0x%zx) for elf \"%s\"", (void*)paddr, asize, balign, head->name);
+                    if(p==MAP_FAILED) {
+                        printf_log(LOG_NONE, " error=%d/%s\n", errno, strerror(errno));
+                    } else {
+                        printf_log(LOG_NONE, " got %p\n", p);
+                    }
+                    return 1;
+                }
+                setProtection_elf((uintptr_t)p, asize, prot);
+                head->multiblocks[n].p = p;
+                if(e->p_filesz) {
+                    fseeko64(head->file, head->multiblocks[n].offs, SEEK_SET);
+                    if(fread((void*)head->multiblocks[n].paddr, head->multiblocks[n].size, 1, head->file)!=1) {
+                        printf_log(LOG_NONE, "Cannot read elf block (@%p 0x%zx/0x%zx) for elf \"%s\"\n", (void*)head->multiblocks[n].offs, head->multiblocks[n].asize, balign, head->name);
+                        return 1;
+                    }
+                }
+                if(!(prot&PROT_WRITE) && (paddr==(paddr&(box64_pagesize-1)) && (asize==ALIGN(asize))))
+                    mprotect((void*)paddr, asize, prot);
+            }
+#ifdef DYNAREC
+            if(box64_dynarec && (e->p_flags & PF_X)) {
+                dynarec_log(LOG_DEBUG, "Add ELF eXecutable Memory %p:%p\n", head->multiblocks[n].p, (void*)head->multiblocks[n].asize);
+                addDBFromAddressRange((uintptr_t)head->multiblocks[n].p, head->multiblocks[n].asize);
+            }
+#endif
+            if((uintptr_t)head->memory>(uintptr_t)head->multiblocks[n].p)
+                head->memory = (char*)head->multiblocks[n].p;
+            ++n;
+        }
+        if(head->PHEntries._32[i].p_type == PT_TLS) {
+            Elf32_Phdr * e = &head->PHEntries._32[i];
+            char* dest = (char*)(context->tlsdata+context->tlssize+head->tlsbase);
+            printf_log(LOG_DEBUG, "Loading TLS block #%zu @%p (0x%zx/0x%zx)\n", i, dest, e->p_filesz, e->p_memsz);
+            if(e->p_filesz) {
+                fseeko64(head->file, e->p_offset, SEEK_SET);
+                if(fread(dest, e->p_filesz, 1, head->file)!=1) {
+                    printf_log(LOG_NONE, "Fail to read PT_TLS part #%zu (size=%zd)\n", i, e->p_filesz);
+                    return 1;
+                }
+            }
+            // zero'd difference between filesz and memsz
+            if(e->p_filesz != e->p_memsz)
+                memset(dest+e->p_filesz, 0, e->p_memsz - e->p_filesz);
+        }
+    }
+
+    // can close the elf file now!
+    fclose(head->file);
+    head->file = NULL;
+    head->fileno = -1;
+
+    return 0;
+}
diff --git a/src/include/custommem.h b/src/include/custommem.h
index dda21053..ba5441d1 100644
--- a/src/include/custommem.h
+++ b/src/include/custommem.h
@@ -102,6 +102,7 @@ void* find31bitBlockNearHint(void* hint, size_t size, uintptr_t mask);
 void* find47bitBlock(size_t size);
 void* find47bitBlockNearHint(void* hint, size_t size, uintptr_t mask); // mask can be 0 for default one (0xffff)
 void* find47bitBlockElf(size_t size, int mainbin, uintptr_t mask);
+void* find31bitBlockElf(size_t size, int mainbin, uintptr_t mask);
 int isBlockFree(void* hint, size_t size);
 
 // unlock mutex that are locked by current thread (for signal handling). Return a mask of unlock mutex
@@ -125,4 +126,6 @@ int checkInHotPage(uintptr_t addr);
 void* internal_mmap(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset);
 int internal_munmap(void* addr, unsigned long length);
 
+void reserveHighMem();
+
 #endif //__CUSTOM_MEM__H_
diff --git a/src/librarian/library.c b/src/librarian/library.c
index 350a68a9..69f27d5f 100644
--- a/src/librarian/library.c
+++ b/src/librarian/library.c
@@ -232,6 +232,10 @@ int DummyLib_GetLocal(library_t* lib, const char* name, uintptr_t *offs, uintptr
 }
 
 static void initWrappedLib(library_t *lib, box64context_t* context) {
+    if(box64_is32bits) {
+        // TODO
+        return; // nothing wrapped yet
+    }
     int nb = sizeof(wrappedlibs) / sizeof(wrappedlib_t);
     for (int i=0; i<nb; ++i) {
         if(strcmp(lib->name, wrappedlibs[i].name)==0) {