loados2.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,176 行 · 第 1/3 页

C
1,176
字号
    unsigned            pad_len;
    WResDir             inRes;     // Directory of resources to read
    int                 resHandle;     // Handle for resources file
    ResTable            outRes;  // Resources to go out

    stub_len = Write_Stub_File();
    temp = sizeof(os2_exe_header);
    exe_head.segment_off = temp;
    SeekLoad( stub_len+sizeof(os2_exe_header) );
    adseg = 0;
    exe_head.segments = 0;
    dgroup_size = 0;
    imageguess = 0;
    if( DataGroup != NULL ) {
        adseg = DataGroup->grp_addr.seg;
        if( DataGroup->segflags & SEG_PURE ) {
            FmtData.u.os2.flags |= SHARABLE_DGROUP;
        }
        if( StackSegPtr != NULL ) {
            if( DataGroup->totalsize - DataGroup->size < StackSize ) {
                StackSize = DataGroup->totalsize - DataGroup->size;
                DataGroup->totalsize = DataGroup->size;
            } else {
                DataGroup->totalsize -= StackSize;
            }
        }
        dgroup_size = DataGroup->totalsize;
    }
    for( group = Groups; group != NULL; group = group->next_group ) {
        if( group->totalsize == 0 ) continue;   // DANGER DANGER DANGER <--!!!
        imageguess += group->size;
        exe_head.segments++;
    }
    temp += exe_head.segments * sizeof(segment_record);
    inRes = InitNEResources(&resHandle, &outRes);
    exe_head.resource_off = temp;
    if (inRes) {
        exe_head.resource = outRes.Dir.NumResources;
        temp += outRes.Dir.TableSize;
        temp += outRes.Str.StringBlockSize;
    } else {
        exe_head.resource = 0;
    }
    exe_head.resident_off = temp;
    SeekLoad( stub_len+temp );
    temp += ResNonResNameTable( TRUE );  // TRUE - do resident table.
    exe_head.module_off = temp;
    exe_head.modrefs = ModRefTable();
    temp += exe_head.modrefs * sizeof( unsigned_16 );
    exe_head.import_off = temp;
    temp += ImportNameTable();
    exe_head.entry_off = temp;
    size = DumpEntryTable();
    exe_head.entry_size = size;
    temp += size;
    temp += stub_len;
    exe_head.nonres_off = temp;
    exe_head.nonres_size = ResNonResNameTable( FALSE );  // FALSE = do non-res.
    temp += exe_head.nonres_size;
/*
 * if no segment shift specified, figure out the best one, assuming that
 * the maximum padding will happen every time.
*/
    if( FmtData.u.os2.segment_shift == 0 ) {
        imageguess += temp +(unsigned long)Root->relocs * sizeof(os2_reloc_item)
                     + stub_len + exe_head.segments * 3;
        pad_len = binary_log( (imageguess >> 16) << 1 );
        imageguess += ((1 << pad_len) - 1) * exe_head.segments;
        imageguess += ComputeResourceSize( inRes ); // inRes may be 0
        FmtData.u.os2.segment_shift = binary_log( (imageguess >> 16) << 1 );
        if( FmtData.u.os2.segment_shift == 0 ) {
            FmtData.u.os2.segment_shift = 1;     // since microsoft thinks 0 == 9
        }
    }
    exe_head.gangstart = NullAlign( 1 << FmtData.u.os2.segment_shift ) >>
                         FmtData.u.os2.segment_shift;
    WriteOS2Data( stub_len, &exe_head );
    WriteOS2Resources( resHandle, inRes, &outRes );
    exe_head.gangstart = 0;
    exe_head.ganglength = 0;
    if( inRes ) {
        SeekLoad( exe_head.resource_off + stub_len );
        WriteResTable( &outRes );
        FreeResTable( &outRes );
    }
    SeekEndLoad( 0 );
    FiniNEResources( resHandle, inRes, &outRes );
    WriteDBI();
    exe_head.signature = OS2_SIGNATURE_WORD;
    exe_head.version = 0x0105;          /* version 5.1 */
    exe_head.chk_sum = 0L;
    exe_head.info = 0;
    if( FmtData.type & MK_WINDOWS ) {
        exe_head.target = TARGET_WINDOWS;
    } else {
        exe_head.target = TARGET_OS2;
    }
    if( FmtData.u.os2.flags & PROTMODE_ONLY ) {
        exe_head.info |= OS2_PROT_MODE_ONLY;
    }
    if( FmtData.u.os2.flags & SINGLE_AUTO_DATA ) {
        exe_head.info |= OS2_SINGLE_AUTO;
    } else if( FmtData.u.os2.flags & MULTIPLE_AUTO_DATA ){
        exe_head.info |= OS2_MULT_AUTO;
    } else {
        adseg = 0;    // no automatic data segment.
    }
    if( FmtData.u.os2.flags & PM_NOT_COMPATIBLE ) {
        exe_head.info |= OS2_NOT_PM_COMPATIBLE;
    } else if( FmtData.u.os2.flags & PM_APPLICATION ) {
        exe_head.info |= OS2_PM_APP;
    } else {
        exe_head.info |= OS2_PM_COMPATIBLE;
    }
    if( FmtData.u.os2.is_private_dll ) {
        exe_head.info |= WIN_PRIVATE_DLL;
    }
    if( FmtData.dll ) {
        exe_head.info |= OS2_IS_DLL;
        if( FmtData.u.os2.flags & INIT_INSTANCE_FLAG ) {
            exe_head.info |= OS2_INIT_INSTANCE;
        }
    }
    if( LinkState & LINK_ERROR ) {
        exe_head.info |= OS2_LINK_ERROR;
    }
    exe_head.adsegnum = adseg;
    exe_head.heap = FmtData.u.os2.heapsize;
