ne_segment.c 33.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
 *
 * 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
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 "winternl.h"
39
#include "wine/library.h"
40
#include "kernel16_private.h"
41
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
42

43
WINE_DEFAULT_DEBUG_CHANNEL(fixup);
44 45
WINE_DECLARE_DEBUG_CHANNEL(dll);
WINE_DECLARE_DEBUG_CHANNEL(module);
46

47 48 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
/*
 * 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

78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
/* 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;

94
#define SEL(x) ((x)|1)
Alexandre Julliard's avatar
Alexandre Julliard committed
95

96 97
static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum);

98

Alexandre Julliard's avatar
Alexandre Julliard committed
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
/***********************************************************************
 *           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
117
/***********************************************************************
118
 *           NE_OpenFile
Alexandre Julliard's avatar
Alexandre Julliard committed
119
 */
120
static HFILE16 NE_OpenFile( NE_MODULE *pModule )
Alexandre Julliard's avatar
Alexandre Julliard committed
121
{
122 123 124
    char *name = NE_MODULE_NAME( pModule );
    HANDLE handle = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ,
                                 NULL, OPEN_EXISTING, 0, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
125

126
    if (handle == INVALID_HANDLE_VALUE)
127
    {
128 129
        ERR( "Can't open file '%s' for module %04x\n", name, pModule->self );
        return HFILE_ERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
130
    }
131 132
    return Win32HandleToDosFileHandle( handle );
}
Alexandre Julliard's avatar
Alexandre Julliard committed
133

Alexandre Julliard's avatar
Alexandre Julliard committed
134

135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
/***********************************************************************
 *           apply_relocations
 *
 * Apply relocations to a segment. Helper for NE_LoadSegment.
 */
