segment.c

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

C
1,496
字号
/****************************************************************************
*
*                            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:  WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
*               DESCRIBE IT HERE!
*
****************************************************************************/


#include "plusplus.h"

#include "compcfg.h"
#include "tgtenv.h"

#include "cgfront.h"
#include "cgback.h"
#include "cgdata.h"
#include "codegen.h"
#include "ring.h"
#include "errdefns.h"
#include "vbuf.h"
#include "memmgr.h"
#include "pragdefn.h"
#include "cginfo.h"
#include "pcheader.h"
#include "dbgsupp.h"
#include "initdefs.h"


typedef struct pc_segment PC_SEGMENT;
PCH_struct pc_segment {                 // PC_SEGMENT -- segment on PC
    PC_SEGMENT      *next;              // - next in ring
    PC_SEGMENT      *sibling;           // - related segment
    char            *class_name;        // - class name
    SYMBOL          label;              // - symbol for label in segment
    unsigned        attrs;              // - attributes
    fe_seg_id       seg_id;             // - id for segment
    target_offset_t align;              // - alignment
    target_size_t   offset;             // - offset within segment
#if _INTEL_CPU
    hw_reg_set      binding;            // - register bound to the segment
#endif
                                        // - segment:
    unsigned        dgroup : 1;         // - is part of DGROUP
    unsigned        lab_gened : 1;      // - label has been generated
    unsigned        used : 1;           // - has been used
    unsigned        fixed_alignment : 1;// - has a fixed alignment (no changes)
    unsigned        cg_defed : 1;       // - defined to code generator
    unsigned        module_prefix : 1;  // - name has ModuleName as a prefix
    unsigned        has_data : 1;       // - has data gened in segment
    unsigned        only_strings : 1;   // - only strings go in segment
    char            name[1];            // - name
};

typedef struct {                        // DEF_SEG -- code/data default segments
    PC_SEGMENT      *pcseg;             // - default pc segment
    unsigned        ctr;                // - # of segments allocated
    unsigned        ds_used : 1;        // - TRUE ==> has been used
} DEF_SEG;

static fe_seg_id seg_max;           // last segment # used
static fe_seg_id seg_import;        // next import segment #
#if _INTEL_CPU
static fe_seg_id seg_code_comdat;   // segment # for code comdat
#endif
static fe_seg_id seg_default_code;  // segment # for default code segment
static target_size_t dgroup_size;   // amount of DGROUP used so far
static PC_SEGMENT *seg_list;        // list of defined segments
static DEF_SEG code_def_seg;        // code segment -- default info.
static DEF_SEG data_def_seg;        // data segment -- default info.

static struct {
    unsigned in_back_end : 1;       // TRUE ==> now in CGBKMAIN
    unsigned use_def_seg : 1;       // TRUE ==> #pragma def_seg active
} flags;

enum                                // SEGMENT-ATTRIBUTE COMBINATIONS USED:
{   SGAT_CODE_BASED                 // - code: based
        = GIVEN_NAME | INIT | GLOBAL | EXEC
,   SGAT_CODE_GEN                   // - code: being generated
        = GIVEN_NAME | INIT | GLOBAL | EXEC
,   SGAT_DATA_BASED                 // - data: based
        = GIVEN_NAME | GLOBAL | INIT | PRIVATE
,   SGAT_STACK                      // - data: stack
        = GIVEN_NAME | GLOBAL
,   SGAT_DATA_CON1                  // - data: constant(1)
        = GIVEN_NAME | BACK | ROM | INIT
,   SGAT_DATA_CON2                  // - data: constant(2)
        = GIVEN_NAME | ROM | INIT
,   SGAT_DATA_RW                    // - data: read/write initialized
        = GIVEN_NAME | GLOBAL | INIT
,   SGAT_CPP                        // - used for common code
        = GIVEN_NAME | GLOBAL | INIT  | EXEC
,   SGAT_BSS                        // - data: read/write uninitialized
        = GIVEN_NAME | GLOBAL
,   SGAT_DATA_PRIVATE_RW            // - data: private read/write
        = GIVEN_NAME | PRIVATE | INIT
,   SGAT_DATA_PRIVATE_RO            // - data: private read-only
        = GIVEN_NAME | PRIVATE | INIT | ROM
,   SGAT_DATA_COMMON_INIT           // - data: common, init'ed, R/W
        = GIVEN_NAME | GLOBAL | INIT | COMMON | COMDAT
,   SGAT_DATA_COMMON_INIT_ROM       // - data: common, init'ed, R/O
        = GIVEN_NAME | GLOBAL | INIT | COMMON | COMDAT | ROM
,   SGAT_DATA_COMMON_ZERO           // - data: common, uninitialized
        = GIVEN_NAME | GLOBAL | COMMON | COMDAT
,   SGAT_TLS_LIMIT                  // - thread-local storage delimiter seg
        = GIVEN_NAME | ROM | INIT | THREAD_LOCAL
,   SGAT_TLS_DATA                   // - thread-local data
        = GIVEN_NAME | GLOBAL | INIT | THREAD_LOCAL
};

