autogrp.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 400 行

C
400
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  Routines for creating auto groups and packing segments
*
****************************************************************************/


#include <string.h>
#include "linkstd.h"
#include "ring.h"
#include "alloc.h"
#include "pcobj.h"
#include "msg.h"
#include "wlnkmsg.h"
#include "specials.h"
#include "overlays.h"
#include "strtab.h"
#include "carve.h"
#include "permdata.h"
#include "objcalc.h"
#include "objnode.h"
#include "objpass1.h"


static group_entry *    GetAutoGroup( bool );
static void             SortGroup( seg_leader * );
static void             PackClass( class_entry *class, section *sec );
static void             PackSegs( seg_leader * seg, unsigned num_segs,
                                  offset size, class_entry *class,
                                  bool isdata, bool isrdwr );
static void             SortGroupList( void );
static void             FindSplitGroups( void );
static void             NumberNonAutos( void );

static group_entry *    CurrGroup;
int                     NumGroups;

static void AutoGroupSect( section * sec );

extern void AutoGroup( void )
/***************************/
{
    ProcAllSects( &AutoGroupSect );
    SortGroupList();
    FindSplitGroups();
    if( NumGroups == 0 ) {
        LnkMsg( FTL+MSG_NO_CODE_OR_DATA, NULL );
    }
    NumberNonAutos();
}

static void AutoGroupSect( section * sec )
/****************************************/
{
    class_entry *           class;
    
    CurrGroup = NULL;
    for( class = sec->classlist; class != NULL; class = class->next_class ) {
        if( !( class->flags & CLASS_DEBUG_INFO ) ) {
            PackClass( class, sec );
        }
    }
}

static offset SetSegType( seg_leader * seg )
/******************************************/
// set packlimit if necessary.
{
    offset      limit;

    if( seg == NULL )
        return( 0xFFFF );
    if( seg->info & SEG_CODE ) {
        if( LinkFlags & PACKCODE_FLAG ) {
            return( PackCodeLimit );
        }
    } else {
        if( LinkFlags & PACKDATA_FLAG ) {
            return( PackDataLimit );
        }
    }
    if( seg->info & USE_32 ) {
        limit = 0xFFFFFFFF;
    } else if( FmtData.type & MK_WINDOWS ) {   /* windows doesn't like */
        limit = 0xFFF0;             /* large code segments */
    } else {
        limit = 0xFFFF;
    }
    return( limit );
}

static bool CanPack( seg_leader *one, seg_leader *two )
/*****************************************************/
{
    if( one->info & SEG_CODE) {
        if( two->combine == COMBINE_INVALID ) {
            return( FALSE );
        }
    } else {
        if( one->align != two->align ) {
            return( FALSE );
        }
    }
    if( ( one->info & USE_32 ) != ( two->info & USE_32 ) )
        return( FALSE );
    if( one->segflags != two->segflags )
        return( FALSE );
    return( TRUE );
}

static void PackClass( class_entry *class, section *sec )
/*******************************************************/
{
    seg_leader *    seg;
    seg_leader *    packstart;
    seg_leader *    anchor;
    offset          size;
    offset          new_size;
    offset          align_size;
    unsigned        num_segs;
    bool            lastseg;    // TRUE iff this should be last seg in group.
    bool            isdata;
    bool            isreadwrite;
    offset          limit;

    isreadwrite = !( class->flags & CLASS_READ_ONLY );
    CurrentSeg = NULL;
    seg = (seg_leader *)RingStep( class->segs, NULL );
    anchor = seg;
    packstart = seg;
    size = 0;
    num_segs = 0;
    lastseg = FALSE;
    isdata = FALSE;
    if( seg != NULL ) {
        limit = SetSegType( seg );
        isdata = !( seg->info & SEG_CODE );
    }
    while( seg != NULL ) {
        if( seg->group == NULL ) {
            align_size = CAlign( size, seg->align );
            new_size = align_size + seg->size;
            if( ( new_size >= limit )      // group overflow 16/32-bit
                || ( new_size < size )     // group overflow 32-bit
                || seg->size && ( lastseg || !CanPack( packstart, seg ) ) ) {
                PackSegs( packstart, num_segs, size, class, isdata, isreadwrite );
                packstart = seg;
                num_segs = 1;
                if( FmtData.type & MK_REAL_MODE ) {
                    size = ( align_size & 0xF ) + seg->size;
                } else {
                    size = seg->size;
                }
                lastseg = FALSE;
                limit = SetSegType( seg );
            } else {
                size = new_size;
                ++num_segs;
            }
            if( seg->info & LAST_SEGMENT ) {
                lastseg = TRUE;
            }
        } else {
            seg->group->section = sec;
            if( !( seg->info & SEG_CODE ) ) {
                seg->group->segflags |= SEG_DATA;
            }
            if( isreadwrite ) {
                seg->group->segflags &= ~SEG_READ_ONLY;
            }
            PackSegs( packstart, num_segs, size, class, isdata, isreadwrite );
            packstart = (seg_leader *)RingStep( class->segs, seg );
            num_segs = 0;
            if( FmtData.type & MK_REAL_MODE ) {
                size = ( CAlign( size, seg->align ) + seg->size ) & 0xF;
            } else {
                size = 0;
            }
            lastseg = FALSE;
            limit = SetSegType( packstart );
        }
        seg = (seg_leader *)RingStep( class->segs, seg );
    }
    PackSegs( packstart, num_segs, size, class, isdata, isreadwrite );
}

static void PackSegs( seg_leader * seg, unsigned num_segs, offset size,
                      class_entry *class, bool isdata, bool isrdwr )