static inline BOOL apply_relocations( NE_MODULE *pModule, const struct relocation_entry_s *rep,
                                      int count, int segnum )
{
    BYTE *func_name;
    char buffer[256];
    int i, ordinal;
    WORD offset, *sp;
    HMODULE16 module;
    FARPROC16 address = 0;
    HMODULE16 *pModuleTable = (HMODULE16 *)((char *)pModule + pModule->ne_modtab);
    SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
    SEGTABLEENTRY *pSeg = pSegTable + segnum - 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
152 153

    /*
Alexandre Julliard's avatar
Alexandre Julliard committed
154
     * Go through the relocation table one entry at a time.
Alexandre Julliard's avatar
Alexandre Julliard committed
155
     */
Alexandre Julliard's avatar
Alexandre Julliard committed
156
    for (i = 0; i < count; i++, rep++)
Alexandre Julliard's avatar
Alexandre Julliard committed
157
    {
158 159 160 161 162 163 164 165 166 167
        /*
         * Get the target address corresponding to this entry.
         */

        /* If additive, there is no target chain list. Instead, add source
           and target */
        int additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
        switch (rep->relocation_type & 3)
        {
        case NE_RELTYPE_ORDINAL:
Alexandre Julliard's avatar
Alexandre Julliard committed
168
            module = pModuleTable[rep->target1-1];
169
            ordinal = rep->target2;
Alexandre Julliard's avatar
Alexandre Julliard committed
170
            address = NE_GetEntryPoint( module, ordinal );
Alexandre Julliard's avatar
Alexandre Julliard committed
171 172
            if (!address)
            {
Alexandre Julliard's avatar
Alexandre Julliard committed
173
                NE_MODULE *pTarget = NE_GetPtr( module );
Alexandre Julliard's avatar
Alexandre Julliard committed
174
                if (!pTarget)
175
                    WARN_(module)("Module not found: %04x, reference %d of module %*.*s\n",
176
                             module, rep->target1,
177 178 179
                             *((BYTE *)pModule + pModule->ne_restab),
                             *((BYTE *)pModule + pModule->ne_restab),
                             (char *)pModule + pModule->ne_restab + 1 );
Alexandre Julliard's avatar
Alexandre Julliard committed
180
                else
Alexandre Julliard's avatar
Alexandre Julliard committed
181
                {
182
                    ERR("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
183 184
                            *((BYTE *)pTarget + pTarget->ne_restab),
                            (char *)pTarget + pTarget->ne_restab + 1,
Alexandre Julliard's avatar
Alexandre Julliard committed
185
                            ordinal );
Alexandre Julliard's avatar
Alexandre Julliard committed
186
                    address = (FARPROC16)0xdeadbeef;
Alexandre Julliard's avatar
Alexandre Julliard committed
187
                }
Alexandre Julliard's avatar
Alexandre Julliard committed
188
            }
Alexandre Julliard's avatar
Alexandre Julliard committed
189
            if (TRACE_ON(fixup))
Alexandre Julliard's avatar
Alexandre Julliard committed
190
            {
Alexandre Julliard's avatar
Alexandre Julliard committed
191
                NE_MODULE *pTarget = NE_GetPtr( module );
192
                TRACE("%d: %.*s.%d=%04x:%04x %s\n", i + 1,
193 194
                       *((BYTE *)pTarget + pTarget->ne_restab),
                       (char *)pTarget + pTarget->ne_restab + 1,
Alexandre Julliard's avatar
Alexandre Julliard committed
195 196
                       ordinal, HIWORD(address), LOWORD(address),
                       NE_GetRelocAddrName( rep->address_type, additive ) );
Alexandre Julliard's avatar
Alexandre Julliard committed
197
            }
198
            break;
199

200
        case NE_RELTYPE_NAME:
Alexandre Julliard's avatar
Alexandre Julliard committed
201
            module = pModuleTable[rep->target1-1];
Mike McCormack's avatar
Mike McCormack committed
202
            func_name = (BYTE *)pModule + pModule->ne_imptab + rep->target2;
Alexandre Julliard's avatar
Alexandre Julliard committed
203 204
            memcpy( buffer, func_name+1, *func_name );
            buffer[*func_name] = '\0';
Mike McCormack's avatar
Mike McCormack committed
205
            ordinal = NE_GetOrdinal( module, buffer );
Alexandre Julliard's avatar
Alexandre Julliard committed
206
            address = NE_GetEntryPoint( module, ordinal );
Alexandre Julliard's avatar
Alexandre Julliard committed
207

Alexandre Julliard's avatar
Alexandre Julliard committed
208
            if (ERR_ON(fixup) && !address)
Alexandre Julliard's avatar
Alexandre Julliard committed
209
            {
Alexandre Julliard's avatar
Alexandre Julliard committed
210
                NE_MODULE *pTarget = NE_GetPtr( module );
211
                ERR("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
212
                    *((BYTE *)pTarget + pTarget->ne_restab),
Mike McCormack's avatar
Mike McCormack committed
213
                    (char *)pTarget + pTarget->ne_restab + 1, buffer );
Alexandre Julliard's avatar
Alexandre Julliard committed
214
            }
Alexandre Julliard's avatar
Alexandre Julliard committed
215
            if (!address) address = (FARPROC16) 0xdeadbeef;
Alexandre Julliard's avatar
Alexandre Julliard committed
216
            if (TRACE_ON(fixup))
Alexandre Julliard's avatar
Alexandre Julliard committed
217
            {
218
                NE_MODULE *pTarget = NE_GetPtr( module );
219
                TRACE("%d: %.*s.%s=%04x:%04x %s\n", i + 1,
220 221
                       *((BYTE *)pTarget + pTarget->ne_restab),
                       (char *)pTarget + pTarget->ne_restab + 1,
Mike McCormack's avatar
Mike McCormack committed
222
                       buffer, HIWORD(address), LOWORD(address),
Alexandre Julliard's avatar
Alexandre Julliard committed
223
                       NE_GetRelocAddrName( rep->address_type, additive ) );
Alexandre Julliard's avatar
Alexandre Julliard committed
224
            }
225 226 227 228 229 230 231 232 233
            break;

        case NE_RELTYPE_INTERNAL:
            if ((rep->target1 & 0xff) == 0xff)
            {
                address  = NE_GetEntryPoint( pModule->self, rep->target2 );
            }
            else
            {
234
                address = (FARPROC16)MAKESEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
            }

            TRACE("%d: %04x:%04x %s\n",
                  i + 1, HIWORD(address), LOWORD(address),
                  NE_GetRelocAddrName( rep->address_type, additive ) );
            break;

        case NE_RELTYPE_OSFIXUP:
            /* 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.
             */
            TRACE("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
                  i + 1, rep->relocation_type, rep->offset,
                  rep->target1, rep->target2,
                  NE_GetRelocAddrName( rep->address_type, additive ) );
            continue;
        }

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

Alexandre Julliard's avatar
Alexandre Julliard committed
260 261
        /* Apparently, high bit of address_type is sometimes set; */
        /* we ignore it for now */
262
        if (rep->address_type > NE_RADDR_OFFSET32)
Alexandre Julliard's avatar
Alexandre Julliard committed
263 264
        {
            char module[10];
265
            GetModuleName16( pModule->self, module, sizeof(module) );
266
            ERR("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
267 268
                 module, rep->address_type );
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
269

Alexandre Julliard's avatar
Alexandre Julliard committed
270 271
        if (additive)
        {
272
            sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
273
            TRACE("    %04x:%04x\n", offset, *sp );
Alexandre Julliard's avatar
Alexandre Julliard committed
274 275 276 277 278 279
            switch (rep->address_type & 0x7f)
            {
            case NE_RADDR_LOWBYTE:
                *(BYTE *)sp += LOBYTE((int)address);
                break;
            case NE_RADDR_OFFSET16:
280
                *sp += LOWORD(address);
Alexandre Julliard's avatar
Alexandre Julliard committed
281 282
                break;
            case NE_RADDR_POINTER32:
283 284
                *sp += LOWORD(address);
                *(sp+1) = HIWORD(address);
Alexandre Julliard's avatar
Alexandre Julliard committed
285 286
                break;
            case NE_RADDR_SELECTOR:
287
                /* Borland creates additive records with offset zero. Strange, but OK */
Alexandre Julliard's avatar
Alexandre Julliard committed
288
                if (*sp)
289
                    ERR("Additive selector to %04x.Please report\n",*sp);
290
                else
Alexandre Julliard's avatar
Alexandre Julliard committed
291
                    *sp = HIWORD(address);
Alexandre Julliard's avatar
Alexandre Julliard committed
292
                break;
Alexandre Julliard's avatar
Alexandre Julliard committed
293 294
            default:
                goto unknown;
Alexandre Julliard's avatar
Alexandre Julliard committed
295
            }
Alexandre Julliard's avatar
Alexandre Julliard committed
296 297 298 299 300
        }
        else  /* non-additive fixup */
        {
            do
            {
301 302
                WORD next_offset;

303
                sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
Alexandre Julliard's avatar
Alexandre Julliard committed
304
                next_offset = *sp;
305
                TRACE("    %04x:%04x\n", offset, *sp );
Alexandre Julliard's avatar
Alexandre Julliard committed
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
                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
324
                if (next_offset >= GlobalSize16(pSeg->hSeg)) break;
Alexandre Julliard's avatar
Alexandre Julliard committed
325
                offset = next_offset;
Alexandre Julliard's avatar
Alexandre Julliard committed
326
            } while (offset != 0xffff);
Alexandre Julliard's avatar
Alexandre Julliard committed
327
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
328
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
329
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
330 331

unknown:
332
    WARN("WARNING: %d: unknown ADDR TYPE %d,  "
Alexandre Julliard's avatar
Alexandre Julliard committed
333
         "TYPE %d,  OFFSET %04x,  TARGET %04x %04x\n",
334
         i + 1, rep->address_type, rep->relocation_type,
Alexandre Julliard's avatar
Alexandre Julliard committed
335 336
         rep->offset, rep->target1, rep->target2);
    return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
337 338
}

Alexandre Julliard's avatar
Alexandre Julliard committed
339

340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
/***********************************************************************
 *           NE_LoadSegment
 */
BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
{
    WORD count;
    DWORD pos;
    const struct relocation_entry_s *rep;
    int size;
    SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
    SEGTABLEENTRY *pSeg = pSegTable + segnum - 1;

    if (pSeg->flags & NE_SEGFLAGS_LOADED)
    {
	/* self-loader ? -> already loaded it */
	if (pModule->ne_flags & NE_FFLAGS_SELFLOAD)
	    return TRUE;

	/* leave, except for DGROUP, as this may be the second instance */
	if (segnum != pModule->ne_autodata)
            return TRUE;
    }

    if (!pSeg->filepos) return TRUE;  /* No file image, just return */

    TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
                    segnum, pSeg->hSeg, pSeg->flags );
    pos = pSeg->filepos << pModule->ne_align;
    if (pSeg->size) size = pSeg->size;
    else size = pSeg->minsize ? pSeg->minsize : 0x10000;

    if (pModule->ne_flags & NE_FFLAGS_SELFLOAD && segnum > 1)
    {
 	/* Implement self-loading segments */
 	SELFLOADHEADER *selfloadheader;
        void *oldstack;
        HFILE16 hFile16;
        WORD args[3];
        DWORD ret;

 	selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg),0) );
        oldstack = NtCurrentTeb()->WOW32Reserved;
        NtCurrentTeb()->WOW32Reserved = (void *)MAKESEGPTR(pModule->self_loading_sel,
                                                           0xff00 - sizeof(STACK16FRAME));

        hFile16 = NE_OpenFile( pModule );
386
        TRACE_(dll)("Call LoadAppSegProc(hmodule=0x%04x,hf=%x,segnum=%d)\n",
387 388 389 390 391 392
                    pModule->self,hFile16,segnum );
        args[2] = pModule->self;
        args[1] = hFile16;
        args[0] = segnum;
        WOWCallback16Ex( (DWORD)selfloadheader->LoadAppSeg, WCB16_PASCAL, sizeof(args), args, &ret );
        pSeg->hSeg = LOWORD(ret);
393
        TRACE_(dll)("Ret LoadAppSegProc: hSeg=0x%04x\n", pSeg->hSeg);
394 395
        _lclose16( hFile16 );
        NtCurrentTeb()->WOW32Reserved = oldstack;
396 397 398

        pSeg->flags |= NE_SEGFLAGS_LOADED;
        return TRUE;
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
    }
    else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
    {
        void *mem = GlobalLock16(pSeg->hSeg);
        if (!NE_READ_DATA( pModule, mem, pos, size ))
            return FALSE;
        pos += size;
    }
    else
    {
        /*
          The following bit of code for "iterated segments" was written without
          any documentation on the format of these segments. It seems to work,
          but may be missing something.
        */
        const char *buff = NE_GET_DATA( pModule, pos, size );
        const char* curr = buff;
        char *mem = GlobalLock16(pSeg->hSeg);

        pos += size;
        if (buff == NULL) return FALSE;

        while(curr < buff + size) {
422 423
            unsigned int rept = ((const short *)curr)[0];
            unsigned int len =  ((const short *)curr)[1];
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457

            curr += 2*sizeof(short);
            while (rept--)
            {
                memcpy( mem, curr, len );
                mem += len;
            }
            curr += len;
        }
    }

    pSeg->flags |= NE_SEGFLAGS_LOADED;

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

    if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
        return TRUE;  /* No relocation data, we are done */

    if (!NE_READ_DATA( pModule, &count, pos, sizeof(count) ) || !count) return TRUE;
    pos += sizeof(count);

    TRACE("Fixups for %.*s, segment %d, hSeg %04x\n",
          *((BYTE *)pModule + pModule->ne_restab),
          (char *)pModule + pModule->ne_restab + 1,
          segnum, pSeg->hSeg );

    if (!(rep = NE_GET_DATA( pModule, pos, count * sizeof(struct relocation_entry_s) )))
        return FALSE;

    return apply_relocations( pModule, rep, count, segnum );
}


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

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

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

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

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


