cinfo.c

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

C
972
字号
/****************************************************************************
*
*                            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:  Segment management and FE callbacks.
*
****************************************************************************/


#include "cvars.h"
#include "cg.h"
#include "cgdefs.h"
#include "cgswitch.h"
#include "standard.h"
#include "cgaux.h"
#include "langenv.h"
#define BY_CLI
#include "cgprotos.h"
#include "feprotos.h"


struct user_seg {
    struct user_seg *next;
    char            *name;
    SYM_HANDLE      sym_handle;                     /* 15-mar-92 */
    int             segtype;                        /* 22-oct-92 */
    int             segment;                        /* 22-oct-92 */
    char            *class_name;                    /* 22-oct-92 */
    hw_reg_set      pegged_register;                /* 29-may-93 */
    bool            used;
};


void AssignSeg( SYM_ENTRY *sym )
{
    SetFarHuge( sym, 1 );
    if( (sym->stg_class == SC_AUTO) || (sym->stg_class == SC_REGISTER)
     || (sym->stg_class == SC_TYPEDEF) ) {
        /* if stack/register var, there is no segment */
        sym->u.var.segment = 0;
    } else if( sym->stg_class != SC_EXTERN ) {  /* if not imported */
        if( (sym->flags & SYM_INITIALIZED) == 0 ) {
            if( sym->u.var.segment == 0 ) {             /* 15-mar-92 */
                SetSegment( sym );
            }
            if( sym->u.var.segment == SEG_DATA ) {
                sym->u.var.segment = SEG_BSS;
                CompFlags.bss_segment_used = 1;
            }
            SetSegAlign( sym );                 /* 02-feb-92 */
        }
    } else if( sym->attrib & (FLAG_FAR | FLAG_HUGE) ) {
        sym->u.var.segment = SegImport;
        --SegImport;
    } else if( (SegData != 0) && (sym->attrib & FLAG_NEAR) ) {  // imported and near
        sym->u.var.segment = SegData;
    }
}


void SetFarHuge( SYMPTR sym, int report )
{
    TYPEPTR             typ;
    type_modifiers      attrib;
    unsigned long       size;

    report = report; /* in case not used */
#if _CPU == 8086
    if( sym->declspec == DECLSPEC_DLLIMPORT
     || sym->declspec == DECLSPEC_DLLEXPORT ) {      /* 16-dec-94 */
        sym->attrib |= FLAG_FAR;
    } else if( sym->attrib & FLAG_EXPORT ) {
        sym->attrib |= FLAG_FAR;
    }
#endif
    size = SizeOfArg( sym->sym_type );
    if( TargetSwitches & BIG_DATA ) {
        attrib = sym->attrib;
        if( (attrib & (FLAG_NEAR | FLAG_FAR | FLAG_HUGE)) == 0 ) {
            if( size == 0 ) {   /* unspecified array size */
                if( sym->stg_class == SC_EXTERN ) {
                    typ = sym->sym_type;
                    if( typ->decl_type == TYPE_ARRAY ) {
                        attrib |= FLAG_FAR;
                    }
                }
            } else if( size > DataThreshold ) {
                attrib |= FLAG_FAR;
            } else if( CompFlags.strings_in_code_segment
                       && ( sym->attrib & FLAG_CONST ) ) {
                attrib |= FLAG_FAR;
            }
#if _CPU == 8086
            if( (attrib & FLAG_FAR) && size > 0x10000 ) {
                attrib &= ~FLAG_FAR;
                attrib |= FLAG_HUGE;
            }
#endif
            sym->attrib = attrib;
        }
    }
#if _CPU == 8086
   if( report && size > 0x10000 && !(sym->attrib & FLAG_HUGE) ) {
        SetSymLoc( sym );
        CErr( ERR_VAR_TOO_LARGE );
   }
#endif
}


#define CONSTANT( decl_flags ) ( ( decl_flags & (FLAG_CONST | FLAG_VOLATILE) ) == FLAG_CONST )



static fe_attr FESymAttr( SYMPTR sym )
/************************************/
{
    fe_attr         attr;

    attr = 0;
    switch( sym->stg_class ) {
    case SC_FORWARD:
    case SC_EXTERN:
        attr = FE_GLOBAL | FE_IMPORT | FE_STATIC;
        break;
    case SC_NULL:
        attr = FE_GLOBAL | FE_STATIC;
        break;
    case SC_STATIC:
        attr = FE_STATIC | FE_VISIBLE;
        if( sym->level != 0 ) {
            attr |= FE_INTERNAL;
        }
        break;
    }
    if( sym->flags & SYM_FUNCTION ) {
        attr |= FE_PROC | FE_STATIC;
        if( VarFunc( sym ) )
            attr |= FE_VARARGS;
        if( CompFlags.unique_functions ) {
            if( (attr & FE_GLOBAL) || (sym->flags & SYM_ADDR_TAKEN) ) {
                attr |= FE_UNIQUE;
            }
        }
    }
    if( sym->flags & SYM_USED_IN_PRAGMA ) {
        attr |= FE_MEMORY | FE_ADDR_TAKEN | FE_VOLATILE;
    }
    if( sym->flags & SYM_TRY_VOLATILE ) {
        attr |= FE_MEMORY | FE_VOLATILE;
    }
    if( sym->attrib & FLAG_VOLATILE ) {
        attr |= FE_MEMORY | FE_VOLATILE;
    } else if( sym->attrib & FLAG_CONST ) {
        attr |= FE_CONSTANT;
    }
    switch( sym->declspec ) {
    case DECLSPEC_DLLIMPORT:
        if( (attr & FE_IMPORT) || CompFlags.rent ) {
            attr |= FE_DLLIMPORT;
        }
        break;
    case DECLSPEC_DLLEXPORT:
        if( sym->stg_class == SC_NULL ) {
            attr |= FE_DLLEXPORT;
        }
        break;
    case DECLSPEC_THREAD:
        attr |= FE_THREAD_DATA;
        break;
    }
    if( sym->naked ) {
        attr |= FE_NAKED;
    }
    if( sym->rent ) {   //Override on function or r/w data
        attr |= FE_THREAD_DATA;
    }
    return( attr );
}


