Release 940714
[wine/multimedia.git] / loader / ne_image.c
blob4247e6a2ac36b9e325a5b16253749e2280a867f2
1 static char RCSId[] = "$Id: wine.c,v 1.2 1993/07/04 04:04:21 root Exp root $";
2 static char Copyright[] = "Copyright Robert J. Amstadt, 1993";
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <fcntl.h>
9 #include <unistd.h>
10 #ifdef linux
11 #include <linux/unistd.h>
12 #include <linux/head.h>
13 #include <linux/ldt.h>
14 #include <linux/segment.h>
15 #endif
16 #include <string.h>
17 #include <errno.h>
18 #include "neexe.h"
19 #include "segmem.h"
20 #include "prototypes.h"
21 #include "dlls.h"
22 #include "wine.h"
23 #include "windows.h"
24 #include "wineopts.h"
25 #include "arch.h"
26 #include "options.h"
28 /* #define DEBUG_FIXUP /* */
30 extern HANDLE CreateNewTask(HINSTANCE hInst);
31 extern int CallToInit16(unsigned long csip, unsigned long sssp,
32 unsigned short ds);
33 extern void InitializeLoadedDLLs(struct w_files *wpnt);
34 extern void FixupFunctionPrologs(struct w_files * wpnt);
36 char * GetModuleName(struct w_files * wpnt, int index, char *buffer);
37 extern char WindowsPath[256];
38 char *WIN_ProgramName;
40 HINSTANCE hSysRes;
42 #ifndef WINELIB
44 /**********************************************************************/
46 void load_ne_header (int fd, struct ne_header_s *ne_header)
48 if (read(fd, ne_header, sizeof(struct ne_header_s))
49 != sizeof(struct ne_header_s))
51 myerror("Unable to read NE header from file");
54 #endif
56 /**********************************************************************
57 * LoadNEImage
58 * Load one NE format executable into memory
60 HINSTANCE LoadNEImage(struct w_files *wpnt)
62 unsigned int read_size, status, segment;
63 int i;
64 char buffer[256];
65 char *fullname;
66 HANDLE t;
68 wpnt->ne_header = (struct ne_header_s *) malloc(sizeof(struct ne_header_s));
69 status = lseek(wpnt->fd, wpnt->mz_header->ne_offset, SEEK_SET);
70 load_ne_header (wpnt->fd, wpnt->ne_header);
72 #ifndef WINELIB
74 * Create segment selectors.
76 status = lseek(wpnt->fd, wpnt->mz_header->ne_offset +
77 wpnt->ne_header->segment_tab_offset,
78 SEEK_SET);
79 read_size = wpnt->ne_header->n_segment_tab *
80 sizeof(struct ne_segment_table_entry_s);
81 wpnt->seg_table = (struct ne_segment_table_entry_s *) malloc(read_size);
82 if (read(wpnt->fd, wpnt->seg_table, read_size) != read_size)
83 myerror("Unable to read segment table header from file");
84 wpnt->selector_table = CreateSelectors(wpnt);
85 wpnt->hinstance = (wpnt->
86 selector_table[wpnt->ne_header->auto_data_seg-1].
87 selector);
88 #endif
89 /* Get the lookup table. This is used for looking up the addresses
90 of functions that are exported */
92 read_size = wpnt->ne_header->entry_tab_length;
93 wpnt->lookup_table = (char *) malloc(read_size);
94 lseek(wpnt->fd, wpnt->mz_header->ne_offset +
95 wpnt->ne_header->entry_tab_offset, SEEK_SET);
96 if (read(wpnt->fd, wpnt->lookup_table, read_size) != read_size)
97 myerror("Unable to read lookup table header from file");
99 /* Get the iname table. This is used for looking up the names
100 of functions that are exported */
102 status = lseek(wpnt->fd, wpnt->ne_header->nrname_tab_offset, SEEK_SET);
103 read_size = wpnt->ne_header->nrname_tab_length;
104 wpnt->nrname_table = (char *) malloc(read_size);
105 if (read(wpnt->fd, wpnt->nrname_table, read_size) != read_size)
106 myerror("Unable to read nrname table header from file");
108 status = lseek(wpnt->fd, wpnt->mz_header->ne_offset +
109 wpnt->ne_header->rname_tab_offset, SEEK_SET);
110 read_size = wpnt->ne_header->moduleref_tab_offset -
111 wpnt->ne_header->rname_tab_offset;
112 wpnt->rname_table = (char *) malloc(read_size);
113 if (read(wpnt->fd, wpnt->rname_table, read_size) != read_size)
114 myerror("Unable to read rname table header from file");
116 /* Now get the module name, if the current one is a filename */
117 /* nope, name by which dll is loaded is used !
119 if (strchr(wpnt->name, '\\') || strchr(wpnt->name, '/') ) {
120 wpnt->name = (char*) malloc(*wpnt->rname_table + 1);
121 memcpy(wpnt->name, wpnt->rname_table+1, *wpnt->rname_table);
123 wpnt->name[*wpnt->rname_table] = 0;
126 * Now load any DLLs that this module refers to.
128 for(i=0; i<wpnt->ne_header->n_mod_ref_tab; i++)
130 char buff[14];
131 GetModuleName(wpnt, i + 1, buff);
133 if (strcasecmp(buff, wpnt->name) != 0 )
134 LoadImage(buff, DLL, 0);
136 #ifndef WINELIB
137 /* fixup references */
139 for (segment = 0; segment < wpnt->ne_header->n_segment_tab; segment++)
140 if (FixupSegment(wpnt, segment) < 0)
141 myerror("fixup failed.");
143 FixupFunctionPrologs(wpnt);
144 InitializeLoadedDLLs(wpnt);
145 #endif
146 return(wpnt->hinstance);
149 /**********************************************************************
150 * GetImportedName
152 char *
153 GetImportedName(int fd, struct mz_header_s *mz_header,
154 struct ne_header_s *ne_header, int name_offset, char *buffer)
156 int length;
157 int status;
159 status = lseek(fd, mz_header->ne_offset + ne_header->iname_tab_offset +
160 name_offset, SEEK_SET);
161 length = 0;
162 read(fd, &length, 1); /* Get the length byte */
163 length = CONV_CHAR_TO_LONG (length);
164 read(fd, buffer, length);
165 buffer[length] = 0;
166 return buffer;
169 /**********************************************************************
170 * GetModuleName
172 char *
173 GetModuleName(struct w_files * wpnt, int index, char *buffer)
175 int fd = wpnt->fd;
176 struct mz_header_s *mz_header = wpnt->mz_header;
177 struct ne_header_s *ne_header = wpnt->ne_header;
178 int length;
179 WORD name_offset, status;
180 int i;
182 status = lseek(fd, mz_header->ne_offset + ne_header->moduleref_tab_offset +
183 2*(index - 1), SEEK_SET);
184 name_offset = 0;
185 read(fd, &name_offset, 2);
186 name_offset = CONV_SHORT (name_offset);
187 status = lseek(fd, mz_header->ne_offset + ne_header->iname_tab_offset +
188 name_offset, SEEK_SET);
189 length = 0;
190 read(fd, &length, 1); /* Get the length byte */
191 length = CONV_CHAR_TO_LONG (length);
192 read(fd, buffer, length);
193 buffer[length] = 0;
195 /* Module names are always upper case */
196 for(i=0; i<length; i++)
197 if(buffer[i] >= 'a' && buffer[i] <= 'z') buffer[i] &= ~0x20;
199 return buffer;
203 #ifndef WINELIB
204 /**********************************************************************
205 * FixupSegment
208 FixupSegment(struct w_files * wpnt, int segment_num)
210 int fd = wpnt->fd;
211 struct mz_header_s * mz_header = wpnt->mz_header;
212 struct ne_header_s *ne_header = wpnt->ne_header;
213 struct ne_segment_table_entry_s *seg_table = wpnt->seg_table;
214 struct segment_descriptor_s *selector_table = wpnt->selector_table;
215 struct relocation_entry_s *rep, *rep1;
216 struct ne_segment_table_entry_s *seg;
217 struct segment_descriptor_s *sel;
218 struct dll_table_entry_s *dll_table;
219 int status;
220 unsigned short *sp;
221 unsigned int selector, address;
222 unsigned int next_addr;
223 int ordinal;
224 char dll_name[257];
225 char func_name[257];
226 int i, n_entries;
227 int additive;
229 seg = &seg_table[segment_num];
230 sel = &selector_table[segment_num];
232 #ifdef DEBUG_FIXUP
233 printf("Segment fixups for %s, segment %d, selector %x\n",
234 wpnt->name, segment_num, (int) sel->base_addr >> 16);
235 #endif
237 if ((seg->seg_data_offset == 0) ||
238 !(seg->seg_flags & NE_SEGFLAGS_RELOC_DATA))
239 return 0;
242 * Go through the relocation table on entry at a time.
244 i = seg->seg_data_length;
245 if (i == 0)
246 i = 0x10000;
248 status = lseek(fd, seg->seg_data_offset *
249 (1 << ne_header->align_shift_count) + i, SEEK_SET);
250 n_entries = 0;
251 read(fd, &n_entries, sizeof(short int));
252 rep = (struct relocation_entry_s *)
253 malloc(n_entries * sizeof(struct relocation_entry_s));
255 if (read(fd,rep, n_entries * sizeof(struct relocation_entry_s)) !=
256 n_entries * sizeof(struct relocation_entry_s))
258 myerror("Unable to read relocation information");
261 rep1 = rep;
263 for (i = 0; i < n_entries; i++, rep++)
266 * Get the target address corresponding to this entry.
268 additive = 0;
270 switch (rep->relocation_type)
272 case NE_RELTYPE_ORDINALADD:
273 additive = 1;
275 case NE_RELTYPE_ORDINAL:
276 if (GetModuleName(wpnt, rep->target1,
277 dll_name) == NULL)
279 fprintf(stderr, "NE_RELTYPE_ORDINAL failed");
280 return -1;
283 ordinal = rep->target2;
285 status = GetEntryDLLOrdinal(dll_name, ordinal, &selector,
286 &address);
287 if (status)
289 char s[80];
291 sprintf(s, "Bad DLL name '%s.%d'", dll_name, ordinal);
292 myerror(s);
293 return -1;
296 #ifdef DEBUG_FIXUP
297 printf("%d: %s.%d: %04.4x:%04.4x\n", i + 1, dll_name, ordinal,
298 selector, address);
299 #endif
300 break;
302 case NE_RELTYPE_NAMEADD:
303 additive = 1;
305 case NE_RELTYPE_NAME:
306 if (GetModuleName(wpnt, rep->target1, dll_name)
307 == NULL)
309 fprintf(stderr,"NE_RELTYPE_NAME failed");
310 return -1;
313 if (GetImportedName(fd, mz_header, ne_header,
314 rep->target2, func_name) == NULL)
316 fprintf(stderr,"getimportedname failed");
317 return -1;
320 status = GetEntryDLLName(dll_name, func_name, &selector,
321 &address);
322 if (status)
324 char s[80];
326 sprintf(s, "Bad DLL name '%s (%s)'", dll_name,func_name);
327 myerror(s);
328 return -1;
331 #ifdef DEBUG_FIXUP
332 printf("%d: %s %s.%d: %04.4x:%04.4x\n", i + 1, func_name,
333 dll_name, ordinal, selector, address);
334 #endif
335 break;
337 case NE_RELTYPE_INTERNAL:
338 case NE_RELTYPE_INT1:
339 if (rep->target1 == 0x00ff)
341 address = GetEntryPointFromOrdinal(wpnt, rep->target2);
342 selector = (address >> 16) & 0xffff;
343 address &= 0xffff;
345 else
347 selector = selector_table[rep->target1-1].selector;
348 address = rep->target2;
351 #ifdef DEBUG_FIXUP
352 printf("%d: %04.4x:%04.4x\n", i + 1, selector, address);
353 #endif
354 break;
356 case 7:
357 /* Relocation type 7:
359 * These appear to be used as fixups for the Windows
360 * floating point emulator. Let's just ignore them and
361 * try to use the hardware floating point. Linux should
362 * successfully emulate the coprocessor if it doesn't
363 * exist.
365 #ifdef DEBUG_FIXUP
366 printf("%d: ADDR TYPE %d, TYPE %d, OFFSET %04.4x, ",
367 i + 1, rep->address_type, rep->relocation_type,
368 rep->offset);
369 printf("TARGET %04.4x %04.4x\n", rep->target1, rep->target2);
370 #endif
371 continue;
373 default:
374 fprintf(stderr,"%d: ADDR TYPE %d, TYPE %d, OFFSET %04.4x, ",
375 i + 1, rep->address_type, rep->relocation_type,
376 rep->offset);
377 fprintf(stderr,"TARGET %04.4x %04.4x\n",
378 rep->target1, rep->target2);
379 free(rep1);
380 return -1;
384 * Stuff the right size result in.
386 sp = (unsigned short *) ((char *) sel->base_addr + rep->offset);
387 if (additive)
389 if (FindDLLTable(dll_name) == NULL)
390 additive = 2;
392 fprintf(stderr,"%d: ADDR TYPE %d, TYPE %d, OFFSET %04.4x, ",
393 i + 1, rep->address_type, rep->relocation_type,
394 rep->offset);
395 fprintf(stderr,"TARGET %04.4x %04.4x\n",
396 rep->target1, rep->target2);
397 fprintf(stderr, " Additive = %d\n", additive);
400 switch (rep->address_type)
402 case NE_RADDR_OFFSET16:
403 do {
404 #ifdef DEBUG_FIXUP
405 printf(" %04.4x:%04.4x:%04.4x OFFSET16\n",
406 (unsigned long) sp >> 16, (int) sp & 0xFFFF, *sp);
407 #endif
408 next_addr = *sp;
409 *sp = (unsigned short) address;
410 if (additive == 2)
411 *sp += next_addr;
412 sp = (unsigned short *) ((char *) sel->base_addr + next_addr);
414 while (next_addr != 0xffff && !additive);
416 break;
418 case NE_RADDR_POINTER32:
419 do {
420 #ifdef DEBUG_FIXUP
421 printf(" %04.4x:%04.4x:%04.4x POINTER32\n",
422 (unsigned long) sp >> 16, (int) sp & 0xFFFF, *sp);
423 #endif
424 next_addr = *sp;
425 *sp = (unsigned short) address;
426 if (additive == 2)
427 *sp += next_addr;
428 *(sp+1) = (unsigned short) selector;
429 sp = (unsigned short *) ((char *) sel->base_addr + next_addr);
431 while (next_addr != 0xffff && !additive);
433 break;
435 case NE_RADDR_SELECTOR:
436 do {
437 #ifdef DEBUG_FIXUP
438 printf(" %04.4x:%04.4x:%04.4x SELECTOR\n",
439 (unsigned long) sp >> 16, (int) sp & 0xFFFF, *sp);
440 #endif
441 next_addr = *sp;
442 *sp = (unsigned short) selector;
443 sp = (unsigned short *) ((char *) sel->base_addr + next_addr);
444 if (rep->relocation_type == NE_RELTYPE_INT1)
445 break;
447 while (next_addr != 0xffff && !additive);
449 break;
451 default:
452 printf("%d: ADDR TYPE %d, TYPE %d, OFFSET %04.4x, ",
453 i + 1, rep->address_type, rep->relocation_type,
454 rep->offset);
455 printf("TARGET %04.4x %04.4x\n", rep->target1, rep->target2);
456 free(rep1);
457 return -1;
461 free(rep1);
462 return 0;
465 #endif /* !WINELIB */