ne_segment.c 32.9 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1
/*
Alexandre Julliard's avatar
Alexandre Julliard committed
2
 * NE segment loading
Alexandre Julliard's avatar
Alexandre Julliard committed
3 4 5
 *
 * Copyright 1993 Robert J. Amstadt
 * Copyright 1995 Alexandre Julliard
6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Alexandre Julliard's avatar
Alexandre Julliard committed
20 21
 */

22
#include "config.h"
23
#include "wine/port.h"
24

Alexandre Julliard's avatar
Alexandre Julliard committed
25
#include <assert.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
26 27 28 29
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
30 31 32
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
33
#include <ctype.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
34
#include <string.h>
35 36

#include "wine/winbase16.h"
37
#include "wownt32.h"
38
#include "wine/library.h"
39
#include "kernel_private.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
40 41
#include "module.h"
#include "stackframe.h"
42
#include "builtin16.h"
43
#include "toolhelp.h"
44
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
45

46
WINE_DEFAULT_DEBUG_CHANNEL(fixup);
47 48
WINE_DECLARE_DEBUG_CHANNEL(dll);
WINE_DECLARE_DEBUG_CHANNEL(module);
49

50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
/*
 * Relocation table entry
 */
struct relocation_entry_s
{
    BYTE address_type;    /* Relocation address type */
    BYTE relocation_type; /* Relocation type */
    WORD offset;          /* Offset in segment to fixup */
    WORD target1;         /* Target specification */
    WORD target2;         /* Target specification */
};

/*
 * Relocation address types
 */
#define NE_RADDR_LOWBYTE      0
#define NE_RADDR_SELECTOR     2
#define NE_RADDR_POINTER32    3
#define NE_RADDR_OFFSET16     5
#define NE_RADDR_POINTER48    11
#define NE_RADDR_OFFSET32     13

/*
 * Relocation types
 */
#define NE_RELTYPE_INTERNAL  0
#define NE_RELTYPE_ORDINAL   1
#define NE_RELTYPE_NAME      2
#define NE_RELTYPE_OSFIXUP   3
#define NE_RELFLAG_ADDITIVE  4

81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
/* Self-loading modules contain this structure in their first segment */
typedef struct
{
    WORD      version;       /* Must be "A0" (0x3041) */
    WORD      reserved;
    FARPROC16 BootApp;       /* startup procedure */
    FARPROC16 LoadAppSeg;    /* procedure to load a segment */
    FARPROC16 reserved2;
    FARPROC16 MyAlloc;       /* memory allocation procedure,
                              * wine must write this field */
    FARPROC16 EntryAddrProc;
    FARPROC16 ExitProc;      /* exit procedure */
    WORD      reserved3[4];
    FARPROC16 SetOwner;      /* Set Owner procedure, exported by wine */
} SELFLOADHEADER;

97
#define SEL(x) ((x)|1)
Alexandre Julliard's avatar
Alexandre Julliard committed
98

99 100
static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum);

101

Alexandre Julliard's avatar
Alexandre Julliard committed
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
/***********************************************************************
 *           NE_GetRelocAddrName
 */
static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
{
    switch(addr_type & 0x7f)
    {
    case NE_RADDR_LOWBYTE:   return additive ? "BYTE add" : "BYTE";
    case NE_RADDR_OFFSET16:  return additive ? "OFFSET16 add" : "OFFSET16";
    case NE_RADDR_POINTER32: return additive ? "POINTER32 add" : "POINTER32";
    case NE_RADDR_SELECTOR:  return additive ? "SELECTOR add" : "SELECTOR";
    case NE_RADDR_POINTER48: return additive ? "POINTER48 add" : "POINTER48";
    case NE_RADDR_OFFSET32:  return additive ? "OFFSET32 add" : "OFFSET32";
    }
    return "???";
}


Alexandre Julliard's avatar
Alexandre Julliard committed
120 121
/***********************************************************************
 *           NE_LoadSegment
Alexandre Julliard's avatar
Alexandre Julliard committed
122
 */
123
BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
Alexandre Julliard's avatar
Alexandre Julliard committed
124
{
Alexandre Julliard's avatar
Alexandre Julliard committed
125
    SEGTABLEENTRY *pSegTable, *pSeg;
126
    HMODULE16 *pModuleTable;
Alexandre Julliard's avatar
Alexandre Julliard committed
127
    WORD count, i, offset, next_offset;
Alexandre Julliard's avatar
Alexandre Julliard committed
128
    HMODULE16 module;
Alexandre Julliard's avatar
Alexandre Julliard committed
129
    FARPROC16 address = 0;
130
    HANDLE hf;
131
    DWORD res;
Alexandre Julliard's avatar
Alexandre Julliard committed
132
    struct relocation_entry_s *rep, *reloc_entries;
Alexandre Julliard's avatar
Alexandre Julliard committed
133
    BYTE *func_name;
Alexandre Julliard's avatar
Alexandre Julliard committed
134 135
    int size;
    char* mem;
Alexandre Julliard's avatar
Alexandre Julliard committed
136

Alexandre Julliard's avatar
Alexandre Julliard committed
137
    char buffer[256];
Alexandre Julliard's avatar
Alexandre Julliard committed
138 139
    int ordinal, additive;
    unsigned short *sp;
Alexandre Julliard's avatar
Alexandre Julliard committed
140

Alexandre Julliard's avatar
Alexandre Julliard committed
141 142
    pSegTable = NE_SEG_TABLE( pModule );
    pSeg = pSegTable + segnum - 1;
143

144 145 146 147 148 149 150 151 152 153
    if (pSeg->flags & NE_SEGFLAGS_LOADED)
    {
	/* self-loader ? -> already loaded it */
	if (pModule->flags & NE_FFLAGS_SELFLOAD)
	    return TRUE;

	/* leave, except for DGROUP, as this may be the second instance */
	if (segnum != pModule->dgroup)
            return TRUE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
154

Alexandre Julliard's avatar
Alexandre Julliard committed
155
    if (!pSeg->filepos) return TRUE;  /* No file image, just return */
156

157
    pModuleTable = (HMODULE16 *)((char *)pModule + pModule->modref_table);
158

159
    hf = NE_OpenFile( pModule );
160
    TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
161
                    segnum, pSeg->hSeg, pSeg->flags );
162
    SetFilePointer( hf, pSeg->filepos << pModule->alignment, NULL, SEEK_SET );
Alexandre Julliard's avatar
Alexandre Julliard committed
163
    if (pSeg->size) size = pSeg->size;
164
    else size = pSeg->minsize ? pSeg->minsize : 0x10000;
Alexandre Julliard's avatar
Alexandre Julliard committed
165
    mem = GlobalLock16(pSeg->hSeg);
Alexandre Julliard's avatar
Alexandre Julliard committed
166 167
    if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
    {
168
 	/* Implement self-loading segments */
Alexandre Julliard's avatar
Alexandre Julliard committed
169
 	SELFLOADHEADER *selfloadheader;
Alexandre Julliard's avatar
Alexandre Julliard committed
170
        DWORD oldstack;
171
        HANDLE hFile32;
172
        HFILE16 hFile16;
173 174
        WORD args[3];
        DWORD ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
175

176
 	selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg),0) );