/*********************************************************************/
{
    group_entry *       group;
    bool                fakegroup;

    if( num_segs == 0 )
        return;
    /* Do not pack empty segments in DOS executables; some code relies on
     * this behaviour and we have little to gain by packing anyway */
    fakegroup = ( size == 0 ) && !( FmtData.type & MK_REAL_MODE ) && ( CurrGroup != NULL );
    if( fakegroup ) {
        group = CurrGroup;
    } else {
        group = GetAutoGroup( ( seg->info & SEG_ABSOLUTE ) != 0 );
        if( isdata ) {
            group->segflags |= SEG_DATA;
        }
        if( isrdwr ) {
            group->segflags &= ~SEG_READ_ONLY;
        }
        group->section = seg->class->section;
        if( class->flags & CLASS_COPY ) {  // If class is copied, mark group accordingly
            group-> isdup = TRUE;
        }
    }
    while( num_segs != 0 ) {
        if( seg->group == NULL ) {  // if its not in a group add it to this one
            seg->group = group;
            if( !fakegroup ) {
                Ring2Append( &group->leaders, seg );
            }
            --num_segs;
        }
        seg = (seg_leader *)RingStep( class->segs, seg );
    }
}

static void InitGroup( group_entry *group )
/*****************************************/
{
    group->grp_addr.seg = UNDEFINED;
    group->grp_addr.off = 0;
    group->totalsize = 0;
    group->size = 0;
    group->segflags = DEFAULT_GRP_FLAGS;
    group->u.miscflags = 0;
    group->isfree = FALSE;
    group->isautogrp = FALSE;
    group->isdup = FALSE;
    group->g.grp_relocs = NULL;
}

extern group_entry * AllocGroup( char *name, group_entry ** grp_list )
/********************************************************************/
{
    group_entry *group;
    symbol *    sym;

    group = CarveAlloc( CarveGroup );
    group->leaders = NULL;
    _PermAlloc( sym, sizeof *sym  ); // second class slave citizen
    BasicInitSym( sym );
    sym->name = AddStringTable( &PermStrings, name, strlen( name ) + 1 );
    sym->namelen = strlen( name ) + 1;
    SET_SYM_TYPE( sym, SYM_GROUP );
    sym->info |= SYM_STATIC;
    group->next_group = NULL;
    InitGroup( group );
    group->sym = sym;
    LinkList( grp_list, group );
    if( strcmp( name, DataGrpName ) == 0 ) {
        DataGroup = group;
    } else if( name == AutoGrpName ) {
        group->isautogrp = 1;
    }
    return( group );
}

static group_entry * GetAutoGroup( bool abs_seg )
/***********************************************/
{
    group_entry *    group;
    group_entry **   grp_list;

    if( abs_seg ) {
        grp_list = &AbsGroups;
    } else {
        grp_list = &Groups;
    }
    group = AllocGroup( AutoGrpName, grp_list );
    if( !abs_seg ) {
        CurrGroup = group;
    }
    return( group );
}

static void SortGroupList( void )
/*******************************/
// Sort the group list by segments within classes.
{
    group_entry *   group;
    unsigned        number;

    NumGroups = 0;
    if( Groups == NULL )
        return;
// first, set all of the links in the group list to NULL
    group = Groups;
    while( Groups != NULL ) {
        Groups = Groups->next_group;
        group->next_group = NULL;
        group->leaders = NULL;
        group = Groups;
        NumGroups++;
    }
    number = NumGroups;
    CurrGroup = NULL;
    WalkLeaders( SortGroup );
    CurrGroup->next_group = NULL;  // break the circular list.
    NumGroups = number;            // save # of groups.
}

static void SortGroup( seg_leader *seg )
/**************************************/
// Go through the classes & segments, and rebuild the group list in sorted form
{
    if( seg->group == NULL )
        return;
    if( seg->info & SEG_ABSOLUTE )
        return;
    Ring2Append( &seg->group->leaders, seg );
    if( seg->group->next_group == NULL ) { // not in the list yet
        if( CurrGroup == NULL ) {
            Groups = CurrGroup = seg->group;
        } else {
            CurrGroup->next_group = seg->group;
            CurrGroup = CurrGroup->next_group;
        }
// Make the list circular so we have an easy way of telling if a node
// is in the list.
        CurrGroup->next_group = Groups;
        NumGroups--;
        DbgAssert( NumGroups >= 0 );
    }
}

static bool CheckGroupSplit( void *leader, void *sect )
/*****************************************************/
{
    return( ((seg_leader *)leader)->class->section != (section *)sect );
}

static void FindSplitGroups( void )
/*********************************/
// a group can be split by accidentally putting parts of it into different
// overlays. This causes all hell to break loose, so this checks to make sure
// that this doesn't happen.
{
    group_entry *   group;

    if( !( FmtData.type & MK_OVERLAYS ) )
        return;
    group = Groups;
    while( group != NULL ) {
        if( Ring2Lookup( group->leaders, CheckGroupSplit, group->section ) ) {
            LnkMsg( ERR+MSG_OVL_GROUP_SPLIT, "s", group->sym->name );
        }
        group = group->next_group;
    }
}

static void NumberNonAutos( void )
/********************************/
{
    group_entry *       group;
    unsigned            num;

    num = 0;
    for( group = Groups; group != NULL; group = group->next_group ) {
        if( group->isautogrp ) {
            group->num = 0;
        } else {
            num++;
            group->num = num;
        }
    }
}

⌨️ 快捷键说明

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