objcalc.c

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

C
1,292
字号
/****************************************************************************
*
*                            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:  Address calculation for pass 2 of wlink.
*
****************************************************************************/


#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include "linkstd.h"
#include "pcobj.h"
#include "newmem.h"
#include "msg.h"
#include "alloc.h"
#include "specials.h"
#include "loados2.h"
#include "loadpe.h"
#include "loadqnx.h"
#include "loadelf.h"
#include "loadfile.h"
#include "wlnkmsg.h"
#include "overlays.h"
#include "dbgall.h"
#include "objcalc.h"
#include "ring.h"
#include "mapio.h"
#include "virtmem.h"

static struct {
    char *name;
    char idx;
} FloatNames[] = {
    { "FIWRQQ", FFIX_WR_SYMBOL },
    { "FIDRQQ", FFIX_DR_SYMBOL },
    { "FIERQQ", FFIX_ES_OVERRIDE },
    { "FICRQQ", FFIX_CS_OVERRIDE },
    { "FISRQQ", FFIX_SS_OVERRIDE },
    { "FIARQQ", FFIX_DS_OVERRIDE },
    { "FJCRQQ", FFIX_IGNORE },
    { "FJSRQQ", FFIX_IGNORE },
    { "FJARQQ", FFIX_IGNORE }
};


static unsigned long NumMapSyms;

static seg_leader *     FindASeg( class_entry *, char * );
static void             SortSegments( void );
static void             ReOrderClasses( section *sec );
static void             AllocSeg( void * );
static void             AllocFileSegs( void );
static void             ReallocFileSegs( void );
static void             FindUninitDataStart( void );
static void             CalcGrpAddr( group_entry *currgrp );
static void             DefinePublics( void );
static void             WriteSymArray( symbol ** symarray, unsigned num );
static void             FillClassFlags( char *name, unsigned_16 flags );
static void             FillTypeFlags( unsigned_16 flags, segflag_type type );
static void             FindFloatSyms( void );
static void             CheckClassUninitialized( class_entry * currcl );
static void             SortClasses ( section *sec );

extern void CheckClassOrder( void )
/*********************************/
/* Reorder the classes if DOSSEG flag set or ORDER directive given */
{
    SortSegments();
    if( Root->orderlist != NULL ) {
       SortClasses( Root );
    }
    else if( LinkState & DOSSEG_FLAG ) {
       ReOrderClasses( Root );
    }
}

static void ReOrderAreas( OVL_AREA *ovl )
/***************************************/
{
    for( ; ovl != NULL; ovl = ovl->next_area ) {
        ReOrderClasses( ovl->sections );
    }
}

enum class_orders {
    ORD_REALMODE,
    ORD_BEGCODE,
    ORD_CODE,
    ORD_OVLMGR,
    ORD_OTHER,
    ORD_BEGDGROUP,
    ORD_DATA,
    ORD_INITDGROUP,
    ORD_UNINITDGROUP,
    ORD_BSS,
    ORD_STACK,
    ORD_LAST = ORD_STACK,
    ORD_FIRST = 0
};

