Release 950901
[wine] / loader / ne_image.c
1 /*
2  * NE modules
3  *
4  * Copyright 1993 Robert J. Amstadt
5  * Copyright 1995 Alexandre Julliard
6  */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <fcntl.h>
13 #include <unistd.h>
14 #include <ctype.h>
15 #include <string.h>
16 #include <errno.h>
17 #include "neexe.h"
18 #include "dlls.h"
19 #include "windows.h"
20 #include "arch.h"
21 #include "selectors.h"
22 #include "callback.h"
23 #include "module.h"
24 #include "stackframe.h"
25 #include "stddebug.h"
26 #include "debug.h"
27
28
29 /***********************************************************************
30  *           NE_LoadSegment
31  */
32 BOOL NE_LoadSegment( HMODULE hModule, WORD segnum )
33 {
34     NE_MODULE *pModule;
35     SEGTABLEENTRY *pSegTable, *pSeg;
36     WORD *pModuleTable;
37     WORD count, i, module, offset;
38     DWORD address;
39     int fd;
40     struct relocation_entry_s *rep, *reloc_entries;
41     BYTE *func_name;
42     int size;
43     char* mem;
44
45     char buffer[100];
46     int ordinal, additive;
47     unsigned short *sp;
48
49     if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return FALSE;
50     pSegTable = NE_SEG_TABLE( pModule );
51     pSeg = pSegTable + segnum - 1;
52     pModuleTable = NE_MODULE_TABLE( pModule );
53
54     if (!pSeg->filepos) return TRUE;  /* No file image, just return */
55         
56     fd = MODULE_OpenFile( hModule );
57     dprintf_module( stddeb, "Loading segment %d, selector=%04x\n",
58                     segnum, pSeg->selector );
59     lseek( fd, pSeg->filepos << pModule->alignment, SEEK_SET );
60     size = pSeg->size ? pSeg->size : 0x10000;
61     mem = GlobalLock(pSeg->selector);
62     if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
63       read(fd, mem, size);
64     else {
65       /*
66          The following bit of code for "iterated segments" was written without
67          any documentation on the format of these segments. It seems to work,
68          but may be missing something. If you have any doco please either send
69          it to me or fix the code yourself. gfm@werple.mira.net.au
70       */
71       char* buff = malloc(size);
72       char* curr = buff;
73       read(fd, buff, size);
74       while(curr < buff + size) {
75         unsigned int rept = *((short*) curr)++;
76         unsigned int len = *((short*) curr)++;
77         for(; rept > 0; rept--) {
78           char* bytes = curr;
79           unsigned int byte;
80           for(byte = 0; byte < len; byte++)
81             *mem++ = *bytes++;
82         }
83         curr += len;
84       }
85       free(buff);
86     }
87
88     if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
89         return TRUE;  /* No relocation data, we are done */
90
91     read( fd, &count, sizeof(count) );
92     if (!count) return TRUE;
93
94     dprintf_fixup( stddeb, "Fixups for %*.*s, segment %d, selector %04x\n",
95                    *((BYTE *)pModule + pModule->name_table),
96                    *((BYTE *)pModule + pModule->name_table),
97                    (char *)pModule + pModule->name_table + 1,
98                    segnum, pSeg->selector );
99
100     reloc_entries = (struct relocation_entry_s *)malloc(count * sizeof(struct relocation_entry_s));
101     if (read( fd, reloc_entries, count * sizeof(struct relocation_entry_s)) !=
102             count * sizeof(struct relocation_entry_s))
103     {
104         dprintf_fixup( stddeb, "Unable to read relocation information\n" );
105         return FALSE;
106     }
107
108     /*
109      * Go through the relocation table on entry at a time.
110      */
111     rep = reloc_entries;
112     for (i = 0; i < count; i++, rep++)
113     {
114         /*
115          * Get the target address corresponding to this entry.
116          */
117
118         /* If additive, there is no target chain list. Instead, add source
119            and target */
120         additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
121         rep->relocation_type &= 0x3;
122         
123         switch (rep->relocation_type)
124         {
125           case NE_RELTYPE_ORDINAL:
126             module = pModuleTable[rep->target1-1];
127             ordinal = rep->target2;
128             address = MODULE_GetEntryPoint( module, ordinal );
129             if (!address)
130             {
131                 NE_MODULE *pTarget = (NE_MODULE *)GlobalLock( module );
132                 if (!pTarget)
133                     fprintf( stderr, "Module not found: %04x, reference %d of module %*.*s\n",
134                              module, rep->target1, 
135                              *((BYTE *)pModule + pModule->name_table),
136                              *((BYTE *)pModule + pModule->name_table),
137                              (char *)pModule + pModule->name_table + 1 );
138                 else
139                     fprintf( stderr, "Warning: no handler for %*.*s.%d, setting to 0:0\n",
140                             *((BYTE *)pTarget + pTarget->name_table),
141                             *((BYTE *)pTarget + pTarget->name_table),
142                             (char *)pTarget + pTarget->name_table + 1,
143                             ordinal );
144             }
145             if (debugging_fixup)
146             {
147                 NE_MODULE *pTarget = (NE_MODULE *)GlobalLock( module );
148                 fprintf( stddeb,"%d: %*.*s.%d=%04x:%04x\n", i + 1, 
149                          *((BYTE *)pTarget + pTarget->name_table),
150                          *((BYTE *)pTarget + pTarget->name_table),
151                          (char *)pTarget + pTarget->name_table + 1,
152                          ordinal, HIWORD(address), LOWORD(address) );
153             }
154             break;
155             
156           case NE_RELTYPE_NAME:
157             module = pModuleTable[rep->target1-1];
158             func_name = (char *)pModule + pModule->import_table + rep->target2;
159             memcpy( buffer, func_name+1, *func_name );
160             buffer[*func_name] = '\0';
161             func_name = buffer;
162             ordinal = MODULE_GetOrdinal( module, func_name );
163
164             address = MODULE_GetEntryPoint( module, ordinal );
165
166             if (!address)
167             {
168                 NE_MODULE *pTarget = (NE_MODULE *)GlobalLock( module );
169                 fprintf( stderr, "Warning: no handler for %*.*s.%s, setting to 0:0\n",
170                         *((BYTE *)pTarget + pTarget->name_table),
171                         *((BYTE *)pTarget + pTarget->name_table),
172                         (char *)pTarget + pTarget->name_table + 1, func_name );
173             }
174             if (debugging_fixup)
175             {
176                 NE_MODULE *pTarget = (NE_MODULE *)GlobalLock( module );
177                 fprintf( stddeb,"%d: %*.*s.%s=%04x:%04x\n", i + 1, 
178                          *((BYTE *)pTarget + pTarget->name_table),
179                          *((BYTE *)pTarget + pTarget->name_table),
180                          (char *)pTarget + pTarget->name_table + 1,
181                          func_name, HIWORD(address), LOWORD(address) );
182             }
183             break;
184             
185           case NE_RELTYPE_INTERNAL:
186             if (rep->target1 == 0x00ff)
187             {
188                 address  = MODULE_GetEntryPoint( hModule, rep->target2 );
189             }
190             else
191             {
192                 address = MAKELONG( rep->target2, pSegTable[rep->target1-1].selector );
193             }
194             
195             dprintf_fixup(stddeb,"%d: %04x:%04x\n", 
196                           i + 1, HIWORD(address), LOWORD(address) );
197             break;
198
199           case NE_RELTYPE_OSFIXUP:
200             /* Relocation type 7:
201              *
202              *    These appear to be used as fixups for the Windows
203              * floating point emulator.  Let's just ignore them and
204              * try to use the hardware floating point.  Linux should
205              * successfully emulate the coprocessor if it doesn't
206              * exist.
207              */
208             dprintf_fixup(stddeb,
209                    "%d: ADDR TYPE %d,  TYPE %d,  OFFSET %04x,  ",
210                    i + 1, rep->address_type, rep->relocation_type, 
211                    rep->offset);
212             dprintf_fixup(stddeb,"TARGET %04x %04x\n", 
213                    rep->target1, rep->target2);
214             continue;
215             
216           default:
217             dprintf_fixup(stddeb,
218                    "%d: ADDR TYPE %d,  TYPE %d,  OFFSET %04x,  ",
219                    i + 1, rep->address_type, rep->relocation_type, 
220                    rep->offset);
221             dprintf_fixup(stddeb,"TARGET %04x %04x\n", 
222                     rep->target1, rep->target2);
223             free(reloc_entries);
224             return FALSE;
225         }
226
227         offset  = rep->offset;
228
229         switch (rep->address_type)
230         {
231           case NE_RADDR_LOWBYTE:
232             do {
233                 sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
234                 dprintf_fixup(stddeb,"    %04x:%04x:%04x BYTE%s\n",
235                               pSeg->selector, offset, *sp, additive ? " additive":"");
236                 offset = *sp;
237                 if(additive)
238                     *(unsigned char*)sp = (unsigned char)((address+offset) & 0xFF);
239                 else
240                     *(unsigned char*)sp = (unsigned char)(address & 0xFF);
241             }
242             while (offset != 0xffff && !additive);
243             break;
244
245           case NE_RADDR_OFFSET16:
246             do {
247                 sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
248                 dprintf_fixup(stddeb,"    %04x:%04x:%04x OFFSET16%s\n",
249                               pSeg->selector, offset, *sp, additive ? " additive" : "" );
250                 offset = *sp;
251                 *sp = LOWORD(address);
252                 if (additive) *sp += offset;
253             } 
254             while (offset != 0xffff && !additive);
255             break;
256             
257           case NE_RADDR_POINTER32:
258             do {
259                 sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
260                 dprintf_fixup(stddeb,"    %04x:%04x:%04x POINTER32%s\n",
261                               pSeg->selector, offset, *sp, additive ? " additive" : "" );
262                 offset = *sp;
263                 *sp    = LOWORD(address);
264                 if (additive) *sp += offset;
265                 *(sp+1) = HIWORD(address);
266             } 
267             while (offset != 0xffff && !additive);
268             break;
269             
270           case NE_RADDR_SELECTOR:
271             do {
272                 sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
273                 dprintf_fixup(stddeb,"    %04x:%04x:%04x SELECTOR%s\n",
274                               pSeg->selector, offset, *sp, additive ? " additive" : "" );
275                 offset = *sp;
276                 *sp    = HIWORD(address);
277                 /* Borland creates additive records with offset zero. Strange, but OK */
278                 if(additive && offset)
279                 fprintf(stderr,"Additive selector to %4.4x.Please report\n",offset);
280             } 
281             while (offset != 0xffff && !additive);
282             break;
283             
284           default:
285             dprintf_fixup(stddeb,
286                    "%d: ADDR TYPE %d,  TYPE %d,  OFFSET %04x,  ",
287                    i + 1, rep->address_type, rep->relocation_type, 
288                    rep->offset);
289             dprintf_fixup(stddeb,
290                    "TARGET %04x %04x\n", rep->target1, rep->target2);
291             free(reloc_entries);
292             return FALSE;
293         }
294     }
295
296     free(reloc_entries);
297     return TRUE;
298 }
299
300
301 /***********************************************************************
302  *           NE_FixupPrologs
303  *
304  * Fixup the exported functions prologs.
305  */
306 void NE_FixupPrologs( HMODULE hModule )
307 {
308 #ifdef WINELIB
309         fprintf(stderr,"NE_FixupPrologs should not be called for libwine\n");
310 #else
311     NE_MODULE *pModule;
312     SEGTABLEENTRY *pSegTable;
313     WORD dgroup = 0;
314     WORD sel;
315     BYTE *p, *fixup_ptr, count;
316
317     pModule = (NE_MODULE *)GlobalLock( hModule );
318     pSegTable = NE_SEG_TABLE(pModule);
319     if (pModule->flags & NE_FFLAGS_SINGLEDATA)
320         dgroup = pSegTable[pModule->dgroup-1].selector;
321
322     dprintf_module( stddeb, "MODULE_FixupPrologs(%04x)\n", hModule );
323     p = (BYTE *)pModule + pModule->entry_table;
324     while (*p)
325     {
326         if (p[1] == 0)  /* Unused entry */
327         {
328             p += 2;  /* Skip it */
329             continue;
330         }
331         if (p[1] == 0xfe)  /* Constant entry */
332         {
333             p += 2 + *p * 3;  /* Skip it */
334             continue;
335         }
336
337         /* Now fixup the entries of this bundle */
338         count = *p;
339         sel = p[1];
340         p += 2;
341         while (count-- > 0)
342         {
343             dprintf_module( stddeb,"Flags: %04x, sel %02x ", *p, sel);
344             /* According to the output generated by TDUMP, the flags mean:
345              * 0x0001 function is exported
346              * 0x0002 Single data (seems to occur only in DLLs)
347              */
348             if (sel == 0xff) { /* moveable */
349                 dprintf_module( stddeb, "(%02x) o %04x ", p[3], *(WORD *)(p+4) );
350                 fixup_ptr = (char *)GET_SEL_BASE(pSegTable[p[3]-1].selector) + *(WORD *)(p + 4);
351             } else { /* fixed */
352                 dprintf_module( stddeb, "offset %04x ", *(WORD *)(p+1) );
353                 fixup_ptr = (char *)GET_SEL_BASE(pSegTable[sel-1].selector) + *(WORD *)(p + 1);
354             }
355             dprintf_module( stddeb, "Signature: %02x %02x %02x,ff %x\n",
356                            fixup_ptr[0], fixup_ptr[1], fixup_ptr[2],
357                            pModule->flags );
358             if (*p & 0x0001)
359             {
360                 /* Verify the signature */
361                 if (((fixup_ptr[0] == 0x1e && fixup_ptr[1] == 0x58)
362                      || (fixup_ptr[0] == 0x8c && fixup_ptr[1] == 0xd8))
363                     && fixup_ptr[2] == 0x90)
364                 {
365                     if (*p & 0x0002)
366                     {
367                         if (pModule->flags & NE_FFLAGS_MULTIPLEDATA) {
368                             /* can this happen? */
369                             fprintf( stderr, "FixupPrologs got confused\n" );
370                         }
371                         *fixup_ptr = 0xb8;      /* MOV AX, */
372                         *(WORD *)(fixup_ptr+1) = dgroup;
373                     }
374                     else
375                     {
376                         if (pModule->flags & NE_FFLAGS_MULTIPLEDATA) {
377                             fixup_ptr[0] = 0x90; /* non-library: NOPs */
378                             fixup_ptr[1] = 0x90;
379                             fixup_ptr[2] = 0x90;
380                         }
381                     }
382                 } else {
383                     dprintf_fixup( stddeb, "Unknown signature\n" );
384                 }
385             }
386             else
387               dprintf_module( stddeb,"\n");
388             p += (sel == 0xff) ? 6 : 3;  
389         }
390     }
391 #endif
392 }
393
394
395 /***********************************************************************
396  *           NE_InitDLL
397  *
398  * Call the DLL initialization code
399  */
400 static BOOL NE_InitDLL( HMODULE hModule )
401 {
402     int cs_reg, ds_reg, ip_reg, cx_reg, di_reg, bp_reg;
403     NE_MODULE *pModule;
404     SEGTABLEENTRY *pSegTable;
405
406     /* Registers at initialization must be:
407      * cx     heap size
408      * di     library instance
409      * ds     data segment if any
410      * es:si  command line (always 0)
411      */
412
413     pModule = (NE_MODULE *)GlobalLock( hModule );
414     pSegTable = NE_SEG_TABLE( pModule );
415
416     if (!(pModule->flags & NE_FFLAGS_LIBMODULE)) return TRUE; /*not a library*/
417     if (!pModule->cs) return TRUE;  /* no initialization code */
418
419     if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
420     {
421         if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
422         {
423             /* Not SINGLEDATA */
424             fprintf(stderr, "Library is not marked SINGLEDATA\n");
425             exit(1);
426         }
427         else  /* DATA NONE DLL */
428         {
429             ds_reg = 0;
430             cx_reg = 0;
431         }
432     }
433     else  /* DATA SINGLE DLL */
434     {
435         ds_reg = pSegTable[pModule->dgroup-1].selector;
436         cx_reg = pModule->heap_size;
437     }
438
439     cs_reg = pSegTable[pModule->cs-1].selector;
440     ip_reg = pModule->ip;
441     di_reg = ds_reg ? ds_reg : hModule;
442     bp_reg = IF1632_Saved16_sp + ((WORD)&((STACK16FRAME*)1)->bp - 1);
443
444     pModule->cs = 0;  /* Don't initialize it twice */
445     dprintf_dll( stddeb, "Calling LibMain, cs:ip=%04x:%04x ds=%04x di=%04x cx=%04x\n", 
446                  cs_reg, ip_reg, ds_reg, di_reg, cx_reg );
447     return CallTo16_regs_( (FARPROC)(cs_reg << 16 | ip_reg), ds_reg,
448                            0 /*es*/, 0 /*bp*/, 0 /*ax*/, 0 /*bx*/,
449                            cx_reg, 0 /*dx*/, 0 /*si*/, di_reg );
450 }
451
452
453 /***********************************************************************
454  *           NE_InitializeDLLs
455  *
456  * Initialize the loaded DLLs.
457  */
458 void NE_InitializeDLLs( HMODULE hModule )
459 {
460     NE_MODULE *pModule;
461     WORD *pDLL;
462
463     pModule = (NE_MODULE *)GlobalLock( hModule );
464     if (pModule->dlls_to_init)
465     {
466         HANDLE to_init = pModule->dlls_to_init;
467         pModule->dlls_to_init = 0;
468         for (pDLL = (WORD *)GlobalLock( to_init ); *pDLL; pDLL++)
469         {
470             NE_InitializeDLLs( *pDLL );
471             NE_InitDLL( *pDLL );
472         }
473         GlobalFree( to_init );
474     }
475     NE_InitDLL( hModule );
476 }