enum {
    SA_IN_DGROUP        = 0x01,
    SA_MODULE_PREFIX    = 0x02,
    SA_DEFINE_ANYTIME   = 0x04,
    SA_NULL             = 0x00
};

enum {
    ADS_MODULE_PREFIX   = 0x01,
    ADS_CONST_SEGMENT   = 0x02,
    ADS_STRING_SEGMENT  = 0x04,
    ADS_CODE_SEGMENT    = 0x08,
    ADS_ZM_SEGMENT      = 0x10,
    ADS_NULL            = 0x00
};

#define _markUsed( s, v ) \
        {   PC_SEGMENT *t = s, *p; \
            t->used = v; \
            for( p = t->sibling; p != t; p = p->sibling ) { \
                p->used = v; \
            } \
        }

static void addSibling( PC_SEGMENT *seg, PC_SEGMENT *sib )
{
    DbgAssert( sib->sibling == sib );
    sib->sibling = seg->sibling;
    seg->sibling = sib;
}

static SYMBOL segEmitLabel(         // EMIT SEGMENT LABEL
    PC_SEGMENT* seg )               // - current segment
{
    SYMBOL label;                   // - label in segment

    label = seg->label;
    if( label != NULL && ! seg->lab_gened ) {
        if( seg->seg_id == SEG_STACK ) {
            CGAutoDecl( (cg_sym_handle)label, T_UINT_1 );
        } else {
            CgBackGenLabel( label );
        }
        seg->lab_gened = TRUE;
        _markUsed( seg, TRUE );
    }
    return label;
}


static void checkSegmentOverflow(   // CHECK FOR SEGMENTS OVERFLOW
    void )
{
    if( seg_max < 0 || seg_import >= 0 ) {
        CFatal( "Too many segments -- sub-divide source module" );
    }
}


static PC_SEGMENT *segIdLookup( // LOOKUP SEGMENT FOR ID
    fe_seg_id seg_id )          // - segment id
{
    PC_SEGMENT* curr;           // - current segment
    PC_SEGMENT* retn;           // - segment for id

    retn = NULL;
    RingIterBeg( seg_list, curr ) {
        if( curr->seg_id == seg_id ) {
            retn = curr;
            break;
        }
    } RingIterEnd( curr );
    return retn;
}


#if _CPU == _AXP || COMP_CFG_COFF == 1
static fe_seg_id markSegmentComdat(  // MARK SEGMENT AS COMDAT SEGMENT
    fe_seg_id seg_id )          // - segment id
{
    PC_SEGMENT* seg = segIdLookup( seg_id );
    DbgVerify( NULL != seg, "markSegmentComdat -- no segment" );
    seg->attrs |= COMDAT;
    return( seg_id );
}
#endif


static PC_SEGMENT *segNameLookup( // LOOKUP SEGMENT FOR NAME
    char *name )                // - segment name
{
    PC_SEGMENT* curr;           // - current segment
    PC_SEGMENT* retn;           // - segment for id

    retn = NULL;
    RingIterBeg( seg_list, curr ) {
        if( 0 == strcmp( curr->name, name ) ) {
            retn = curr;
            break;
        }
    } RingIterEnd( curr );
    return retn;
}


static void segmentCgDefine(    // DEFINE A SEGMENT
    PC_SEGMENT *segment )       // - current segment
{
    if( ! segment->cg_defed ) {
        BEDefSeg( segment->seg_id
                , segment->attrs
                , segment->name
                , segment->align );
        segment->cg_defed = TRUE;
    }
}


