Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 1 | /* |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 2 | * UNIX dynamic loader |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 3 | * |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 4 | * Currently only supports stuff using the dl* API. |
| 5 | * |
| 6 | * Copyright 1998 Marcus Meissner |
| 7 | * |
Alexandre Julliard | 0799c1a | 2002-03-09 23:29:33 +0000 | [diff] [blame] | 8 | * This library is free software; you can redistribute it and/or |
| 9 | * modify it under the terms of the GNU Lesser General Public |
| 10 | * License as published by the Free Software Foundation; either |
| 11 | * version 2.1 of the License, or (at your option) any later version. |
| 12 | * |
| 13 | * This library is distributed in the hope that it will be useful, |
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 16 | * Lesser General Public License for more details. |
| 17 | * |
| 18 | * You should have received a copy of the GNU Lesser General Public |
| 19 | * License along with this library; if not, write to the Free Software |
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 21 | * |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 22 | * FIXME: Small reentrancy problem. |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 23 | * IDEA(s): could be used to split up shell32,comctl32... |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 24 | */ |
| 25 | |
François Gouget | 1425941 | 2001-11-06 20:57:11 +0000 | [diff] [blame] | 26 | #include "config.h" |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 27 | #include "wine/port.h" |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 28 | |
| 29 | #include <assert.h> |
| 30 | #include <stdio.h> |
| 31 | #include <string.h> |
| 32 | #include <sys/types.h> |
| 33 | |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 34 | #include "snoop.h" |
Aric Stewart | e4d0932 | 2000-12-03 03:14:29 +0000 | [diff] [blame] | 35 | #include "file.h" |
Alexandre Julliard | 0799c1a | 2002-03-09 23:29:33 +0000 | [diff] [blame] | 36 | #include "wine/debug.h" |
Bertho Stultiens | c1d1cfe | 1999-04-18 12:14:06 +0000 | [diff] [blame] | 37 | #include "winerror.h" |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 38 | |
Alexandre Julliard | 0799c1a | 2002-03-09 23:29:33 +0000 | [diff] [blame] | 39 | WINE_DEFAULT_DEBUG_CHANNEL(win32); |
Patrik Stridvall | b4b9fae | 1999-04-19 14:56:29 +0000 | [diff] [blame] | 40 | |
Alexandre Julliard | 081ee94 | 2000-08-07 04:12:41 +0000 | [diff] [blame] | 41 | typedef struct { |
| 42 | WORD popl WINE_PACKED; /* 0x8f 0x05 */ |
| 43 | DWORD addr_popped WINE_PACKED;/* ... */ |
| 44 | BYTE pushl1 WINE_PACKED; /* 0x68 */ |
| 45 | DWORD newret WINE_PACKED; /* ... */ |
| 46 | BYTE pushl2 WINE_PACKED; /* 0x68 */ |
| 47 | DWORD origfun WINE_PACKED; /* original function */ |
| 48 | BYTE ret1 WINE_PACKED; /* 0xc3 */ |
| 49 | WORD addesp WINE_PACKED; /* 0x83 0xc4 */ |
| 50 | BYTE nrofargs WINE_PACKED; /* nr of arguments to add esp, */ |
| 51 | BYTE pushl3 WINE_PACKED; /* 0x68 */ |
| 52 | DWORD oldret WINE_PACKED; /* Filled out from popl above */ |
| 53 | BYTE ret2 WINE_PACKED; /* 0xc3 */ |
| 54 | } ELF_STDCALL_STUB; |
Ulrich Weigand | 9ffd403 | 2000-02-03 01:33:48 +0000 | [diff] [blame] | 55 | |
| 56 | #define UNIX_DLL_ENDING "so" |
| 57 | |
| 58 | #define STUBSIZE 4095 |
Alexandre Julliard | 081ee94 | 2000-08-07 04:12:41 +0000 | [diff] [blame] | 59 | #define STUBOFFSET (sizeof(IMAGE_DOS_HEADER) + \ |
| 60 | sizeof(IMAGE_NT_HEADERS) + \ |
| 61 | sizeof(IMAGE_SECTION_HEADER)) |
Ulrich Weigand | 9ffd403 | 2000-02-03 01:33:48 +0000 | [diff] [blame] | 62 | |
Alexandre Julliard | 891d23e | 2002-07-24 19:04:41 +0000 | [diff] [blame] | 63 | static FARPROC ELF_FindExportedFunction( WINE_MODREF *wm, LPCSTR funcName, int hint, BOOL snoop ); |
Ulrich Weigand | 9ffd403 | 2000-02-03 01:33:48 +0000 | [diff] [blame] | 64 | |
Alexandre Julliard | 081ee94 | 2000-08-07 04:12:41 +0000 | [diff] [blame] | 65 | static HMODULE ELF_CreateDummyModule( LPCSTR libname, LPCSTR modname ) |
Ulrich Weigand | 7df1fbb | 1998-11-01 18:01:53 +0000 | [diff] [blame] | 66 | { |
Uwe Bonnes | 73d6c13 | 1998-10-16 09:30:33 +0000 | [diff] [blame] | 67 | PIMAGE_DOS_HEADER dh; |
| 68 | PIMAGE_NT_HEADERS nth; |
| 69 | PIMAGE_SECTION_HEADER sh; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 70 | HMODULE hmod; |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 71 | |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 72 | hmod = (HMODULE)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, |
| 73 | sizeof(IMAGE_DOS_HEADER) + |
Ulrich Weigand | 1d90d69 | 1999-02-24 14:27:07 +0000 | [diff] [blame] | 74 | sizeof(IMAGE_NT_HEADERS) + |
Alexandre Julliard | 081ee94 | 2000-08-07 04:12:41 +0000 | [diff] [blame] | 75 | sizeof(IMAGE_SECTION_HEADER) + STUBSIZE ); |
Uwe Bonnes | 73d6c13 | 1998-10-16 09:30:33 +0000 | [diff] [blame] | 76 | dh = (PIMAGE_DOS_HEADER)hmod; |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 77 | dh->e_magic = IMAGE_DOS_SIGNATURE; |
| 78 | dh->e_lfanew = sizeof(IMAGE_DOS_HEADER); |
Alexandre Julliard | a5dea21 | 2002-08-09 19:57:38 +0000 | [diff] [blame] | 79 | nth = (IMAGE_NT_HEADERS *)(dh + 1); |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 80 | nth->Signature = IMAGE_NT_SIGNATURE; |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 81 | nth->FileHeader.Machine = IMAGE_FILE_MACHINE_I386; |
| 82 | nth->FileHeader.NumberOfSections = 1; |
| 83 | nth->FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER); |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 84 | nth->FileHeader.Characteristics = |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 85 | IMAGE_FILE_RELOCS_STRIPPED|IMAGE_FILE_LINE_NUMS_STRIPPED| |
| 86 | IMAGE_FILE_LOCAL_SYMS_STRIPPED|IMAGE_FILE_32BIT_MACHINE| |
| 87 | IMAGE_FILE_DLL|IMAGE_FILE_DEBUG_STRIPPED; |
| 88 | nth->OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR_MAGIC; |
| 89 | nth->OptionalHeader.SizeOfCode = 0; |
| 90 | nth->OptionalHeader.SizeOfInitializedData = 0; |
| 91 | nth->OptionalHeader.SizeOfUninitializedData = 0; |
| 92 | nth->OptionalHeader.AddressOfEntryPoint = 0; |
| 93 | nth->OptionalHeader.BaseOfCode = 0; |
| 94 | nth->OptionalHeader.MajorOperatingSystemVersion = 4; |
| 95 | nth->OptionalHeader.MajorImageVersion = 4; |
| 96 | nth->OptionalHeader.SizeOfImage = 0; |
| 97 | nth->OptionalHeader.SizeOfHeaders = 0; |
| 98 | nth->OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_NATIVE; |
| 99 | nth->OptionalHeader.DllCharacteristics = 0; |
| 100 | nth->OptionalHeader.NumberOfRvaAndSizes = 0; |
| 101 | |
| 102 | /* allocate one code section that crosses the whole process range |
| 103 | * (we could find out from internal tables ... hmm ) |
| 104 | */ |
Uwe Bonnes | 73d6c13 | 1998-10-16 09:30:33 +0000 | [diff] [blame] | 105 | sh=(PIMAGE_SECTION_HEADER)(nth+1); |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 106 | strcpy(sh->Name,".text"); |
Alexandre Julliard | 081ee94 | 2000-08-07 04:12:41 +0000 | [diff] [blame] | 107 | sh->Misc.VirtualSize = STUBSIZE; |
| 108 | sh->VirtualAddress = STUBOFFSET; /* so snoop can use it ... */ |
| 109 | sh->SizeOfRawData = STUBSIZE; |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 110 | sh->PointerToRawData = 0; |
| 111 | sh->Characteristics = IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ; |
Alexandre Julliard | 081ee94 | 2000-08-07 04:12:41 +0000 | [diff] [blame] | 112 | return hmod; |
Ulrich Weigand | 7df1fbb | 1998-11-01 18:01:53 +0000 | [diff] [blame] | 113 | } |
| 114 | |
Alexandre Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 115 | WINE_MODREF *ELF_LoadLibraryExA( LPCSTR libname, DWORD flags) |
Ulrich Weigand | 1d90d69 | 1999-02-24 14:27:07 +0000 | [diff] [blame] | 116 | { |
Ulrich Weigand | 7df1fbb | 1998-11-01 18:01:53 +0000 | [diff] [blame] | 117 | WINE_MODREF *wm; |
Alexandre Julliard | 081ee94 | 2000-08-07 04:12:41 +0000 | [diff] [blame] | 118 | HMODULE hmod; |
Ulrich Weigand | 7df1fbb | 1998-11-01 18:01:53 +0000 | [diff] [blame] | 119 | char *modname,*s,*t,*x; |
| 120 | LPVOID *dlhandle; |
James Abbatiello | e675887 | 2000-12-13 21:32:55 +0000 | [diff] [blame] | 121 | char error[256]; |
Ulrich Weigand | 7df1fbb | 1998-11-01 18:01:53 +0000 | [diff] [blame] | 122 | |
Ulrich Weigand | 1d90d69 | 1999-02-24 14:27:07 +0000 | [diff] [blame] | 123 | t = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, |
| 124 | strlen(libname) + strlen("lib.so") + 1 ); |
Ulrich Weigand | 7df1fbb | 1998-11-01 18:01:53 +0000 | [diff] [blame] | 125 | *t = '\0'; |
| 126 | /* copy path to tempvar ... */ |
| 127 | s=strrchr(libname,'/'); |
| 128 | if (!s) |
| 129 | s=strrchr(libname,'\\'); |
| 130 | if (s) { |
Marcus Meissner | 623c0d6 | 1999-07-03 16:01:42 +0000 | [diff] [blame] | 131 | s++; /* skip / or \ */ |
| 132 | /* copy everything up to s-1 */ |
| 133 | memcpy(t,libname,s-libname); |
| 134 | t[s-libname]= '\0'; |
Ulrich Weigand | 7df1fbb | 1998-11-01 18:01:53 +0000 | [diff] [blame] | 135 | } else |
| 136 | s = (LPSTR)libname; |
| 137 | modname = s; |
| 138 | /* append "lib" foo ".so" */ |
| 139 | strcat(t,"lib"); |
| 140 | x = t+strlen(t); |
| 141 | strcat(t,s); |
| 142 | s = strchr(x,'.'); |
Marcus Meissner | 9c6735e | 1999-04-01 10:09:46 +0000 | [diff] [blame] | 143 | if (s) { |
| 144 | while (s) { |
Aric Stewart | e4d0932 | 2000-12-03 03:14:29 +0000 | [diff] [blame] | 145 | if (!FILE_strcasecmp(s,".dll")) { |
Marcus Meissner | 9c6735e | 1999-04-01 10:09:46 +0000 | [diff] [blame] | 146 | strcpy(s+1,UNIX_DLL_ENDING); |
| 147 | break; |
Ulrich Weigand | 7df1fbb | 1998-11-01 18:01:53 +0000 | [diff] [blame] | 148 | } |
| 149 | s=strchr(s+1,'.'); |
Marcus Meissner | 9c6735e | 1999-04-01 10:09:46 +0000 | [diff] [blame] | 150 | } |
| 151 | } else { |
| 152 | strcat(x,"."UNIX_DLL_ENDING); |
Ulrich Weigand | 7df1fbb | 1998-11-01 18:01:53 +0000 | [diff] [blame] | 153 | } |
| 154 | |
Andreas Mohr | 786c9a6 | 2000-11-06 05:26:27 +0000 | [diff] [blame] | 155 | /* grab just the last piece of the path/filename |
| 156 | which should be the name of the library we are |
| 157 | looking to load. increment by 1 to skip the DOS slash */ |
| 158 | s = strrchr(t,'\\'); |
| 159 | s++; |
Ulrich Weigand | 7df1fbb | 1998-11-01 18:01:53 +0000 | [diff] [blame] | 160 | |
Andreas Mohr | 786c9a6 | 2000-11-06 05:26:27 +0000 | [diff] [blame] | 161 | /* ... and open the library pointed by s, while t points |
| 162 | points to the ENTIRE DOS filename of the library |
| 163 | t is returned by HeapAlloc() above and so is also used |
| 164 | with HeapFree() below */ |
James Abbatiello | e675887 | 2000-12-13 21:32:55 +0000 | [diff] [blame] | 165 | dlhandle = wine_dlopen(s,RTLD_NOW,error,sizeof(error)); |
Ulrich Weigand | 7df1fbb | 1998-11-01 18:01:53 +0000 | [diff] [blame] | 166 | if (!dlhandle) { |
James Abbatiello | e675887 | 2000-12-13 21:32:55 +0000 | [diff] [blame] | 167 | WARN("failed to load %s: %s\n", s, error); |
Ulrich Weigand | 1d90d69 | 1999-02-24 14:27:07 +0000 | [diff] [blame] | 168 | HeapFree( GetProcessHeap(), 0, t ); |
Alexandre Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 169 | SetLastError( ERROR_FILE_NOT_FOUND ); |
Bertho Stultiens | c1d1cfe | 1999-04-18 12:14:06 +0000 | [diff] [blame] | 170 | return NULL; |
Ulrich Weigand | 7df1fbb | 1998-11-01 18:01:53 +0000 | [diff] [blame] | 171 | } |
| 172 | |
Alexandre Julliard | 081ee94 | 2000-08-07 04:12:41 +0000 | [diff] [blame] | 173 | hmod = ELF_CreateDummyModule( t, modname ); |
Ulrich Weigand | 7df1fbb | 1998-11-01 18:01:53 +0000 | [diff] [blame] | 174 | |
Andreas Mohr | 9abd553 | 2001-05-24 18:43:16 +0000 | [diff] [blame] | 175 | SNOOP_RegisterDLL(hmod,libname,0,STUBSIZE/sizeof(ELF_STDCALL_STUB)); |
Alexandre Julliard | 081ee94 | 2000-08-07 04:12:41 +0000 | [diff] [blame] | 176 | |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 177 | wm = PE_CreateModule( hmod, libname, 0, 0, FALSE ); |
Alexandre Julliard | 081ee94 | 2000-08-07 04:12:41 +0000 | [diff] [blame] | 178 | wm->find_export = ELF_FindExportedFunction; |
| 179 | wm->dlhandle = dlhandle; |
Bertho Stultiens | c1d1cfe | 1999-04-18 12:14:06 +0000 | [diff] [blame] | 180 | return wm; |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 181 | } |
| 182 | |
Alexandre Julliard | 891d23e | 2002-07-24 19:04:41 +0000 | [diff] [blame] | 183 | static FARPROC ELF_FindExportedFunction( WINE_MODREF *wm, LPCSTR funcName, int hint, BOOL snoop ) |
Ulrich Weigand | 1d90d69 | 1999-02-24 14:27:07 +0000 | [diff] [blame] | 184 | { |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 185 | LPVOID fun; |
| 186 | int i,nrofargs = 0; |
Alexandre Julliard | 081ee94 | 2000-08-07 04:12:41 +0000 | [diff] [blame] | 187 | ELF_STDCALL_STUB *stub, *first_stub; |
James Abbatiello | e675887 | 2000-12-13 21:32:55 +0000 | [diff] [blame] | 188 | char error[256]; |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 189 | |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 190 | if (!HIWORD(funcName)) { |
Alexandre Julliard | a099a55 | 1999-06-12 15:45:58 +0000 | [diff] [blame] | 191 | ERR("Can't import from UNIX dynamic libs by ordinal, sorry.\n"); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 192 | return (FARPROC)0; |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 193 | } |
James Abbatiello | e675887 | 2000-12-13 21:32:55 +0000 | [diff] [blame] | 194 | fun = wine_dlsym(wm->dlhandle,funcName,error,sizeof(error)); |
Alexandre Julliard | 886604c | 2000-12-05 21:17:59 +0000 | [diff] [blame] | 195 | if (!fun) |
| 196 | { |
Alexandre Julliard | 886604c | 2000-12-05 21:17:59 +0000 | [diff] [blame] | 197 | /* we sometimes have an excess '_' at the beginning of the name */ |
| 198 | if (funcName[0]=='_') |
| 199 | { |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 200 | funcName++ ; |
James Abbatiello | e675887 | 2000-12-13 21:32:55 +0000 | [diff] [blame] | 201 | fun = wine_dlsym(wm->dlhandle,funcName,error,sizeof(error)); |
Alexandre Julliard | 886604c | 2000-12-05 21:17:59 +0000 | [diff] [blame] | 202 | } |
| 203 | } |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 204 | if (!fun) { |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 205 | /* Function@nrofargs usually marks a stdcall function |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 206 | * with nrofargs bytes that are popped at the end |
| 207 | */ |
Alexandre Julliard | 5f728ca | 2001-07-24 21:45:22 +0000 | [diff] [blame] | 208 | LPCSTR t; |
| 209 | if ((t = strchr(funcName,'@'))) |
| 210 | { |
| 211 | LPSTR fn = HeapAlloc( GetProcessHeap(), 0, t - funcName + 1 ); |
| 212 | memcpy( fn, funcName, t - funcName ); |
| 213 | fn[t - funcName] = 0; |
| 214 | nrofargs = 0; |
| 215 | sscanf(t+1,"%d",&nrofargs); |
| 216 | fun = wine_dlsym(wm->dlhandle,fn,error,sizeof(error)); |
| 217 | HeapFree( GetProcessHeap(), 0, fn ); |
| 218 | } |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 219 | } |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 220 | /* We sometimes have Win32 dlls implemented using stdcall but UNIX |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 221 | * dlls using cdecl. If we find out the number of args the function |
| 222 | * uses, we remove them from the stack using two small stubs. |
| 223 | */ |
Alexandre Julliard | 081ee94 | 2000-08-07 04:12:41 +0000 | [diff] [blame] | 224 | stub = first_stub = (ELF_STDCALL_STUB *)((char *)wm->module + STUBOFFSET); |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 225 | for (i=0;i<STUBSIZE/sizeof(ELF_STDCALL_STUB);i++) { |
| 226 | if (!stub->origfun) |
| 227 | break; |
| 228 | if (stub->origfun == (DWORD)fun) |
| 229 | break; |
| 230 | stub++; |
| 231 | } |
| 232 | if (i==STUBSIZE/sizeof(ELF_STDCALL_STUB)) { |
Alexandre Julliard | a099a55 | 1999-06-12 15:45:58 +0000 | [diff] [blame] | 233 | ERR("please report, that there are not enough slots for stdcall stubs in the ELF loader.\n"); |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 234 | assert(i<STUBSIZE/sizeof(ELF_STDCALL_STUB)); |
| 235 | } |
| 236 | if (!stub->origfun) |
| 237 | stub->origfun=(DWORD)fun; /* just a marker */ |
| 238 | |
| 239 | if (fun && nrofargs) { /* we don't need it for 0 args */ |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 240 | /* Selfmodifying entry/return stub for stdcall -> cdecl |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 241 | * conversion. |
| 242 | * - Pop returnaddress directly into our return code |
| 243 | * popl <into code below> |
| 244 | * - Replace it by pointer to start of our returncode |
| 245 | * push $newret |
| 246 | * - And call the original function |
| 247 | * jmp $orgfun |
| 248 | * - Remove the arguments no longer needed |
| 249 | * newret: add esp, <nrofargs> |
| 250 | * - Push the original returnvalue on the stack |
| 251 | * pushl <poppedvalue> |
| 252 | * - And return to it. |
| 253 | * ret |
| 254 | */ |
| 255 | |
| 256 | /* FIXME: The function stub is not reentrant. */ |
| 257 | |
| 258 | ((LPBYTE)&(stub->popl))[0] = 0x8f; |
| 259 | ((LPBYTE)&(stub->popl))[1] = 0x05; |
| 260 | stub->addr_popped = (DWORD)&(stub->oldret); |
| 261 | stub->pushl1 = 0x68; |
| 262 | stub->newret = (DWORD)&(stub->addesp); |
| 263 | stub->pushl2 = 0x68; |
| 264 | stub->origfun = (DWORD)fun; |
| 265 | stub->ret1 = 0xc3; |
| 266 | ((LPBYTE)&(stub->addesp))[0]=0x83; |
| 267 | ((LPBYTE)&(stub->addesp))[1]=0xc4; |
| 268 | stub->nrofargs = nrofargs; |
| 269 | stub->pushl3 = 0x68; |
| 270 | /* filled out by entrycode */ |
| 271 | stub->oldret = 0xdeadbeef; |
| 272 | stub->ret2 = 0xc3; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 273 | fun=(FARPROC)stub; |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 274 | } |
| 275 | if (!fun) { |
James Abbatiello | e675887 | 2000-12-13 21:32:55 +0000 | [diff] [blame] | 276 | FIXME("function %s not found: %s\n",funcName,error); |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 277 | return fun; |
| 278 | } |
Alexandre Julliard | 081ee94 | 2000-08-07 04:12:41 +0000 | [diff] [blame] | 279 | fun = SNOOP_GetProcAddress(wm->module,funcName,stub-first_stub,fun); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 280 | return (FARPROC)fun; |
Marcus Meissner | 8220bc9 | 1998-10-11 11:10:27 +0000 | [diff] [blame] | 281 | } |