void    FEGenProc( CGSYM_HANDLE hdl, call_handle call_list )
/**********************************************************/
{
    SYM_HANDLE      sym_handle = hdl;

    GenInLineFunc( sym_handle );
}


fe_attr FEAttr( CGSYM_HANDLE cgsym_handle )
/*****************************************/
{
    SYM_HANDLE sym_handle = cgsym_handle;

    return( FESymAttr( SymGetPtr( sym_handle ) ) );
}


segment_id SymSegId( SYMPTR sym )
{
    fe_attr     attr;

    attr = FESymAttr( sym );
    if( attr & FE_PROC ) return( SEG_CODE );
    if( !CompFlags.rent ) {
        if( attr & FE_CONSTANT ) return( SEG_CONST2 );
    }
    return( SEG_DATA );
}


void SetSegment( SYMPTR sym )
{
    struct segment_list     *seg;
    unsigned long           size;


#if _CPU == 8086
    if( (sym->attrib & FLAG_FAR) && CompFlags.zc_switch_used ) {
        if( CONSTANT( sym->attrib )
        || (sym->stg_class == SC_STATIC  &&  (sym->flags & SYM_TEMP)) ) {
            sym->u.var.segment = SEG_CODE;
            return;
        }
    }
#elif _CPU == 386
    if( !CompFlags.rent ) {
        if( (sym->attrib & FLAG_FAR) || (TargetSwitches & FLAT_MODEL) ) {
           if( CONSTANT( sym->attrib ) && CompFlags.zc_switch_used ) {
                sym->u.var.segment = SEG_CODE;
                return;
           }
           if( (sym->stg_class == SC_STATIC) && (sym->flags & SYM_TEMP) ) {
                sym->u.var.segment = SEG_CODE;
                return;
            }
         }
     }
#endif
    if( sym->attrib & ( FLAG_FAR | FLAG_HUGE ) ) {
        size = SizeOfArg( sym->sym_type );
        seg = NULL;
#if _CPU == 8086
        if( size < 0x10000 ) {
            unsigned int    isize;

            isize = size;
            for( seg = SegListHead; seg; seg = seg->next_segment ) {
                if( seg->size_left >= isize ) break;
            }
        }
#else
        seg = SegListHead;
#endif
        if( seg == NULL ) {
            if( SegListHead == NULL ) {
                SegListHead = CMemAlloc( sizeof( struct segment_list ) );
                seg = SegListHead;
            } else {
                for( seg = SegListHead; seg->next_segment; ) {
                    seg = seg->next_segment;
                }
                seg->next_segment =
                            CMemAlloc( sizeof( struct segment_list ) );
                seg = seg->next_segment;
            }
            seg->segment_number = SegmentNum;
            ++SegmentNum;
#if _CPU == 8086
            if( size > 0xFFFF ) {
                while( size > 0x0FFFF ) {       /* while >= 64K */
                    ++SegmentNum;
                    size -= 0x10000;
                }
                seg->size_left = 0;
            } else {
                seg->size_left = 0x10000 - size;
            }
#endif
        } else {
            seg->size_left -= size;
        }
        sym->u.var.segment = seg->segment_number;
    } else {
        sym->u.var.segment = SymSegId( sym );
    }
}

struct  seg_name {
    char            *name;
    int             segment;
    SYM_HANDLE      sym_handle;                     /* 13-jan-06 */
};

static struct seg_name Predefined_Segs[] = {
    { "_CODE",      SEG_CODE,   0 },
    { "_CONST",     SEG_CONST,  0 },
    { "_DATA",      SEG_DATA,   0 },
    { "_STACK",     SEG_STACK,  0 },                /* 13-dec-92 */
    { NULL,         0,          0 }
};

static  int     UserSegment;

#define FIRST_USER_SEGMENT      10000

static struct user_seg *AllocUserSeg( char *segname, char *class_name, seg_type segtype )
{
    struct user_seg     *useg;

