segment.c

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

C
1,496
字号
    VStrNull( &seg_name );
    ++def_seg->ctr;
    sa_control = SA_NULL;
    if( ads_control & ADS_MODULE_PREFIX ) {
        if(( ads_control & ADS_CODE_SEGMENT ) == 0 && DataSegName[0] != '\0' ) {
            VStrConcStr( &seg_name, DataSegName );
        } else {
            VStrConcStr( &seg_name, ModuleName );
        }
        sa_control |= SA_MODULE_PREFIX;
    }
    if( ads_control & ADS_STRING_SEGMENT ) {
        sa_control |= SA_DEFINE_ANYTIME;
    }
    VStrConcStr( &seg_name, def_seg->pcseg->name );
    if( ads_control & ADS_ZM_SEGMENT ) {
        VStrConcDecimal( &seg_name, def_seg->ctr );
    }
    if( def_seg == &code_def_seg ) {
        attrs = SGAT_CODE_GEN;
    } else {
        if( ads_control & ADS_CONST_SEGMENT ) {
            attrs = SGAT_DATA_PRIVATE_RO;
        } else {
            attrs = SGAT_DATA_PRIVATE_RW;
        }
        VStrConcDecimal( &seg_name, def_seg->ctr );
    }
    curr = segmentAlloc( seg_name.buf, NULL, SEG_NULL, attrs, sa_control );
    if( 0 == ( attrs & EXEC ) ) {
        _markUsed( curr, TRUE );
    }
    if( ads_control & ADS_STRING_SEGMENT ) {
        curr->only_strings = TRUE;
    }
    VbufFree( &seg_name );
    return( curr );
}


static
target_size_t segmentTypeSize(  // SEGMENT: SIZE OF TYPE
    TYPE type )                 // - type to be sized
{
    target_size_t size;

    size = CgMemorySize( type );
    if( size == 0 ) {
        size = TARGET_CHAR;
    }
    return( size );
}


