objcalc.c

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

C
1,292
字号
                        break;
                    }
                    prev = comp;
                    comp = RingStep( newlist, comp );
                }
            }
            if( !added ) {
                RingAppend( &newlist, curr );
            }
            curr = RingPop( &currcl->segs );
        }
        currcl->segs = newlist;
    }
}

#define CODECL_SIZE ( sizeof( CodeClassName ) - 1 )

extern bool IsCodeClass( char *name, unsigned namelen )
/*****************************************************/
{
    return( ( namelen >= CODECL_SIZE )
        && ( memicmp( name + namelen - CODECL_SIZE, CodeClassName, CODECL_SIZE ) == 0 ) );
}

#define CONSTCL_SIZE ( sizeof( ConstClassName ) - 1 )

extern bool IsConstClass( char *name, unsigned namelen )
/******************************************************/
{
    return( ( namelen >= CONSTCL_SIZE )
        && ( memicmp( name + namelen - CONSTCL_SIZE, ConstClassName, CONSTCL_SIZE ) == 0 ) );
}

#define STACKCL_SIZE ( sizeof( StackClassName ) - 1 )

extern bool IsStackClass( char *name, unsigned namelen )
/******************************************************/
{
    return( ( namelen >= STACKCL_SIZE )
        && ( stricmp( name, StackClassName ) == 0 ) );
}

/* -----------------------Allocating Segments-------------------------------- */

static void AddUpSegData( void *_sdata )
/**************************************/
{
    segdata     *sdata = _sdata;
    seg_leader  *leader;
    offset      align_size;

    if( sdata->isdead )
        return;
    leader = sdata->u.leader;
    align_size = CAlign( leader->size, sdata->align );
    sdata->a.delta = align_size;
    leader->size = align_size + sdata->length;
    if( sdata->align > leader->align ) {
        leader->align = sdata->align;
    }
}

static void CalcSeg( seg_leader *seg )
/************************************/
{
    RingWalk( seg->pieces, AddUpSegData );
}

extern void CalcSegSizes( void )
/******************************/
{
    WalkLeaders( CalcSeg );
}

static bool SetGroupInitSize( void *_sdata, void *_delta )
/********************************************************/
{
    segdata     *sdata = _sdata;
    offset      *delta = _delta;

    if( !sdata->isuninit && ( sdata->length > 0 ) && !sdata->isdead ) {
        sdata->u.leader->group->size = *delta + sdata->a.delta + sdata->length;
    }
    return( FALSE );
}

static void CalcInitSize( seg_leader *seg )
/*****************************************/
{
    offset      delta;

    if( seg->group != NULL ) {
        delta = GetLeaderDelta( seg );
        RingLookup( seg->pieces, SetGroupInitSize, &delta );
    }
}

