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