/*
 * the microsoft linker for windows will generate a stack even if no stack
 * segment has been explicitly specified. (as long as the user specifies a stack
 * size). Since microsoft's windows libraries rely on this, we have to mimic
 * it.
*/
    if( FmtData.u.os2.flags & PHONEY_STACK_FLAG ) {
        exe_head.SP = 0;
        exe_head.stacknum = adseg;
    } else {
        exe_head.SP = 0;
        //exe_head.SP = StackAddr.off;
        if( StackAddr.seg != UNDEFINED ) {
            exe_head.stacknum = StackAddr.seg;
        } else {
            exe_head.stacknum = 0;
        }
    }
    exe_head.stack = StackSize;
    if( dgroup_size + exe_head.heap > MAX_DGROUP_SIZE ) {
        LnkMsg( WRN+MSG_HEAP_TOO_BIG, NULL );
        if( dgroup_size < MAX_DGROUP_SIZE ) {
            exe_head.heap = MAX_DGROUP_SIZE - dgroup_size;
        }
    }
    exe_head.IP = StartInfo.addr.off;
    if( StartInfo.type == START_UNDEFED ) {
        exe_head.entrynum = 0;
    } else {
        exe_head.entrynum = StartInfo.addr.seg;
    }
    exe_head.align = FmtData.u.os2.segment_shift;
    exe_head.movable = 0;
    for( exp = FmtData.u.os2.exports; exp != NULL; exp = exp->next ) {
        if( exp->ismovable ) {
            exe_head.movable++;
        }
    }
    exe_head.otherflags = 0;
    if( FmtData.u.os2.flags & LONG_FILENAMES ) {
        exe_head.otherflags = OS2_LONG_FILE_NAMES;
    }
    if( FmtData.u.os2.flags & PROPORTIONAL_FONT ) {
        exe_head.otherflags |= WIN_CLEAN_MEMORY | WIN_PROPORTIONAL_FONT;
    } else if( FmtData.u.os2.flags & CLEAN_MEMORY ) {
        exe_head.otherflags |= WIN_CLEAN_MEMORY;
    }
    if (exe_head.ganglength) {
        exe_head.otherflags |= WIN_GANGLOAD_PRESENT;
    }
    exe_head.swaparea = 0;
    if( FmtData.type & MK_WINDOWS ) {
        if( FmtData.ver_specified ) {
            exe_head.expver = (FmtData.major << 8) | (FmtData.minor & 0xFF);
        } else {
            exe_head.expver = 0x300;
        }
    } else {
        exe_head.expver = 0;
    }
    SeekLoad( stub_len );
    WriteLoad( &exe_head, sizeof(os2_exe_header) );
}