extern void CalcAddresses( void )
/*******************************/
/* Calculate the starting address in the file of each segment. */
{
    offset          size;
    group_entry     *grp;
    offset          flat;

    DEBUG(( DBG_OLD, "CalcAddresses()" ));
    if( FmtData.base == NO_BASE_SPEC ) {
        if( FmtData.type & MK_PE ) {
            FmtData.base = PE_DEFAULT_BASE;
        } else if( FmtData.type & MK_QNX_FLAT ) {
            FmtData.base = ROUND_UP( StackSize + QNX_DEFAULT_BASE, 4 * 1024 );
        } else if( FmtData.type & MK_WIN_VXD ) {
            FmtData.base = 0;
        } else if( FmtData.type & MK_OS2_FLAT ) {
            FmtData.base = FLAT_GRANULARITY;
        } else if( FmtData.type & MK_ELF ) {
            if( LinkState & HAVE_PPC_CODE )
                FmtData.base = 0x10000000;
            else if( LinkState & HAVE_MIPS_CODE )
                FmtData.base = 0x00400000;
            else
                FmtData.base = 0x08048000;
        } else {
            FmtData.base = 0;
        }
    }
    DBIPreAddrCalc();
    CurrSect = Root;
    if( FmtData.type & MK_PROT_MODE ) {
        AllocFileSegs();
        if( FmtData.objalign == NO_BASE_SPEC ) {
            if( FmtData.type & MK_PE ) {
                if( !( LinkState & HAVE_I86_CODE ) ) {
                    FmtData.objalign = ( 64 * 1024UL );
                } else {
                    FmtData.objalign = 4*1024;
                }
            } else if( FmtData.type & MK_QNX ) {
                FmtData.objalign = QNX_GROUP_ALIGN;
            } else if( IS_PPC_OS2 ) {
                // Development temporarly on hold:
                // FmtData.objalign = 1024;
            } else if( FmtData.type & MK_ELF ) {
                FmtData.objalign = 4*1024;
            } else if( FmtData.type & MK_WIN_VXD ) {
                FmtData.objalign = 4*1024;
            } else {
                FmtData.objalign = FLAT_GRANULARITY;
            }
        }
        if( FmtData.type & MK_SPLIT_DATA ) {
            FindUninitDataStart();
        }
    }
    StartMemMap();
    AllocClasses( Root->classlist );
    if( FmtData.type & ( MK_REAL_MODE | MK_FLAT | MK_ID_SPLIT ) ) {
        if( FmtData.type & MK_OVERLAYS ) {
            CalcOvl();
        }
        CalcGrpAddr( Groups );
        CalcGrpAddr( AbsGroups );
    } else if( FmtData.type & ( MK_PE | MK_OS2_FLAT | MK_QNX_FLAT | MK_ELF ) ) {
        if( FmtData.output_raw || FmtData.output_hex ) {
            flat = 0;
        } else if( FmtData.type & MK_PE ) {
            flat = GetPEHeaderSize();
        } else if( FmtData.type & MK_ELF ) {
            flat = GetElfHeaderSize();
        } else {
            flat = FmtData.base;
        }
        for( grp = Groups; grp != NULL; grp = grp->next_group ) {
            size = grp->totalsize;
            if( grp->grp_addr.off > flat + FmtData.base) {
               // ORDER CLNAME name OFFSET option sets grp_addr,
               //   retrieve this information here and wrap into linear address
               flat = grp->grp_addr.off - FmtData.base;
               grp->grp_addr.off = 0;
            }
            grp->linear = flat;
            if(( grp == DataGroup ) && ( FmtData.dgroupsplitseg != NULL )) {
                if( StackSegPtr != NULL ) {
                    size -= StackSize;
                }
            }
            flat = ROUND_UP( flat + size, FmtData.objalign );
        }
        if( FmtData.type & ( MK_QNX_FLAT | MK_PE | MK_ELF ) ) {
            ReallocFileSegs();
        }
    } else if( FmtData.type & ( MK_QNX | MK_OS2_16BIT ) ) {
        ReallocFileSegs();
    }
    DBIAddrStart();
    WalkLeaders( CalcInitSize );
    DefinePublics();
}

static void AllocFileSegs( void )
/*******************************/
{
    group_entry         *currgrp;
    unsigned            seg_num;

    seg_num = 1;
    for( currgrp = Groups; currgrp != NULL; currgrp = currgrp->next_group ){
        if( FmtData.type & MK_FLAT ) {
            currgrp->grp_addr.seg = 1;   // only segment 1 in flat mem.model
        } else if( FmtData.type & MK_ID_SPLIT ) {
            if( currgrp->segflags & SEG_DATA ) {
                currgrp->grp_addr.seg = DATA_SEGMENT;
            } else {
                currgrp->grp_addr.seg = CODE_SEGMENT;
            }
        } else if( FmtData.type & MK_QNX ) {
            currgrp->grp_addr.seg = ToQNXSel( seg_num++ );
        } else if( FmtData.type & MK_PHAR_MULTISEG ) {
            currgrp->grp_addr.seg = ( seg_num << 3 ) | 4;
            seg_num++;
        } else {
            currgrp->grp_addr.seg = seg_num++;
        }
        currgrp->grp_addr.off = 0;
    }
}