target_offset_t SegmentAlignment(   // SEGMENT: ALIGNMENT FOR SYMBOL
    SYMBOL sym )                    // - symbol to align
{
    target_offset_t align;
    TYPE type;
    TYPE align_type;

    if( CompFlags.dont_align_segs ) {
        return( TARGET_CHAR );
    }
#if _CPU == _AXP
    if( PackAmount != TARGET_CHAR ) {
#else
    if( OptSize <= 50 || PackAmount != TARGET_CHAR ) {
#endif
        type = sym->sym_type;
        align_type = AlignmentType( type );
        align = segmentTypeSize( align_type );
        if( align == TARGET_CHAR ) {
            // no alignment; let PackAlignment know the real size
            align = segmentTypeSize( type );
        }
        align = PackAlignment( TARGET_MAX_PACKING, align );
    } else {
        align = TARGET_CHAR;
    }
    return( align );
}


target_offset_t SegmentAdjust(  // SEGMENT: ADJUST OFFSET TO ALIGN
    fe_seg_id segid,            // - segment identifier
    target_size_t offset,       // - current offset
    target_offset_t align )     // - required aligment
{
    target_size_t   calc_offset;
    target_offset_t adjust;

    switch( segid ) {
    case SEG_INIT_BEG:
    case SEG_INIT_REF:
    case SEG_INIT_END:
    case SEG_FINI_BEG:
    case SEG_FINI_REF:
    case SEG_FINI_END:
        /* no padding in these segments */
        return( 0 );
    }
    calc_offset = offset;
    calc_offset += align - 1;
    calc_offset &= ~(((target_size_t) align ) - 1 );
    adjust = calc_offset - offset;
    _CHECK_ADJUST( adjust, calc_offset, offset );
    return( adjust );
}


struct seg_look {                           // used to lookup segments
    const char      *seg_name;              // - segment name
    const char      *class_name;            // - segment class name
    unsigned        attrs;                  // - attributes
    fe_seg_id       seg_id;                 // - id for segment
    target_offset_t align;                  // - segment alignment
    target_size_t   sym_size;               // - space needed for symbol
    target_size_t   sym_align;              // - alignment needed for symbol
    unsigned        use_seg_id : 1;         // - for lookup
    unsigned        use_attrs : 1;          // - for lookup
    unsigned        use_align : 1;          // - for lookup
    unsigned        use_sym_size_align : 1; // - for lookup
    unsigned        use_name : 1;           // - for lookup
    unsigned        use_only_strings : 1;   // - for lookup
};


static boolean same_segment(    // DETERMINE IF SAME SEGMENT
    void * _curr,           // - current segment
    const void * _lk )  // - segment lookup structure
{
    PC_SEGMENT *curr = _curr;
    const struct seg_look* lk = _lk;

    target_offset_t     align_adjust;
    target_size_t       new_offset;

    if( lk->use_seg_id && lk->seg_id != SEG_NULL && curr->seg_id != lk->seg_id ) {
        return( FALSE );
    }
    if( lk->use_attrs && curr->attrs != lk->attrs ) {
        return( FALSE );
    }
    if( lk->use_align && curr->align != lk->align ) {
        return( FALSE );
    }
    if( lk->use_sym_size_align ) {
        align_adjust = SegmentAdjust( curr->seg_id, curr->offset, lk->sym_align );
        new_offset = curr->offset + align_adjust + lk->sym_size;
        _CHECK_ADJUST( new_offset, new_offset, curr->offset );
        if( new_offset == 0 ) {
            return( FALSE );
        }
    }
    if( lk->use_name ) {
        if( strcmp( curr->name, lk->seg_name ) != 0 ) {
            return( FALSE );
        }
        if( curr->class_name != NULL ) {
            if( lk->class_name == NULL ) {
                return( FALSE );
            }
            if( strcmp( curr->class_name, lk->class_name ) != 0 ) {
                return( FALSE );
            }
        } else {
            if( lk->class_name != NULL ) {
                return( FALSE );
            }
        }
    }
    if( lk->use_only_strings && !curr->only_strings ) {
        return( FALSE );
    }
    return( TRUE );
}


static PC_SEGMENT *segmentDefine(// SEGMENT: DEFINE IF REQUIRED
    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 )          // - segmentAlloc control mask
{
    PC_SEGMENT *curr;           // - current segment
    struct seg_look lk;         // - look-up structure
#if _INTEL_CPU
    const char* pc_reg;         // - scans register bound to segment
    char pc_reg_name[8];        // - name of pc register

    for( pc_reg = seg_name; ; ++pc_reg ) {
        if( *pc_reg == '\0' ) {
            pc_reg_name[0] = '\0';
            break;
        }
        if( *pc_reg == ':' ) {
            stvcpy( pc_reg_name, seg_name, pc_reg - seg_name );
            seg_name = pc_reg + 1;
            break;
        }
    }
#endif
    lk.seg_id = seg_id;
    lk.use_seg_id = TRUE;
    lk.attrs = attrs;
    lk.use_attrs = TRUE;
    lk.use_align = FALSE;
    lk.use_sym_size_align = FALSE;
    lk.seg_name = seg_name;
    lk.class_name = class_name;
    lk.use_name = TRUE;
    lk.use_only_strings = FALSE;
    curr = RingLookup( seg_list, &same_segment, &lk );
    if( curr == NULL ) {
        curr = segmentAlloc( lk.seg_name, lk.class_name, lk.seg_id, lk.attrs, control );
#if _INTEL_CPU
        if( pc_reg_name[0] != '\0' ) {
            curr->binding = PragRegName( pc_reg_name );
        }
#endif
    }
    return curr;
}


#if _CPU == 8086
static fe_seg_id createHugeSegment( target_size_t size, unsigned ads_control )
{
    PC_SEGMENT *curr;
    fe_seg_id id;
    target_size_t used;

    id = SEG_NULL;
    while( size > 0 ) {
        curr = addDefSeg( &data_def_seg, ads_control );
        if( id == SEG_NULL ) {
            id = curr->seg_id;
        }
        used = min( size, TARGET_UINT_MAX+1 );
        curr->offset = used;
        curr->align = 16;
        _markUsed( curr, TRUE );
        curr->has_data = TRUE;
        size -= used;
    }
    return( id );
}


fe_seg_id SegmentAddHuge(       // SEGMENT: ADD SYMBOL TO HUGE SEGMENT
    target_size_t size )        // - size of symbol
{
    return( createHugeSegment( size, ADS_MODULE_PREFIX ) );
}


fe_seg_id SegmentAddConstHuge(  // SEGMENT: ADD CONST SYMBOL TO HUGE SEGMENT
    target_size_t size )        // - size of symbol
{
    return( createHugeSegment( size, ADS_MODULE_PREFIX | ADS_CONST_SEGMENT ) );
}
#else
fe_seg_id SegmentAddHuge(       // SEGMENT: ADD SYMBOL TO HUGE SEGMENT
    target_size_t size )        // - size of symbol
{
    return( SegmentAddFar( size, 16 ) );
}


fe_seg_id SegmentAddConstHuge(  // SEGMENT: ADD CONST SYMBOL TO HUGE SEGMENT
    target_size_t size )        // - size of symbol
{
    return( SegmentAddConstFar( size, 16 ) );
}
#endif


static void accumAlignment( PC_SEGMENT *curr, target_offset_t align )
{
    if( ! curr->fixed_alignment ) {
        curr->align = max( curr->align, align );
    }
}

static fe_seg_id findFarSegment(// SEGMENT: ADD SYMBOL TO FAR SEGMENT
    target_size_t size,         // - size of symbol
    target_offset_t align,      // - alignment of symbol
    unsigned ads_control )      // - addDefSeg control word
{
    PC_SEGMENT *curr;           // - new segment
    struct seg_look lk;         // - look-up structure

    lk.use_seg_id = FALSE;
    if( ads_control & ADS_CODE_SEGMENT ) {
        lk.attrs = SGAT_CODE_BASED;
    } else if( ads_control & ADS_CONST_SEGMENT ) {
        lk.attrs = SGAT_DATA_PRIVATE_RO;
    } else {
        lk.attrs = SGAT_DATA_PRIVATE_RW;
    }
    lk.use_attrs = TRUE;
    lk.use_align = FALSE;
    lk.sym_size = size;
    lk.sym_align = align;
    lk.use_sym_size_align = TRUE;
    lk.use_name = FALSE;
    lk.use_only_strings = FALSE;
    if( ads_control & ADS_STRING_SEGMENT ) {
        lk.use_only_strings = TRUE;
    }
    curr = RingLookup( seg_list, &same_segment, &lk );
    if( curr == NULL ) {
        if( ads_control & ADS_CODE_SEGMENT ) {
            curr = addDefSeg( &code_def_seg, ads_control );
            code_def_seg.ds_used = TRUE;
        } else {
            curr = addDefSeg( &data_def_seg, ads_control );
            data_def_seg.ds_used = TRUE;
        }
    }
    curr->offset += SegmentAdjust( curr->seg_id, curr->offset, align );
    curr->offset += size;
    accumAlignment( curr, align );
    _markUsed( curr, TRUE );
    curr->has_data = TRUE;
    return( curr->seg_id );
}

fe_seg_id SegmentAddFar(        // SEGMENT: ADD SYMBOL TO FAR SEGMENT
    target_size_t size,         // - size of symbol
    target_offset_t align )     // - alignment of symbol
{
    return( findFarSegment( size, align, ADS_MODULE_PREFIX ) );
}


fe_seg_id SegmentAddConstFar(   // SEGMENT: ADD CONST SYMBOL TO FAR SEGMENT
    target_size_t size,         // - size of symbol
    target_offset_t align )     // - alignment of symbol
{
    return( findFarSegment( size, align, ADS_MODULE_PREFIX | ADS_CONST_SEGMENT ) );
}


fe_seg_id SegmentAddStringConstFar(// SEGMENT: ADD CONST STRING TO FAR SEGMENT
    target_size_t size,         // - size of symbol
    target_offset_t align )     // - alignment of symbol
{
    return( findFarSegment( size, align,
                            ADS_MODULE_PREFIX |
                            ADS_CONST_SEGMENT |
                            ADS_STRING_SEGMENT ) );
}


fe_seg_id SegmentAddStringCodeFar(// SEGMENT: ADD CONST STRING TO CODE SEGMENT
    target_size_t size,         // - size of symbol
    target_offset_t align )     // - alignment of symbol
{
    return( findFarSegment( size, align,
                            ADS_CODE_SEGMENT |
                            ADS_STRING_SEGMENT ) );
}


fe_seg_id SegmentAddSym(        // SEGMENT: ADD SYMBOL TO SPECIFIED SEGMENT
    SYMBOL sym,                 // - sym to add
    fe_seg_id id,               // - id of segment to use
    target_size_t size,         // - size of sym
    target_offset_t align )     // - alignment for sym
{
    PC_SEGMENT *curr;           // - new segment

⌨️ 快捷键说明

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