_PORTABILITY BY DESIGN_ by Michael Ross Listing One /* Machine dependent information required by front-end */ #ifndef CALLCONV_H #include "callconv.h" #endif #ifndef LANGUAGE_H #include "language.h" #endif #ifndef FP_H #include "fp.h" #endif #ifndef TCLASSES_H #include "tclasses.h" #endif typedef unsigned long inline_flags_type; typedef enum { CPU_unknown, CPU_I386, /* Intel 386 */ CPU_370, /* IBM 370 */ CPU_RT, /* IBM RT */ CPU_AM29K, /* AM29000 */ CPU_I860, /* Intel 860 */ CPU_MC68000, /* Motorola 68000 */ CPU_MC68020, /* Motorola 68020 */ CPU_VAX, /* DEC VAX */ CPU_MDD, /* McDonald Douglas */ CPU_SPARC, /* SPARC (Sun 4) */ CPU_R3000, /* MIPS R3000 */ CPU_HOBBIT, CPU_PARISC, /* HP9000-600/700/800 PA-RISC */ CPU_Ix86, /* 80x86 -- 16-bit Intel */ CPU_RS6000, /* IBM RS-6000 */ CPU_PPC /* IBM Power PC */ } CPU_type; /*Object module formats*/ typedef enum { NOFORMAT, /* OMF not applicable or unknown*/ COFF, /* Basic AT&T COFF */ AMDCOFF, /* AMD version of COFF */ LAMDCOFF, /*AMD version of COFF (little-endian mode) */ INTELOMF, /* Intel OMF (MSDOS) */ ADOTOUT, /* BSD a.out */ ELF, /* SVR4 ELF format */ MACH, /* MACH object module format */ HPUXCOFF, /* HPUX version of COFF */ } objformat_type; /* Operating systems */ typedef enum { NOOS, /* OS unknown */ AIX_OS, /* IBM's UNIX */ BSD_OS, /* Berkeley UNIX BSD4.x */ SUN_OS, /* Sun OS */ ATT_OS, /* AT&T UNIX System V.3 */ EPI_OS, /* EPI-OS (AM29000) */ VMS_OS, /* DEC */ MSDOS_OS, /* MS-DOS */ OS2_OS, /* OS/2 */ XNX_OS, /* Xenix */ ISIS_OS, /* Isis */ ATT4_OS, /* AT&T UNIX System V.4 */ NeXT_OS, /* NeXTStep from NeXT */ NEWS_OS, /* Sony NEWS-OS */ MSNT_OS, /* Microsoft NT */ SOL_OS, /* Solaris */ HPUX_OS, /* HP UNIX System V. */ } os_type; /* Inline transcendentals */ #define SIN_INLINE 0x00000001 #define COS_INLINE 0x00000002 #define ASIN_INLINE 0x00000004 /* Arcsin or Arccos */ #define SQRT_INLINE 0x00000008 #define LOG_INLINE 0x00000010 /* Natural or common log */ #define EXP_INLINE 0x00000020 #define TAN_INLINE 0x00000040 #define ATAN_INLINE 0x00000080 #define ATAN2_INLINE 0x00000100 /* Arctan(a,b) */ #define SINH_INLINE 0x00000200 #define COSH_INLINE 0x00000400 #define TANH_INLINE 0x00000800 /* tanh */ #define FABS_INLINE 0x00001000 /* fabs */ #define ASM_INLINE 0x00002000 /* ASM directive supported */ #define INS_INLINE 0x00004000 /* _inline(bytes) */ /* Status of pragma processing: */ typedef enum { OKAY_DELETE_p, /* Pragma fully processed; do not pass to backend */ OKAY_PASS_p, /* Pass pragma to back-end */ TOO_LATE_p, /* Pragma specified too late */ ERROR_p, /* Suboperands of pragma incorrect */ /* badptr set to bad parameter */ IGNORED_p, /* Already specified */ } PRAG_STATUS; struct struct_aligns {char if_its_this_big, align_to_this;}; extern struct mapping_entry{ /* False if structs are packed by default */ bool align_members; ubyte shortsize; /* size of "short" in bytes */ ubyte intsize; /* size of "int" in bytes */ ubyte longsize; /* size of "long" in bytes */ ubyte floatsize; /* size of "float" */ ubyte doublesize; /* size of "double" */ ubyte longdoublesize;/* size of "long double" */ ubyte min_parm_align;/* Min alignment of a passed parm */ bool unsigned_char; /*"char" unsigned by default? */ bool pure_32_bit; /* All integer operations in 32 bits?*/ ubyte code_ptr_size; /* Code pointer size */ ubyte data_ptr_size; /* Data pointer size */ /* Size of "near" pointer to code */ ubyte near_code_ptr_size; /* Size of "far" pointer to code */ ubyte far_code_ptr_size; /* Size of "near" pointer to data */ ubyte near_data_ptr_size; /*Size of "far" pointer to data */ ubyte far_data_ptr_size; ubyte short_align; /* Alignment of shorts */ ubyte long_align; /* Long alignment */ ubyte int_align; /* int alignment */ ubyte ptr_align; /* pointer alignment */ ubyte double_align; /* double alignment */ ubyte max_field_align; /* Maximum field alignment */ bool msb_first; /*integers stored MSB first? */ /* Align all vars to int boundary (even chars) */ bool word_align_vars; bool off_boundary_refs;/* Are off-boundary refs supported?*/ char *version; /* Version number of compiler */ /* Align structs 3 bytes or longer to word boundary */ bool word_align_structs; calling_convention_set default_calling_convention; /* If true varargs must be explicitly specified with "..." syntax */ bool ansi_varargs_only; /* Which transcendentals may be inline? */ inline_flags_type inline_flags; ubyte max_parm_align;/* Max alignment of a passed parm */ ubyte offset_size; /* Pascal offset size */ ubyte area_size; /* Pascal area size */ /* Largest array in bytes (Pascal) */ unsigned long max_data_size; bool signed_halfwords_preferred; /*True for 370. (Pascal)*/ bool range_checks_require_range; /*Do we need a lower and upper value for rangecheck?*/ /* How are Pascal sets mapped? */ /* Also see "set_unit_size" below */ bool sets_mapped_LSB_first; /* used in machines where pointer arithmetic will not work unless the * computed address is a multiple of machine's word size. */ ubyte address_resolution; /* In creating a common block for Professional Pascal interface packages, * we use the name of the package, prefixed and suffixed with a * special character. */ /* char to be prefixed to Pascal package block*/ char package_prefix; /* char to be suffixed to Pascal package block*/ char package_suffix; /* size of "char" in bytes, believe it or not char is 8 bytes on NAM */ ubyte charsize; /* Format of floating point */ real_form floating_point_format; /* If off-boundary references are NOT supported, do we * handle packed structures nevertheless? */ bool packed_structs_supported; ubyte char_align; /*Alignment of "char" */ ubyte float_align; /*Alignment of "float" */ ubyte longdouble_align; /*Alignment of "long double" */ char bits_per_int; /*bits per integer used for bitfields */ /* Implies the machine can convert (signed|unsigned)(char|short) to float * in a way more efficient than to double. The result is that the front * end is careful to generate FLT vs FLTU in this context so back end can * tell from register length and FLT/FLTU whether to generate the better * code and which kind of better code (it differs from U to nonU). */ bool short_to_float; /* Given the case index of a pseudo-function that target machine is * usually supports, do we support it with corrent configuration? */ bool (*recognize_pseudo_function)(func_case_index); CPU_type cpu; /* Target CPU */ os_type os; /* Target OS */ objformat_type omf; /*Target OMF*/ /* For non-padded structs, search this array, terminated by {0,0}. * If struct size is >= first member, align to at least 2nd member. * Thus "word_align_structs" could be {3,4},{2,2},{0,0}. */ struct struct_aligns *struct_aligns, *array_aligns; bool use_INFO; /* Can code generator tolerate INFO * rather than LINE/FILE/STAB ? */ type_class wchartype; /* this can be any intger type */ ubyte wcharsize; /* sizeof (wchar_t) */ /* We changed the way debugger information is passed to code generator. * If "debug_info_scheme" is 0, then old way is used. Otherwise, the * new way. */ ubyte debug_info_scheme; bool try_supported; bool wchar_is_short; /* wchar_t is short int */ bool wchar_is_long; /* wchar_t is long int */ /* Given a toggle that may have been defined in * establish_machine_dependencies, is it still good at this point? */ /* Return TRUE if so. Otherwise, the compiler will issued */ /* "Toggle cannot be specified here." */ bool (*toggle_is_valid)(toggle t, bool turn_it_on); /* "init", if not zero, is called when the first non-pragma is seen. * Its primary purpose is to adjust other fields in mapping that are * dependant on pragmas and toggles. E.g. 1167 toggle for 386 causes long * doubles to be 8 bytes instead of 12 */ void (*init)(void); /* The default global aliasing convention. NULL implies "%r". */ char *global_aliasing_convention; /* Are "far" variables support? That is, does it make * sense to qualify a variable declaration with "_far"? */ /* This must be FALSE on ESA/370. */ bool far_variables_supported; /* Are "far" functions supported? If false, compiler will */ /* ignore "_far" and issue a warning. */ bool far_functions_supported; /* Does the target machine's OMF handle multiple named */ /* control sections (segments)? */ /* If this is false, then the front-end will ignore */ /* "pragma code", "pragma literals(xx)", and "pragma static_segment()". */ /* (Pragma data is handled on UNIX by converting to named blocks). */ bool multiple_named_sections_supported; /* Can control sections of class "common" be initialized? */ /* On DOS and VMS this is true. */ bool common_section_initialization_supported; /* Are we generated code for a strict IEEE machine? */ /* If true, we must generate unordered comparisons. */ /* I.e., X < Y is a different operation than !(X >= Y). */ bool IEEE_unordered_compares_supported; /* code_sections_supported -- if true, the target machine */ /* had separate I & D spaces but is able to reference the */ /* I space as data. (E.g.,386 with its segment override). */ /* If set to TRUE, the toggles "const_in_code" and "literals_in_code" * will be supported for putting const variables into instruction space.*/ bool code_sections_supported; /* Is the calling convention "CALLEE_POPS_STACK" supported? */ bool callee_pops_stack_supported; /* Is the calling convention "REVERSE_PARMS" supported? */ /* (Applies to those machines that have a "PUSH" instruction only. */ bool reverse_parms_supported; /* Default data aliasing convention for Professional Pascal */ /* Default routine aliasing convention for Professional Pascal */ char *data_aliasing_convention; char *routine_aliasing_convention; /* set_unit_size in conjunction with the "sets_mapped_LSB_first" */ /* flag above determine how (Pascal) sets are mapped in storage. */ /* High C/Professional Pascal ordinarily maps sets as a sequence * of halfwords. Microsoft maps them as an even number of bytes, * MSB first. */ ubyte set_unit_size; /* type_checking is true if type information should be kept even when * g_flag is off. This is used for 370/ESA type checking at link time. */ bool type_checking; /* Size of a "long long" type. If such types are not supported, * then the size should match "long". */ ubyte longlongsize; ubyte longlong_align; /* Alignment of long long */ /* What is the largest auto-variable of type struct that can be mapped * directly into a series of one or more registers? Value is in bytes. */ uint largest_aggregate_in_registers; /* When doubles or long doubles are just plain variables (or arrays * thereof), what should the alignment be? For Pentium, it's much * better for them to be 8-byte aligned. */ ubyte double_variable_align; /*double variable alignment */ /*Alignment of "long double" variable */ ubyte longdouble_variable_align; bool supports_call_lit; /* Code generator supports call-lit construct.*/ /* These tell if we require certain calling convention bits: */ /* Must have cc_CALLEE_POPS_STACK.*/ bool callee_pops_stack_required; bool reverse_parms_required;/* Must have cc_REVERSE_PARMS.*/ /* For C++ constructors/destructors of static/global variables, does * get handle the initialization level protocol? True for systems * that support .init/.fini sections. */ bool support_initialization_order; /* Use Sun's and AT&T's convention for mapping bit fields? */ bool ABI_bit_fields; /* SYS_SIZETTYPE takes on one of the values s, i, l for short, int, long. * SYS_SIZETSIGNED takes one of the values s, u, or n for signed, * unsigned or non-signed (for "char"). */ char sizet_signed; /* s, u, n. */ char sizet_type; /* s, i, l. c not supported currently. */ }mapping; extern const char *machine_name; /*Name of machine*/ #define LONGLONG_SUPPORTED (SYS_LONGLONGSIZE > SYS_LONGSIZE) #define SYS_PACKEDSTRUCT (!mapping.align_members) /* CHARSIZE is always the same on all machines. Wrong!! not on NAM */ #define SYS_CHARSIZE mapping.charsize #define SYS_INTSIZE mapping.intsize #define SYS_FLOATSIZE mapping.floatsize #define SYS_DOUBLESIZE mapping.doublesize #define SYS_EXTENDEDSIZE mapping.longdoublesize #define SYS_LINKSIZE mapping.near_data_ptr_size #define SYS_LONGLONGSIZE mapping.longlongsize #define SYS_SHORTSIZE mapping.shortsize #define SYS_LONGSIZE mapping.longsize #define SYS_SIGNEDCHAR (!mapping.unsigned_char) /*Pointer that is loaded into reg*/ #define SYS_PTRSIZE SYS_LINKSIZE #define SYS_DPTRSIZE mapping.data_ptr_size #define SYS_CPTRSIZE mapping.code_ptr_size #define SYS_WCHARSIZE mapping.wcharsize #define SYS_WCHARTYPE mapping.wchartype #define SYS_WCHARSHORT mapping.wchar_is_short #define SYS_WCHARLONG mapping.wchar_is_long #define SYS_SIZETSIGNED mapping.sizet_signed #define SYS_SIZETTYPE mapping.sizet_type #define BITS_PER_BYTE 8 #define BITS_PER_INT mapping.bits_per_int #define BITS_PER_LONG (sizeof(long)*BITS_PER_BYTE) #define SYS_INTAL mapping.int_align #define SYS_LONGAL mapping.long_align #define SYS_LONGLONGAL mapping.longlong_align #define SYS_SHORTAL mapping.short_align #define SYS_FLOATAL mapping.float_align #define SYS_CHARAL mapping.char_align #define SYS_DOUBLEAL mapping.double_align #define SYS_LONGDOUBLEAL mapping.longdouble_align #define SYS_DOUBLE_VARIABLE_AL mapping.double_variable_align #define SYS_LONGDOUBLE_VARIABLE_AL \ mapping.longdouble_variable_align #define SYS_PTRAL mapping.ptr_align #define SYS_OFF_BOUNDARY_REFS mapping.off_boundary_refs #define SYS_STRINGAL 1 /*Alignment of strings*/ #define SYS_MSB_FIRST mapping.msb_first #define SYS_LSB_FIRST (!SYS_MSB_FIRST) #define SYS_STACK_AL mapping.min_parm_align #define SYS_32_BIT_ARITHMETIC_ONLY mapping.pure_32_bit #define SYS_MAX_FIELD_AL mapping.max_field_align #define SYS_WORD_ALIGN_STRUCTS mapping.word_align_structs #define SYS_ADR_RESOLUTION mapping.address_resolution #define SEGMENT_REG_SIZE (mapping.far_data_ptr_size - \ SYS_INTSIZE ) #define NEW_DEBUG_INFO (mapping.debug_info_scheme> 0) /* Establish_machine_dependencies -- initializes "mapping" to correspond * to "machine". Returns FALSE if machine is not recognized. */ extern bool establish_machine_dependencies( const char *machine, language_type l); /* Defines which object module formatter should be used for the target OS and * machine name of the target operating system passed by the driver */ extern const char *targetos_name; Listing Two #define LS (sizeof(long)*8) /* Maximum bits for left shift */ #define BS (sizeof(long long)*8) /* Maximum bits for long long shift */ struct longlong{ /* Define structure for systems that don't support long long*/ long lo; long hi; }; typedef struct longlong Big_int; /* Grab a mantissa from a floating point number */ static long extract_mantissa(FP_number F){ Big_int b; int cnt, rbit; cnt = BS -1 - F->Exp; /* Determine how far to shift to find exponent */ if (cnt >= LS){ /* If shifting at least a longword */ cnt -= LS; /* subtract longword length from shift count */ if (cnt == 0) rbit = long(b.lo) < 0; /* Guard bit needed? */ b.lo = b.hi; b.hi = 0; } if (cnt){ /* Anything left to shift? */ rbit = (b.lo & (1L << (cnt-1))) !=0; if (cnt == LS){ /* Some machines can't shift by long word length */ b.lo = 0; /* Defend against this. Result would be zero */ b.hi = 0; } else{ b.lo = ((unsigned long)b.lo >> cnt | (b.hi << (LS-cnt)); b.hi = (unsigned long) b.hi >> cnt; } } } Listing Three #ifndef Process_h #define Process_h #include "addrvect.h" #include "disassem.h" #include "itemnumb.h" #include "linklist.h" #include "memacces.h" #include "modulemg.h" #include "stmt.h" #include "symbolta.h" #include "tempbkpt.h" typedef int Outcome; #define user_failure -1 #define failure 0 #define success 1 class Declaration; class DiFile; class EventMgr; class ExecSpec; class ExprObj; class StackFrame; class Status; class Thread; enum PSA1 { psa1_none, psa1_replace_breakop, psa1_replace_libpt, }; enum PSA2 { psa_none, psa_run_to_retaddr, }; class Process : public ItemNumber { Key key; Thread * current; // 0 in ctor LinkList threadlist; TempBkptMgr tempbkptmgr; EventMgr * eventmgr; // set in ctor MemAccess memaccess; Disassembler disassembler; Symboltable symboltable; ModuleMgr modulemgr; AddrVector destvector; Stmt startstmt; Boolean now_executing; DiFile * target_difile; PSA1 psa1; PSA2 psa2; char *current_lang; // Temporary hack to be able // to set the language. Thread * lookup_thread( unsigned int ); Outcome check_state(); Outcome set_execspec( const ExecSpec & ); Boolean goal_attained(); Outcome start_step_into( Thread * ); Outcome start_step_over( Thread * ); Outcome start_step_retaddr( Thread * ); Outcome start_run( Thread * ); Outcome analyse_stmt_into( Boolean & ); Outcome analyse_stmt_over( Boolean & ); Outcome run_to_return_addr( Thread * ); Outcome execute_to_return_addr( Thread * ); Outcome run_to_caller( Thread * ); Outcome end_instr_step_into( Thread * ); Outcome end_instr_step_over( Thread * ); Outcome end_stmt_step_into( Thread * ); Outcome end_stmt_step_over( Thread * ); Outcome end_run( Thread * ); Outcome check_instr_step_into( Thread * ); Outcome check_instr_step_over( Thread * ); Outcome check_stmt_step_into( Thread * ); Outcome check_stmt_step_over( Thread * ); Outcome check_run( Thread * ); Outcome respond_to_hop_completion( Thread * ); Outcome respond_to_retpoint( Thread * ); Outcome respond_to_destpoint( Thread * ); Outcome respond_to_breakpoint( Thread * ); Outcome respond_to_watchpoint( Thread * ); Outcome respond_to_exception( Thread * ); Outcome respond_to_step_completion( Thread * ); Outcome respond_to_suspension( Thread * ); Outcome respond_to_exec( Thread *, DiFile * ); Outcome respond_to_libpt( Thread * ); Outcome respond_to_module_load( const Status & ); Outcome respond_to_module_unload( const Status & ); Outcome respond_to_thread_creation( const Status & ); Outcome respond_to_thread_destruction( const Status & ); Outcome start_stmt_step_into( Thread * ); Outcome start_stmt_step_over( Thread * ); public: Process( unsigned int, DiFile * ); ~Process(); Outcome get_status( Status & ); Outcome wait_status( Status & ); Outcome update_status( const Status & ); Boolean is_executing() { return now_executing; } Outcome run( const ExecSpec & ); Outcome instr_step_into( const ExecSpec & ); Outcome instr_step_over( const ExecSpec & ); Outcome stmt_step_into( const ExecSpec & ); Outcome stmt_step_over( const ExecSpec & ); Outcome resume(); Outcome stop(); Thread * current_thread() { return current; } Outcome disassemble( const Addr &, Instruction &, Addr & ); Outcome find_stmt( const Addr &, Stmt & ); Outcome find_function( const Addr &, Declaration & ); Outcome evaluate( char *, StackFrame &, ExprObj & ); Outcome set_language(char *input_language); char *get_lang_string(); Process * next() { return (Process *)Item::get_next(); } }; #endif Example 1 (a) #include struct bad_layout{ char direction; union { char var; float fvar; double dvar; } mess; int myint; }; main(){ struct bad_layout mystruct; printf("sizeof(mystruct) = %d\n", sizeof(mystruct)); } (b) COMMON /SLOW/ I,D,L EQUIVALENCE (D,N(2)),(I,N(1)) INTEGER I,N(2) DOUBLE PRECISION D LOGICAL L PRINT *,D END (c) SUBROUTINE USELESS(I,J) INTEGER I,J IF (J.EQ.0) GOTO 10 I = J ** 2 GOTO 20 10 I = 3 J = 10 20 CONTINUE END