static PC_SEGMENT *segmentAlloc(    // SEGMENT: ALLOCATE NEW SEGMENT
    const char *seg_name,           // - segment name
    const char *class_name,         // - segment class name
    fe_seg_id seg_id,               // - segment id (if not SEG_NULL)
    unsigned attrs,                 // - segment attributes
    unsigned control )              // - control mask
{
    PC_SEGMENT *curr;               // - segment pointer
    size_t size;                    // - size of segment name

#if _INTEL_CPU && COMP_CFG_COFF == 0
//alpha permits segments defined anywhere and we need it for comdat data
//ditto for COFF
    DbgVerify( ! flags.in_back_end || ( attrs & PRIVATE ) || ( control & SA_DEFINE_ANYTIME )
             , "segmentAlloc -- defining in back end" );
#endif
    size = strlen( seg_name );
    curr = RingAlloc( &seg_list, sizeof( PC_SEGMENT ) + size );
    curr->sibling = curr;
    stvcpy( curr->name, seg_name, size );
    curr->offset = 0;
    curr->dgroup = (( control & SA_IN_DGROUP ) != 0 );
    curr->lab_gened = FALSE;
    if( class_name != NULL ) {
        curr->class_name = strpermsave( class_name );
    } else {
        curr->class_name = NULL;
    }
    curr->used = FALSE;
    curr->module_prefix = (( control & SA_MODULE_PREFIX ) != 0 );
    curr->fixed_alignment = FALSE;
    curr->cg_defed = FALSE;
    curr->has_data = FALSE;
    curr->only_strings = FALSE;
    curr->label = NULL;
    curr->attrs = attrs;
#if _INTEL_CPU
    HW_CAsgn( curr->binding, HW_EMPTY );
#endif
    if( seg_id == SEG_NULL ) {
        seg_id = ++seg_max;
        checkSegmentOverflow();
    } else {
        if( seg_id > seg_max ) {
            seg_max = seg_id;
            checkSegmentOverflow();
        }
    }
    curr->seg_id = seg_id;
    switch( seg_id ) {
    case SEG_PROF_BEG:
    case SEG_PROF_REF:
    case SEG_PROF_END:
        // we don't want padding introduced
        curr->align = TARGET_LONG;
        // we don't want alignment changed either
        curr->fixed_alignment = TRUE;
        break;
    case SEG_INIT_BEG:
    case SEG_INIT_REF:
    case SEG_INIT_END:
    case SEG_FINI_BEG:
    case SEG_FINI_REF:
    case SEG_FINI_END:
        // we don't want padding introduced
#if _INTEL_CPU
        curr->align = TARGET_SHORT;
#elif _CPU == _AXP
        curr->align = TARGET_POINTER;
#else
#error no alignment set
#endif
        // we don't want alignment changed either
        curr->fixed_alignment = TRUE;
        break;
    default:
        curr->align = TARGET_CHAR;
        if( flags.in_back_end ) {
            segmentCgDefine( curr );
        }
        break;
    }
    return( curr );
}


static void initDefSeg(         // SET NEW DEFAULT SEGMENT INFO
    DEF_SEG *def_seg,           // - default segment info.
    PC_SEGMENT *pcseg )         // - default segment
{
    if( def_seg->pcseg != pcseg ) {
        def_seg->pcseg = pcseg;
        def_seg->ctr = 0;
        def_seg->ds_used = FALSE;
    }
}


static void pruneDefSeg(        // PRUNE A DEFAULT SEGMENT IF NOT USED
    DEF_SEG *def_seg )          // - default segment info.
{
    PC_SEGMENT *pcseg;          // - pc segment for default

    if( ! def_seg->ds_used ) {
        pcseg = def_seg->pcseg;
        if( pcseg != NULL && ! pcseg->used ) {
            RingDealloc( &seg_list, pcseg );
        }
    }
}


static PC_SEGMENT *addDefSeg(   // ADD A DEFAULT PC SEGMENT
    DEF_SEG *def_seg,           // - default segment info.
    unsigned ads_control )      // - control mask
{
    unsigned attrs;             // - attributes for segment
    PC_SEGMENT *curr;           // - segment pointer
    VBUF seg_name;              // - virtual buffer for name
    unsigned sa_control;        // - segmentAlloc control mask

    VbufInit( &seg_name );

⌨️ 快捷键说明

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