Touch to test auto mailing of commits.
[wine/multimedia.git] / loader / elf.c
blob5c5c9b4e25a6ae78aa15ef157384abbdc21944e5
1 /*
2 * UNIX dynamic loader
3 *
4 * Currently only supports stuff using the dl* API.
6 * Copyright 1998 Marcus Meissner
8 * FIXME: Small reentrancy problem.
9 * IDEA(s): could be used to split up shell32,comctl32...
12 #include "config.h"
14 #include <assert.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <sys/types.h>
19 #include "windows.h"
20 #include "snoop.h"
21 #include "process.h"
22 #include "peexe.h"
23 #include "heap.h"
24 #include "pe_image.h"
25 #include "module.h"
26 #include "debug.h"
28 #if defined(HAVE_LIBDL) && defined(HAVE_DLFCN_H)
30 #define UNIX_DLL_ENDING "so"
32 #define STUBSIZE 4095
34 #include <dlfcn.h>
36 HMODULE32
37 ELF_LoadLibraryEx32A(LPCSTR libname,PDB32 *process,HANDLE32 hf,DWORD flags) {
38 WINE_MODREF *wm;
39 char *modname,*s,*t,*x;
40 LPVOID *dlhandle;
41 LPIMAGE_DOS_HEADER dh;
42 LPIMAGE_NT_HEADERS nth;
43 LPIMAGE_SECTION_HEADER sh;
44 HMODULE32 hmod;
46 t = HeapAlloc(process->heap,HEAP_ZERO_MEMORY,strlen(libname)+strlen("lib.so")+1);
47 *t = '\0';
48 /* copy path to tempvar ... */
49 s=strrchr(libname,'/');
50 if (!s)
51 s=strrchr(libname,'\\');
52 if (s) {
53 strncpy(t,libname,s-libname+1);
54 t[libname-s+1]= '\0';
55 } else
56 s = (LPSTR)libname;
57 modname = s;
58 /* append "lib" foo ".so" */
59 strcat(t,"lib");
60 x = t+strlen(t);
61 strcat(t,s);
62 s = strchr(x,'.');
63 while (s) {
64 if (!strcasecmp(s,".dll")) {
65 strcpy(s+1,UNIX_DLL_ENDING);
66 break;
68 s=strchr(s+1,'.');
71 /* FIXME: make UNIX filename from DOS fn? */
73 /* ... and open it */
74 dlhandle = dlopen(t,RTLD_NOW);
75 if (!dlhandle) {
76 HeapFree(process->heap,0,t);
77 return 0;
79 wm=(WINE_MODREF*)HeapAlloc(process->heap,HEAP_ZERO_MEMORY,sizeof(*wm));
80 wm->type = MODULE32_ELF;
81 wm->binfmt.elf.dlhandle = dlhandle;
83 /* FIXME: hmm, order? */
84 wm->next = process->modref_list;
85 process->modref_list = wm;
87 wm->modname = HEAP_strdupA(process->heap,0,modname);
88 wm->longname = HEAP_strdupA(process->heap,0,t);
90 hmod = (HMODULE32)HeapAlloc(process->heap,HEAP_ZERO_MEMORY,sizeof(IMAGE_DOS_HEADER)+sizeof(IMAGE_NT_HEADERS)+sizeof(IMAGE_SECTION_HEADER)+100);
91 dh = (LPIMAGE_DOS_HEADER)hmod;
92 dh->e_magic = IMAGE_DOS_SIGNATURE;
93 dh->e_lfanew = sizeof(IMAGE_DOS_HEADER);
94 nth = PE_HEADER(hmod);
95 nth->Signature = IMAGE_NT_SIGNATURE;
96 nth->FileHeader.Machine = IMAGE_FILE_MACHINE_I386;
97 nth->FileHeader.NumberOfSections = 1;
98 nth->FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
99 nth->FileHeader.Characteristics =
100 IMAGE_FILE_RELOCS_STRIPPED|IMAGE_FILE_LINE_NUMS_STRIPPED|
101 IMAGE_FILE_LOCAL_SYMS_STRIPPED|IMAGE_FILE_32BIT_MACHINE|
102 IMAGE_FILE_DLL|IMAGE_FILE_DEBUG_STRIPPED;
103 nth->OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR_MAGIC;
104 nth->OptionalHeader.SizeOfCode = 0;
105 nth->OptionalHeader.SizeOfInitializedData = 0;
106 nth->OptionalHeader.SizeOfUninitializedData = 0;
107 nth->OptionalHeader.AddressOfEntryPoint = 0;
108 nth->OptionalHeader.BaseOfCode = 0;
109 nth->OptionalHeader.MajorOperatingSystemVersion = 4;
110 nth->OptionalHeader.MajorImageVersion = 4;
111 nth->OptionalHeader.SizeOfImage = 0;
112 nth->OptionalHeader.SizeOfHeaders = 0;
113 nth->OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_NATIVE;
114 nth->OptionalHeader.DllCharacteristics = 0;
115 nth->OptionalHeader.NumberOfRvaAndSizes = 0;
117 /* allocate one code section that crosses the whole process range
118 * (we could find out from internal tables ... hmm )
120 sh=(LPIMAGE_SECTION_HEADER)(nth+1);
121 strcpy(sh->Name,".text");
122 sh->Misc.VirtualSize = 0x7fffffff;
123 sh->VirtualAddress = 0x42; /* so snoop can use it ... */
124 sh->SizeOfRawData = 0x7fffffff;
125 sh->PointerToRawData = 0;
126 sh->Characteristics = IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ;
127 wm->module = hmod;
128 SNOOP_RegisterDLL(hmod,libname,STUBSIZE/sizeof(ELF_STDCALL_STUB));
129 return hmod;
132 FARPROC32
133 ELF_FindExportedFunction( PDB32 *process,WINE_MODREF *wm, LPCSTR funcName) {
134 LPVOID fun;
135 int i,nrofargs = 0;
136 ELF_STDCALL_STUB *stub;
138 assert(wm->type == MODULE32_ELF);
139 if (!HIWORD(funcName)) {
140 ERR(win32,"Can't import from UNIX dynamic libs by ordinal, sorry.\n");
141 return (FARPROC32)0;
143 fun = dlsym(wm->binfmt.elf.dlhandle,funcName);
144 /* we sometimes have an excess '_' at the beginning of the name */
145 if (!fun && (funcName[0]=='_')) {
146 funcName++ ;
147 fun = dlsym(wm->binfmt.elf.dlhandle,funcName);
149 if (!fun) {
150 /* Function@nrofargs usually marks a stdcall function
151 * with nrofargs bytes that are popped at the end
153 if (strchr(funcName,'@')) {
154 LPSTR t,fn = HEAP_strdupA(process->heap,0,funcName);
156 t = strchr(fn,'@');
157 *t = '\0';
158 nrofargs = 0;
159 sscanf(t+1,"%d",&nrofargs);
160 fun = dlsym(wm->binfmt.elf.dlhandle,fn);
161 HeapFree(process->heap,0,fn);
164 /* We sometimes have Win32 dlls implemented using stdcall but UNIX
165 * dlls using cdecl. If we find out the number of args the function
166 * uses, we remove them from the stack using two small stubs.
168 if (!wm->binfmt.elf.stubs) {
169 /* one page should suffice */
170 wm->binfmt.elf.stubs = VirtualAlloc(NULL,STUBSIZE,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);
171 memset(wm->binfmt.elf.stubs,0,STUBSIZE);
173 stub = wm->binfmt.elf.stubs;
174 for (i=0;i<STUBSIZE/sizeof(ELF_STDCALL_STUB);i++) {
175 if (!stub->origfun)
176 break;
177 if (stub->origfun == (DWORD)fun)
178 break;
179 stub++;
181 if (i==STUBSIZE/sizeof(ELF_STDCALL_STUB)) {
182 ERR(win32,"please report, that there are not enough slots for stdcall stubs in the ELF loader.\n");
183 assert(i<STUBSIZE/sizeof(ELF_STDCALL_STUB));
185 if (!stub->origfun)
186 stub->origfun=(DWORD)fun; /* just a marker */
188 if (fun && nrofargs) { /* we don't need it for 0 args */
189 /* Selfmodifying entry/return stub for stdcall -> cdecl
190 * conversion.
191 * - Pop returnaddress directly into our return code
192 * popl <into code below>
193 * - Replace it by pointer to start of our returncode
194 * push $newret
195 * - And call the original function
196 * jmp $orgfun
197 * - Remove the arguments no longer needed
198 * newret: add esp, <nrofargs>
199 * - Push the original returnvalue on the stack
200 * pushl <poppedvalue>
201 * - And return to it.
202 * ret
205 /* FIXME: The function stub is not reentrant. */
207 ((LPBYTE)&(stub->popl))[0] = 0x8f;
208 ((LPBYTE)&(stub->popl))[1] = 0x05;
209 stub->addr_popped = (DWORD)&(stub->oldret);
210 stub->pushl1 = 0x68;
211 stub->newret = (DWORD)&(stub->addesp);
212 stub->pushl2 = 0x68;
213 stub->origfun = (DWORD)fun;
214 stub->ret1 = 0xc3;
215 ((LPBYTE)&(stub->addesp))[0]=0x83;
216 ((LPBYTE)&(stub->addesp))[1]=0xc4;
217 stub->nrofargs = nrofargs;
218 stub->pushl3 = 0x68;
219 /* filled out by entrycode */
220 stub->oldret = 0xdeadbeef;
221 stub->ret2 = 0xc3;
222 fun=(FARPROC32)stub;
224 if (!fun) {
225 FIXME(win32,"function %s not found: %s\n",funcName,dlerror());
226 return fun;
228 fun = SNOOP_GetProcAddress32(wm->module,funcName,stub-wm->binfmt.elf.stubs,fun);
229 return (FARPROC32)fun;
231 #else
233 HMODULE32
234 ELF_LoadLibraryEx32A(LPCSTR libname,PDB32 *process,HANDLE32 hf,DWORD flags) {
235 return 0;
237 FARPROC32
238 ELF_FindExportedFunction( PDB32 *process,WINE_MODREF *wm, LPCSTR funcName) {
239 return (FARPROC32)0;
242 #endif