This patch provides Mach-O support in WineLib. As Mach-O doesn't have init and fini section, it adds support for it in dlopen. A new file mach-o.c is created. It contains functions which add support for init, and fini section.
Moreover, ntdll needs to be loaded as global. I don't know what you will think about this, but tell me if you don't like the way it is done. I change dlopen_dll() test_only params, to a flag param. When we want to do a test_only we pass 0x1 to dlopen. And when we want dlopen to open a file with RTLD_GLOBAL, we use flags other bits, to tell dlopen_dll we are in a such case. We pass the value 0x2 to load a file as RTLD_GLOBAL. This option is commented out on other platform others than Mac OS X.
By the way I didn't add a specific Macro for Mach-O, because only Darwin use this file format, but we probably should add one.
Thanks,
Pierre.
ChangeLog: - Add Support for Mach-O quirks when dlopening
Index: libs/wine/Makefile.in =================================================================== RCS file: /home/wine/wine/libs/wine/Makefile.in,v retrieving revision 1.3 diff -u -r1.3 Makefile.in --- libs/wine/Makefile.in 1 May 2003 00:39:29 -0000 1.3 +++ libs/wine/Makefile.in 21 Jul 2003 13:45:23 -0000 @@ -4,7 +4,7 @@ VPATH = @srcdir@ LIBRARY = wine SOVERSION = 1 -EXTRADEFS = -D__WINESRC__ -DDLLDIR="\"$(dlldir)\"" +EXTRADEFS = @LIBCOMMONFLAGS@ -D__WINESRC__ -DDLLDIR="\"$(dlldir)\"" EXTRALIBS = $(LIBPORT) @DLLIBS@ @CRTLIBS@ C_SRCS = \ @@ -12,7 +12,8 @@ debug.c \ errno.c \ ldt.c \ - loader.c + loader.c \ + mach-o.c @MAKE_LIB_RULES@ Index: libs/wine/loader.c =================================================================== RCS file: /home/wine/wine/libs/wine/loader.c,v retrieving revision 1.4 diff -u -r1.4 loader.c --- libs/wine/loader.c 3 Jul 2003 18:23:10 -0000 1.4 +++ libs/wine/loader.c 21 Jul 2003 13:45:24 -0000 @@ -125,9 +125,14 @@ } /* open a library for a given dll, searching in the dll path - * 'name' must be the Windows dll name (e.g. "kernel32.dll") */ + * 'name' must be the Windows dll name (e.g. "kernel32.dll") + * flags value : + * - 0 dlopen RTLD_NOW + * - 1 test only + * - 2 dlopen RTLD_NOW | RTLD_GLOBAL (only on Darwin) + */ static void *dlopen_dll( const char *name, char *error, int errorsize, - int test_only, int *exists ) + int flags, int *exists ) { int i, namelen = strlen(name); char *buffer, *p; @@ -149,7 +154,10 @@ int len = strlen(dll_paths[i]); p = buffer + dll_path_maxlen - len; memcpy( p, dll_paths[i], len ); - if (!test_only && (ret = wine_dlopen( p, RTLD_NOW, error, errorsize ))) break; + if (!flags && (ret = wine_dlopen( p, RTLD_NOW, error, errorsize ))) break; +#ifdef __APPLE__ + if ((flags == 0x2) && (ret = wine_dlopen( p, RTLD_NOW | RTLD_GLOBAL, error, errorsize ))) break; +#endif if ((*exists = file_exists( p ))) break; /* exists but cannot be loaded, return the error */ } free( buffer ); @@ -422,7 +430,7 @@ void *ntdll; void (*init_func)(int, char **); - if (!(ntdll = dlopen_dll( "ntdll.dll", error, error_size, 0, &file_exists ))) return; + if (!(ntdll = dlopen_dll( "ntdll.dll", error, error_size, 0x2, &file_exists ))) return; if (!(init_func = wine_dlsym( ntdll, "__wine_process_init", error, error_size ))) return; init_func( argc, argv ); } @@ -506,7 +514,7 @@ return result == addr; } -#endif /* __svr4__ || __NetBSD__ */ +#endif /* __svr4__ || __NetBSD__ */ /*********************************************************************** @@ -580,6 +588,12 @@ error[errorsize - 1] = '\0'; } dlerror(); + +# ifdef __APPLE__ + if(ret) + macho_call_functions_from_section_name( ret, "__wine_init"); +# endif + return ret; #else if (error) @@ -627,6 +641,11 @@ #ifdef HAVE_DLOPEN int ret; const char *s; + +# ifdef __APPLE__ + macho_call_functions_from_section_name( handle, "__wine_fini"); +# endif + dlerror(); dlerror(); ret = dlclose( handle ); s = dlerror(); --- /dev/null Mon Jul 21 14:57:03 2003 +++ libs/wine/mach-o.c Mon Jul 21 15:46:05 2003 @@ -0,0 +1,126 @@ +/* + * Mach-O (Mac OS X file format) Support + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef __APPLE__ + +#include "config.h" +#include "wine/port.h" + +#include <assert.h> +#include <ctype.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include <mach-o/loader.h> +#include <mach-o/dyld.h> +#include <mach-o/getsect.h> + +/* This is our (dlcompat) central data structure. Whenever a module is loaded via + * dlopen(), we create such a struct. + * (from the dlcompat lib) + */ +typedef struct dlstatus +{ + struct dlstatus *next; /* pointer to next element in the linked list */ + NSModule module; + const struct mach_header *lib; + /* skipped things */ +} dlstatus ; + + +/*********************************************************************** + * mach_header_from_module + */ +static const struct mach_header *mach_header_from_module(NSModule * module) +{ + struct mach_header *mach_header; + const char *name = NSNameOfModule(module); + unsigned int count = _dyld_image_count(); + unsigned int i; + + if(!module) return 0; + if(!name) return 0; + + for (i = 0; i < count; i++) + { + if (!strcmp(name, _dyld_get_image_name(i))) + { + mach_header = _dyld_get_image_header(i); + return mach_header; + } + } + return 0; +} + + +/*********************************************************************** + * macho_call_functions_from_section_name + * + * Mach-O doesn't have an init and a fini sections. Here is a Hack to + * provide one. Note that the section is a data section, with names of + * each function Separated by a '\0'. + */ +void macho_call_functions_from_section_name( dlstatus *status, char * section_name ) +{ + const struct mach_header *mach_header; + char *wine_init_section ; + unsigned long section_size; + char *function_name; + int i; + /* Check for the module */ + if(!status->module) return; + + /* Get the Mach Header */ + mach_header = mach_header_from_module(status->module); + if(!mach_header) return; + + /* point to the relative address of the section */ + wine_init_section = (void *)getsectdatafromheader(mach_header, "__DATA", section_name, §ion_size); + + if(!wine_init_section) + return; /* No section defined */ + + /* point to the absolut address of the section */ + wine_init_section = (char *)((long)wine_init_section + (long)mach_header); + + function_name = wine_init_section; + for(i = 0; i < section_size ; i++) + { + /* Are we at the end of the name */ + if(wine_init_section[i] == '\0') + { + void (*func)(); + if(!function_name) + continue; + + /* Check for function_name */ + func = dlsym(status, function_name); + + /* Call the function if it does exist */ + if(func) + func(); + + /* Set function_name to the new name we are looking for */ + function_name = wine_init_section + i + 1; + } + } +} + +#endif /* __APPLE__ */