extern void FreeImpNameTab( void )
/********************************/
{
    FmtData.u.os2.mod_ref_list = NULL;  /* these are permalloc'd */
    FmtData.u.os2.imp_tab_list = NULL;
}

#define DEF_SEG_ON (SEG_PURE|SEG_READ_ONLY|SEG_CONFORMING|SEG_MOVABLE|SEG_DISCARD|SEG_RESIDENT|SEG_CONTIGUOUS|SEG_NOPAGE)
#define DEF_SEG_OFF (SEG_PRELOAD|SEG_INVALID)

static void CheckGrpFlags( void *_leader )
/****************************************/
{
    seg_leader     *leader = _leader;
    unsigned_16     sflags;

    sflags = leader->segflags;
// if any of these flags are on, turn it on for the entire group.
    leader->group->segflags |= sflags & DEF_SEG_OFF;
// if any of these flags off, make sure they are off in the group.
    leader->group->segflags &= sflags & DEF_SEG_ON | ~DEF_SEG_ON;
    if( (sflags & SEG_LEVEL_MASK) == SEG_LEVEL_2 ) {
        /* if any are level 2 then all have to be. */
        leader->group->segflags &= ~SEG_LEVEL_MASK;
        leader->group->segflags |= SEG_LEVEL_2;
    }
}

static void SetGroupFlags( void )
/*******************************/
// This goes through the groups, setting the flag word to be compatible with
// the flag words that are specified in the segments.
{
    group_entry *   group;

    for( group = Groups; group != NULL; group = group->next_group ) {
        if( group->totalsize == 0 ) continue;   // DANGER DANGER DANGER <--!!!
        group->segflags |= DEF_SEG_ON;
        Ring2Walk( group->leaders, CheckGrpFlags );
        /* for some insane reason, level 2 segments must be marked as
            movable */
        if( (group->segflags & SEG_LEVEL_MASK) == SEG_LEVEL_2 ) {
            group->segflags |= SEG_MOVABLE;
        }
    }
}

static unsigned DoExeName( void )
/*******************************/
/* make up the "program is %f" string, and put it in tokbuff.*/
{
    char        rc_buff[RESOURCE_MAX_SIZE];
    unsigned    msgsize;

    Msg_Get( MSG_IS_A_EXE, rc_buff );
    msgsize = FmtStr( TokBuff, TokSize, rc_buff );
    TokBuff[msgsize++] = '\r';
    TokBuff[msgsize++] = '\n';
    TokBuff[msgsize] = '$';     /* end of string for int 21 fn. 9 */
    return( msgsize + 1 );
}

#define STUB_ALIGN 8    /* for PE format */

#define PARA_ALIGN( x ) (((x)+0xf) &  ~0xfUL)

extern unsigned_32 GetStubSize( void )
/************************************/
/* return the size of the stub file */
{
    unsigned_32     stub_len;
    f_handle        the_file;
    dos_exe_header  dosheader;
    unsigned_32     read_len;
    unsigned_32     reloc_size;
    unsigned_32     code_start;
    char *          name;

    name = FmtData.u.os2.stub_file_name;
    stub_len = PARA_ALIGN( sizeof(DosStub) + DoExeName() );
    if( name != NULL && stricmp( name, Root->outfile->fname ) != 0 ) {
        the_file = SearchPath( name );
        if( the_file != NIL_HANDLE ) {
            QRead( the_file, &dosheader, sizeof(dos_exe_header), name );
            if( dosheader.signature == 0x5A4D ) {
                if( dosheader.mod_size == 0 ) {
                    read_len = 512;
                } else {
                    read_len = dosheader.mod_size;
                }
                code_start = dosheader.hdr_size * 16ul;
                read_len += (dosheader.file_size - 1) * 512ul - code_start;
    // make sure reloc_size is a multiple of 16.
                reloc_size = (dosheader.num_relocs * 4ul + 15) & ~0xFul;
                dosheader.hdr_size = 4 + reloc_size/16;
                stub_len = read_len + dosheader.hdr_size * 16ul;
                stub_len = (stub_len + (STUB_ALIGN-1)) & ~(STUB_ALIGN-1);
            }
            QClose( the_file, name );
        }
    }
    return( stub_len );
}

