[PATCH] libwine: Use getsegmentdata(3) on Mac OS to find the end of the __TEXT segment.

Chip Davis cdavis at codeweavers.com
Wed Aug 1 15:46:09 CDT 2018


Don't assume it ends with the fake PE header. This assumption doesn't
hold on Mac OS: the __data section where it was placed is located after
several other sections, all in the __DATA segment.

Unfortunately, this causes Wine, when DEP/NX is turned off, to override
the page protections for the start of the __DATA segment, removing write
permission from them, leading to a crash when winemac.drv attempted to
use an Objective-C class for the first time.

Also, be sure to include the zero-fill (i.e. BSS) sections in the total
size of the .data section. This should fix some tests that use large
uninitialized arrays.

Signed-off-by: Chip Davis <cdavis at codeweavers.com>
---

Notes:
    Try 2: Don't make data_start the same as code_end.
    Try 3: Reduce duplication a bit.

 libs/wine/loader.c | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/libs/wine/loader.c b/libs/wine/loader.c
index c07042a583e6..0af3b8e5204d 100644
--- a/libs/wine/loader.c
+++ b/libs/wine/loader.c
@@ -49,6 +49,7 @@
 #undef LoadResource
 #undef GetCurrentThread
 #include <pthread.h>
+#include <mach-o/getsect.h>
 #else
 extern char **environ;
 #endif
@@ -387,11 +388,15 @@ static void *map_dll( const IMAGE_NT_HEADERS *nt_descr )
     IMAGE_NT_HEADERS *nt;
     IMAGE_SECTION_HEADER *sec;
     BYTE *addr;
-    DWORD code_start, data_start, data_end;
+    DWORD code_start, code_end, data_start, data_end;
     const size_t page_size = sysconf( _SC_PAGESIZE );
     const size_t page_mask = page_size - 1;
     int delta, nb_sections = 2;  /* code + data */
     unsigned int i;
+#ifdef __APPLE__
+    Dl_info dli;
+    unsigned long data_size;
+#endif
 
     size_t size = (sizeof(IMAGE_DOS_HEADER)
                    + sizeof(IMAGE_NT_HEADERS)
@@ -425,7 +430,15 @@ static void *map_dll( const IMAGE_NT_HEADERS *nt_descr )
     delta      = (const BYTE *)nt_descr - addr;
     code_start = page_size;
     data_start = delta & ~page_mask;
+#ifdef __APPLE__
+    /* Need the mach_header, not the PE header, to give to getsegmentdata(3) */
+    dladdr(addr, &dli);
+    code_end   = getsegmentdata(dli.dli_fbase, "__DATA", &data_size) - addr;
+    data_end   = (code_end + data_size + page_mask) & ~page_mask;
+#else
+    code_end   = data_start;
     data_end   = (nt->OptionalHeader.SizeOfImage + delta + page_mask) & ~page_mask;
+#endif
 
     fixup_rva_ptrs( &nt->OptionalHeader.AddressOfEntryPoint, addr, 1 );
 
@@ -434,7 +447,7 @@ static void *map_dll( const IMAGE_NT_HEADERS *nt_descr )
 #ifndef _WIN64
     nt->OptionalHeader.BaseOfData                  = data_start;
 #endif
-    nt->OptionalHeader.SizeOfCode                  = data_start - code_start;
+    nt->OptionalHeader.SizeOfCode                  = code_end - code_start;
     nt->OptionalHeader.SizeOfInitializedData       = data_end - data_start;
     nt->OptionalHeader.SizeOfUninitializedData     = 0;
     nt->OptionalHeader.SizeOfImage                 = data_end;
@@ -443,7 +456,7 @@ static void *map_dll( const IMAGE_NT_HEADERS *nt_descr )
     /* Build the code section */
 
     memcpy( sec->Name, ".text", sizeof(".text") );
-    sec->SizeOfRawData = data_start - code_start;
+    sec->SizeOfRawData = code_end - code_start;
     sec->Misc.VirtualSize = sec->SizeOfRawData;
     sec->VirtualAddress   = code_start;
     sec->PointerToRawData = code_start;
-- 
2.18.0




More information about the wine-devel mailing list