static void SetLeaderSeg( void *_seg )
/*****************************************/
{
    seg_leader      *seg = _seg;

    if( !( seg->info & SEG_ABSOLUTE ) ) {
        seg->seg_addr.seg = seg->group->grp_addr.seg;
    }
}

static void ReallocFileSegs( void )
/*********************************/
/* In many cases we can't have any size 0 physical segments, so after we have
 * calculated the size of everything we have to go back and reallocate the
 * segment numbers so there aren't any "gaps" where the 0 size physical
 * segments (groups) are. */
{
    group_entry         *currgrp;
    class_entry         *class;
    unsigned            seg_num;

    seg_num = 1;
    for( currgrp = Groups; currgrp != NULL; currgrp = currgrp->next_group ){
        if( currgrp->totalsize != 0 ) {
            if( FmtData.type & MK_QNX ) {
                currgrp->grp_addr.seg = ToQNXSel( seg_num++ );
            } else {
                currgrp->grp_addr.seg = seg_num++;
            }
        } else {
            NumGroups--;        /* <-- to make life easier in loadxxx */
        }
    }
    for( class = Root->classlist; class != NULL; class = class->next_class ){
        if( !( class->flags & CLASS_DEBUG_INFO ) ) {
            RingWalk( class->segs, SetLeaderSeg );
        }
    }
}

static void FindUninitDataStart( void )
/*************************************/
/* for some formats we have to split the uninitialized data off of the rest of
 * DGROUP. So - this finds the start of the uninitialized portion of DGROUP */
{
    class_entry         *class;
    bool                setnext;

    setnext = TRUE;
    FmtData.dgroupsplitseg = NULL;
    FmtData.bsspad = 0;
    if( !( LinkState & DOSSEG_FLAG ) )
        return;
    class = Root->classlist;
    while( class != NULL ) {
        if( !( class->flags & CLASS_DEBUG_INFO ) ) {
            if( class->flags & CLASS_LXDATA_SEEN ) {
                setnext = TRUE;
            } else if( setnext ) {
                FmtData.dgroupsplitseg = RingFirst( class->segs );
                setnext = FALSE;
            }
        }
        class = class->next_class;
    }
    if( setnext ) {             //last one was had an LXDATA or no segs.
        FmtData.dgroupsplitseg = NULL;
    }
}

typedef struct  {
    unsigned_32 grp_addr;
    unsigned_32 end_addr;
    group_entry *currgrp;
    group_entry *lastgrp;  // used only for copy classes
    bool        first_time;
} grpaddrinfo;


static bool FindEndAddr( void *_seg, void *_info )
/**************************************************/
{
    seg_leader  *seg  = _seg;
    grpaddrinfo *info = _info;
    unsigned_32 seg_addr;

    if( FmtData.type & MK_REAL_MODE ) {
        seg_addr = MK_REAL_ADDR( seg->seg_addr.seg, seg->seg_addr.off );
    } else {
        seg_addr = seg->seg_addr.off;
    }
    if( info->first_time ) {
        info->currgrp->grp_addr = seg->seg_addr;
        info->grp_addr = seg_addr;
        info->end_addr = seg_addr + seg->size;
        info->first_time = FALSE;
    } else {
        if( info->grp_addr > seg_addr ) {
            info->currgrp->grp_addr = seg->seg_addr;
            info->grp_addr = seg_addr;
        }
        if( info->end_addr < seg_addr + seg->size ) {
            info->end_addr = seg_addr + seg->size;
        }
    }
    return( FALSE );
}