    useg = CMemAlloc( sizeof( struct user_seg ) );
    useg->next = NULL;
    useg->name = CStrSave( segname );
    useg->class_name = NULL;
    useg->segtype = segtype;
    if( class_name != NULL ) {
        useg->class_name = CStrSave( class_name );
    }
    useg->segment = UserSegment;
    ++UserSegment;
    return( useg );
}

#define INITFINI_SIZE 12

struct spc_info {
    char        *name;
    char        *class_name;
    seg_type    segtype;
};

static struct spc_info InitFiniSegs[INITFINI_SIZE] = {
    { TS_SEG_TIB, "DATA",           SEGTYPE_INITFINI },
    { TS_SEG_TI,  "DATA",           SEGTYPE_INITFINI },
    { TS_SEG_TIE, "DATA",           SEGTYPE_INITFINI },
    { TS_SEG_XIB, "DATA",           SEGTYPE_INITFINI },
    { TS_SEG_XI,  "DATA",           SEGTYPE_INITFINI },
    { TS_SEG_XIE, "DATA",           SEGTYPE_INITFINI },
    { TS_SEG_YIB, "DATA",           SEGTYPE_INITFINI },
    { TS_SEG_YI,  "DATA",           SEGTYPE_INITFINI },
    { TS_SEG_YIE, "DATA",           SEGTYPE_INITFINI },
    { TS_SEG_TLSB, TS_SEG_TLS_CLASS,SEGTYPE_INITFINITR },
    { TS_SEG_TLS,  TS_SEG_TLS_CLASS,SEGTYPE_INITFINITR },
    { TS_SEG_TLSE, TS_SEG_TLS_CLASS,SEGTYPE_INITFINITR },
};


static struct spc_info *InitFiniLookup( char *name )
{
    int     i;

    for( i = 0; i < INITFINI_SIZE; ++i ) {
        if( strcmp( InitFiniSegs[i].name, name ) == 0 ) {
            i = (i / 3) * 3;
            return( &InitFiniSegs[i] );
        }
    }
    return( NULL );
}


static int AddSeg( char *segname, char *class_name, int segtype )
{
    struct seg_name     *seg;
    struct user_seg     *useg, **lnk;
    hw_reg_set          reg;
    char                *p;

    for( seg = &Predefined_Segs[0]; seg->name; seg++ ) {
        if( strcmp( segname, seg->name ) == 0 ) {
            return( seg->segment );
        }
    }
    HW_CAsgn( reg, HW_EMPTY );
    p = segname;
    for( ;; ) {
        if( *p == '\0' ) break;
        if( *p == ':' ) {
            *p = '\0';
            reg = PragRegName( segname );
            *p = ':';
            segname = p + 1;
            break;
        }
        ++p;
    }
    lnk = &UserSegments;
    while( (useg = *lnk) != NULL ) {
        if( strcmp( segname, useg->name ) == 0 ) {
            return( useg->segment ); /* 11-mar-93 - was return( segment ) */
        }
        lnk = &useg->next;
    }
    useg = AllocUserSeg( segname, class_name, segtype );
    useg->next = *lnk;
    useg->pegged_register = reg;
    *lnk = useg;
    return( useg->segment );
}


int AddSegName( char *segname, char *class_name, int segtype )
{
    struct spc_info     *initfini;
    int                 segid;

    initfini = InitFiniLookup( segname );
    if( initfini != NULL ) {
        AddSeg( initfini[0].name, initfini[0].class_name, initfini[0].segtype );
        AddSeg( initfini[1].name, initfini[1].class_name, initfini[1].segtype );
        AddSeg( initfini[2].name, initfini[2].class_name, initfini[2].segtype );
    }
    segid = AddSeg( segname, class_name, segtype );
    return( segid );
}


int DefThreadSeg( void )
{
    int     segid;

    segid = AddSegName( TS_SEG_TLS, "DATA", SEGTYPE_INITFINI );
    return( segid );
}


void SetFuncSegment( SYMPTR sym, int segment )
{
    struct user_seg     *useg;

    for( useg = UserSegments; useg; useg = useg->next ) {
        if( useg->segment == segment ) {
            sym->seginfo = LkSegName( useg->name, "CODE" );
            break;
        }
    }
}


char *SegClassName( unsigned requested_seg )
{
    struct user_seg     *useg;
    struct textsegment  *tseg;
    char                *classname;
    int                 len;

    if( requested_seg == SEG_CODE ) {
        return( CodeClassName );                        /* 01-mar-90*/
    }
    for( useg = UserSegments; useg; useg = useg->next ) {
        if( useg->segment == requested_seg  &&  useg->class_name != NULL ) {
            classname = useg->class_name;
            if( classname[0] == '\0' ) {                /* 07-jun-94 */
                len = strlen( useg->name );
                if( len >= 4 ) {
                    if( stricmp( useg->name + len - 4, "DATA" ) == 0 ) {
                        classname = "FAR_DATA";
                    } else if( stricmp( useg->name + len - 4, "TEXT" ) == 0 ) {
                        classname = "CODE";
                    }
                }
            }
            return( classname );

⌨️ 快捷键说明

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