177
 	oldstack = NtCurrentTeb()->cur_stack;
178 179
 	NtCurrentTeb()->cur_stack = MAKESEGPTR(pModule->self_loading_sel,
                                               0xff00 - sizeof(STACK16FRAME));
180

181
	TRACE_(dll)("CallLoadAppSegProc(hmodule=0x%04x,hf=%p,segnum=%d\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
182
		pModule->self,hf,segnum );
183 184
        DuplicateHandle( GetCurrentProcess(), hf, GetCurrentProcess(), &hFile32,
                         0, FALSE, DUPLICATE_SAME_ACCESS );
185
        hFile16 = Win32HandleToDosFileHandle( hFile32 );
186 187 188 189 190
        args[2] = pModule->self;
        args[1] = hFile16;
        args[0] = segnum;
        WOWCallback16Ex( (DWORD)selfloadheader->LoadAppSeg, WCB16_PASCAL, sizeof(args), args, &ret );
        pSeg->hSeg = LOWORD(ret);
191
	TRACE_(dll)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n", pSeg->hSeg);
192
        _lclose16( hFile16 );
193
 	NtCurrentTeb()->cur_stack = oldstack;
Alexandre Julliard's avatar
Alexandre Julliard committed
194
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
195
    else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
196
        ReadFile(hf, mem, size, &res, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
197 198 199 200
    else {
      /*
	 The following bit of code for "iterated segments" was written without
	 any documentation on the format of these segments. It seems to work,
Alexandre Julliard's avatar
Alexandre Julliard committed
201
	 but may be missing something. If you have any doc please either send
Alexandre Julliard's avatar
Alexandre Julliard committed
202 203
	 it to me or fix the code yourself. gfm@werple.mira.net.au
      */
204
      char* buff = HeapAlloc(GetProcessHeap(), 0, size);
Alexandre Julliard's avatar
Alexandre Julliard committed
205
      char* curr = buff;
206 207

      if(buff == NULL) {
208
          WARN_(dll)("Memory exhausted!\n");
209
          goto fail;
210 211
      }

212
      ReadFile(hf, buff, size, &res, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
213
      while(curr < buff + size) {
214 215 216 217
	unsigned int rept = ((short*)curr)[0];
	unsigned int len =  ((short*)curr)[1];

	curr += 2*sizeof(short);
Alexandre Julliard's avatar
Alexandre Julliard committed
218 219 220 221 222 223 224 225
	for(; rept > 0; rept--) {
	  char* bytes = curr;
	  unsigned int byte;
	  for(byte = 0; byte < len; byte++)
	    *mem++ = *bytes++;
	}
	curr += len;
      }
226
      HeapFree(GetProcessHeap(), 0, buff);
Alexandre Julliard's avatar
Alexandre Julliard committed
227
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
228

Alexandre Julliard's avatar
Alexandre Julliard committed
229
    pSeg->flags |= NE_SEGFLAGS_LOADED;
230 231 232 233

    /* Perform exported function prolog fixups */
    NE_FixupSegmentPrologs( pModule, segnum );

Alexandre Julliard's avatar
Alexandre Julliard committed
234
    if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
235
        goto succeed;  /* No relocation data, we are done */
Alexandre Julliard's avatar
Alexandre Julliard committed
236

237
    ReadFile(hf, &count, sizeof(count), &res, NULL);
238
    if (!count) goto succeed;
Alexandre Julliard's avatar
Alexandre Julliard committed
239

240
    TRACE("Fixups for %.*s, segment %d, hSeg %04x\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
241 242
                   *((BYTE *)pModule + pModule->name_table),
                   (char *)pModule + pModule->name_table + 1,
Alexandre Julliard's avatar
Alexandre Julliard committed
243
                   segnum, pSeg->hSeg );
Alexandre Julliard's avatar
Alexandre Julliard committed
244

245 246
    reloc_entries = (struct relocation_entry_s *)HeapAlloc(GetProcessHeap(), 0, count * sizeof(struct relocation_entry_s));
    if(reloc_entries == NULL) {
247
        WARN("Not enough memory for relocation entries!\n");
248
        goto fail;
249
    }
250 251
    if (!ReadFile( hf, reloc_entries, count * sizeof(struct relocation_entry_s), &res, NULL) ||
        (res != count * sizeof(struct relocation_entry_s)))
Alexandre Julliard's avatar
Alexandre Julliard committed
252
    {
253
        WARN("Unable to read relocation information\n" );
254
        goto fail;
Alexandre Julliard's avatar
Alexandre Julliard committed
255
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
256 257

    /*
Alexandre Julliard's avatar
Alexandre Julliard committed
258
     * Go through the relocation table one entry at a time.
Alexandre Julliard's avatar
Alexandre Julliard committed
259
     */
Alexandre Julliard's avatar
Alexandre Julliard committed
260 261
    rep = reloc_entries;
    for (i = 0; i < count; i++, rep++)
Alexandre Julliard's avatar
Alexandre Julliard committed
262 263 264 265
    {
	/*
	 * Get the target address corresponding to this entry.
	 */
Alexandre Julliard's avatar
Alexandre Julliard committed
266 267 268 269 270

	/* If additive, there is no target chain list. Instead, add source
	   and target */
	additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
	rep->relocation_type &= 0x3;
Alexandre Julliard's avatar
Alexandre Julliard committed
271

Alexandre Julliard's avatar
Alexandre Julliard committed
272 273 274
	switch (rep->relocation_type)
	{
	  case NE_RELTYPE_ORDINAL:
Alexandre Julliard's avatar
Alexandre Julliard committed
275 276
            module = pModuleTable[rep->target1-1];
	    ordinal = rep->target2;
Alexandre Julliard's avatar
Alexandre Julliard committed
277
            address = NE_GetEntryPoint( module, ordinal );
Alexandre Julliard's avatar
Alexandre Julliard committed
278 279
            if (!address)
            {
Alexandre Julliard's avatar
Alexandre Julliard committed
280
                NE_MODULE *pTarget = NE_GetPtr( module );
Alexandre Julliard's avatar
Alexandre Julliard committed
281
                if (!pTarget)
282
                    WARN_(module)("Module not found: %04x, reference %d of module %*.*s\n",
283
                             module, rep->target1,
Alexandre Julliard's avatar
Alexandre Julliard committed
284 285 286 287
                             *((BYTE *)pModule + pModule->name_table),
                             *((BYTE *)pModule + pModule->name_table),
                             (char *)pModule + pModule->name_table + 1 );
                else
Alexandre Julliard's avatar
Alexandre Julliard committed
288
                {
289
                    ERR("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
290 291 292
                            *((BYTE *)pTarget + pTarget->name_table),
                            (char *)pTarget + pTarget->name_table + 1,
                            ordinal );
Alexandre Julliard's avatar
Alexandre Julliard committed
293
                    address = (FARPROC16)0xdeadbeef;
Alexandre Julliard's avatar
Alexandre Julliard committed
294
                }
Alexandre Julliard's avatar
Alexandre Julliard committed
295
            }
Alexandre Julliard's avatar
Alexandre Julliard committed
296
            if (TRACE_ON(fixup))
Alexandre Julliard's avatar
Alexandre Julliard committed
297
            {
Alexandre Julliard's avatar
Alexandre Julliard committed
298
                NE_MODULE *pTarget = NE_GetPtr( module );
299
                TRACE("%d: %.*s.%d=%04x:%04x %s\n", i + 1,
Alexandre Julliard's avatar
Alexandre Julliard committed
300 301 302 303
                       *((BYTE *)pTarget + pTarget->name_table),
                       (char *)pTarget + pTarget->name_table + 1,
                       ordinal, HIWORD(address), LOWORD(address),
                       NE_GetRelocAddrName( rep->address_type, additive ) );
Alexandre Julliard's avatar
Alexandre Julliard committed
304
            }
Alexandre Julliard's avatar
Alexandre Julliard committed
305
	    break;
306

Alexandre Julliard's avatar
Alexandre Julliard committed
307
	  case NE_RELTYPE_NAME:
Alexandre Julliard's avatar
Alexandre Julliard committed
308 309
            module = pModuleTable[rep->target1-1];
            func_name = (char *)pModule + pModule->import_table + rep->target2;
Alexandre Julliard's avatar
Alexandre Julliard committed
310 311 312
            memcpy( buffer, func_name+1, *func_name );
            buffer[*func_name] = '\0';
            func_name = buffer;
Alexandre Julliard's avatar
Alexandre Julliard committed
313 314
            ordinal = NE_GetOrdinal( module, func_name );
            address = NE_GetEntryPoint( module, ordinal );
Alexandre Julliard's avatar
Alexandre Julliard committed
315

Alexandre Julliard's avatar
Alexandre Julliard committed
316
            if (ERR_ON(fixup) && !address)
Alexandre Julliard's avatar
Alexandre Julliard committed
317
            {
Alexandre Julliard's avatar
Alexandre Julliard committed
318
                NE_MODULE *pTarget = NE_GetPtr( module );
319
                ERR("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
320 321
                    *((BYTE *)pTarget + pTarget->name_table),
                    (char *)pTarget + pTarget->name_table + 1, func_name );
Alexandre Julliard's avatar
Alexandre Julliard committed
322
            }
Alexandre Julliard's avatar
Alexandre Julliard committed
323
            if (!address) address = (FARPROC16) 0xdeadbeef;
Alexandre Julliard's avatar
Alexandre Julliard committed
324
            if (TRACE_ON(fixup))
Alexandre Julliard's avatar
Alexandre Julliard committed
325
            {
Alexandre Julliard's avatar
Alexandre Julliard committed
326
	        NE_MODULE *pTarget = NE_GetPtr( module );
327
                TRACE("%d: %.*s.%s=%04x:%04x %s\n", i + 1,
Alexandre Julliard's avatar
Alexandre Julliard committed
328 329 330 331
                       *((BYTE *)pTarget + pTarget->name_table),
                       (char *)pTarget + pTarget->name_table + 1,
                       func_name, HIWORD(address), LOWORD(address),
                       NE_GetRelocAddrName( rep->address_type, additive ) );
Alexandre Julliard's avatar
Alexandre Julliard committed
332
            }
Alexandre Julliard's avatar
Alexandre Julliard committed
333
	    break;
334

Alexandre Julliard's avatar
Alexandre Julliard committed
335
	  case NE_RELTYPE_INTERNAL:
Alexandre Julliard's avatar
Alexandre Julliard committed
336
	    if ((rep->target1 & 0xff) == 0xff)
Alexandre Julliard's avatar
Alexandre Julliard committed
337
	    {
Alexandre Julliard's avatar
Alexandre Julliard committed
338
		address  = NE_GetEntryPoint( pModule->self, rep->target2 );
Alexandre Julliard's avatar
Alexandre Julliard committed
339 340 341
	    }
	    else
	    {
342
                address = (FARPROC16)MAKESEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
Alexandre Julliard's avatar
Alexandre Julliard committed
343
	    }
344

345
	    TRACE("%d: %04x:%04x %s\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
346 347
                   i + 1, HIWORD(address), LOWORD(address),
                   NE_GetRelocAddrName( rep->address_type, additive ) );
Alexandre Julliard's avatar
Alexandre Julliard committed
348 349
	    break;

Alexandre Julliard's avatar
Alexandre Julliard committed
350
	  case NE_RELTYPE_OSFIXUP:
Alexandre Julliard's avatar
Alexandre Julliard committed
351 352 353 354 355 356 357 358
	    /* Relocation type 7:
	     *
	     *    These appear to be used as fixups for the Windows
	     * floating point emulator.  Let's just ignore them and
	     * try to use the hardware floating point.  Linux should
	     * successfully emulate the coprocessor if it doesn't
	     * exist.
	     */
359
	    TRACE("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
360 361 362
                   i + 1, rep->relocation_type, rep->offset,
                   rep->target1, rep->target2,
                   NE_GetRelocAddrName( rep->address_type, additive ) );
Alexandre Julliard's avatar
Alexandre Julliard committed
363 364 365
	    continue;
	}

Alexandre Julliard's avatar
Alexandre Julliard committed
366
	offset  = rep->offset;
Alexandre Julliard's avatar
Alexandre Julliard committed
367

Alexandre Julliard's avatar
Alexandre Julliard committed
368 369
        /* Apparently, high bit of address_type is sometimes set; */
        /* we ignore it for now */
Alexandre Julliard's avatar
Alexandre Julliard committed
370
	if (rep->address_type > NE_RADDR_OFFSET32)
Alexandre Julliard's avatar
Alexandre Julliard committed
371 372
        {
            char module[10];
373
            GetModuleName16( pModule->self, module, sizeof(module) );
374
            ERR("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
375 376
                 module, rep->address_type );
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
377

Alexandre Julliard's avatar
Alexandre Julliard committed
378 379
        if (additive)
        {
380
            sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
381
            TRACE("    %04x:%04x\n", offset, *sp );
Alexandre Julliard's avatar
Alexandre Julliard committed
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396
            switch (rep->address_type & 0x7f)
            {
            case NE_RADDR_LOWBYTE:
                *(BYTE *)sp += LOBYTE((int)address);
                break;
            case NE_RADDR_OFFSET16:
		*sp += LOWORD(address);
                break;
            case NE_RADDR_POINTER32:
		*sp += LOWORD(address);
		*(sp+1) = HIWORD(address);
                break;
            case NE_RADDR_SELECTOR:
		/* Borland creates additive records with offset zero. Strange, but OK */
                if (*sp)
397
                    ERR("Additive selector to %04x.Please report\n",*sp);
Alexandre Julliard's avatar
Alexandre Julliard committed
398
		else
Alexandre Julliard's avatar
Alexandre Julliard committed
399
                    *sp = HIWORD(address);
Alexandre Julliard's avatar
Alexandre Julliard committed
400
                break;
Alexandre Julliard's avatar
Alexandre Julliard committed
401 402
            default:
                goto unknown;
Alexandre Julliard's avatar
Alexandre Julliard committed
403
            }
Alexandre Julliard's avatar
Alexandre Julliard committed
404 405 406 407 408
        }
        else  /* non-additive fixup */
        {
            do
            {
409
                sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
Alexandre Julliard's avatar
Alexandre Julliard committed
410
                next_offset = *sp;
411
                TRACE("    %04x:%04x\n", offset, *sp );
Alexandre Julliard's avatar
Alexandre Julliard committed
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
                switch (rep->address_type & 0x7f)
                {
                case NE_RADDR_LOWBYTE:
                    *(BYTE *)sp = LOBYTE((int)address);
                    break;
                case NE_RADDR_OFFSET16:
                    *sp = LOWORD(address);
                    break;
                case NE_RADDR_POINTER32:
                    *(FARPROC16 *)sp = address;
                    break;
                case NE_RADDR_SELECTOR:
                    *sp = SELECTOROF(address);
                    break;
                default:
                    goto unknown;
                }
                if (next_offset == offset) break;  /* avoid infinite loop */
Alexandre Julliard's avatar
Alexandre Julliard committed
430
                if (next_offset >= GlobalSize16(pSeg->hSeg)) break;
Alexandre Julliard's avatar
Alexandre Julliard committed
431
                offset = next_offset;
Alexandre Julliard's avatar
Alexandre Julliard committed
432
            } while (offset != 0xffff);
Alexandre Julliard's avatar
Alexandre Julliard committed
433
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
434 435
    }

436
    HeapFree(GetProcessHeap(), 0, reloc_entries);
437 438 439

succeed:
    CloseHandle(hf);
Alexandre Julliard's avatar
Alexandre Julliard committed
440
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
441 442

unknown:
443
    WARN("WARNING: %d: unknown ADDR TYPE %d,  "
Alexandre Julliard's avatar
Alexandre Julliard committed
444
         "TYPE %d,  OFFSET %04x,  TARGET %04x %04x\n",
445
         i + 1, rep->address_type, rep->relocation_type,
Alexandre Julliard's avatar
Alexandre Julliard committed
446
         rep->offset, rep->target1, rep->target2);
447
    HeapFree(GetProcessHeap(), 0, reloc_entries);
448 449 450

fail:
    CloseHandle(hf);
Alexandre Julliard's avatar
Alexandre Julliard committed
451
    return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
452 453
}

Alexandre Julliard's avatar
Alexandre Julliard committed
454

Alexandre Julliard's avatar
Alexandre Julliard committed
455 456 457
/***********************************************************************
 *           NE_LoadAllSegments
 */
458
BOOL NE_LoadAllSegments( NE_MODULE *pModule )
Alexandre Julliard's avatar
Alexandre Julliard committed
459 460
{
    int i;
461
    SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
Alexandre Julliard's avatar
Alexandre Julliard committed
462 463 464

    if (pModule->flags & NE_FFLAGS_SELFLOAD)
    {
465
        HANDLE hf;
466
        HFILE16 hFile16;
467
        HGLOBAL16 sel;
468
        /* Handle self-loading modules */
Alexandre Julliard's avatar
Alexandre Julliard committed
469
        SELFLOADHEADER *selfloadheader;
470
        HMODULE16 mod = GetModuleHandle16("KERNEL");
Alexandre Julliard's avatar
Alexandre Julliard committed
471
        DWORD oldstack;
472
        WORD args[2];
Alexandre Julliard's avatar
Alexandre Julliard committed
473

474
        TRACE_(module)("%.*s is a self-loading module!\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
475 476
		     *((BYTE*)pModule + pModule->name_table),
		     (char *)pModule + pModule->name_table + 1);
Alexandre Julliard's avatar
Alexandre Julliard committed
477
        if (!NE_LoadSegment( pModule, 1 )) return FALSE;
478
        selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg), 0) );
479 480 481
        selfloadheader->EntryAddrProc = GetProcAddress16(mod,"EntryAddrProc");
        selfloadheader->MyAlloc       = GetProcAddress16(mod,"MyAlloc");
        selfloadheader->SetOwner      = GetProcAddress16(mod,"FarSetOwner");
482 483 484
        sel = GlobalAlloc16( GMEM_ZEROINIT, 0xFF00 );
        pModule->self_loading_sel = SEL(sel);
        FarSetOwner16( sel, pModule->self );
485
        oldstack = NtCurrentTeb()->cur_stack;
486 487
        NtCurrentTeb()->cur_stack = MAKESEGPTR(pModule->self_loading_sel,
                                               0xff00 - sizeof(STACK16FRAME) );
Alexandre Julliard's avatar
Alexandre Julliard committed
488

489
        hf = NE_OpenFile(pModule);
490
        hFile16 = Win32HandleToDosFileHandle( hf );
491
        TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
492
              pModule->self,hFile16);
493 494 495
        args[1] = pModule->self;
        args[0] = hFile16;
        WOWCallback16Ex( (DWORD)selfloadheader->BootApp, WCB16_PASCAL, sizeof(args), args, NULL );
496
	TRACE_(dll)("Return from CallBootAppProc\n");
497
        _lclose16(hFile16);
498
        NtCurrentTeb()->cur_stack = oldstack;
Alexandre Julliard's avatar
Alexandre Julliard committed
499

500 501
        for (i = 2; i <= pModule->seg_count; i++)
            if (!NE_LoadSegment( pModule, i )) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
502 503 504 505 506 507 508 509 510 511
    }
    else
    {
        for (i = 1; i <= pModule->seg_count; i++)
            if (!NE_LoadSegment( pModule, i )) return FALSE;
    }
    return TRUE;
}


512
/***********************************************************************
513
 *           NE_FixupSegmentPrologs
514
 *
515
 * Fixup exported functions prologs of one segment
516
 */
517
static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum)
518
{
519 520 521 522 523
    SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
    ET_BUNDLE *bundle;
    ET_ENTRY *entry;
    WORD dgroup, num_entries, sel = SEL(pSegTable[segnum-1].hSeg);
    BYTE *pSeg, *pFunc;
524

525
    TRACE("(%d);\n", segnum);
526

527
    if (pSegTable[segnum-1].flags & NE_SEGFLAGS_DATA)
528
    {
529 530 531
	pSegTable[segnum-1].flags |= NE_SEGFLAGS_LOADED;
	return;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
532

533 534 535
    if (!pModule->dgroup) return;

    if (!(dgroup = SEL(pSegTable[pModule->dgroup-1].hSeg))) return;
536

537
    pSeg = MapSL( MAKESEGPTR(sel, 0) );
Alexandre Julliard's avatar
Alexandre Julliard committed
538

539 540 541
    bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->entry_table);

    do {
542
	TRACE("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle->last - bundle->first, bundle, bundle->next, pSeg);
543 544 545 546
	if (!(num_entries = bundle->last - bundle->first))
	    return;
	entry = (ET_ENTRY *)((BYTE *)bundle+6);
	while (num_entries--)
Alexandre Julliard's avatar
Alexandre Julliard committed
547
    {
548
	    /*TRACE("entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/
549
	    if (entry->segnum == segnum)
Alexandre Julliard's avatar
Alexandre Julliard committed
550
        {
551
		pFunc = ((BYTE *)pSeg+entry->offs);
552
		TRACE("pFunc: %p, *(DWORD *)pFunc: %08lx, num_entries: %d\n", pFunc, *(DWORD *)pFunc, num_entries);
553
		if (*(pFunc+2) == 0x90)
Alexandre Julliard's avatar
Alexandre Julliard committed
554
        {
555 556
		    if (*(WORD *)pFunc == 0x581e) /* push ds, pop ax */
		    {
557
			TRACE("patch %04x:%04x -> mov ax, ds\n", sel, entry->offs);
558
			*(WORD *)pFunc = 0xd88c; /* mov ax, ds */
Alexandre Julliard's avatar
Alexandre Julliard committed
559 560
        }

561
		    if (*(WORD *)pFunc == 0xd88c)
Alexandre Julliard's avatar
Alexandre Julliard committed
562
                        {
563
			if ((entry->flags & 2)) /* public data ? */
Alexandre Julliard's avatar
Alexandre Julliard committed
564
                        {
565
			    TRACE("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel, entry->offs, dgroup);
566 567
			    *pFunc = 0xb8; /* mov ax, */
			    *(WORD *)(pFunc+1) = dgroup;
Alexandre Julliard's avatar
Alexandre Julliard committed
568 569
                    }
                    else
570 571
			if ((pModule->flags & NE_FFLAGS_MULTIPLEDATA)
			&& (entry->flags & 1)) /* exported ? */
Alexandre Julliard's avatar
Alexandre Julliard committed
572
                    {
573
			    TRACE("patch %04x:%04x -> nop, nop\n", sel, entry->offs);
574
			    *(WORD *)pFunc = 0x9090; /* nop, nop */
Alexandre Julliard's avatar
Alexandre Julliard committed
575
			}
Alexandre Julliard's avatar
Alexandre Julliard committed
576
                    }
Alexandre Julliard's avatar
Alexandre Julliard committed
577
		}
Alexandre Julliard's avatar
Alexandre Julliard committed
578
            }
579 580 581 582 583 584 585 586
	    entry++;
	}
    } while ( (bundle->next)
	 && (bundle = ((ET_BUNDLE *)((BYTE *)pModule + bundle->next))) );
}