static unsigned WriteDefStub( void )
/**********************************/
/* write the default stub to the executable file */
{
    unsigned            msgsize;
    unsigned            fullsize;
    unsigned_32 *       stubend;

    msgsize = DoExeName();
    fullsize = PARA_ALIGN(msgsize + sizeof(DosStub) );
    stubend = (unsigned_32 *) (DosStub + 0x3c);
    *stubend = fullsize;
    WriteLoad( DosStub, sizeof(DosStub) );
    WriteLoad( TokBuff, msgsize );
    PadLoad( fullsize - msgsize - sizeof(DosStub) );
    return( fullsize );
}

extern unsigned_32 Write_Stub_File( void )
/****************************************/
{
    unsigned_32     stub_len;
    f_handle        the_file;
    dos_exe_header  dosheader;
    unsigned_32     read_len;
    unsigned        amount;
    unsigned_32     reloc_size;
    unsigned_16     num_relocs;
    unsigned_32     the_reloc;
    unsigned_32     code_start;
    char *          name;

    name = FmtData.u.os2.stub_file_name;
    if( name == NULL ) {
        stub_len = WriteDefStub();
    } else if( stricmp( name, Root->outfile->fname ) == 0 ) {
        LnkMsg( ERR+MSG_STUB_SAME_AS_LOAD, NULL );
        stub_len = WriteDefStub();
    } else {
        the_file = SearchPath( name );
        if( the_file == NIL_HANDLE ) {
            LnkMsg( WRN+MSG_CANT_OPEN_NO_REASON, "s", name );
            return( WriteDefStub() );   // NOTE: <== a return here.
        }
        QRead( the_file, &dosheader, sizeof(dos_exe_header), name );
        if( dosheader.signature != 0x5A4D ) {
            LnkMsg( ERR + MSG_INV_STUB_FILE, NULL );
            stub_len = WriteDefStub();
        } else {
            if( dosheader.mod_size == 0 ) {
                read_len = 512;
            } else {
                read_len = dosheader.mod_size;
            }
            QSeek( the_file, dosheader.reloc_offset, name );
            dosheader.reloc_offset = 0x40;
            code_start = dosheader.hdr_size * 16ul;
            read_len += (dosheader.file_size - 1) * 512ul - code_start;
// make sure reloc_size is a multiple of 16.
            reloc_size = (dosheader.num_relocs * 4ul + 15) & ~0xFul;
            dosheader.hdr_size = 4 + reloc_size/16;
            stub_len = read_len + dosheader.hdr_size * 16ul;
            dosheader.file_size = (stub_len + 511) >> 9;  // round up.
            dosheader.mod_size = stub_len % 512;
            WriteLoad( &dosheader, sizeof( dos_exe_header ) );
            PadLoad( 0x3c - sizeof( dos_exe_header ) );
            stub_len = (stub_len + (STUB_ALIGN-1)) & ~(STUB_ALIGN-1);
            WriteLoad( &stub_len, sizeof( unsigned_32 ) );
            for(num_relocs = dosheader.num_relocs;num_relocs > 0;num_relocs--) {
                QRead( the_file, &the_reloc, sizeof( unsigned_32 ), name );
                WriteLoad( &the_reloc, sizeof( unsigned_32 ) );
                reloc_size -= sizeof(unsigned_32 );
            }
            if( reloc_size != 0 ) {    // need padding
                PadLoad( reloc_size );
            }
            QSeek( the_file, code_start, name );
            while( read_len > 0 ) {
                if( read_len < TokSize ) {
                    amount = read_len;
                } else {
                    amount = TokSize;
                }
                QRead( the_file, TokBuff, amount, name );
                WriteLoad( TokBuff, amount );
                read_len -= amount;
            }
        }
        QClose( the_file, name );
        _LnkFree( name );
        FmtData.u.os2.stub_file_name = NULL;
        stub_len = NullAlign( STUB_ALIGN );
    }
    return( stub_len );
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?