static void ReOrderClasses( section *sec )
/****************************************/
// rebuild the class list using the Microsoft DOS segment ordering.
// This builds various classes into separate rings, and then joins them
// together.
{
    class_entry         *rings[ORD_LAST+1];
    class_entry         *nextcl;
    class_entry         *currcl;
    class_entry         **owner;
    seg_leader          *currseg;
    seg_leader          *prevseg;
    char                *name;
    int                 i;
    int                 ord;

    while( sec != NULL ) {
        for( i = ORD_FIRST; i <= ORD_LAST; ++i ) {
            rings[i] = NULL;
        }
        currcl = sec->classlist;
        while( currcl != NULL ) {
            nextcl = currcl->next_class;
            currcl->next_class = NULL;
            CheckClassUninitialized( currcl );
            if( ( FmtData.type & ( MK_NOVELL | MK_PHAR_LAP | MK_OS2_LX ) )
                && !( currcl->flags & CLASS_32BIT ) ) {
                ord = ORD_REALMODE;
            } else {
                name = currcl->name;
                if( currcl->flags & CLASS_CODE ) {
                    if( stricmp( name, OvlMgrClass ) == 0 ) {
                        ord = ORD_OVLMGR;
                    } else if( stricmp( name, BegCodeClassName ) == 0 ) {
                        ord = ORD_BEGCODE;
                    } else {
                        ord = ORD_CODE;
                    }
                } else if( ( currcl->segs == NULL )
                    || ( currcl->segs->group == NULL )
                    || ( currcl->segs->group != DataGroup ) ) {
                    ord = ORD_OTHER;
                } else {     // it's the DGROUP segments.
                    if( stricmp( name, BSSClassName ) == 0 ) {
                        ord = ORD_BSS;
                    } else if( stricmp( name, StackClassName ) == 0 ) {
                        ord = ORD_STACK;
                    } else if( stricmp( name, BegDataClassName ) == 0 ) {
                        ord = ORD_BEGDGROUP;
                    } else if( stricmp( name, DataClassName ) == 0 ) {
                        ord = ORD_DATA;
                    } else if( currcl->flags & CLASS_LXDATA_SEEN ) {
                        ord = ORD_INITDGROUP;
                    } else {
                        ord = ORD_UNINITDGROUP;
                    }
                }
            }
            /* add the class to the appropriate ring */
            /* 'rings[ord]' points to the _last_ element of the ring */
            if( rings[ord] == NULL ) {
                currcl->next_class = currcl;
            } else {
                currcl->next_class = rings[ord]->next_class;
                rings[ord]->next_class = currcl;
            }
            rings[ord] = currcl;
            currcl = nextcl;
        }

        /* move the BEGTEXT segment in CODE class to front of segment list */
        currcl = rings[ORD_CODE];
        if( currcl != NULL ) {
            do {
                prevseg = currcl->segs;
                if( prevseg == NULL )
                    break;
                currseg = prevseg->next_seg;
                for( ;; ) {
                    if( stricmp( currseg->segname, BegTextSegName ) == 0 ) {
                        RingPromote( &currcl->segs, currseg, prevseg );
                        break;
                    }
                    if( currseg == currcl->segs )
                        break;
                    prevseg = currseg;
                    currseg = currseg->next_seg;
                }
                currcl = currcl->next_class;
            } while( currcl != rings[ORD_CODE] );
        }

        /* now construct list out of the collected parts. */
        owner = &sec->classlist;
        for( i = ORD_FIRST; i <= ORD_LAST; ++i ) {
            if( rings[i] != NULL ) {
                *owner = rings[i]->next_class;
                owner = &rings[i]->next_class;
            }
        }
        *owner = NULL;
        ReOrderAreas( sec->areas );
        sec = sec->next_sect;
    }
}

static void SortAreas( OVL_AREA *ovl )
/***************************************/
{
    for( ; ovl != NULL; ovl = ovl->next_area ) {
        SortClasses( ovl->sections );
    }
}

static void SortClasses( section *sec )
/****************************************/
// rebuild the class list in the order specified by the ORDER directive
// This builds various classes into separate rings, and then joins them
// together.  Pass class and segment address and output information
// to the class and segment structures.  Sort segments in a class if
// information is provided.
{
    class_entry         *DefaultRing;   // Where to put classes that don't match anything
    class_entry         *nextcl;
    class_entry         *currcl;
    class_entry         **NewRing;
    class_entry         **owner;
    seg_leader          *currseg;
    seg_leader          *prevseg;
    ORDER_CLASS         *MatchClass;
    ORDER_SEGMENT       *MatchSeg;

    DefaultRing = NULL;

    while( sec != NULL ) {
        currcl = sec->classlist;
        while( currcl != NULL ) {
            nextcl = currcl->next_class;  // Take class out of original ring
            currcl->next_class = NULL;
            CheckClassUninitialized( currcl );
            NewRing = &DefaultRing;  // In case no special class is found
            for( MatchClass = sec->orderlist; MatchClass != NULL; MatchClass = MatchClass->NextClass ) {
                if( stricmp( currcl->name, MatchClass->Name ) == 0 ) { // search order list for name match
                    NewRing = &(MatchClass->Ring);   // if found save ptr to instance
                    if( MatchClass->FixedAddr) {     // and copy any flags or address from it
                        currcl->flags |= CLASS_FIXED;
                        currcl->BaseAddr = MatchClass->Base;
                        FmtData.base = 0;  // Otherwise PE will use default and blow up
                    }
                    if( MatchClass->NoEmit ) {
                        currcl->flags |= CLASS_NOEMIT;
                    }
                    break;
                }
            }
            // add the class to front of ring attached to order class, or to default ring
            if( *NewRing == NULL ) {
                currcl->next_class = currcl;
            }
            else {
                currcl->next_class = (*NewRing)->next_class;
                (*NewRing)->next_class = currcl;
            }
            *NewRing = currcl;
            currcl = nextcl;
        }
        // Now re-arrange segments in any order classes for which we have segments specified
        for( MatchClass = sec->orderlist; MatchClass != NULL; MatchClass = MatchClass->NextClass ) {
            for( MatchSeg = MatchClass->SegList; MatchSeg != NULL; MatchSeg = MatchSeg->NextSeg ) {
               currcl = MatchClass->Ring;
                do {
                    prevseg = currcl->segs;
                    if( prevseg == NULL )
                        break;
                    currseg = prevseg->next_seg;

                    for( ;; ) {
                        if( stricmp( currseg->segname, MatchSeg->Name ) == 0 ) {
                            if( MatchSeg->FixedAddr) {     // and copy any flags or address from it
                                currseg->segflags |= SEG_FIXED;
                                currseg->seg_addr = MatchSeg->Base;
                            }
                            if( MatchSeg->NoEmit ) {
                                currseg->segflags |= SEG_NOEMIT;
                            }
                            RingPromote( &currcl->segs, currseg, prevseg );
                            break;
                        }
                        if( currseg == currcl->segs ) {
                            break;
                        }
                        prevseg = currseg;
                        currseg = currseg->next_seg;
                    }
                    currcl = currcl->next_class;
                } while( currcl != MatchClass->Ring );
            }
        }
        /* now construct list out of the collected parts. */
        owner = &sec->classlist;
        for( MatchClass = sec->orderlist; MatchClass != NULL; MatchClass = MatchClass->NextClass ) {
            if( MatchClass->Ring != NULL ) {
                *owner = MatchClass->Ring->next_class;
                owner = &(MatchClass->Ring->next_class);
            }
        }
        if( DefaultRing != NULL ) { // Finish with unmatched ones
            *owner = DefaultRing->next_class;
            owner = &(DefaultRing->next_class);
        }
        *owner = NULL;
        // This has to happen after the class list is rebuilt, so it can be searched
        for( MatchClass = sec->orderlist; MatchClass != NULL; MatchClass = MatchClass->NextClass ) {
             if( MatchClass->Copy && MatchClass->Ring != NULL ) {   // If this is a duplicate destination, find the source
                 for( currcl = sec->classlist; currcl != NULL; currcl = currcl->next_class ) {
                    if( stricmp( MatchClass->SrcName, currcl->name ) == 0 ) {
                        MatchClass->Ring->DupClass = currcl;
                        MatchClass->Ring->flags |= CLASS_COPY;
                        break;
                    }
                }
            }
        }

        SortAreas( sec->areas ); // Not tested, not sure if needed
        sec = sec->next_sect;
    }
}