/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
587
 *           PatchCodeHandle (KERNEL.110)
588 589 590 591 592 593 594 595 596 597
 *
 * Needed for self-loading modules.
 */
DWORD WINAPI PatchCodeHandle16(HANDLE16 hSeg)
{
    WORD segnum;
    WORD sel = SEL(hSeg);
    NE_MODULE *pModule = NE_GetPtr(FarGetOwner16(sel));
    SEGTABLEENTRY *pSegTable = NE_SEG_TABLE(pModule);

598
    TRACE_(module)("(%04x);\n", hSeg);
599 600 601 602 603 604 605 606

    /* find the segment number of the module that belongs to hSeg */
    for (segnum = 1; segnum <= pModule->seg_count; segnum++)
    {
	if (SEL(pSegTable[segnum-1].hSeg) == sel)
	{
	    NE_FixupSegmentPrologs(pModule, segnum);
	    break;
Alexandre Julliard's avatar
Alexandre Julliard committed
607 608
        }
    }
609 610 611 612

    return MAKELONG(hSeg, sel);
}

Alexandre Julliard's avatar
Alexandre Julliard committed
613

Alexandre Julliard's avatar
Alexandre Julliard committed
614 615 616
/***********************************************************************
 *           NE_GetDLLInitParams
 */
617
static VOID NE_GetDLLInitParams( NE_MODULE *pModule,
Alexandre Julliard's avatar
Alexandre Julliard committed
618 619 620 621 622 623 624 625 626
				 WORD *hInst, WORD *ds, WORD *heap )
{
    SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );

    if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
    {
        if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
        {
            /* Not SINGLEDATA */
627
            ERR_(dll)("Library is not marked SINGLEDATA\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
628 629 630 631 632 633 634 635 636 637 638
            exit(1);
        }
        else  /* DATA NONE DLL */
        {
            *ds = 0;
            *heap = 0;
        }
    }
    else  /* DATA SINGLE DLL */
    {
	if (pModule->dgroup) {
Alexandre Julliard's avatar
Alexandre Julliard committed
639
            *ds   = SEL(pSegTable[pModule->dgroup-1].hSeg);
Alexandre Julliard's avatar
Alexandre Julliard committed
640 641 642 643 644 645 646 647 648 649 650
            *heap = pModule->heap_size;
	}
	else /* hmm, DLL has no dgroup,
		but why has it NE_FFLAGS_SINGLEDATA set ?
		Buggy DLL compiler ? */
	{
            *ds   = 0;
            *heap = 0;
	}
    }

651
    *hInst = *ds ? GlobalHandle16(*ds) : pModule->self;
Alexandre Julliard's avatar
Alexandre Julliard committed
652 653
}