513
/***********************************************************************
514
 *           NE_FixupSegmentPrologs
515
 *
516
 * Fixup exported functions prologs of one segment
517
 */
518
static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum)
519
{
520 521 522 523 524
    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;
525

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

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

534
    if (!pModule->ne_autodata) return;
535

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

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

541
    bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->ne_enttab);
542 543

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

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


/***********************************************************************
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

    /* find the segment number of the module that belongs to hSeg */
601
    for (segnum = 1; segnum <= pModule->ne_cseg; segnum++)
602 603 604 605 606
    {
	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
				 WORD *hInst, WORD *ds, WORD *heap )
{
    SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );

622
    if (!(pModule->ne_flags & NE_FFLAGS_SINGLEDATA))
Alexandre Julliard's avatar
Alexandre Julliard committed
623
    {
624
        if (pModule->ne_flags & NE_FFLAGS_MULTIPLEDATA || pModule->ne_autodata)
Alexandre Julliard's avatar
Alexandre Julliard committed
625 626
        {
            /* 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
            exit(1);
        }
        else  /* DATA NONE DLL */
        {
            *ds = 0;
            *heap = 0;
        }
    }
    else  /* DATA SINGLE DLL */
    {
638 639 640
	if (pModule->ne_autodata) {
            *ds   = SEL(pSegTable[pModule->ne_autodata-1].hSeg);
            *heap = pModule->ne_heap;
Alexandre Julliard's avatar
Alexandre Julliard committed
641 642 643 644 645 646 647 648 649 650
	}
	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
    CONTEXT 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

668 669
    if (!(pModule->ne_flags & NE_FFLAGS_LIBMODULE) ||
        (pModule->ne_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

674
    if (!SELECTOROF(pModule->ne_csip)) 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
    context.SegDs = ds;
    context.SegEs = ds;   /* who knows ... */
    context.SegFs = wine_get_fs();
    context.SegGs = wine_get_gs();
694 695
    context.SegCs = SEL(pSegTable[SELECTOROF(pModule->ne_csip)-1].hSeg);
    context.Eip   = OFFSETOF(pModule->ne_csip);
696
    context.Ebp   = OFFSETOF(NtCurrentTeb()->WOW32Reserved) + FIELD_OFFSET(STACK16FRAME,bp);
Alexandre Julliard's avatar
Alexandre Julliard committed
697

698
    pModule->ne_csip = 0;  /* Don't initialize it twice */
699
    TRACE_(dll)("Calling LibMain for %.*s, cs:ip=%04x:%04x ds=%04x di=%04x cx=%04x\n",
700 701
                *((BYTE*)pModule + pModule->ne_restab),
                (char *)pModule + pModule->ne_restab + 1,
702 703
                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
 * they where loaded).
 */
void NE_InitializeDLLs( HMODULE16 hModule )
{
    NE_MODULE *pModule;
    HMODULE16 *pDLL;

    if (!(pModule = NE_GetPtr( hModule ))) return;
720
    assert( !(pModule->ne_flags & NE_FFLAGS_WIN32) );
721 722 723 724 725

    if (pModule->dlls_to_init)
    {
	HGLOBAL16 to_init = pModule->dlls_to_init;
	pModule->dlls_to_init = 0;
726
        for (pDLL = GlobalLock16( to_init ); *pDLL; pDLL++)
727 728 729 730 731
        {
            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 774
    if (!(pModule->ne_flags & NE_FFLAGS_LIBMODULE)) return;
    if (!(pModule->ne_flags & NE_FFLAGS_BUILTIN) && pModule->ne_expver < 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
    if ( pModule->ne_flags & NE_FFLAGS_BUILTIN )
784
    {
785
        WinNEEntryProc entryProc = (WinNEEntryProc)((ENTRYPOINT16 *)MapSL( (SEGPTR)entryPoint ))->target;
Alexandre Julliard's avatar
Alexandre Julliard committed
786

787 788 789 790
        entryProc( dwReason, hInst, ds, heap, 0, 0 );
    }
    else
    {
791
        CONTEXT 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
        context.SegCs = HIWORD(entryPoint);
800
        context.Eip   = LOWORD(entryPoint);
801
        context.Ebp   = OFFSETOF(NtCurrentTeb()->WOW32Reserved) + FIELD_OFFSET(STACK16FRAME,bp);
802

803 804 805 806 807 808 809 810 811
        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 );
812
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
813 814
}

Alexandre Julliard's avatar
Alexandre Julliard committed
815
/***********************************************************************
816
 *           NE_DllProcessAttach
817
 *
818 819 820 821
 * 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
822
 * of 'module loaded into a process' for NE modules, and hence we
823 824 825 826 827 828 829 830
 * 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.
831
 *
832 833
 * FIXME:  We should actually abort loading in case the DllEntryPoint
 *         returns FALSE ...
Alexandre Julliard's avatar
Alexandre Julliard committed
834
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
835
 */
836 837 838 839 840 841 842 843 844 845

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 )
{
846
    NE_MODULE **newModule = NULL;
847 848 849
    if ( list->count == list->size )
    {
        int newSize = list->size + 128;
850 851 852

	if (list->module) 
            newModule = HeapReAlloc( GetProcessHeap(), 0,
853
                                             list->module, newSize*sizeof(NE_MODULE *) );
854 855 856
	else
            newModule = HeapAlloc( GetProcessHeap(), 0,
                                             newSize*sizeof(NE_MODULE *) );
857 858
        if ( !newModule )
        {
859
            FIXME_(dll)("Out of memory!\n");
860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879
            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
880
{
Alexandre Julliard's avatar
Alexandre Julliard committed
881
    NE_MODULE *pModule;
882
    HMODULE16 *pModRef;
883
    int i;
Alexandre Julliard's avatar
Alexandre Julliard committed
884

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

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

893
    /* Check for recursive call */
894
    if ( pModule->ne_flagsothers & 0x80 ) return;
895 896 897 898

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

    /* Tag current module to prevent recursive loop */
899
    pModule->ne_flagsothers |= 0x80;
900 901

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

906 907
    /* Add current module */
    add_to_init_list( list, pModule );
908 909

    /* Remove recursion flag */
910
    pModule->ne_flagsothers &= ~0x80;
911 912

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

915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931
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
932

933 934 935 936 937 938
/***********************************************************************
 *           NE_Ne2MemFlags
 *
 * This function translates NE segment flags to GlobalAlloc flags
 */
static WORD NE_Ne2MemFlags(WORD flags)
939
{
940 941
    WORD memflags = 0;
#if 1
942
    if (flags & NE_SEGFLAGS_DISCARDABLE)
943
      memflags |= GMEM_DISCARDABLE;
944
    if (flags & NE_SEGFLAGS_MOVEABLE ||
945 946 947 948 949 950 951 952 953 954 955 956 957
	( ! (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
958
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
959
 *           MyAlloc   (KERNEL.668) Wine-specific export
960 961
 *
 * MyAlloc() function for self-loading apps.
Alexandre Julliard's avatar
Alexandre Julliard committed
962
 */
963
DWORD WINAPI MyAlloc16( WORD wFlags, WORD wSize, WORD wElem )
Alexandre Julliard's avatar
Alexandre Julliard committed
964 965
{
    WORD size = wSize << wElem;
966 967 968 969
    HANDLE16 hMem = 0;

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

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

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

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

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

1010
    assert( !(pModule->ne_flags & NE_FFLAGS_WIN32) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1011

1012
    if ( segnum < 1 || segnum > pModule->ne_cseg )
1013
        return FALSE;
1014

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

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

1021
    minsize = pSeg->minsize ? pSeg->minsize : 0x10000;
1022 1023
    if ( segnum == SELECTOROF(pModule->ne_sssp) ) minsize += pModule->ne_stack;
    if ( segnum == pModule->ne_autodata ) minsize += pModule->ne_heap;
1024

1025 1026 1027
    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 );
1028
    if (!pSeg->hSeg) return FALSE;
1029

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

/***********************************************************************
 *           NE_CreateAllSegments
 */
BOOL NE_CreateAllSegments( NE_MODULE *pModule )
{
    int i;
1040
    for ( i = 1; i <= pModule->ne_cseg; i++ )
1041 1042
        if ( !NE_CreateSegment( pModule, i ) )
            return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1043

1044 1045
    pModule->dgroup_entry = pModule->ne_autodata ? pModule->ne_segtab +
                            (pModule->ne_autodata - 1) * sizeof(SEGTABLEENTRY) : 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1046 1047
    return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1048 1049 1050 1051 1052


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