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 + -
显示快捷键?