Alexandre Julliard's avatar
Alexandre Julliard committed
654

Alexandre Julliard's avatar
Alexandre Julliard committed
655 656 657 658 659
/***********************************************************************
 *           NE_InitDLL
 *
 * Call the DLL initialization code
 */
660
static BOOL NE_InitDLL( NE_MODULE *pModule )
Alexandre Julliard's avatar
Alexandre Julliard committed
661 662
{
    SEGTABLEENTRY *pSegTable;
Alexandre Julliard's avatar
Alexandre Julliard committed
663
    WORD hInst, ds, heap;
664
    CONTEXT86 context;
Alexandre Julliard's avatar
Alexandre Julliard committed
665

Alexandre Julliard's avatar
Alexandre Julliard committed
666
    pSegTable = NE_SEG_TABLE( pModule );
Alexandre Julliard's avatar
Alexandre Julliard committed
667

Alexandre Julliard's avatar
Alexandre Julliard committed
668 669
    if (!(pModule->flags & NE_FFLAGS_LIBMODULE) ||
        (pModule->flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
Alexandre Julliard's avatar
Alexandre Julliard committed
670

671
    /* Call USER signal handler for Win3.1 compatibility. */
672
    NE_CallUserSignalProc( pModule->self, USIG16_DLL_LOAD );
Alexandre Julliard's avatar
Alexandre Julliard committed
673

Alexandre Julliard's avatar
Alexandre Julliard committed
674
    if (!pModule->cs) return TRUE;  /* no initialization code */
Alexandre Julliard's avatar
Alexandre Julliard committed
675

Alexandre Julliard's avatar
Alexandre Julliard committed
676 677 678 679 680 681 682 683

    /* Registers at initialization must be:
     * cx     heap size
     * di     library instance
     * ds     data segment if any
     * es:si  command line (always 0)
     */

Alexandre Julliard's avatar
Alexandre Julliard committed
684 685
    memset( &context, 0, sizeof(context) );

Alexandre Julliard's avatar
Alexandre Julliard committed
686 687
    NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );

688 689
    context.Ecx = heap;
    context.Edi = hInst;
690 691 692 693 694
    context.SegDs = ds;
    context.SegEs = ds;   /* who knows ... */
    context.SegFs = wine_get_fs();
    context.SegGs = wine_get_gs();
    context.SegCs = SEL(pSegTable[pModule->cs-1].hSeg);
695 696
    context.Eip = pModule->ip;
    context.Ebp = OFFSETOF(NtCurrentTeb()->cur_stack) + (WORD)&((STACK16FRAME*)0)->bp;
Alexandre Julliard's avatar
Alexandre Julliard committed
697

Alexandre Julliard's avatar
Alexandre Julliard committed
698
    pModule->cs = 0;  /* Don't initialize it twice */
699 700 701 702 703
    TRACE_(dll)("Calling LibMain for %.*s, cs:ip=%04lx:%04lx ds=%04lx di=%04x cx=%04x\n",
                *((BYTE*)pModule + pModule->name_table),
                (char *)pModule + pModule->name_table + 1,
                context.SegCs, context.Eip, context.SegDs,
                LOWORD(context.Edi), LOWORD(context.Ecx) );
704
    WOWCallback16Ex( 0, WCB16_REGS, 0, NULL, (DWORD *)&context );
Alexandre Julliard's avatar
Alexandre Julliard committed
705
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
706 707
}

708 709 710
/***********************************************************************
 *           NE_InitializeDLLs
 *
711
 * Recursively initialize all DLLs (according to the order in which
712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731
 * they where loaded).
 */
void NE_InitializeDLLs( HMODULE16 hModule )
{
    NE_MODULE *pModule;
    HMODULE16 *pDLL;

    if (!(pModule = NE_GetPtr( hModule ))) return;
    assert( !(pModule->flags & NE_FFLAGS_WIN32) );

    if (pModule->dlls_to_init)
    {
	HGLOBAL16 to_init = pModule->dlls_to_init;
	pModule->dlls_to_init = 0;
        for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
        {
            NE_InitializeDLLs( *pDLL );
        }
        GlobalFree16( to_init );
    }
732
    NE_InitDLL( pModule );
733 734 735
}


736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
/**********************************************************************
 *	    NE_CallUserSignalProc
 *
 * According to "Undocumented Windows", the task signal proc is
 * bypassed for module load/unload notifications, and the USER signal
 * proc is called directly instead. This is what this function does.
 */
typedef DWORD (WINAPI *pSignalProc)( HANDLE16 module, UINT16 code, UINT16 exit,
                                     HINSTANCE16 inst, HQUEUE16 queue );

void NE_CallUserSignalProc( HMODULE16 hModule, UINT16 code )
{
    FARPROC16 proc;
    HMODULE16 user = GetModuleHandle16("user.exe");

    if (!user) return;
    if ((proc = GetProcAddress16( user, "SignalProc" )))
    {
        /* USER is always a builtin dll */
        pSignalProc sigproc = (pSignalProc)((ENTRYPOINT16 *)MapSL( (SEGPTR)proc ))->target;
        sigproc( hModule, code, 0, 0, 0 );
    }
}


Alexandre Julliard's avatar
Alexandre Julliard committed
761 762 763
/***********************************************************************
 *           NE_CallDllEntryPoint
 *
764
 * Call the DllEntryPoint of DLLs with subsystem >= 4.0
Alexandre Julliard's avatar
Alexandre Julliard committed
765
 */
766
typedef DWORD (WINAPI *WinNEEntryProc)(DWORD,WORD,WORD,WORD,DWORD,WORD);
Alexandre Julliard's avatar
Alexandre Julliard committed
767 768 769

static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
{
Alexandre Julliard's avatar
Alexandre Julliard committed
770
    WORD hInst, ds, heap;
Alexandre Julliard's avatar
Alexandre Julliard committed
771 772
    FARPROC16 entryPoint;

773
    if (!(pModule->flags & NE_FFLAGS_LIBMODULE)) return;
774
    if (!(pModule->flags & NE_FFLAGS_BUILTIN) && pModule->expected_version < 0x0400) return;
775
    if (!(entryPoint = GetProcAddress16( pModule->self, "DllEntryPoint" ))) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
776

Alexandre Julliard's avatar
Alexandre Julliard committed
777 778
    NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );

779 780 781
    TRACE_(dll)( "Calling %s DllEntryPoint, cs:ip=%04x:%04x\n",
                 NE_MODULE_NAME( pModule ),
                 SELECTOROF(entryPoint), OFFSETOF(entryPoint) );
Alexandre Julliard's avatar
Alexandre Julliard committed
782

783 784
    if ( pModule->flags & NE_FFLAGS_BUILTIN )
    {
785
        WinNEEntryProc entryProc = (WinNEEntryProc)((ENTRYPOINT16 *)MapSL( (SEGPTR)entryPoint ))->target;
Alexandre Julliard's avatar
Alexandre Julliard committed
786

787 788 789 790 791
        entryProc( dwReason, hInst, ds, heap, 0, 0 );
    }
    else
    {
        CONTEXT86 context;
792
        WORD args[8];
793 794

        memset( &context, 0, sizeof(context) );
795 796
        context.SegDs = ds;
        context.SegEs = ds;   /* who knows ... */
797 798
        context.SegFs = wine_get_fs();
        context.SegGs = wine_get_gs();
799 800 801
        context.SegCs = HIWORD(entryPoint);
        context.Eip = LOWORD(entryPoint);
        context.Ebp =  OFFSETOF( NtCurrentTeb()->cur_stack )
802 803
                             + (WORD)&((STACK16FRAME*)0)->bp;

804 805 806 807 808 809 810 811 812
        args[7] = HIWORD(dwReason);
        args[6] = LOWORD(dwReason);
        args[5] = hInst;
        args[4] = ds;
        args[3] = heap;
        args[2] = 0;     /* HIWORD(dwReserved1) */
        args[1] = 0;     /* LOWORD(dwReserved1) */
        args[0] = 0;     /* wReserved2 */
        WOWCallback16Ex( 0, WCB16_REGS, sizeof(args), args, (DWORD *)&context );
813
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
814 815
}

Alexandre Julliard's avatar
Alexandre Julliard committed
816
/***********************************************************************
817
 *           NE_DllProcessAttach
818
 *
819 820 821 822
 * Call the DllEntryPoint of all modules this one (recursively)
 * depends on, according to the order in which they were loaded.
 *
 * Note that --as opposed to the PE module case-- there is no notion
823
 * of 'module loaded into a process' for NE modules, and hence we
824 825 826 827 828 829 830 831
 * have no place to store the fact that the DllEntryPoint of a
 * given module was already called on behalf of this process (e.g.
 * due to some earlier LoadLibrary16 call).
 *
 * Thus, we just call the DllEntryPoint twice in that case.  Win9x
 * appears to behave this way as well ...
 *
 * This routine must only be called with the Win16Lock held.
832
 *
833 834
 * FIXME:  We should actually abort loading in case the DllEntryPoint
 *         returns FALSE ...
Alexandre Julliard's avatar
Alexandre Julliard committed
835
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
836
 */
837 838 839 840 841 842 843 844 845 846

struct ne_init_list
{
    int count;
    int size;
    NE_MODULE **module;
};

static void add_to_init_list( struct ne_init_list *list, NE_MODULE *hModule )
{
847
    NE_MODULE **newModule = NULL;
848 849 850
    if ( list->count == list->size )
    {
        int newSize = list->size + 128;
851 852 853

	if (list->module) 
            newModule = HeapReAlloc( GetProcessHeap(), 0,
854
                                             list->module, newSize*sizeof(NE_MODULE *) );
855 856 857
	else
            newModule = HeapAlloc( GetProcessHeap(), 0,
                                             newSize*sizeof(NE_MODULE *) );
858 859
        if ( !newModule )
        {
860
            FIXME_(dll)("Out of memory!\n");
861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880
            return;
        }

        list->module = newModule;
        list->size   = newSize;
    }

    list->module[list->count++] = hModule;
}

static void free_init_list( struct ne_init_list *list )
{
    if ( list->module )
    {
        HeapFree( GetProcessHeap(), 0, list->module );
        memset( list, 0, sizeof(*list) );
    }
}

static void fill_init_list( struct ne_init_list *list, HMODULE16 hModule )
Alexandre Julliard's avatar
Alexandre Julliard committed
881
{
Alexandre Julliard's avatar
Alexandre Julliard committed
882
    NE_MODULE *pModule;
883
    HMODULE16 *pModRef;
884
    int i;
Alexandre Julliard's avatar
Alexandre Julliard committed
885

Alexandre Julliard's avatar
Alexandre Julliard committed
886 887
    if (!(pModule = NE_GetPtr( hModule ))) return;
    assert( !(pModule->flags & NE_FFLAGS_WIN32) );
Alexandre Julliard's avatar
Alexandre Julliard committed
888

889 890 891 892 893
    /* Never add a module twice */
    for ( i = 0; i < list->count; i++ )
        if ( list->module[i] == pModule )
            return;

894 895 896 897 898 899 900 901 902
    /* Check for recursive call */
    if ( pModule->misc_flags & 0x80 ) return;

    TRACE_(dll)("(%s) - START\n", NE_MODULE_NAME(pModule) );

    /* Tag current module to prevent recursive loop */
    pModule->misc_flags |= 0x80;

    /* Recursively attach all DLLs this one depends on */
903
    pModRef = (HMODULE16 *)((char *)pModule + pModule->modref_table);
904
    for ( i = 0; i < pModule->modref_count; i++ )
905
        if ( pModRef[i] ) fill_init_list( list, pModRef[i] );
906

907 908
    /* Add current module */
    add_to_init_list( list, pModule );
909 910 911 912 913

    /* Remove recursion flag */
    pModule->misc_flags &= ~0x80;

    TRACE_(dll)("(%s) - END\n", NE_MODULE_NAME(pModule) );
Alexandre Julliard's avatar
Alexandre Julliard committed
914 915
}

916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932
static void call_init_list( struct ne_init_list *list )
{
    int i;
    for ( i = 0; i < list->count; i++ )
        NE_CallDllEntryPoint( list->module[i], DLL_PROCESS_ATTACH );
}

void NE_DllProcessAttach( HMODULE16 hModule )
{
    struct ne_init_list list;
    memset( &list, 0, sizeof(list) );

    fill_init_list( &list, hModule );
    call_init_list( &list );
    free_init_list( &list );
}

Alexandre Julliard's avatar
Alexandre Julliard committed
933

934 935 936 937 938 939
/***********************************************************************
 *           NE_Ne2MemFlags
 *
 * This function translates NE segment flags to GlobalAlloc flags
 */
static WORD NE_Ne2MemFlags(WORD flags)
940
{
941 942
    WORD memflags = 0;
#if 1
943
    if (flags & NE_SEGFLAGS_DISCARDABLE)
944
      memflags |= GMEM_DISCARDABLE;
945
    if (flags & NE_SEGFLAGS_MOVEABLE ||
946 947 948 949 950 951 952 953 954 955 956 957 958
	( ! (flags & NE_SEGFLAGS_DATA) &&
	  ! (flags & NE_SEGFLAGS_LOADED) &&
	  ! (flags & NE_SEGFLAGS_ALLOCATED)
	 )
	)
      memflags |= GMEM_MOVEABLE;
    memflags |= GMEM_ZEROINIT;
#else
    memflags = GMEM_ZEROINIT | GMEM_FIXED;
#endif
    return memflags;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
959
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
960
 *           MyAlloc   (KERNEL.668) Wine-specific export
961 962
 *
 * MyAlloc() function for self-loading apps.
Alexandre Julliard's avatar
Alexandre Julliard committed
963
 */
964
DWORD WINAPI MyAlloc16( WORD wFlags, WORD wSize, WORD wElem )
Alexandre Julliard's avatar
Alexandre Julliard committed
965 966
{
    WORD size = wSize << wElem;
967 968 969 970
    HANDLE16 hMem = 0;

    if (wSize || (wFlags & NE_SEGFLAGS_MOVEABLE))
        hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
971

972 973 974 975
    if ( ((wFlags & 0x7) != 0x1) && /* DATA */
         ((wFlags & 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
    {
        WORD hSel = SEL(hMem);
976
        WORD access = SelectorAccessRights16(hSel,0,0);
977 978

	access |= 2<<2; /* SEGMENT_CODE */
979
	SelectorAccessRights16(hSel,1,access);
980
    }
981 982 983 984
    if (size)
	return MAKELONG( hMem, SEL(hMem) );
    else
	return MAKELONG( 0, hMem );
Alexandre Julliard's avatar
Alexandre Julliard committed
985 986
}

987 988 989 990 991 992 993 994 995
/***********************************************************************
 *           NE_GetInstance
 */
HINSTANCE16 NE_GetInstance( NE_MODULE *pModule )
{
    if ( !pModule->dgroup )
        return pModule->self;
    else
    {
996 997
        SEGTABLEENTRY *pSeg;
        pSeg = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
998
        return pSeg->hSeg;
999
    }
1000
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1001 1002

/***********************************************************************
1003
 *           NE_CreateSegment
Alexandre Julliard's avatar
Alexandre Julliard committed
1004
 */
1005
BOOL NE_CreateSegment( NE_MODULE *pModule, int segnum )
Alexandre Julliard's avatar
Alexandre Julliard committed
1006
{
1007
    SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule ) + segnum - 1;
1008
    int minsize;
1009
    unsigned char selflags;
Alexandre Julliard's avatar
Alexandre Julliard committed
1010 1011 1012

    assert( !(pModule->flags & NE_FFLAGS_WIN32) );

1013 1014
    if ( segnum < 1 || segnum > pModule->seg_count )
        return FALSE;
1015

1016 1017 1018
    if ( (pModule->flags & NE_FFLAGS_SELFLOAD) && segnum != 1 )
        return TRUE;    /* selfloader allocates segment itself */

1019
    if ( (pSeg->flags & NE_SEGFLAGS_ALLOCATED) && segnum != pModule->dgroup )
1020 1021
        return TRUE;    /* all but DGROUP only allocated once */

1022
    minsize = pSeg->minsize ? pSeg->minsize : 0x10000;
1023 1024 1025
    if ( segnum == pModule->ss )     minsize += pModule->stack_size;
    if ( segnum == pModule->dgroup ) minsize += pModule->heap_size;

1026 1027 1028
    selflags = (pSeg->flags & NE_SEGFLAGS_DATA) ? WINE_LDT_FLAGS_DATA : WINE_LDT_FLAGS_CODE;
    if (pSeg->flags & NE_SEGFLAGS_32BIT) selflags |= WINE_LDT_FLAGS_32BIT;
    pSeg->hSeg = GLOBAL_Alloc( NE_Ne2MemFlags(pSeg->flags), minsize, pModule->self, selflags );
1029
    if (!pSeg->hSeg) return FALSE;
1030

1031
    pSeg->flags |= NE_SEGFLAGS_ALLOCATED;
1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043
    return TRUE;
}

/***********************************************************************
 *           NE_CreateAllSegments
 */
BOOL NE_CreateAllSegments( NE_MODULE *pModule )
{
    int i;
    for ( i = 1; i <= pModule->seg_count; i++ )
        if ( !NE_CreateSegment( pModule, i ) )
            return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1044 1045 1046 1047 1048

    pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
                            (pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
    return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1049 1050 1051 1052 1053


/**********************************************************************
 *	    IsSharedSelector    (KERNEL.345)
 */
1054
BOOL16 WINAPI IsSharedSelector16( HANDLE16 selector )
Alexandre Julliard's avatar
Alexandre Julliard committed
1055 1056 1057 1058 1059 1060
{
    /* Check whether the selector belongs to a DLL */
    NE_MODULE *pModule = NE_GetPtr( selector );
    if (!pModule) return FALSE;
    return (pModule->flags & NE_FFLAGS_LIBMODULE) != 0;
}