blob: 0d3df107215b72bde3f01c506612db88f736c17c [file] [log] [blame]
Alexandre Julliard234bc241994-12-10 13:02:28 +00001/*
Alexandre Julliard46ea8b31998-05-03 19:01:20 +00002 * NE segment loading
Alexandre Julliard594997c1995-04-30 10:05:20 +00003 *
4 * Copyright 1993 Robert J. Amstadt
5 * Copyright 1995 Alexandre Julliard
6 */
7
Alexandre Julliard46ea8b31998-05-03 19:01:20 +00008#include <assert.h>
Alexandre Julliard490a27e1994-06-08 13:57:50 +00009#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>
Alexandre Julliardaca05781994-10-17 18:12:41 +000015#include <ctype.h>
Alexandre Julliard490a27e1994-06-08 13:57:50 +000016#include <string.h>
Marcus Meissner317af321999-02-17 13:51:06 +000017
18#include "wine/winbase16.h"
Alexandre Julliard982a2232000-12-13 20:20:09 +000019#include "wine/library.h"
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +000020#include "global.h"
Alexandre Julliard77b99181997-09-14 17:17:23 +000021#include "task.h"
Alexandre Julliard8cc3a5e1996-08-11 15:49:51 +000022#include "file.h"
Alexandre Julliard594997c1995-04-30 10:05:20 +000023#include "module.h"
24#include "stackframe.h"
Ulrich Weigand21499341999-12-05 02:50:38 +000025#include "builtin16.h"
Alexandre Julliard06c275a1999-05-02 14:32:27 +000026#include "debugtools.h"
Alexandre Julliard490a27e1994-06-08 13:57:50 +000027
Alexandre Julliard198746d2000-08-14 14:29:22 +000028DECLARE_DEBUG_CHANNEL(dll);
29DECLARE_DEBUG_CHANNEL(fixup);
30DECLARE_DEBUG_CHANNEL(module);
31DECLARE_DEBUG_CHANNEL(segment);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000032
Alexandre Julliard7afce0e2000-12-01 21:25:31 +000033/*
34 * Relocation table entry
35 */
36struct relocation_entry_s
37{
38 BYTE address_type; /* Relocation address type */
39 BYTE relocation_type; /* Relocation type */
40 WORD offset; /* Offset in segment to fixup */
41 WORD target1; /* Target specification */
42 WORD target2; /* Target specification */
43};
44
45/*
46 * Relocation address types
47 */
48#define NE_RADDR_LOWBYTE 0
49#define NE_RADDR_SELECTOR 2
50#define NE_RADDR_POINTER32 3
51#define NE_RADDR_OFFSET16 5
52#define NE_RADDR_POINTER48 11
53#define NE_RADDR_OFFSET32 13
54
55/*
56 * Relocation types
57 */
58#define NE_RELTYPE_INTERNAL 0
59#define NE_RELTYPE_ORDINAL 1
60#define NE_RELTYPE_NAME 2
61#define NE_RELTYPE_OSFIXUP 3
62#define NE_RELFLAG_ADDITIVE 4
63
Andreas Mohr5a08a021999-07-31 13:11:22 +000064#define SEL(x) ((x)|1)
Alexandre Julliard490a27e1994-06-08 13:57:50 +000065
Ulrich Weigand61206bd1999-11-21 00:50:30 +000066static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum);
67
Alexandre Julliard198746d2000-08-14 14:29:22 +000068/* ### start build ### */
69extern WORD CALLBACK NE_CallTo16_word_ww(FARPROC16,WORD,WORD);
70extern WORD CALLBACK NE_CallTo16_word_www(FARPROC16,WORD,WORD,WORD);
71/* ### stop build ### */
72
Alexandre Julliard594997c1995-04-30 10:05:20 +000073/***********************************************************************
Alexandre Julliardc7c217b1998-04-13 12:21:30 +000074 * NE_GetRelocAddrName
75 */
76static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
77{
78 switch(addr_type & 0x7f)
79 {
80 case NE_RADDR_LOWBYTE: return additive ? "BYTE add" : "BYTE";
81 case NE_RADDR_OFFSET16: return additive ? "OFFSET16 add" : "OFFSET16";
82 case NE_RADDR_POINTER32: return additive ? "POINTER32 add" : "POINTER32";
83 case NE_RADDR_SELECTOR: return additive ? "SELECTOR add" : "SELECTOR";
84 case NE_RADDR_POINTER48: return additive ? "POINTER48 add" : "POINTER48";
85 case NE_RADDR_OFFSET32: return additive ? "OFFSET32 add" : "OFFSET32";
86 }
87 return "???";
88}
89
90
91/***********************************************************************
Alexandre Julliard594997c1995-04-30 10:05:20 +000092 * NE_LoadSegment
Alexandre Julliard490a27e1994-06-08 13:57:50 +000093 */
Alexandre Julliarda3960291999-02-26 11:11:13 +000094BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
Alexandre Julliard490a27e1994-06-08 13:57:50 +000095{
Alexandre Julliard594997c1995-04-30 10:05:20 +000096 SEGTABLEENTRY *pSegTable, *pSeg;
97 WORD *pModuleTable;
Alexandre Julliardc7c217b1998-04-13 12:21:30 +000098 WORD count, i, offset, next_offset;
Alexandre Julliard18f92e71996-07-17 20:02:21 +000099 HMODULE16 module;
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000100 FARPROC16 address = 0;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000101 HFILE hf;
Alexandre Julliard13926581999-01-01 16:55:02 +0000102 DWORD res;
Alexandre Julliard594997c1995-04-30 10:05:20 +0000103 struct relocation_entry_s *rep, *reloc_entries;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000104 BYTE *func_name;
Alexandre Julliardb7258be1995-09-01 15:57:28 +0000105 int size;
106 char* mem;
Alexandre Julliard234bc241994-12-10 13:02:28 +0000107
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000108 char buffer[256];
Alexandre Julliard594997c1995-04-30 10:05:20 +0000109 int ordinal, additive;
Alexandre Julliard490a27e1994-06-08 13:57:50 +0000110 unsigned short *sp;
Alexandre Julliard490a27e1994-06-08 13:57:50 +0000111
Alexandre Julliard594997c1995-04-30 10:05:20 +0000112 pSegTable = NE_SEG_TABLE( pModule );
113 pSeg = pSegTable + segnum - 1;
Andreas Mohre6c12ee1998-10-11 17:36:46 +0000114
Andreas Mohrf2df6a22000-03-07 12:26:16 +0000115 if (pSeg->flags & NE_SEGFLAGS_LOADED)
116 {
117 /* self-loader ? -> already loaded it */
118 if (pModule->flags & NE_FFLAGS_SELFLOAD)
119 return TRUE;
120
121 /* leave, except for DGROUP, as this may be the second instance */
122 if (segnum != pModule->dgroup)
123 return TRUE;
124 }
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +0000125
Alexandre Julliard594997c1995-04-30 10:05:20 +0000126 if (!pSeg->filepos) return TRUE; /* No file image, just return */
Alexandre Julliardded30381995-07-06 17:18:27 +0000127
Andreas Mohre6c12ee1998-10-11 17:36:46 +0000128 pModuleTable = NE_MODULE_TABLE( pModule );
129
Alexandre Julliard13926581999-01-01 16:55:02 +0000130 hf = NE_OpenFile( pModule );
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000131 TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000132 segnum, pSeg->hSeg, pSeg->flags );
Alexandre Julliard13926581999-01-01 16:55:02 +0000133 SetFilePointer( hf, pSeg->filepos << pModule->alignment, NULL, SEEK_SET );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000134 if (pSeg->size) size = pSeg->size;
Andreas Mohre6c12ee1998-10-11 17:36:46 +0000135 else size = pSeg->minsize ? pSeg->minsize : 0x10000;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000136 mem = GlobalLock16(pSeg->hSeg);
Alexandre Julliard21979011997-03-05 08:22:35 +0000137 if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
138 {
Andreas Mohrdca5e561999-04-16 08:17:17 +0000139 /* Implement self-loading segments */
Alexandre Julliardff8331e1995-09-18 11:19:54 +0000140 SELFLOADHEADER *selfloadheader;
Alexandre Julliardd37eb361997-07-20 16:23:21 +0000141 DWORD oldstack;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000142 HFILE hFile32;
Alexandre Julliard8da12c41999-01-17 16:55:11 +0000143 HFILE16 hFile16;
Alexandre Julliardf1aa3031996-08-05 17:42:43 +0000144
Alexandre Julliard982a2232000-12-13 20:20:09 +0000145 selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg),0) );
Alexandre Julliard0a860a01999-06-22 11:43:42 +0000146 oldstack = NtCurrentTeb()->cur_stack;
Alexandre Julliard982a2232000-12-13 20:20:09 +0000147 NtCurrentTeb()->cur_stack = MAKESEGPTR(pModule->self_loading_sel,
148 0xff00 - sizeof(STACK16FRAME));
Ulrich Weigandc50a1d01999-08-15 12:45:01 +0000149
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000150 TRACE_(dll)("CallLoadAppSegProc(hmodule=0x%04x,hf=0x%04x,segnum=%d\n",
Alexandre Julliarda0d77311998-09-13 16:32:00 +0000151 pModule->self,hf,segnum );
Alexandre Julliard8da12c41999-01-17 16:55:11 +0000152 DuplicateHandle( GetCurrentProcess(), hf, GetCurrentProcess(), &hFile32,
153 0, FALSE, DUPLICATE_SAME_ACCESS );
Alexandre Julliard5ce902b2000-11-27 21:59:08 +0000154 hFile16 = Win32HandleToDosFileHandle( hFile32 );
Alexandre Julliard198746d2000-08-14 14:29:22 +0000155 pSeg->hSeg = NE_CallTo16_word_www( selfloadheader->LoadAppSeg,
156 pModule->self, hFile16, segnum );
Ulrich Weigand61206bd1999-11-21 00:50:30 +0000157 TRACE_(dll)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n", pSeg->hSeg);
Alexandre Julliard8da12c41999-01-17 16:55:11 +0000158 _lclose16( hFile16 );
Alexandre Julliard0a860a01999-06-22 11:43:42 +0000159 NtCurrentTeb()->cur_stack = oldstack;
Alexandre Julliard21979011997-03-05 08:22:35 +0000160 }
Alexandre Julliardff8331e1995-09-18 11:19:54 +0000161 else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
Alexandre Julliard13926581999-01-01 16:55:02 +0000162 ReadFile(hf, mem, size, &res, NULL);
Alexandre Julliardb7258be1995-09-01 15:57:28 +0000163 else {
164 /*
165 The following bit of code for "iterated segments" was written without
166 any documentation on the format of these segments. It seems to work,
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000167 but may be missing something. If you have any doc please either send
Alexandre Julliardb7258be1995-09-01 15:57:28 +0000168 it to me or fix the code yourself. gfm@werple.mira.net.au
169 */
Dimitrie O. Paun9ad96362000-03-19 14:29:50 +0000170 char* buff = HeapAlloc(GetProcessHeap(), 0, size);
Alexandre Julliardb7258be1995-09-01 15:57:28 +0000171 char* curr = buff;
Dimitrie O. Paun9ad96362000-03-19 14:29:50 +0000172
173 if(buff == NULL) {
174 WARN_(dll)("Memory exausted!");
175 return FALSE;
176 }
177
Alexandre Julliard638f1691999-01-17 16:32:32 +0000178 ReadFile(hf, buff, size, &res, NULL);
Alexandre Julliardb7258be1995-09-01 15:57:28 +0000179 while(curr < buff + size) {
180 unsigned int rept = *((short*) curr)++;
181 unsigned int len = *((short*) curr)++;
182 for(; rept > 0; rept--) {
183 char* bytes = curr;
184 unsigned int byte;
185 for(byte = 0; byte < len; byte++)
186 *mem++ = *bytes++;
187 }
188 curr += len;
189 }
Dimitrie O. Paun9ad96362000-03-19 14:29:50 +0000190 HeapFree(GetProcessHeap(), 0, buff);
Alexandre Julliardb7258be1995-09-01 15:57:28 +0000191 }
Alexandre Julliard490a27e1994-06-08 13:57:50 +0000192
Alexandre Julliardff8331e1995-09-18 11:19:54 +0000193 pSeg->flags |= NE_SEGFLAGS_LOADED;
Ulrich Weigand61206bd1999-11-21 00:50:30 +0000194
195 /* Perform exported function prolog fixups */
196 NE_FixupSegmentPrologs( pModule, segnum );
197
Alexandre Julliard594997c1995-04-30 10:05:20 +0000198 if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
199 return TRUE; /* No relocation data, we are done */
200
Alexandre Julliard13926581999-01-01 16:55:02 +0000201 ReadFile(hf, &count, sizeof(count), &res, NULL);
Alexandre Julliard594997c1995-04-30 10:05:20 +0000202 if (!count) return TRUE;
203
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000204 TRACE_(fixup)("Fixups for %.*s, segment %d, hSeg %04x\n",
Alexandre Julliard2787be81995-05-22 18:23:01 +0000205 *((BYTE *)pModule + pModule->name_table),
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000206 (char *)pModule + pModule->name_table + 1,
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000207 segnum, pSeg->hSeg );
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000208 TRACE_(segment)("Fixups for %.*s, segment %d, hSeg %04x\n",
Alexandre Julliard2787be81995-05-22 18:23:01 +0000209 *((BYTE *)pModule + pModule->name_table),
210 (char *)pModule + pModule->name_table + 1,
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000211 segnum, pSeg->hSeg );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000212
Dimitrie O. Paun9ad96362000-03-19 14:29:50 +0000213 reloc_entries = (struct relocation_entry_s *)HeapAlloc(GetProcessHeap(), 0, count * sizeof(struct relocation_entry_s));
214 if(reloc_entries == NULL) {
215 WARN_(fixup)("Not enough memory for relocation entries!");
216 return FALSE;
217 }
Alexandre Julliard13926581999-01-01 16:55:02 +0000218 if (!ReadFile( hf, reloc_entries, count * sizeof(struct relocation_entry_s), &res, NULL) ||
219 (res != count * sizeof(struct relocation_entry_s)))
Alexandre Julliard594997c1995-04-30 10:05:20 +0000220 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000221 WARN_(fixup)("Unable to read relocation information\n" );
Alexandre Julliard594997c1995-04-30 10:05:20 +0000222 return FALSE;
223 }
Alexandre Julliard490a27e1994-06-08 13:57:50 +0000224
225 /*
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000226 * Go through the relocation table one entry at a time.
Alexandre Julliard490a27e1994-06-08 13:57:50 +0000227 */
Alexandre Julliard594997c1995-04-30 10:05:20 +0000228 rep = reloc_entries;
229 for (i = 0; i < count; i++, rep++)
Alexandre Julliard490a27e1994-06-08 13:57:50 +0000230 {
231 /*
232 * Get the target address corresponding to this entry.
233 */
Alexandre Julliarde2abbb11995-03-19 17:39:39 +0000234
235 /* If additive, there is no target chain list. Instead, add source
236 and target */
237 additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
238 rep->relocation_type &= 0x3;
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000239
Alexandre Julliard490a27e1994-06-08 13:57:50 +0000240 switch (rep->relocation_type)
241 {
Alexandre Julliard490a27e1994-06-08 13:57:50 +0000242 case NE_RELTYPE_ORDINAL:
Alexandre Julliard594997c1995-04-30 10:05:20 +0000243 module = pModuleTable[rep->target1-1];
Alexandre Julliard594997c1995-04-30 10:05:20 +0000244 ordinal = rep->target2;
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000245 address = NE_GetEntryPoint( module, ordinal );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000246 if (!address)
247 {
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000248 NE_MODULE *pTarget = NE_GetPtr( module );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000249 if (!pTarget)
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000250 WARN_(module)("Module not found: %04x, reference %d of module %*.*s\n",
Alexandre Julliard2787be81995-05-22 18:23:01 +0000251 module, rep->target1,
252 *((BYTE *)pModule + pModule->name_table),
253 *((BYTE *)pModule + pModule->name_table),
254 (char *)pModule + pModule->name_table + 1 );
255 else
Alexandre Julliard829fe321998-07-26 14:27:39 +0000256 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000257 ERR_(fixup)("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
Alexandre Julliard2787be81995-05-22 18:23:01 +0000258 *((BYTE *)pTarget + pTarget->name_table),
259 (char *)pTarget + pTarget->name_table + 1,
260 ordinal );
Alexandre Julliarda0d77311998-09-13 16:32:00 +0000261 address = (FARPROC16)0xdeadbeef;
Alexandre Julliard829fe321998-07-26 14:27:39 +0000262 }
Alexandre Julliard2787be81995-05-22 18:23:01 +0000263 }
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000264 if (TRACE_ON(fixup))
Alexandre Julliard2787be81995-05-22 18:23:01 +0000265 {
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000266 NE_MODULE *pTarget = NE_GetPtr( module );
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000267 TRACE_(fixup)("%d: %.*s.%d=%04x:%04x %s\n", i + 1,
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000268 *((BYTE *)pTarget + pTarget->name_table),
269 (char *)pTarget + pTarget->name_table + 1,
270 ordinal, HIWORD(address), LOWORD(address),
271 NE_GetRelocAddrName( rep->address_type, additive ) );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000272 }
Alexandre Julliard490a27e1994-06-08 13:57:50 +0000273 break;
274
Alexandre Julliard490a27e1994-06-08 13:57:50 +0000275 case NE_RELTYPE_NAME:
Alexandre Julliard594997c1995-04-30 10:05:20 +0000276 module = pModuleTable[rep->target1-1];
Alexandre Julliard594997c1995-04-30 10:05:20 +0000277 func_name = (char *)pModule + pModule->import_table + rep->target2;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000278 memcpy( buffer, func_name+1, *func_name );
279 buffer[*func_name] = '\0';
280 func_name = buffer;
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000281 ordinal = NE_GetOrdinal( module, func_name );
282 address = NE_GetEntryPoint( module, ordinal );
Alexandre Julliard594997c1995-04-30 10:05:20 +0000283
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000284 if (ERR_ON(fixup) && !address)
Alexandre Julliard2787be81995-05-22 18:23:01 +0000285 {
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000286 NE_MODULE *pTarget = NE_GetPtr( module );
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000287 ERR_(fixup)("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000288 *((BYTE *)pTarget + pTarget->name_table),
289 (char *)pTarget + pTarget->name_table + 1, func_name );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000290 }
Alexandre Julliarda0d77311998-09-13 16:32:00 +0000291 if (!address) address = (FARPROC16) 0xdeadbeef;
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000292 if (TRACE_ON(fixup))
Alexandre Julliard2787be81995-05-22 18:23:01 +0000293 {
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000294 NE_MODULE *pTarget = NE_GetPtr( module );
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000295 TRACE_(fixup)("%d: %.*s.%s=%04x:%04x %s\n", i + 1,
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000296 *((BYTE *)pTarget + pTarget->name_table),
297 (char *)pTarget + pTarget->name_table + 1,
298 func_name, HIWORD(address), LOWORD(address),
299 NE_GetRelocAddrName( rep->address_type, additive ) );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000300 }
Alexandre Julliard490a27e1994-06-08 13:57:50 +0000301 break;
302
303 case NE_RELTYPE_INTERNAL:
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000304 if ((rep->target1 & 0xff) == 0xff)
Alexandre Julliard490a27e1994-06-08 13:57:50 +0000305 {
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000306 address = NE_GetEntryPoint( pModule->self, rep->target2 );
Alexandre Julliard490a27e1994-06-08 13:57:50 +0000307 }
308 else
309 {
Alexandre Julliard982a2232000-12-13 20:20:09 +0000310 address = (FARPROC16)MAKESEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
Alexandre Julliard490a27e1994-06-08 13:57:50 +0000311 }
312
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000313 TRACE_(fixup)("%d: %04x:%04x %s\n",
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000314 i + 1, HIWORD(address), LOWORD(address),
315 NE_GetRelocAddrName( rep->address_type, additive ) );
Alexandre Julliard490a27e1994-06-08 13:57:50 +0000316 break;
317
Alexandre Julliarde2abbb11995-03-19 17:39:39 +0000318 case NE_RELTYPE_OSFIXUP:
Alexandre Julliard490a27e1994-06-08 13:57:50 +0000319 /* Relocation type 7:
320 *
321 * These appear to be used as fixups for the Windows
322 * floating point emulator. Let's just ignore them and
323 * try to use the hardware floating point. Linux should
324 * successfully emulate the coprocessor if it doesn't
325 * exist.
326 */
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000327 TRACE_(fixup)("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000328 i + 1, rep->relocation_type, rep->offset,
329 rep->target1, rep->target2,
330 NE_GetRelocAddrName( rep->address_type, additive ) );
Alexandre Julliard490a27e1994-06-08 13:57:50 +0000331 continue;
Alexandre Julliard490a27e1994-06-08 13:57:50 +0000332 }
333
Alexandre Julliardfa68b751995-04-03 16:55:37 +0000334 offset = rep->offset;
Alexandre Julliarde2abbb11995-03-19 17:39:39 +0000335
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000336 /* Apparently, high bit of address_type is sometimes set; */
337 /* we ignore it for now */
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000338 if (rep->address_type > NE_RADDR_OFFSET32)
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000339 {
340 char module[10];
Alexandre Julliarda3960291999-02-26 11:11:13 +0000341 GetModuleName16( pModule->self, module, sizeof(module) );
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000342 ERR_(fixup)("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000343 module, rep->address_type );
344 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000345
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000346 if (additive)
347 {
Alexandre Julliard982a2232000-12-13 20:20:09 +0000348 sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000349 TRACE_(fixup)(" %04x:%04x\n", offset, *sp );
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000350 switch (rep->address_type & 0x7f)
351 {
352 case NE_RADDR_LOWBYTE:
353 *(BYTE *)sp += LOBYTE((int)address);
354 break;
355 case NE_RADDR_OFFSET16:
356 *sp += LOWORD(address);
357 break;
358 case NE_RADDR_POINTER32:
359 *sp += LOWORD(address);
Alexandre Julliard594997c1995-04-30 10:05:20 +0000360 *(sp+1) = HIWORD(address);
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000361 break;
362 case NE_RADDR_SELECTOR:
Alexandre Julliardfa68b751995-04-03 16:55:37 +0000363 /* Borland creates additive records with offset zero. Strange, but OK */
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000364 if (*sp)
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000365 ERR_(fixup)("Additive selector to %04x.Please report\n",*sp);
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000366 else
367 *sp = HIWORD(address);
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000368 break;
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000369 default:
370 goto unknown;
371 }
372 }
373 else /* non-additive fixup */
374 {
375 do
376 {
Alexandre Julliard982a2232000-12-13 20:20:09 +0000377 sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000378 next_offset = *sp;
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000379 TRACE_(fixup)(" %04x:%04x\n", offset, *sp );
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000380 switch (rep->address_type & 0x7f)
381 {
382 case NE_RADDR_LOWBYTE:
383 *(BYTE *)sp = LOBYTE((int)address);
384 break;
385 case NE_RADDR_OFFSET16:
386 *sp = LOWORD(address);
387 break;
388 case NE_RADDR_POINTER32:
389 *(FARPROC16 *)sp = address;
390 break;
391 case NE_RADDR_SELECTOR:
392 *sp = SELECTOROF(address);
393 break;
394 default:
395 goto unknown;
396 }
397 if (next_offset == offset) break; /* avoid infinite loop */
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000398 if (next_offset >= GlobalSize16(pSeg->hSeg)) break;
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000399 offset = next_offset;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +0000400 } while (offset != 0xffff);
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000401 }
Alexandre Julliard490a27e1994-06-08 13:57:50 +0000402 }
403
Dimitrie O. Paun9ad96362000-03-19 14:29:50 +0000404 HeapFree(GetProcessHeap(), 0, reloc_entries);
Alexandre Julliard594997c1995-04-30 10:05:20 +0000405 return TRUE;
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000406
407unknown:
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000408 WARN_(fixup)("WARNING: %d: unknown ADDR TYPE %d, "
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000409 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
410 i + 1, rep->address_type, rep->relocation_type,
411 rep->offset, rep->target1, rep->target2);
Dimitrie O. Paun9ad96362000-03-19 14:29:50 +0000412 HeapFree(GetProcessHeap(), 0, reloc_entries);
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000413 return FALSE;
Alexandre Julliard490a27e1994-06-08 13:57:50 +0000414}
415
Alexandre Julliard594997c1995-04-30 10:05:20 +0000416
417/***********************************************************************
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000418 * NE_LoadAllSegments
419 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000420BOOL NE_LoadAllSegments( NE_MODULE *pModule )
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000421{
422 int i;
Andreas Mohre6c12ee1998-10-11 17:36:46 +0000423 SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000424
425 if (pModule->flags & NE_FFLAGS_SELFLOAD)
426 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000427 HFILE hf;
Alexandre Julliard8da12c41999-01-17 16:55:11 +0000428 HFILE16 hFile16;
Andreas Mohrdca5e561999-04-16 08:17:17 +0000429 /* Handle self-loading modules */
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000430 SELFLOADHEADER *selfloadheader;
Alexandre Julliard7afce0e2000-12-01 21:25:31 +0000431 HMODULE16 mod = GetModuleHandle16("KERNEL");
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000432 DWORD oldstack;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000433
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000434 TRACE_(module)("%.*s is a self-loading module!\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000435 *((BYTE*)pModule + pModule->name_table),
436 (char *)pModule + pModule->name_table + 1);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000437 if (!NE_LoadSegment( pModule, 1 )) return FALSE;
Alexandre Julliard982a2232000-12-13 20:20:09 +0000438 selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg), 0) );
Alexandre Julliard7afce0e2000-12-01 21:25:31 +0000439 selfloadheader->EntryAddrProc = GetProcAddress16(mod,"EntryAddrProc");
440 selfloadheader->MyAlloc = GetProcAddress16(mod,"MyAlloc");
441 selfloadheader->SetOwner = GetProcAddress16(mod,"FarSetOwner");
Alexandre Julliard914406f2000-11-14 01:54:49 +0000442 pModule->self_loading_sel = SEL(GLOBAL_Alloc(GMEM_ZEROINIT, 0xFF00, pModule->self, WINE_LDT_FLAGS_DATA));
Alexandre Julliard0a860a01999-06-22 11:43:42 +0000443 oldstack = NtCurrentTeb()->cur_stack;
Alexandre Julliard982a2232000-12-13 20:20:09 +0000444 NtCurrentTeb()->cur_stack = MAKESEGPTR(pModule->self_loading_sel,
445 0xff00 - sizeof(STACK16FRAME) );
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000446
Alexandre Julliard8da12c41999-01-17 16:55:11 +0000447 DuplicateHandle( GetCurrentProcess(), NE_OpenFile(pModule),
448 GetCurrentProcess(), &hf, 0, FALSE, DUPLICATE_SAME_ACCESS );
Alexandre Julliard5ce902b2000-11-27 21:59:08 +0000449 hFile16 = Win32HandleToDosFileHandle( hf );
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000450 TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
Alexandre Julliard8da12c41999-01-17 16:55:11 +0000451 pModule->self,hFile16);
Alexandre Julliard198746d2000-08-14 14:29:22 +0000452 NE_CallTo16_word_ww(selfloadheader->BootApp, pModule->self,hFile16);
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000453 TRACE_(dll)("Return from CallBootAppProc\n");
Alexandre Julliard8da12c41999-01-17 16:55:11 +0000454 _lclose16(hf);
Alexandre Julliard0a860a01999-06-22 11:43:42 +0000455 NtCurrentTeb()->cur_stack = oldstack;
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000456
Andreas Mohre6c12ee1998-10-11 17:36:46 +0000457 for (i = 2; i <= pModule->seg_count; i++)
458 if (!NE_LoadSegment( pModule, i )) return FALSE;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000459 }
460 else
461 {
462 for (i = 1; i <= pModule->seg_count; i++)
463 if (!NE_LoadSegment( pModule, i )) return FALSE;
464 }
465 return TRUE;
466}
467
468
469/***********************************************************************
Andreas Mohrdca5e561999-04-16 08:17:17 +0000470 * NE_FixupSegmentPrologs
471 *
472 * Fixup exported functions prologs of one segment
473 */
Ulrich Weigand61206bd1999-11-21 00:50:30 +0000474static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum)
Andreas Mohrdca5e561999-04-16 08:17:17 +0000475{
476 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
477 ET_BUNDLE *bundle;
478 ET_ENTRY *entry;
479 WORD dgroup, num_entries, sel = SEL(pSegTable[segnum-1].hSeg);
480 BYTE *pSeg, *pFunc;
481
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000482 TRACE_(module)("(%d);\n", segnum);
Andreas Mohrdca5e561999-04-16 08:17:17 +0000483
484 if (pSegTable[segnum-1].flags & NE_SEGFLAGS_DATA)
Michael Karchera21fe341999-08-15 14:16:42 +0000485 {
Andreas Mohrdca5e561999-04-16 08:17:17 +0000486 pSegTable[segnum-1].flags |= NE_SEGFLAGS_LOADED;
487 return;
488 }
Andreas Mohrdca5e561999-04-16 08:17:17 +0000489
Michael Karchera21fe341999-08-15 14:16:42 +0000490 if (!pModule->dgroup) return;
491
492 if (!(dgroup = SEL(pSegTable[pModule->dgroup-1].hSeg))) return;
493
Alexandre Julliard982a2232000-12-13 20:20:09 +0000494 pSeg = MapSL( MAKESEGPTR(sel, 0) );
Andreas Mohrdca5e561999-04-16 08:17:17 +0000495
496 bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->entry_table);
497
498 do {
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000499 TRACE_(module)("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle->last - bundle->first, bundle, bundle->next, pSeg);
Andreas Mohrdca5e561999-04-16 08:17:17 +0000500 if (!(num_entries = bundle->last - bundle->first))
501 return;
502 entry = (ET_ENTRY *)((BYTE *)bundle+6);
503 while (num_entries--)
504 {
Alexandre Julliard908464d2000-11-01 03:11:12 +0000505 /*TRACE_(module)("entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/
Andreas Mohrdca5e561999-04-16 08:17:17 +0000506 if (entry->segnum == segnum)
507 {
508 pFunc = ((BYTE *)pSeg+entry->offs);
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000509 TRACE_(module)("pFunc: %p, *(DWORD *)pFunc: %08lx, num_entries: %d\n", pFunc, *(DWORD *)pFunc, num_entries);
Andreas Mohrdca5e561999-04-16 08:17:17 +0000510 if (*(pFunc+2) == 0x90)
511 {
512 if (*(WORD *)pFunc == 0x581e) /* push ds, pop ax */
513 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000514 TRACE_(module)("patch %04x:%04x -> mov ax, ds\n", sel, entry->offs);
Andreas Mohrdca5e561999-04-16 08:17:17 +0000515 *(WORD *)pFunc = 0xd88c; /* mov ax, ds */
516 }
517
518 if (*(WORD *)pFunc == 0xd88c)
519 {
520 if ((entry->flags & 2)) /* public data ? */
521 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000522 TRACE_(module)("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel, entry->offs, dgroup);
Andreas Mohrdca5e561999-04-16 08:17:17 +0000523 *pFunc = 0xb8; /* mov ax, */
524 *(WORD *)(pFunc+1) = dgroup;
525 }
526 else
527 if ((pModule->flags & NE_FFLAGS_MULTIPLEDATA)
528 && (entry->flags & 1)) /* exported ? */
529 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000530 TRACE_(module)("patch %04x:%04x -> nop, nop\n", sel, entry->offs);
Andreas Mohrdca5e561999-04-16 08:17:17 +0000531 *(WORD *)pFunc = 0x9090; /* nop, nop */
532 }
533 }
534 }
535 }
536 entry++;
537 }
538 } while ( (bundle->next)
539 && (bundle = ((ET_BUNDLE *)((BYTE *)pModule + bundle->next))) );
540}
541
542
543/***********************************************************************
Andreas Mohre6c12ee1998-10-11 17:36:46 +0000544 * PatchCodeHandle
545 *
546 * Needed for self-loading modules.
547 */
Andreas Mohrdca5e561999-04-16 08:17:17 +0000548DWORD WINAPI PatchCodeHandle16(HANDLE16 hSeg)
Andreas Mohre6c12ee1998-10-11 17:36:46 +0000549{
Andreas Mohrdca5e561999-04-16 08:17:17 +0000550 WORD segnum;
551 WORD sel = SEL(hSeg);
552 NE_MODULE *pModule = NE_GetPtr(FarGetOwner16(sel));
553 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE(pModule);
Andreas Mohre6c12ee1998-10-11 17:36:46 +0000554
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000555 TRACE_(module)("(%04x);\n", hSeg);
Andreas Mohrdca5e561999-04-16 08:17:17 +0000556
557 /* find the segment number of the module that belongs to hSeg */
558 for (segnum = 1; segnum <= pModule->seg_count; segnum++)
559 {
560 if (SEL(pSegTable[segnum-1].hSeg) == sel)
561 {
562 NE_FixupSegmentPrologs(pModule, segnum);
563 break;
564 }
565 }
566
567 return MAKELONG(hSeg, sel);
568}
Andreas Mohre6c12ee1998-10-11 17:36:46 +0000569
Alexandre Julliard594997c1995-04-30 10:05:20 +0000570
Alexandre Julliarda845b881998-06-01 10:44:35 +0000571/***********************************************************************
572 * NE_GetDLLInitParams
573 */
574static VOID NE_GetDLLInitParams( NE_MODULE *pModule,
575 WORD *hInst, WORD *ds, WORD *heap )
576{
577 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
578
579 if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
580 {
581 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
582 {
583 /* Not SINGLEDATA */
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000584 ERR_(dll)("Library is not marked SINGLEDATA\n");
Alexandre Julliarda845b881998-06-01 10:44:35 +0000585 exit(1);
586 }
587 else /* DATA NONE DLL */
588 {
589 *ds = 0;
590 *heap = 0;
591 }
592 }
593 else /* DATA SINGLE DLL */
594 {
595 if (pModule->dgroup) {
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000596 *ds = SEL(pSegTable[pModule->dgroup-1].hSeg);
Alexandre Julliarda845b881998-06-01 10:44:35 +0000597 *heap = pModule->heap_size;
598 }
599 else /* hmm, DLL has no dgroup,
600 but why has it NE_FFLAGS_SINGLEDATA set ?
601 Buggy DLL compiler ? */
602 {
603 *ds = 0;
604 *heap = 0;
605 }
606 }
607
Bernd Herd4d057612000-05-11 00:10:36 +0000608 *hInst = *ds ? GlobalHandle16(*ds) : pModule->self;
Alexandre Julliarda845b881998-06-01 10:44:35 +0000609}
610
Alexandre Julliard594997c1995-04-30 10:05:20 +0000611
Alexandre Julliard2787be81995-05-22 18:23:01 +0000612/***********************************************************************
613 * NE_InitDLL
614 *
615 * Call the DLL initialization code
616 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000617static BOOL NE_InitDLL( TDB* pTask, NE_MODULE *pModule )
Alexandre Julliard594997c1995-04-30 10:05:20 +0000618{
Alexandre Julliard594997c1995-04-30 10:05:20 +0000619 SEGTABLEENTRY *pSegTable;
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000620 WORD hInst, ds, heap;
Alexandre Julliard617955d1999-06-26 18:40:24 +0000621 CONTEXT86 context;
Alexandre Julliardfa68b751995-04-03 16:55:37 +0000622
Alexandre Julliard594997c1995-04-30 10:05:20 +0000623 pSegTable = NE_SEG_TABLE( pModule );
Alexandre Julliardaca05781994-10-17 18:12:41 +0000624
Alexandre Julliard329f0681996-04-14 13:21:20 +0000625 if (!(pModule->flags & NE_FFLAGS_LIBMODULE) ||
626 (pModule->flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
Alexandre Julliard77b99181997-09-14 17:17:23 +0000627
Ulrich Weigand8139c301999-04-01 11:43:05 +0000628 /* Call USER signal handler for Win3.1 compatibility. */
Ulrich Weigandc44ab1f1999-09-20 18:48:29 +0000629 TASK_CallTaskSignalProc( USIG16_DLL_LOAD, pModule->self );
Alexandre Julliard77b99181997-09-14 17:17:23 +0000630
Alexandre Julliard594997c1995-04-30 10:05:20 +0000631 if (!pModule->cs) return TRUE; /* no initialization code */
Alexandre Julliardaca05781994-10-17 18:12:41 +0000632
Alexandre Julliarda845b881998-06-01 10:44:35 +0000633
634 /* Registers at initialization must be:
635 * cx heap size
636 * di library instance
637 * ds data segment if any
638 * es:si command line (always 0)
639 */
640
Alexandre Julliard21979011997-03-05 08:22:35 +0000641 memset( &context, 0, sizeof(context) );
642
Alexandre Julliarda845b881998-06-01 10:44:35 +0000643 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
Alexandre Julliarda845b881998-06-01 10:44:35 +0000644
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000645 context.Ecx = heap;
646 context.Edi = hInst;
647 context.SegDs = ds;
648 context.SegEs = ds; /* who knows ... */
Alexandre Julliard594997c1995-04-30 10:05:20 +0000649
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000650 context.SegCs = SEL(pSegTable[pModule->cs-1].hSeg);
651 context.Eip = pModule->ip;
652 context.Ebp = OFFSETOF(NtCurrentTeb()->cur_stack) + (WORD)&((STACK16FRAME*)0)->bp;
Alexandre Julliard21979011997-03-05 08:22:35 +0000653
Alexandre Julliard594997c1995-04-30 10:05:20 +0000654
655 pModule->cs = 0; /* Don't initialize it twice */
Alexandre Julliard7d8cfeb1999-08-01 14:58:01 +0000656 TRACE_(dll)("Calling LibMain, cs:ip=%04lx:%04lx ds=%04lx di=%04x cx=%04x\n",
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000657 context.SegCs, context.Eip, context.SegDs,
658 LOWORD(context.Edi), LOWORD(context.Ecx) );
Alexandre Julliarde296bf32000-11-29 19:39:30 +0000659 wine_call_to_16_regs_short( &context, 0 );
Alexandre Julliard21979011997-03-05 08:22:35 +0000660 return TRUE;
Alexandre Julliardaca05781994-10-17 18:12:41 +0000661}
662
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000663/***********************************************************************
Alexandre Julliard2787be81995-05-22 18:23:01 +0000664 * NE_InitializeDLLs
665 *
Alexandre Julliard77b99181997-09-14 17:17:23 +0000666 * Recursively initialize all DLLs (according to the order in which
667 * they where loaded).
Alexandre Julliard234bc241994-12-10 13:02:28 +0000668 */
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000669void NE_InitializeDLLs( HMODULE16 hModule )
Alexandre Julliard234bc241994-12-10 13:02:28 +0000670{
Alexandre Julliard77b99181997-09-14 17:17:23 +0000671 TDB* pTask = (TDB*)GlobalLock16(GetCurrentTask());
Alexandre Julliard594997c1995-04-30 10:05:20 +0000672 NE_MODULE *pModule;
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000673 HMODULE16 *pDLL;
Alexandre Julliard234bc241994-12-10 13:02:28 +0000674
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000675 if (!(pModule = NE_GetPtr( hModule ))) return;
676 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
Alexandre Julliard77b99181997-09-14 17:17:23 +0000677
Alexandre Julliarda2f2e011995-06-06 16:40:35 +0000678 if (pModule->dlls_to_init)
Alexandre Julliard594997c1995-04-30 10:05:20 +0000679 {
Alexandre Julliardbf9130a1996-10-13 17:45:47 +0000680 HGLOBAL16 to_init = pModule->dlls_to_init;
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +0000681 pModule->dlls_to_init = 0;
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000682 for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
Alexandre Julliarda2f2e011995-06-06 16:40:35 +0000683 {
Alexandre Julliarda2f2e011995-06-06 16:40:35 +0000684 NE_InitializeDLLs( *pDLL );
685 }
Alexandre Julliard1285c2f1996-05-06 16:06:24 +0000686 GlobalFree16( to_init );
Alexandre Julliard594997c1995-04-30 10:05:20 +0000687 }
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000688 NE_InitDLL( pTask, pModule );
Ulrich Weigand21499341999-12-05 02:50:38 +0000689}
690
691
692/***********************************************************************
693 * NE_CallDllEntryPoint
694 *
695 * Call the DllEntryPoint of DLLs with subsystem >= 4.0
696 */
Eric Pouechfe088491999-12-05 23:04:00 +0000697typedef DWORD WINAPI (*WinNEEntryProc)(DWORD,WORD,WORD,WORD,DWORD,WORD);
Ulrich Weigand21499341999-12-05 02:50:38 +0000698
699static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
700{
701 WORD hInst, ds, heap;
702 FARPROC16 entryPoint;
Ulrich Weigand21499341999-12-05 02:50:38 +0000703
704 if (!(pModule->flags & NE_FFLAGS_LIBMODULE)) return;
705 if (!(pModule->flags & NE_FFLAGS_BUILTIN) && pModule->expected_version < 0x0400) return;
Alexandre Julliard7afce0e2000-12-01 21:25:31 +0000706 if (!(entryPoint = GetProcAddress16( pModule->self, "DllEntryPoint" ))) return;
Ulrich Weigand21499341999-12-05 02:50:38 +0000707
708 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
709
710 TRACE_(dll)( "Calling %s DllEntryPoint, cs:ip=%04x:%04x\n",
711 NE_MODULE_NAME( pModule ),
712 SELECTOROF(entryPoint), OFFSETOF(entryPoint) );
713
714 if ( pModule->flags & NE_FFLAGS_BUILTIN )
715 {
Alexandre Julliard982a2232000-12-13 20:20:09 +0000716 WinNEEntryProc entryProc = (WinNEEntryProc)((ENTRYPOINT16 *)MapSL( (SEGPTR)entryPoint ))->target;
Ulrich Weigand21499341999-12-05 02:50:38 +0000717
718 entryProc( dwReason, hInst, ds, heap, 0, 0 );
719 }
720 else
721 {
722 LPBYTE stack = (LPBYTE)CURRENT_STACK16;
723 CONTEXT86 context;
724
725 memset( &context, 0, sizeof(context) );
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000726 context.SegDs = ds;
727 context.SegEs = ds; /* who knows ... */
Ulrich Weigand21499341999-12-05 02:50:38 +0000728
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000729 context.SegCs = HIWORD(entryPoint);
730 context.Eip = LOWORD(entryPoint);
731 context.Ebp = OFFSETOF( NtCurrentTeb()->cur_stack )
Ulrich Weigand21499341999-12-05 02:50:38 +0000732 + (WORD)&((STACK16FRAME*)0)->bp;
733
734 *(DWORD *)(stack - 4) = dwReason; /* dwReason */
735 *(WORD *) (stack - 6) = hInst; /* hInst */
736 *(WORD *) (stack - 8) = ds; /* wDS */
737 *(WORD *) (stack - 10) = heap; /* wHeapSize */
738 *(DWORD *)(stack - 14) = 0; /* dwReserved1 */
739 *(WORD *) (stack - 16) = 0; /* wReserved2 */
740
Alexandre Julliarde296bf32000-11-29 19:39:30 +0000741 wine_call_to_16_regs_short( &context, 16 );
Ulrich Weigand21499341999-12-05 02:50:38 +0000742 }
743}
744
745/***********************************************************************
746 * NE_DllProcessAttach
747 *
748 * Call the DllEntryPoint of all modules this one (recursively)
749 * depends on, according to the order in which they were loaded.
750 *
751 * Note that --as opposed to the PE module case-- there is no notion
752 * of 'module loaded into a process' for NE modules, and hence we
753 * have no place to store the fact that the DllEntryPoint of a
754 * given module was already called on behalf of this process (e.g.
755 * due to some earlier LoadLibrary16 call).
756 *
757 * Thus, we just call the DllEntryPoint twice in that case. Win9x
758 * appears to behave this way as well ...
759 *
760 * This routine must only be called with the Win16Lock held.
761 *
762 * FIXME: We should actually abort loading in case the DllEntryPoint
763 * returns FALSE ...
764 *
765 */
766void NE_DllProcessAttach( HMODULE16 hModule )
767{
768 NE_MODULE *pModule;
769 WORD *pModRef;
770 int i;
771
772 if (!(pModule = NE_GetPtr( hModule ))) return;
773 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
774
775 /* Check for recursive call */
776 if ( pModule->misc_flags & 0x80 ) return;
777
778 TRACE_(dll)("(%s) - START\n", NE_MODULE_NAME(pModule) );
779
780 /* Tag current module to prevent recursive loop */
781 pModule->misc_flags |= 0x80;
782
783 /* Recursively attach all DLLs this one depends on */
784 pModRef = NE_MODULE_TABLE( pModule );
785 for ( i = 0; i < pModule->modref_count; i++ )
786 if ( pModRef[i] )
787 NE_DllProcessAttach( (HMODULE16)pModRef[i] );
788
789 /* Call DLL entry point */
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000790 NE_CallDllEntryPoint( pModule, DLL_PROCESS_ATTACH );
Ulrich Weigand21499341999-12-05 02:50:38 +0000791
792 /* Remove recursion flag */
793 pModule->misc_flags &= ~0x80;
794
795 TRACE_(dll)("(%s) - END\n", NE_MODULE_NAME(pModule) );
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000796}
797
798
799/***********************************************************************
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000800 * NE_Ne2MemFlags
801 *
802 * This function translates NE segment flags to GlobalAlloc flags
803 */
804static WORD NE_Ne2MemFlags(WORD flags)
805{
806 WORD memflags = 0;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000807#if 1
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000808 if (flags & NE_SEGFLAGS_DISCARDABLE)
809 memflags |= GMEM_DISCARDABLE;
810 if (flags & NE_SEGFLAGS_MOVEABLE ||
811 ( ! (flags & NE_SEGFLAGS_DATA) &&
812 ! (flags & NE_SEGFLAGS_LOADED) &&
813 ! (flags & NE_SEGFLAGS_ALLOCATED)
814 )
815 )
816 memflags |= GMEM_MOVEABLE;
817 memflags |= GMEM_ZEROINIT;
818#else
819 memflags = GMEM_ZEROINIT | GMEM_FIXED;
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000820#endif
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000821 return memflags;
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000822}
823
824/***********************************************************************
Alexandre Julliard7afce0e2000-12-01 21:25:31 +0000825 * MyAlloc16 (KERNEL Wine-specific export)
Andreas Mohrdca5e561999-04-16 08:17:17 +0000826 *
827 * MyAlloc() function for self-loading apps.
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000828 */
Alexandre Julliard7afce0e2000-12-01 21:25:31 +0000829DWORD WINAPI MyAlloc16( WORD wFlags, WORD wSize, WORD wElem )
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000830{
831 WORD size = wSize << wElem;
Andreas Mohrdca5e561999-04-16 08:17:17 +0000832 HANDLE16 hMem = 0;
Alexandre Julliard638f1691999-01-17 16:32:32 +0000833
Andreas Mohrdca5e561999-04-16 08:17:17 +0000834 if (wSize || (wFlags & NE_SEGFLAGS_MOVEABLE))
835 hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
836
837 if ( ((wFlags & 0x7) != 0x1) && /* DATA */
838 ((wFlags & 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
839 {
840 WORD hSel = SEL(hMem);
Alexandre Julliarda3960291999-02-26 11:11:13 +0000841 WORD access = SelectorAccessRights16(hSel,0,0);
Alexandre Julliard638f1691999-01-17 16:32:32 +0000842
843 access |= 2<<2; /* SEGMENT_CODE */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000844 SelectorAccessRights16(hSel,1,access);
Alexandre Julliard638f1691999-01-17 16:32:32 +0000845 }
Andreas Mohrdca5e561999-04-16 08:17:17 +0000846 if (size)
847 return MAKELONG( hMem, SEL(hMem) );
848 else
849 return MAKELONG( 0, hMem );
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000850}
851
Ulrich Weigand61206bd1999-11-21 00:50:30 +0000852/***********************************************************************
853 * NE_GetInstance
854 */
855HINSTANCE16 NE_GetInstance( NE_MODULE *pModule )
856{
857 if ( !pModule->dgroup )
858 return pModule->self;
859 else
860 {
Andreas Mohrf2df6a22000-03-07 12:26:16 +0000861 SEGTABLEENTRY *pSeg;
862 pSeg = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
Bernd Herd4d057612000-05-11 00:10:36 +0000863 return pSeg->hSeg;
Ulrich Weigand61206bd1999-11-21 00:50:30 +0000864 }
865}
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000866
867/***********************************************************************
Ulrich Weigand61206bd1999-11-21 00:50:30 +0000868 * NE_CreateSegment
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000869 */
Ulrich Weigand61206bd1999-11-21 00:50:30 +0000870BOOL NE_CreateSegment( NE_MODULE *pModule, int segnum )
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000871{
Andreas Mohrf2df6a22000-03-07 12:26:16 +0000872 SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule ) + segnum - 1;
Ulrich Weigand61206bd1999-11-21 00:50:30 +0000873 int minsize;
Alexandre Julliard914406f2000-11-14 01:54:49 +0000874 unsigned char selflags;
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000875
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000876 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
877
Ulrich Weigand61206bd1999-11-21 00:50:30 +0000878 if ( segnum < 1 || segnum > pModule->seg_count )
879 return FALSE;
Andreas Mohrdca5e561999-04-16 08:17:17 +0000880
Ulrich Weigand61206bd1999-11-21 00:50:30 +0000881 if ( (pModule->flags & NE_FFLAGS_SELFLOAD) && segnum != 1 )
882 return TRUE; /* selfloader allocates segment itself */
883
Andreas Mohrf2df6a22000-03-07 12:26:16 +0000884 if ( (pSeg->flags & NE_SEGFLAGS_ALLOCATED) && segnum != pModule->dgroup )
Ulrich Weigand61206bd1999-11-21 00:50:30 +0000885 return TRUE; /* all but DGROUP only allocated once */
886
Andreas Mohrf2df6a22000-03-07 12:26:16 +0000887 minsize = pSeg->minsize ? pSeg->minsize : 0x10000;
Ulrich Weigand61206bd1999-11-21 00:50:30 +0000888 if ( segnum == pModule->ss ) minsize += pModule->stack_size;
889 if ( segnum == pModule->dgroup ) minsize += pModule->heap_size;
890
Alexandre Julliard914406f2000-11-14 01:54:49 +0000891 selflags = (pSeg->flags & NE_SEGFLAGS_DATA) ? WINE_LDT_FLAGS_DATA : WINE_LDT_FLAGS_CODE;
892 if (pSeg->flags & NE_SEGFLAGS_32BIT) selflags |= WINE_LDT_FLAGS_32BIT;
893 pSeg->hSeg = GLOBAL_Alloc( NE_Ne2MemFlags(pSeg->flags), minsize, pModule->self, selflags );
Andreas Mohrf2df6a22000-03-07 12:26:16 +0000894 if (!pSeg->hSeg) return FALSE;
Ulrich Weigand61206bd1999-11-21 00:50:30 +0000895
Andreas Mohrf2df6a22000-03-07 12:26:16 +0000896 pSeg->flags |= NE_SEGFLAGS_ALLOCATED;
Ulrich Weigand61206bd1999-11-21 00:50:30 +0000897 return TRUE;
898}
899
900/***********************************************************************
901 * NE_CreateAllSegments
902 */
903BOOL NE_CreateAllSegments( NE_MODULE *pModule )
904{
905 int i;
906 for ( i = 1; i <= pModule->seg_count; i++ )
907 if ( !NE_CreateSegment( pModule, i ) )
908 return FALSE;
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000909
910 pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
911 (pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
912 return TRUE;
913}
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000914
915
916/**********************************************************************
917 * IsSharedSelector (KERNEL.345)
918 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000919BOOL16 WINAPI IsSharedSelector16( HANDLE16 selector )
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000920{
921 /* Check whether the selector belongs to a DLL */
922 NE_MODULE *pModule = NE_GetPtr( selector );
923 if (!pModule) return FALSE;
924 return (pModule->flags & NE_FFLAGS_LIBMODULE) != 0;
925}