Release 970804
[wine/multimedia.git] / loader / ne_image.c
blob353620664fe338e43a49a43a2323a8bf676bd4ce
1 #ifndef WINELIB
2 /*
3 * NE modules
5 * Copyright 1993 Robert J. Amstadt
6 * Copyright 1995 Alexandre Julliard
7 */
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <unistd.h>
15 #include <ctype.h>
16 #include <string.h>
17 #include <errno.h>
18 #include "neexe.h"
19 #include "windows.h"
20 #include "arch.h"
21 #include "selectors.h"
22 #include "callback.h"
23 #include "file.h"
24 #include "module.h"
25 #include "stackframe.h"
26 #include "stddebug.h"
27 #include "debug.h"
28 #include "xmalloc.h"
31 /***********************************************************************
32 * NE_LoadSegment
34 BOOL32 NE_LoadSegment( HMODULE16 hModule, WORD segnum )
36 NE_MODULE *pModule;
37 SEGTABLEENTRY *pSegTable, *pSeg;
38 WORD *pModuleTable;
39 WORD count, i, offset;
40 HMODULE16 module;
41 FARPROC16 address;
42 int fd;
43 struct relocation_entry_s *rep, *reloc_entries;
44 BYTE *func_name;
45 int size;
46 char* mem;
48 char buffer[100];
49 int ordinal, additive;
50 unsigned short *sp;
52 if (!(pModule = MODULE_GetPtr( hModule ))) return FALSE;
53 pSegTable = NE_SEG_TABLE( pModule );
54 pSeg = pSegTable + segnum - 1;
55 pModuleTable = NE_MODULE_TABLE( pModule );
57 if (!pSeg->filepos) return TRUE; /* No file image, just return */
59 fd = MODULE_OpenFile( hModule );
60 dprintf_module( stddeb, "Loading segment %d, selector=%04x\n",
61 segnum, pSeg->selector );
62 lseek( fd, pSeg->filepos << pModule->alignment, SEEK_SET );
63 if (pSeg->size) size = pSeg->size;
64 else if (pSeg->minsize) size = pSeg->minsize;
65 else size = 0x10000;
66 mem = GlobalLock16(pSeg->selector);
67 if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
69 /* Implement self loading segments */
70 SELFLOADHEADER *selfloadheader;
71 STACK16FRAME *stack16Top;
72 DWORD oldstack;
73 WORD oldselector, newselector;
74 HFILE32 hf = FILE_DupUnixHandle( fd );
76 selfloadheader = (SELFLOADHEADER *)
77 PTR_SEG_OFF_TO_LIN(pSegTable->selector,0);
78 oldstack = IF1632_Saved16_ss_sp;
79 oldselector = pSeg->selector;
80 IF1632_Saved16_ss_sp = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
81 0xff00 - sizeof(*stack16Top));
82 stack16Top = CURRENT_STACK16;
83 stack16Top->saved_ss_sp = 0;
84 stack16Top->ds = stack16Top->es = pModule->self_loading_sel;
85 stack16Top->entry_point = 0;
86 stack16Top->entry_ip = 0;
87 stack16Top->entry_cs = 0;
88 stack16Top->bp = 0;
89 stack16Top->ip = 0;
90 stack16Top->cs = 0;
91 newselector = CallTo16_word_www( selfloadheader->LoadAppSeg,
92 hModule, hf, segnum );
93 _lclose32( hf );
94 if (newselector != oldselector) {
95 /* Self loaders like creating their own selectors;
96 * they love asking for trouble to Wine developers
98 if (segnum == pModule->dgroup) {
99 memcpy(PTR_SEG_OFF_TO_LIN(oldselector,0),
100 PTR_SEG_OFF_TO_LIN(newselector,0),
101 pSeg->minsize ? pSeg->minsize : 0x10000);
102 FreeSelector(newselector);
103 pSeg->selector = oldselector;
104 fprintf(stderr, "A new selector was allocated for the dgroup segment\n"
105 "Old selector is %d, new one is %d", oldselector, newselector);
106 } else {
107 FreeSelector(pSeg->selector);
108 pSeg->selector = newselector;
112 IF1632_Saved16_ss_sp = oldstack;
114 else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
115 read(fd, mem, size);
116 else {
118 The following bit of code for "iterated segments" was written without
119 any documentation on the format of these segments. It seems to work,
120 but may be missing something. If you have any doco please either send
121 it to me or fix the code yourself. gfm@werple.mira.net.au
123 char* buff = xmalloc(size);
124 char* curr = buff;
125 read(fd, buff, size);
126 while(curr < buff + size) {
127 unsigned int rept = *((short*) curr)++;
128 unsigned int len = *((short*) curr)++;
129 for(; rept > 0; rept--) {
130 char* bytes = curr;
131 unsigned int byte;
132 for(byte = 0; byte < len; byte++)
133 *mem++ = *bytes++;
135 curr += len;
137 free(buff);
140 pSeg->flags |= NE_SEGFLAGS_LOADED;
141 if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
142 return TRUE; /* No relocation data, we are done */
144 read( fd, &count, sizeof(count) );
145 if (!count) return TRUE;
147 dprintf_fixup( stddeb, "Fixups for %*.*s, segment %d, selector %04x\n",
148 *((BYTE *)pModule + pModule->name_table),
149 *((BYTE *)pModule + pModule->name_table),
150 (char *)pModule + pModule->name_table + 1,
151 segnum, pSeg->selector );
153 reloc_entries = (struct relocation_entry_s *)xmalloc(count * sizeof(struct relocation_entry_s));
154 if (read( fd, reloc_entries, count * sizeof(struct relocation_entry_s)) !=
155 count * sizeof(struct relocation_entry_s))
157 dprintf_fixup( stddeb, "Unable to read relocation information\n" );
158 return FALSE;
162 * Go through the relocation table on entry at a time.
164 rep = reloc_entries;
165 for (i = 0; i < count; i++, rep++)
168 * Get the target address corresponding to this entry.
171 /* If additive, there is no target chain list. Instead, add source
172 and target */
173 additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
174 rep->relocation_type &= 0x3;
176 switch (rep->relocation_type)
178 case NE_RELTYPE_ORDINAL:
179 module = pModuleTable[rep->target1-1];
180 ordinal = rep->target2;
181 address = MODULE_GetEntryPoint( module, ordinal );
182 if (!address)
184 NE_MODULE *pTarget = MODULE_GetPtr( module );
185 if (!pTarget)
186 fprintf( stderr, "Module not found: %04x, reference %d of module %*.*s\n",
187 module, rep->target1,
188 *((BYTE *)pModule + pModule->name_table),
189 *((BYTE *)pModule + pModule->name_table),
190 (char *)pModule + pModule->name_table + 1 );
191 else
192 fprintf( stderr, "Warning: no handler for %*.*s.%d, setting to 0:0\n",
193 *((BYTE *)pTarget + pTarget->name_table),
194 *((BYTE *)pTarget + pTarget->name_table),
195 (char *)pTarget + pTarget->name_table + 1,
196 ordinal );
198 if (debugging_fixup)
200 NE_MODULE *pTarget = MODULE_GetPtr( module );
201 fprintf( stddeb,"%d: %*.*s.%d=%04x:%04x\n", i + 1,
202 *((BYTE *)pTarget + pTarget->name_table),
203 *((BYTE *)pTarget + pTarget->name_table),
204 (char *)pTarget + pTarget->name_table + 1,
205 ordinal, HIWORD(address), LOWORD(address) );
207 break;
209 case NE_RELTYPE_NAME:
210 module = pModuleTable[rep->target1-1];
211 func_name = (char *)pModule + pModule->import_table + rep->target2;
212 memcpy( buffer, func_name+1, *func_name );
213 buffer[*func_name] = '\0';
214 func_name = buffer;
215 ordinal = MODULE_GetOrdinal( module, func_name );
217 address = MODULE_GetEntryPoint( module, ordinal );
219 if (!address)
221 NE_MODULE *pTarget = MODULE_GetPtr( module );
222 fprintf( stderr, "Warning: no handler for %*.*s.%s, setting to 0:0\n",
223 *((BYTE *)pTarget + pTarget->name_table),
224 *((BYTE *)pTarget + pTarget->name_table),
225 (char *)pTarget + pTarget->name_table + 1, func_name );
227 if (debugging_fixup)
229 NE_MODULE *pTarget = MODULE_GetPtr( module );
230 fprintf( stddeb,"%d: %*.*s.%s=%04x:%04x\n", i + 1,
231 *((BYTE *)pTarget + pTarget->name_table),
232 *((BYTE *)pTarget + pTarget->name_table),
233 (char *)pTarget + pTarget->name_table + 1,
234 func_name, HIWORD(address), LOWORD(address) );
236 break;
238 case NE_RELTYPE_INTERNAL:
239 if ((rep->target1 & 0xff) == 0xff)
241 address = MODULE_GetEntryPoint( hModule, rep->target2 );
243 else
245 address = (FARPROC16)PTR_SEG_OFF_TO_SEGPTR( pSegTable[rep->target1-1].selector, rep->target2 );
248 dprintf_fixup(stddeb,"%d: %04x:%04x\n",
249 i + 1, HIWORD(address), LOWORD(address) );
250 break;
252 case NE_RELTYPE_OSFIXUP:
253 /* Relocation type 7:
255 * These appear to be used as fixups for the Windows
256 * floating point emulator. Let's just ignore them and
257 * try to use the hardware floating point. Linux should
258 * successfully emulate the coprocessor if it doesn't
259 * exist.
261 dprintf_fixup(stddeb,
262 "%d: ADDR TYPE %d, TYPE %d, OFFSET %04x, ",
263 i + 1, rep->address_type, rep->relocation_type,
264 rep->offset);
265 dprintf_fixup(stddeb,"TARGET %04x %04x\n",
266 rep->target1, rep->target2);
267 continue;
269 default:
270 dprintf_fixup(stddeb,
271 "WARNING: %d: ADDR TYPE %d, unknown TYPE %d, OFFSET %04x, ",
272 i + 1, rep->address_type, rep->relocation_type,
273 rep->offset);
274 dprintf_fixup(stddeb,"TARGET %04x %04x\n",
275 rep->target1, rep->target2);
276 free(reloc_entries);
277 return FALSE;
280 offset = rep->offset;
282 /* Apparently, high bit of address_type is sometimes set; */
283 /* we ignore it for now */
284 if (rep->address_type > NE_RADDR_OFFSET32)
285 fprintf( stderr, "WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
286 MODULE_GetModuleName(hModule), rep->address_type );
288 switch (rep->address_type & 0x7f)
290 case NE_RADDR_LOWBYTE:
291 do {
292 sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
293 dprintf_fixup(stddeb," %04x:%04x:%04x BYTE%s\n",
294 pSeg->selector, offset, *sp, additive ? " additive":"");
295 offset = *sp;
296 if(additive)
297 *(unsigned char*)sp = (unsigned char)(((int)address+offset) & 0xFF);
298 else
299 *(unsigned char*)sp = (unsigned char)((int)address & 0xFF);
301 while (offset != 0xffff && !additive);
302 break;
304 case NE_RADDR_OFFSET16:
305 do {
306 sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
307 dprintf_fixup(stddeb," %04x:%04x:%04x OFFSET16%s\n",
308 pSeg->selector, offset, *sp, additive ? " additive" : "" );
309 offset = *sp;
310 *sp = LOWORD(address);
311 if (additive) *sp += offset;
313 while (offset != 0xffff && !additive);
314 break;
316 case NE_RADDR_POINTER32:
317 do {
318 sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
319 dprintf_fixup(stddeb," %04x:%04x:%04x POINTER32%s\n",
320 pSeg->selector, offset, *sp, additive ? " additive" : "" );
321 offset = *sp;
322 *sp = LOWORD(address);
323 if (additive) *sp += offset;
324 *(sp+1) = HIWORD(address);
326 while (offset != 0xffff && !additive);
327 break;
329 case NE_RADDR_SELECTOR:
330 do {
331 sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
332 dprintf_fixup(stddeb," %04x:%04x:%04x SELECTOR%s\n",
333 pSeg->selector, offset, *sp, additive ? " additive" : "" );
334 offset = *sp;
335 *sp = HIWORD(address);
336 /* Borland creates additive records with offset zero. Strange, but OK */
337 if(additive && offset)
338 fprintf(stderr,"Additive selector to %4.4x.Please report\n",offset);
340 /* FIXME: Quicken 5 has a zero offset fixup. This seems to work */
341 while (offset && offset != 0xffff && !additive);
342 break;
344 default:
345 dprintf_fixup(stddeb,
346 "WARNING: %d: unknown ADDR TYPE %d, TYPE %d, OFFSET %04x, ",
347 i + 1, rep->address_type, rep->relocation_type,
348 rep->offset);
349 dprintf_fixup(stddeb,
350 "TARGET %04x %04x\n", rep->target1, rep->target2);
351 free(reloc_entries);
352 return FALSE;
356 free(reloc_entries);
357 return TRUE;
361 /***********************************************************************
362 * NE_FixupPrologs
364 * Fixup the exported functions prologs.
366 void NE_FixupPrologs( NE_MODULE *pModule )
368 SEGTABLEENTRY *pSegTable;
369 WORD dgroup = 0;
370 WORD sel;
371 BYTE *p, *fixup_ptr, count;
373 pSegTable = NE_SEG_TABLE(pModule);
374 if (pModule->flags & NE_FFLAGS_SINGLEDATA)
375 dgroup = pSegTable[pModule->dgroup-1].selector;
377 dprintf_module( stddeb, "MODULE_FixupPrologs(%04x)\n", pModule->self );
378 p = (BYTE *)pModule + pModule->entry_table;
379 while (*p)
381 if (p[1] == 0) /* Unused entry */
383 p += 2; /* Skip it */
384 continue;
386 if (p[1] == 0xfe) /* Constant entry */
388 p += 2 + *p * 3; /* Skip it */
389 continue;
392 /* Now fixup the entries of this bundle */
393 count = *p;
394 sel = p[1];
395 p += 2;
396 while (count-- > 0)
398 dprintf_module( stddeb,"Flags: %04x, sel %02x ", *p, sel);
399 /* According to the output generated by TDUMP, the flags mean:
400 * 0x0001 function is exported
401 * 0x0002 Single data (seems to occur only in DLLs)
403 if (sel == 0xff) { /* moveable */
404 dprintf_module( stddeb, "(%02x) o %04x ", p[3], *(WORD *)(p+4) );
405 fixup_ptr = (char *)GET_SEL_BASE(pSegTable[p[3]-1].selector) + *(WORD *)(p + 4);
406 } else { /* fixed */
407 dprintf_module( stddeb, "offset %04x ", *(WORD *)(p+1) );
408 fixup_ptr = (char *)GET_SEL_BASE(pSegTable[sel-1].selector) + *(WORD *)(p + 1);
410 dprintf_module( stddeb, "Signature: %02x %02x %02x,ff %x\n",
411 fixup_ptr[0], fixup_ptr[1], fixup_ptr[2],
412 pModule->flags );
413 if (*p & 0x0001)
415 /* Verify the signature */
416 if (((fixup_ptr[0] == 0x1e && fixup_ptr[1] == 0x58)
417 || (fixup_ptr[0] == 0x8c && fixup_ptr[1] == 0xd8))
418 && fixup_ptr[2] == 0x90)
420 if (*p & 0x0002)
422 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA)
424 /* can this happen? */
425 fprintf( stderr, "FixupPrologs got confused\n" );
427 else if (pModule->flags & NE_FFLAGS_SINGLEDATA)
429 *fixup_ptr = 0xb8; /* MOV AX, */
430 *(WORD *)(fixup_ptr+1) = dgroup;
433 else
435 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA) {
436 fixup_ptr[0] = 0x90; /* non-library: NOPs */
437 fixup_ptr[1] = 0x90;
438 fixup_ptr[2] = 0x90;
441 } else {
442 dprintf_fixup( stddeb, "Unknown signature\n" );
445 else
446 dprintf_module( stddeb,"\n");
447 p += (sel == 0xff) ? 6 : 3;
453 /***********************************************************************
454 * NE_InitDLL
456 * Call the DLL initialization code
458 static BOOL32 NE_InitDLL( HMODULE16 hModule )
460 NE_MODULE *pModule;
461 SEGTABLEENTRY *pSegTable;
462 CONTEXT context;
464 /* Registers at initialization must be:
465 * cx heap size
466 * di library instance
467 * ds data segment if any
468 * es:si command line (always 0)
471 if (!(pModule = MODULE_GetPtr( hModule ))) return FALSE;
472 pSegTable = NE_SEG_TABLE( pModule );
474 if (!(pModule->flags & NE_FFLAGS_LIBMODULE) ||
475 (pModule->flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
476 if (!pModule->cs) return TRUE; /* no initialization code */
478 memset( &context, 0, sizeof(context) );
480 if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
482 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
484 /* Not SINGLEDATA */
485 fprintf(stderr, "Library is not marked SINGLEDATA\n");
486 exit(1);
488 else /* DATA NONE DLL */
490 DS_reg(&context) = 0;
491 ECX_reg(&context) = 0;
494 else /* DATA SINGLE DLL */
496 DS_reg(&context) = pSegTable[pModule->dgroup-1].selector;
497 ECX_reg(&context) = pModule->heap_size;
500 CS_reg(&context) = pSegTable[pModule->cs-1].selector;
501 EIP_reg(&context) = pModule->ip;
502 EBP_reg(&context) = OFFSETOF(IF1632_Saved16_ss_sp)
503 + (WORD)&((STACK16FRAME*)0)->bp;
504 EDI_reg(&context) = DS_reg(&context) ? DS_reg(&context) : hModule;
507 pModule->cs = 0; /* Don't initialize it twice */
508 dprintf_dll( stddeb, "Calling LibMain, cs:ip=%04lx:%04x ds=%04lx di=%04x cx=%04x\n",
509 CS_reg(&context), IP_reg(&context), DS_reg(&context),
510 DI_reg(&context), CX_reg(&context) );
511 CallTo16_regs_( &context );
512 return TRUE;
516 /***********************************************************************
517 * NE_InitializeDLLs
519 * Initialize the loaded DLLs.
521 void NE_InitializeDLLs( HMODULE16 hModule )
523 NE_MODULE *pModule;
524 HMODULE16 *pDLL;
526 if (!(pModule = MODULE_GetPtr( hModule ))) return;
527 if (pModule->flags & NE_FFLAGS_WIN32)
529 /* PE_InitializeDLLs(hModule); */
530 return;
532 if (pModule->dlls_to_init)
534 HGLOBAL16 to_init = pModule->dlls_to_init;
535 pModule->dlls_to_init = 0;
536 for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
538 NE_InitializeDLLs( *pDLL );
540 GlobalFree16( to_init );
542 NE_InitDLL( hModule );
546 /***********************************************************************
547 * NE_PatchCodeHandle
549 * Needed for self-loading modules.
552 /* It does nothing */
553 void PatchCodeHandle(HANDLE16 hSel)
556 #endif /* WINELIB */