static bool CheckLxdataSeen( void *_seg, void *dummy )
/****************************************************/
{
    seg_leader  *seg = _seg;

    dummy = dummy;
    if( seg->info & SEG_LXDATA_SEEN ) {
        seg->class->flags |= CLASS_LXDATA_SEEN;
        return( TRUE );
    }
    return( FALSE );
}

static void CheckClassUninitialized( class_entry * currcl )
/*********************************************************/
{
    RingLookup( currcl->segs, CheckLxdataSeen, NULL );
}

static void InsertPrevRing( seg_leader **list, seg_leader *curr,
                            seg_leader *prev )
/**************************************************************/
{
    if( prev == NULL ) {
        RingPush( list, curr );
    } else {
        RingInsert( list, curr, prev );
    }
}

static void SortSegments( void )
/******************************/
// reorder segments based on COFF name grouping
{
    class_entry         *currcl;
    seg_leader          *prev;
    seg_leader          *curr;
    seg_leader          *comp;
    seg_leader          *newlist;
    char                *dollarpos;
    size_t              currlen;
    size_t              complen;
    bool                foundgroup;     // so we don't search for OMF only.
    bool                foundmatch;
    bool                added;


    for( currcl = Root->classlist; currcl != NULL; currcl = currcl->next_class ){
        foundgroup = FALSE;
        newlist = NULL;
        curr = RingPop( &currcl->segs );
        while( curr != NULL ) {
            dollarpos = strchr( curr->segname, '$' );
            if( dollarpos != NULL ) {
                currlen = dollarpos - curr->segname;
                foundgroup = TRUE;
            } else {
                currlen = strlen( curr->segname );
            }
            added = FALSE;
            if( foundgroup ) {
                prev = NULL;
                comp = RingStep( newlist, NULL );
                foundmatch = FALSE;
                while( comp != NULL ) {
                    complen = strcspn( comp->segname, "$" );
                    if( ( complen == currlen )
                        && ( memcmp( comp->segname, curr->segname, complen ) == 0 ) ) {
                        foundmatch = TRUE;
                        if( strcmp( comp->segname + complen,
                                    curr->segname + currlen ) > 0 ) {
                            InsertPrevRing( &newlist, curr, prev );
                            added = TRUE;
                            break;
                        }
                    } else if( foundmatch ) {
                        InsertPrevRing( &newlist, curr, prev );
                        added = TRUE;

⌨️ 快捷键说明

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