static bool FindInitEndAddr( void *_seg, void *_info )
/******************************************************/
// Only use initialized data segments.  Copy doesn't need uninitialized segments
// This is really only advantageous if uninitialized segments are at the end
{
    seg_leader  *seg  = _seg;
    grpaddrinfo *info = _info;
    unsigned_32 seg_addr;

    if( FmtData.type & MK_REAL_MODE ) {
        seg_addr = MK_REAL_ADDR( seg->seg_addr.seg, seg->seg_addr.off );
    } else {
        seg_addr = seg->seg_addr.off;
    }
    if( seg->info & SEG_LXDATA_SEEN ) {
        if( info->first_time ) { // First time, use seg_addr values
            info->grp_addr = seg_addr;
            info->end_addr = seg_addr + seg->size;
            info->first_time = FALSE;
        } else {  // If more segs found, use lowest start address and highest end address;
            if( info->grp_addr > seg_addr ) {
                info->grp_addr = seg_addr;
            }
            if( info->end_addr < seg_addr + seg->size ) {
                info->end_addr = seg_addr + seg->size;
            }
        }
    }
    return( FALSE );
}

static bool FindCopyGroups( void *_seg, void *_info )
/************************************************/
{
    // This is called by the outer level iteration looking for classes
    //  that have more than one group in them
    seg_leader  *seg = _seg;
    grpaddrinfo *info = _info;

    if( info->lastgrp != seg->group ) {   // Only interate new groups
        info->lastgrp = seg->group;
        // Check each initialized segment in group
        Ring2Lookup( seg->group->leaders, FindInitEndAddr, info);
    }
    return FALSE;
}

static void CalcGrpAddr( group_entry *currgrp )
/*********************************************/
/* Find lowest segment within group (the group's address)
 * not useful for OS/2 16-bit mode. */
{
    grpaddrinfo     info;
    seg_leader      *seg;
    class_entry     *class;
    unsigned long   addr;
    targ_addr       save;

    while( currgrp != NULL ) {
        info.currgrp = currgrp;
        info.first_time = TRUE;
        seg = currgrp->leaders;
        class = seg->class;
        if( class->flags & CLASS_COPY ) {
            currgrp->grp_addr = seg->seg_addr; // Get address of real segment (there's only one)
            // For copy classes must check eash segment to see if it is in a new group
            // this could be the case with FAR_DATA class in large model
            info.lastgrp = NULL; // so it will use the first group
            RingLookup( class->DupClass->segs, FindCopyGroups, &info );
            currgrp->size = info.end_addr - info.grp_addr;
            currgrp->totalsize = currgrp->size;
            // for copy classes put it in class size, also, so map file can find it.
            seg->size = currgrp->totalsize;
            // Now must recompute addresses for all segments in all classes beyond this
            addr = (currgrp->grp_addr.seg << FmtData.SegShift) +
                   currgrp->grp_addr.off + currgrp->totalsize;
            CurrLoc.seg = addr >> FmtData.SegShift;
            CurrLoc.off = addr & FmtData.SegMask;
            while( (class = class->next_class) != NULL ) {
                if( class->flags & CLASS_FIXED ) {
                    save = class->BaseAddr;     // If class is fixed, can stop
                    ChkLocated( &save, TRUE );  //   after making sure address
                    break;                      //   isn't already past here
                }
                if( !(class->flags & CLASS_DEBUG_INFO) ) { // skip Debug classes, they've already been done
                    RingWalk( class->segs, AllocSeg );
                }
            }
        }
        else {
            Ring2Lookup( seg, FindEndAddr, &info );
            if( (FmtData.type & MK_REAL_MODE)
                && (info.end_addr - info.grp_addr > 64 * 1024L) ) {
                LnkMsg( ERR+MSG_GROUP_TOO_BIG, "sl", currgrp->sym->name,
                        info.end_addr - info.grp_addr - 64 * 1024L );
                info.grp_addr = info.end_addr - 64 * 1024L - 1;

⌨️ 快捷键说明

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