X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gas%2Fconfig%2Fobj-vms.c;h=91498925b358af0a0c840fa3460a0ccadfc18747;hb=364b6d8b23fffbc773c2bda23348d73e8de86e84;hp=704141fe58b164faa06099a9fdd3e89e8e7cd237;hpb=c999fd9fc23a159a286f9b129992dd5a2969db39;p=binutils-gdb.git diff --git a/gas/config/obj-vms.c b/gas/config/obj-vms.c index 704141fe58b..91498925b35 100644 --- a/gas/config/obj-vms.c +++ b/gas/config/obj-vms.c @@ -1,5 +1,6 @@ /* vms.c -- Write out a VAX/VMS object file - Copyright (C) 1987, 1988, 1992 Free Software Foundation, Inc. + Copyright 1987, 1988, 1992, 1993, 1994, 1995, 1997, 1998, 2000, 2001, 2002 + Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -14,33 +15,47 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +along with GAS; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ /* Written by David L. Kashtan */ /* Modified by Eric Youngdale to write VMS debug records for program variables */ + +/* Want all of obj-vms.h (as obj-format.h, via targ-env.h, via as.h). */ +#define WANT_VMS_OBJ_DEFS + #include "as.h" #include "config.h" +#include "safe-ctype.h" #include "subsegs.h" #include "obstack.h" +#include -/* What we do if there is a goof. */ +/* What we do if there is a goof. */ #define error as_fatal -#ifdef HO_VMS /* These are of no use if we are cross assembling. */ +#ifdef VMS /* These are of no use if we are cross assembling. */ #include /* Define File Access Block */ #include /* Define NAM Block */ #include /* Define XAB - all different types*/ +extern int sys$open(), sys$close(), sys$asctim(); #endif + /* * Version string of the compiler that produced the code we are * assembling. (And this assembler, if we do not have compiler info.) */ char *compiler_version_string; +extern int flag_hash_long_names; /* -+ */ +extern int flag_one; /* -1; compatibility with gcc 1.x */ +extern int flag_show_after_trunc; /* -H */ +extern int flag_no_hash_mixed_case; /* -h NUM */ + /* Flag that determines how we map names. This takes several values, and - * is set with the -h switch. A value of zero implies names should be + * is set with the -h switch. A value of zero implies names should be * upper case, and the presence of the -h switch inhibits the case hack. * No -h switch at all sets vms_name_mapping to 0, and allows case hacking. * A value of 2 (set with -h2) implies names should be @@ -48,14 +63,11 @@ char *compiler_version_string; * that case should be preserved. */ /* If the -+ switch is given, then the hash is appended to any name that is - * longer than 31 characters, irregardless of the setting of the -h switch. + * longer than 31 characters, regardless of the setting of the -h switch. */ char vms_name_mapping = 0; - -extern char *strchr (); -extern char *myname; static symbolS *Entry_Point_Symbol = 0; /* Pointer to "_main" */ /* @@ -64,12 +76,15 @@ static symbolS *Entry_Point_Symbol = 0; /* Pointer to "_main" */ struct VMS_Symbol { struct VMS_Symbol *Next; - struct symbol *Symbol; + symbolS *Symbol; int Size; int Psect_Index; int Psect_Offset; }; + struct VMS_Symbol *VMS_Symbols = 0; +struct VMS_Symbol *Ctors_Symbols = 0; +struct VMS_Symbol *Dtors_Symbols = 0; /* We need this to keep track of the various input files, so that we can * give the debugger the correct source line. @@ -90,8 +105,14 @@ struct input_file static struct input_file *file_root = (struct input_file *) NULL; - -static struct input_file *find_file PARAMS ((symbolS *)); +/* + * Styles of PSECTS (program sections) that we generate; just shorthand + * to avoid lists of section attributes. Used by VMS_Psect_Spec(). + */ +enum ps_type +{ + ps_TEXT, ps_DATA, ps_COMMON, ps_CONST, ps_CTORS, ps_DTORS +}; /* * This enum is used to keep track of the various types of variables that @@ -134,7 +155,9 @@ struct VMS_DBG_Symbol int struc_numb; }; -struct VMS_DBG_Symbol *VMS_Symbol_type_list; +#define SYMTYPLST_SIZE (1<<4) /* 16; must be power of two */ +#define SYMTYP_HASH(x) ((unsigned) (x) & (SYMTYPLST_SIZE-1)) +struct VMS_DBG_Symbol *VMS_Symbol_type_list[SYMTYPLST_SIZE]; /* * We need this structure to keep track of forward references to @@ -151,20 +174,19 @@ struct forward_ref char resolved; }; -struct forward_ref *f_ref_root = -{(struct forward_ref *) NULL}; +struct forward_ref *f_ref_root = (struct forward_ref *) NULL; /* * This routine is used to compare the names of certain types to various * fixed types that are known by the debugger. */ -#define type_check(x) !strcmp( symbol_name , x ) +#define type_check(X) !strcmp (symbol_name, X) /* * This variable is used to keep track of the name of the symbol we are * working on while we are parsing the stabs directives. */ -static char *symbol_name; +static const char *symbol_name; /* We use this counter to assign numbers to all of the structures, unions * and enums that we define. When we actually declare a variable to the @@ -172,10 +194,10 @@ static char *symbol_name; * whole thing each time. */ -static structure_count = 0; +static int structure_count = 0; /* This variable is used to indicate that we are making the last attempt to - parse the stabs, and that we should define as much as we can, and ignore + parse the stabs, and that we should define as much as we can, and ignore the rest */ static int final_pass; @@ -188,6 +210,24 @@ static int final_pass; */ static int struct_number; +/* This is used to distinguish between D_float and G_float for telling + the debugger about doubles. gcc outputs the same .stabs regardless + of whether -mg is used to select alternate doubles. */ + +static int vax_g_doubles = 0; + +/* Local symbol references (used to handle N_ABS symbols; gcc does not + generate those, but they're possible with hand-coded assembler input) + are always made relative to some particular environment. If the current + input has any such symbols, then we expect this to get incremented + exactly once and end up having all of them be in environment #0. */ + +static int Current_Environment = -1; + +/* Every object file must specify an module name, which is also used by + traceback records. Set in Write_VMS_MHD_Records(). */ + +static char Module_Name[255+1]; /* * Variable descriptors are used tell the debugger the data types of certain @@ -215,68 +255,56 @@ static int total_len; /* used to calculate the total length of variable descriptor plus array descriptor - used for len byte*/ /* Flag if we have told user about finding global constants in the text - section. */ -static gave_compiler_message = 0; - -/* A pointer to the current routine that we are working on. */ - -static symbolS *Current_Routine; - -/* The psect number for $code a.k.a. the text section. */ - -static int Text_Psect; - + section. */ +static int gave_compiler_message = 0; /* * Global data (Object records limited to 512 bytes by VAX-11 "C" runtime) */ -static int VMS_Object_File_FD; /* File Descriptor for object file */ +static int VMS_Object_File_FD; /* File Descriptor for object file */ static char Object_Record_Buffer[512]; /* Buffer for object file records */ -static int Object_Record_Offset;/* Offset to end of data */ +static size_t Object_Record_Offset; /* Offset to end of data */ static int Current_Object_Record_Type; /* Type of record in above */ /* * Macros for moving data around. Must work on big-endian systems. */ -#ifdef HO_VMS /* These are more efficient for VMS->VMS systems */ -#define COPY_LONG(dest,val) {*(long *) dest = val; } -#define COPY_SHORT(dest,val) {*(short *) dest = val; } +#ifdef VMS /* These are more efficient for VMS->VMS systems */ +#define COPY_LONG(dest,val) ( *(long *) (dest) = (val) ) +#define COPY_SHORT(dest,val) ( *(short *) (dest) = (val) ) #else -#define COPY_LONG(dest,val) { md_number_to_chars(dest, val, 4); } -#define COPY_SHORT(dest,val) { md_number_to_chars(dest, val, 2); } +#define COPY_LONG(dest,val) md_number_to_chars ((dest), (val), 4) +#define COPY_SHORT(dest,val) md_number_to_chars ((dest), (val), 2) #endif /* - * Macros for placing data into the object record buffer + * Macros for placing data into the object record buffer. */ +#define PUT_LONG(val) \ + ( COPY_LONG (&Object_Record_Buffer[Object_Record_Offset], (val)), \ + Object_Record_Offset += 4 ) -#define PUT_LONG(val) \ -{ md_number_to_chars(Object_Record_Buffer + \ - Object_Record_Offset, val, 4); \ - Object_Record_Offset += 4; } - -#define PUT_SHORT(val) \ -{ md_number_to_chars(Object_Record_Buffer + \ - Object_Record_Offset, val, 2); \ - Object_Record_Offset += 2; } +#define PUT_SHORT(val) \ + ( COPY_SHORT (&Object_Record_Buffer[Object_Record_Offset], (val)), \ + Object_Record_Offset += 2 ) -#define PUT_CHAR(val) Object_Record_Buffer[Object_Record_Offset++] = val +#define PUT_CHAR(val) ( Object_Record_Buffer[Object_Record_Offset++] = (val) ) -#define PUT_COUNTED_STRING(cp) {\ - register char *p = cp; \ - PUT_CHAR(strlen(p)); \ - while (*p) PUT_CHAR(*p++);} +#define PUT_COUNTED_STRING(cp) do { \ + register const char *p = (cp); \ + PUT_CHAR ((char) strlen (p)); \ + while (*p) PUT_CHAR (*p++); } while (0) /* * Macro for determining if a Name has psect attributes attached * to it. */ -#define PSECT_ATTRIBUTES_STRING "$$PsectAttributes_" -#define PSECT_ATTRIBUTES_STRING_LENGTH 18 +#define PSECT_ATTRIBUTES_STRING "$$PsectAttributes_" +#define PSECT_ATTRIBUTES_STRING_LENGTH 18 -#define HAS_PSECT_ATTRIBUTES(Name) \ - (strncmp((Name[0] == '_' ? Name + 1 : Name), \ - PSECT_ATTRIBUTES_STRING, \ - PSECT_ATTRIBUTES_STRING_LENGTH) == 0) +#define HAS_PSECT_ATTRIBUTES(Name) \ + (strncmp ((*Name == '_' ? Name + 1 : Name), \ + PSECT_ATTRIBUTES_STRING, \ + PSECT_ATTRIBUTES_STRING_LENGTH) == 0) /* in: segT out: N_TYPE bits */ @@ -315,19 +343,167 @@ const segT N_TYPE_seg[N_TYPE + 2] = }; +/* Local support routines which return a value. */ + +static struct input_file *find_file + PARAMS ((symbolS *)); +static struct VMS_DBG_Symbol *find_symbol + PARAMS ((int)); +static symbolS *Define_Routine + PARAMS ((symbolS *, int, symbolS *, int)); + +static char *cvt_integer + PARAMS ((char *, int *)); +static char *fix_name + PARAMS ((char *)); +static char *get_struct_name + PARAMS ((char *)); + +static offsetT VMS_Initialized_Data_Size + PARAMS ((symbolS *, unsigned)); + +static int VMS_TBT_Source_File + PARAMS ((char *, int)); +static int gen1 + PARAMS ((struct VMS_DBG_Symbol *, int)); +static int forward_reference + PARAMS ((char *)); +static int final_forward_reference + PARAMS ((struct VMS_DBG_Symbol *)); +static int VMS_typedef_parse + PARAMS ((char *)); +static int hash_string + PARAMS ((const char *)); +static int VMS_Psect_Spec + PARAMS ((const char *, int, enum ps_type, struct VMS_Symbol *)); + +/* Local support routines which don't directly return any value. */ + +static void s_const + PARAMS ((int)); +static void Create_VMS_Object_File + PARAMS ((void)); +static void Flush_VMS_Object_Record_Buffer + PARAMS ((void)); +static void Set_VMS_Object_File_Record + PARAMS ((int)); +static void Close_VMS_Object_File + PARAMS ((void)); +static void vms_tir_stack_psect + PARAMS ((int, int, int)); +static void VMS_Store_Immediate_Data + PARAMS ((const char *, int, int)); +static void VMS_Set_Data + PARAMS ((int, int, int, int)); +static void VMS_Store_Struct + PARAMS ((int)); +static void VMS_Def_Struct + PARAMS ((int)); +static void VMS_Set_Struct + PARAMS ((int)); +static void VMS_TBT_Module_Begin + PARAMS ((void)); +static void VMS_TBT_Module_End + PARAMS ((void)); +static void VMS_TBT_Routine_Begin + PARAMS ((symbolS *, int)); +static void VMS_TBT_Routine_End + PARAMS ((int, symbolS *)); +static void VMS_TBT_Block_Begin + PARAMS ((symbolS *, int, char *)); +static void VMS_TBT_Block_End + PARAMS ((valueT)); +static void VMS_TBT_Line_PC_Correlation + PARAMS ((int, int, int, int)); +static void VMS_TBT_Source_Lines + PARAMS ((int, int, int)); +static void fpush + PARAMS ((int, int)); +static void rpush + PARAMS ((int, int)); +static void array_suffix + PARAMS ((struct VMS_DBG_Symbol *)); +static void new_forward_ref + PARAMS ((int)); +static void generate_suffix + PARAMS ((struct VMS_DBG_Symbol *, int)); +static void bitfield_suffix + PARAMS ((struct VMS_DBG_Symbol *, int)); +static void setup_basic_type + PARAMS ((struct VMS_DBG_Symbol *)); +static void VMS_DBG_record + PARAMS ((struct VMS_DBG_Symbol *, int, int, char *)); +static void VMS_local_stab_Parse + PARAMS ((symbolS *)); +static void VMS_stab_parse + PARAMS ((symbolS *, int, int, int, int)); +static void VMS_GSYM_Parse + PARAMS ((symbolS *, int)); +static void VMS_LCSYM_Parse + PARAMS ((symbolS *, int)); +static void VMS_STSYM_Parse + PARAMS ((symbolS *, int)); +static void VMS_RSYM_Parse + PARAMS ((symbolS *, symbolS *, int)); +static void VMS_LSYM_Parse + PARAMS ((void)); +static void Define_Local_Symbols + PARAMS ((symbolS *, symbolS *, symbolS *, int)); +static void Write_VMS_MHD_Records + PARAMS ((void)); +static void Write_VMS_EOM_Record + PARAMS ((int, valueT)); +static void VMS_Case_Hack_Symbol + PARAMS ((const char *, char *)); +static void VMS_Modify_Psect_Attributes + PARAMS ((const char *, int *)); +static void VMS_Global_Symbol_Spec + PARAMS ((const char *, int, int, int)); +static void VMS_Local_Environment_Setup + PARAMS ((const char *)); +static void VMS_Emit_Globalvalues + PARAMS ((unsigned, unsigned, char *)); +static void VMS_Procedure_Entry_Pt + PARAMS ((char *, int, int, int)); +static void VMS_Set_Psect + PARAMS ((int, int, int)); +static void VMS_Store_Repeated_Data + PARAMS ((int, char *, int, int)); +static void VMS_Store_PIC_Symbol_Reference + PARAMS ((symbolS *, int, int, int, int, int)); +static void VMS_Fix_Indirect_Reference + PARAMS ((int, addressT, fragS *, fragS *)); + +/* Support code which used to be inline within vms_write_object_file. */ +static void vms_fixup_text_section + PARAMS ((unsigned, struct frag *, struct frag *)); +static void synthesize_data_segment + PARAMS ((unsigned, unsigned, struct frag *)); +static void vms_fixup_data_section + PARAMS ((unsigned, unsigned)); +static void global_symbol_directory + PARAMS ((unsigned, unsigned)); +static void local_symbols_DST + PARAMS ((symbolS *, symbolS *)); +static void vms_build_DST + PARAMS ((unsigned)); +static void vms_fixup_xtors_section + PARAMS ((struct VMS_Symbol *, int)); + + /* The following code defines the special types of pseudo-ops that we - * use with VMS. - */ + use with VMS. */ -char const_flag = 0; +unsigned char const_flag = IN_DEFAULT_SECTION; -void -s_const () +static void +s_const (arg) + int arg; /* 3rd field from obj_pseudo_table[]; not needed here */ { - register int temp; - - temp = get_absolute_expression (); - subseg_set (SEG_DATA, (subsegT) temp); + /* Since we don't need `arg', use it as our scratch variable so that + we won't get any "not used" warnings about it. */ + arg = get_absolute_expression (); + subseg_set (SEG_DATA, (subsegT) arg); const_flag = 1; demand_empty_rest_of_line (); } @@ -338,6 +514,8 @@ const pseudo_typeS obj_pseudo_table[] = {0, 0, 0}, }; /* obj_pseudo_table */ +/* Routine to perform RESOLVE_SYMBOL_REDEFINITION(). */ + int vms_resolve_symbol_redef (sym) symbolS *sym; @@ -346,10 +524,10 @@ vms_resolve_symbol_redef (sym) * If the new symbol is .comm AND it has a size of zero, * we ignore it (i.e. the old symbol overrides it) */ - if ((SEGMENT_TO_SYMBOL_TYPE ((int) now_seg) == (N_UNDF | N_EXT)) && - ((obstack_next_free (&frags) - frag_now->fr_literal) == 0)) + if (SEGMENT_TO_SYMBOL_TYPE ((int) now_seg) == (N_UNDF | N_EXT) + && frag_now_fix () == 0) { - as_warn ("compiler emitted zero-size common symbol `%s' already defined", + as_warn (_("compiler emitted zero-size common symbol `%s' already defined"), S_GET_NAME (sym)); return 1; } @@ -357,29 +535,61 @@ vms_resolve_symbol_redef (sym) * If the old symbol is .comm and it has a size of zero, * we override it with the new symbol value. */ - if (S_IS_EXTERNAL(sym) && S_IS_DEFINED(sym) - && (S_GET_VALUE(sym) == 0)) + if (S_IS_EXTERNAL (sym) && S_IS_DEFINED (sym) && S_GET_VALUE (sym) == 0) { - as_warn ("compiler redefined zero-size common symbol `%s'", + as_warn (_("compiler redefined zero-size common symbol `%s'"), S_GET_NAME (sym)); sym->sy_frag = frag_now; - S_GET_OTHER(sym) = const_flag; - S_SET_VALUE(sym, obstack_next_free(& frags) - frag_now->fr_literal); + S_SET_OTHER (sym, const_flag); + S_SET_VALUE (sym, frag_now_fix ()); /* Keep N_EXT bit. */ - sym->sy_symbol.n_type |= SEGMENT_TO_SYMBOL_TYPE((int) now_seg); + sym->sy_symbol.n_type |= SEGMENT_TO_SYMBOL_TYPE ((int) now_seg); return 1; } return 0; } +/* `tc_frob_label' handler for colon(symbols.c), used to examine the + dummy label(s) gcc inserts at the beginning of each file it generates. + gcc 1.x put "gcc_compiled."; gcc 2.x (as of 2.7) puts "gcc2_compiled." + and "__gnu_language_" and possibly "__vax__doubles". */ + +void +vms_check_for_special_label (symbolP) +symbolS *symbolP; +{ + /* Special labels only occur prior to explicit section directives. */ + if ((const_flag & IN_DEFAULT_SECTION) != 0) + { + char *sym_name = S_GET_NAME (symbolP); + + if (*sym_name == '_') + ++sym_name; + + if (!strcmp (sym_name, "__vax_g_doubles")) + vax_g_doubles = 1; +#if 0 /* not necessary */ + else if (!strcmp (sym_name, "__vax_d_doubles")) + vax_g_doubles = 0; +#endif +#if 0 /* these are potential alternatives to tc-vax.c's md_parse_options() */ + else if (!strcmp (sym_name, "gcc_compiled.")) + flag_one = 1; + else if (!strcmp (sym_name, "__gnu_language_cplusplus")) + flag_hash_long_names = 1; +#endif + } + return; +} -void +void obj_read_begin_hook () { + return; } -void +void obj_crawl_symbol_chain (headers) object_headers *headers; { @@ -387,347 +597,305 @@ obj_crawl_symbol_chain (headers) symbolS **symbolPP; int symbol_number = 0; - { /* crawl symbol table */ - register int symbol_number = 0; - + symbolPP = &symbol_rootP; /* -> last symbol chain link. */ + while ((symbolP = *symbolPP) != NULL) { - symbolPP = &symbol_rootP; /* -> last symbol chain link. */ - while ((symbolP = *symbolPP) != NULL) + resolve_symbol_value (symbolP); + + /* OK, here is how we decide which symbols go out into the + brave new symtab. Symbols that do are: + + * symbols with no name (stabd's?) + * symbols with debug info in their N_TYPE + * symbols with \1 as their 3rd character (numeric labels) + * "local labels" needed for PIC fixups + + Symbols that don't are: + * symbols that are registers + + All other symbols are output. We complain if a deleted + symbol was marked external. */ + + if (!S_IS_REGISTER (symbolP)) { - resolve_symbol_value (symbolP); - - /* OK, here is how we decide which symbols go out into the - brave new symtab. Symbols that do are: - - * symbols with no name (stabd's?) - * symbols with debug info in their N_TYPE - - Symbols that don't are: - * symbols that are registers - * symbols with \1 as their 3rd character (numeric labels) - * "local labels" as defined by S_LOCAL_NAME(name) - if the -L switch was passed to gas. - - All other symbols are output. We complain if a deleted - symbol was marked external. */ - - - if (!S_IS_REGISTER (symbolP)) - { - symbolP->sy_name_offset = 0; - symbolPP = &(symbol_next (symbolP)); - } - else + symbolP->sy_number = symbol_number++; + symbolP->sy_name_offset = 0; + symbolPP = &symbolP->sy_next; + } + else + { + if (S_IS_EXTERNAL (symbolP) || !S_IS_DEFINED (symbolP)) { - if (S_IS_EXTERNAL (symbolP) || !S_IS_DEFINED (symbolP)) - { - as_bad ("Local symbol %s never defined", S_GET_NAME (symbolP)); - } /* oops. */ + as_bad (_("Local symbol %s never defined"), S_GET_NAME (symbolP)); + } /* oops. */ - } /* if this symbol should be in the output */ - } /* for each symbol */ - } - H_SET_STRING_SIZE (headers, string_byte_count); - H_SET_SYMBOL_TABLE_SIZE (headers, symbol_number); - } /* crawl symbol table */ + /* Unhook it from the chain. */ + *symbolPP = symbol_next (symbolP); + } /* if this symbol should be in the output */ + } /* for each symbol */ + + H_SET_STRING_SIZE (headers, string_byte_count); + H_SET_SYMBOL_TABLE_SIZE (headers, symbol_number); } /* obj_crawl_symbol_chain() */ /****** VMS OBJECT FILE HACKING ROUTINES *******/ +/* Create the VMS object file. */ -/* - * Create the VMS object file - */ -static +static void Create_VMS_Object_File () { -#if defined(eunice) || !defined(HO_VMS) +#ifdef eunice VMS_Object_File_FD = creat (out_file_name, 0777, "var"); -#else /* eunice */ - VMS_Object_File_FD = creat (out_file_name, 0, "rfm=var", - "mbc=16", "deq=64", "fop=tef", "shr=nil"); -#endif /* eunice */ - /* - * Deal with errors - */ +#else +#ifndef VMS + VMS_Object_File_FD = creat (out_file_name, 0777); +#else /* VMS */ + VMS_Object_File_FD = creat (out_file_name, 0, "rfm=var", + "ctx=bin", "mbc=16", "deq=64", "fop=tef", + "shr=nil"); +#endif /* !VMS */ +#endif /* !eunice */ + /* Deal with errors. */ if (VMS_Object_File_FD < 0) - { - char Error_Line[256]; - - sprintf (Error_Line, "Couldn't create VMS object file \"%s\"", - out_file_name); - error (Error_Line); - } - /* - * Initialize object file hacking variables - */ + as_fatal (_("Couldn't create VMS object file \"%s\""), out_file_name); + /* Initialize object file hacking variables. */ Object_Record_Offset = 0; Current_Object_Record_Type = -1; } - -/* - * Flush the object record buffer to the object file - */ -static +/* Flush the object record buffer to the object file. */ + +static void Flush_VMS_Object_Record_Buffer () { - int i; - short int zero; - int RecLen; - /* - * If the buffer is empty, we are done - */ + /* If the buffer is empty, there's nothing to do. */ if (Object_Record_Offset == 0) return; - /* - * Write the data to the file - */ -#ifndef HO_VMS /* For cross-assembly purposes. */ - md_number_to_chars((char *) &RecLen, Object_Record_Offset, 2); - i = write (VMS_Object_File_FD, &RecLen, 2); -#endif /* not HO_VMS */ - i = write (VMS_Object_File_FD, - Object_Record_Buffer, - Object_Record_Offset); - if (i != Object_Record_Offset) - error ("I/O error writing VMS object file"); -#ifndef HO_VMS /* When cross-assembling, we need to pad the record to an even - number of bytes. */ - /* pad it if needed */ - zero = 0; - if (Object_Record_Offset & 1 != 0) - write (VMS_Object_File_FD, &zero, 1); -#endif /* not HO_VMS */ - /* - * The buffer is now empty - */ + +#ifndef VMS /* For cross-assembly purposes. */ + { + char RecLen[2]; + + /* "Variable-length record" files have a two byte length field + prepended to each record. It's normally out-of-band, and native + VMS output will insert it automatically for this type of file. + When cross-assembling, we must write it explicitly. */ + md_number_to_chars (RecLen, Object_Record_Offset, 2); + if (write (VMS_Object_File_FD, RecLen, 2) != 2) + error (_("I/O error writing VMS object file (length prefix)")); + /* We also need to force the actual record to be an even number of + bytes. For native output, that's automatic; when cross-assembling, + pad with a NUL byte if length is odd. Do so _after_ writing the + pre-padded length. Since our buffer is defined with even size, + an odd offset implies that it has some room left. */ + if ((Object_Record_Offset & 1) != 0) + Object_Record_Buffer[Object_Record_Offset++] = '\0'; + } +#endif /* not VMS */ + + /* Write the data to the file. */ + if ((size_t) write (VMS_Object_File_FD, Object_Record_Buffer, + Object_Record_Offset) != Object_Record_Offset) + error (_("I/O error writing VMS object file")); + + /* The buffer is now empty. */ Object_Record_Offset = 0; } - -/* - * Declare a particular type of object file record - */ -static +/* Declare a particular type of object file record. */ + +static void Set_VMS_Object_File_Record (Type) int Type; { - /* - * If the type matches, we are done - */ + /* If the type matches, we are done. */ if (Type == Current_Object_Record_Type) return; - /* - * Otherwise: flush the buffer - */ + /* Otherwise: flush the buffer. */ Flush_VMS_Object_Record_Buffer (); - /* - * Set the new type - */ + /* Remember the new type. */ Current_Object_Record_Type = Type; } - +/* Close the VMS Object file. */ -/* - * Close the VMS Object file - */ -static +static void Close_VMS_Object_File () { - short int m_one = -1; -#ifndef HO_VMS /* For cross-assembly purposes. */ -/* Write a 0xffff into the file, which means "End of File" */ - write (VMS_Object_File_FD, &m_one, 2); -#endif /* not HO_VMS */ + /* Flush (should never be necessary) and reset saved record-type context. */ + Set_VMS_Object_File_Record (-1); + +#ifndef VMS /* For cross-assembly purposes. */ + { + char RecLen[2]; + int minus_one = -1; + + /* Write a 2 byte record-length field of -1 into the file, which + means end-of-block when read, hence end-of-file when occurring + in the file's last block. It is only needed for variable-length + record files transferred to VMS as fixed-length record files + (typical for binary FTP; NFS shouldn't need it, but it won't hurt). */ + md_number_to_chars (RecLen, minus_one, 2); + write (VMS_Object_File_FD, RecLen, 2); + } +#else + /* When written on a VMS system, the file header (cf inode) will record + the actual end-of-file position and no inline marker is needed. */ +#endif + close (VMS_Object_File_FD); } -/* - * Store immediate data in current Psect - */ -static + /****** Text Information and Relocation routines ******/ + +/* Stack Psect base followed by signed, varying-sized offset. + Common to several object records. */ + +static void +vms_tir_stack_psect (Psect_Index, Offset, Force) + int Psect_Index; + int Offset; + int Force; +{ + int psect_width, offset_width; + + psect_width = ((unsigned) Psect_Index > 255) ? 2 : 1; + offset_width = (Force || Offset > 32767 || Offset < -32768) ? 4 + : (Offset > 127 || Offset < -128) ? 2 : 1; +#define Sta_P(p,o) (((o)<<1) | ((p)-1)) + /* byte or word psect; byte, word, or longword offset */ + switch (Sta_P(psect_width,offset_width)) + { + case Sta_P(1,1): PUT_CHAR (TIR_S_C_STA_PB); + PUT_CHAR ((char) (unsigned char) Psect_Index); + PUT_CHAR ((char) Offset); + break; + case Sta_P(1,2): PUT_CHAR (TIR_S_C_STA_PW); + PUT_CHAR ((char) (unsigned char) Psect_Index); + PUT_SHORT (Offset); + break; + case Sta_P(1,4): PUT_CHAR (TIR_S_C_STA_PL); + PUT_CHAR ((char) (unsigned char) Psect_Index); + PUT_LONG (Offset); + break; + case Sta_P(2,1): PUT_CHAR (TIR_S_C_STA_WPB); + PUT_SHORT (Psect_Index); + PUT_CHAR ((char) Offset); + break; + case Sta_P(2,2): PUT_CHAR (TIR_S_C_STA_WPW); + PUT_SHORT (Psect_Index); + PUT_SHORT (Offset); + break; + case Sta_P(2,4): PUT_CHAR (TIR_S_C_STA_WPL); + PUT_SHORT (Psect_Index); + PUT_LONG (Offset); + break; + } +#undef Sta_P +} + +/* Store immediate data in current Psect. */ + +static void VMS_Store_Immediate_Data (Pointer, Size, Record_Type) - CONST char *Pointer; + const char *Pointer; int Size; int Record_Type; { register int i; - /* - * We are writing a "Record_Type" record - */ Set_VMS_Object_File_Record (Record_Type); - /* - * We can only store 128 bytes at a time - */ + /* We can only store as most 128 bytes at a time due to the way that + TIR commands are encoded. */ while (Size > 0) { - /* - * Store a maximum of 128 bytes - */ i = (Size > 128) ? 128 : Size; Size -= i; - /* - * If we cannot accommodate this record, flush the - * buffer. - */ - if ((Object_Record_Offset + i + 1) >= - sizeof (Object_Record_Buffer)) + /* If we cannot accommodate this record, flush the buffer. */ + if ((Object_Record_Offset + i + 1) >= sizeof Object_Record_Buffer) Flush_VMS_Object_Record_Buffer (); - /* - * If the buffer is empty we must insert record type - */ + /* If the buffer is empty we must insert record type. */ if (Object_Record_Offset == 0) PUT_CHAR (Record_Type); - /* - * Store the count - */ - PUT_CHAR (-i & 0xff); - /* - * Store the data - */ + /* Store the count. The Store Immediate TIR command is implied by + a negative command byte, and the length of the immediate data + is abs(command_byte). So, we write the negated length value. */ + PUT_CHAR ((char) (-i & 0xff)); + /* Now store the data. */ while (--i >= 0) PUT_CHAR (*Pointer++); - /* - * Flush the buffer if it is more than 75% full - */ - if (Object_Record_Offset > - (sizeof (Object_Record_Buffer) * 3 / 4)) - Flush_VMS_Object_Record_Buffer (); } + /* Flush the buffer if it is more than 75% full. */ + if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4)) + Flush_VMS_Object_Record_Buffer (); } -/* - * Make a data reference - */ -static +/* Make a data reference. */ + +static void VMS_Set_Data (Psect_Index, Offset, Record_Type, Force) int Psect_Index; int Offset; int Record_Type; int Force; { - /* - * We are writing a "Record_Type" record - */ Set_VMS_Object_File_Record (Record_Type); - /* - * If the buffer is empty we must insert the record type - */ + /* If the buffer is empty we must insert the record type. */ if (Object_Record_Offset == 0) PUT_CHAR (Record_Type); - /* - * Stack the Psect base + Longword Offset - */ - if (Force == 1) - { - if (Psect_Index > 127) - { - PUT_CHAR (TIR_S_C_STA_WPL); - PUT_SHORT (Psect_Index); - PUT_LONG (Offset); - } - else - { - PUT_CHAR (TIR_S_C_STA_PL); - PUT_CHAR (Psect_Index); - PUT_LONG (Offset); - } - } - else - { - if (Offset > 32767) - { - PUT_CHAR (TIR_S_C_STA_WPL); - PUT_SHORT (Psect_Index); - PUT_LONG (Offset); - } - else if (Offset > 127) - { - PUT_CHAR (TIR_S_C_STA_WPW); - PUT_SHORT (Psect_Index); - PUT_SHORT (Offset); - } - else - { - PUT_CHAR (TIR_S_C_STA_WPB); - PUT_SHORT (Psect_Index); - PUT_CHAR (Offset); - }; - }; - /* - * Set relocation base - */ + /* Stack the Psect base with its offset. */ + vms_tir_stack_psect (Psect_Index, Offset, Force); + /* Set relocation base. */ PUT_CHAR (TIR_S_C_STO_PIDR); - /* - * Flush the buffer if it is more than 75% full - */ - if (Object_Record_Offset > - (sizeof (Object_Record_Buffer) * 3 / 4)) + /* Flush the buffer if it is more than 75% full. */ + if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4)) Flush_VMS_Object_Record_Buffer (); } -/* - * Make a debugger reference to a struct, union or enum. - */ -static +/* Make a debugger reference to a struct, union or enum. */ + +static void VMS_Store_Struct (Struct_Index) int Struct_Index; { - /* - * We are writing a "OBJ_S_C_DBG" record - */ + /* We are writing a debug record. */ Set_VMS_Object_File_Record (OBJ_S_C_DBG); - /* - * If the buffer is empty we must insert the record type - */ + /* If the buffer is empty we must insert the record type. */ if (Object_Record_Offset == 0) PUT_CHAR (OBJ_S_C_DBG); PUT_CHAR (TIR_S_C_STA_UW); PUT_SHORT (Struct_Index); PUT_CHAR (TIR_S_C_CTL_STKDL); PUT_CHAR (TIR_S_C_STO_L); - /* - * Flush the buffer if it is more than 75% full - */ - if (Object_Record_Offset > - (sizeof (Object_Record_Buffer) * 3 / 4)) + /* Flush the buffer if it is more than 75% full. */ + if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4)) Flush_VMS_Object_Record_Buffer (); } -/* - * Make a debugger reference to partially define a struct, union or enum. - */ -static +/* Make a debugger reference to partially define a struct, union or enum. */ + +static void VMS_Def_Struct (Struct_Index) int Struct_Index; { - /* - * We are writing a "OBJ_S_C_DBG" record - */ + /* We are writing a debug record. */ Set_VMS_Object_File_Record (OBJ_S_C_DBG); - /* - * If the buffer is empty we must insert the record type - */ + /* If the buffer is empty we must insert the record type. */ if (Object_Record_Offset == 0) PUT_CHAR (OBJ_S_C_DBG); PUT_CHAR (TIR_S_C_STA_UW); PUT_SHORT (Struct_Index); PUT_CHAR (TIR_S_C_CTL_DFLOC); - /* - * Flush the buffer if it is more than 75% full - */ - if (Object_Record_Offset > - (sizeof (Object_Record_Buffer) * 3 / 4)) + /* Flush the buffer if it is more than 75% full. */ + if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4)) Flush_VMS_Object_Record_Buffer (); } -static +static void VMS_Set_Struct (Struct_Index) int Struct_Index; { /* see previous functions for comments */ @@ -737,113 +905,65 @@ VMS_Set_Struct (Struct_Index) PUT_CHAR (TIR_S_C_STA_UW); PUT_SHORT (Struct_Index); PUT_CHAR (TIR_S_C_CTL_STLOC); - if (Object_Record_Offset > - (sizeof (Object_Record_Buffer) * 3 / 4)) + if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4)) Flush_VMS_Object_Record_Buffer (); } -/* - * Write the Traceback Module Begin record - */ -static + + /****** Traceback Information routines ******/ + +/* Write the Traceback Module Begin record. */ + +static void VMS_TBT_Module_Begin () { register char *cp, *cp1; int Size; - char Module_Name[256]; char Local[256]; - /* - * Get module name (the FILENAME part of the object file) - */ - cp = out_file_name; - cp1 = Module_Name; - while (*cp) - { - if ((*cp == ']') || (*cp == '>') || - (*cp == ':') || (*cp == '/')) - { - cp1 = Module_Name; - cp++; - continue; - } - *cp1++ = islower (*cp) ? toupper (*cp++) : *cp++; - } - *cp1 = 0; - /* - * Limit it to 31 characters - */ - while (--cp1 >= Module_Name) - if (*cp1 == '.') - *cp1 = 0; - if (strlen (Module_Name) > 31) - { - if (flagseen['+']) - printf ("%s: Module name truncated: %s\n", myname, Module_Name); - Module_Name[31] = 0; - } - /* - * Arrange to store the data locally (leave room for size byte) - */ - cp = Local + 1; - /* - * Begin module - */ + /* Arrange to store the data locally (leave room for size byte). */ + cp = &Local[1]; + /* Begin module. */ *cp++ = DST_S_C_MODBEG; - /* - * Unused - */ - *cp++ = 0; + *cp++ = 0; /* flags; not used */ /* * Language type == "C" + * + * (FIXME: this should be based on the input...) */ COPY_LONG (cp, DST_S_C_C); - cp += sizeof (long); - /* - * Store the module name - */ - *cp++ = strlen (Module_Name); + cp += 4; + /* Store the module name. */ + *cp++ = (char) strlen (Module_Name); cp1 = Module_Name; while (*cp1) *cp++ = *cp1++; - /* - * Now we can store the record size - */ + /* Now we can store the record size. */ Size = (cp - Local); Local[0] = Size - 1; - /* - * Put it into the object record - */ + /* Put it into the object record. */ VMS_Store_Immediate_Data (Local, Size, OBJ_S_C_TBT); } - -/* - * Write the Traceback Module End record -*/ -static +/* Write the Traceback Module End record. */ + +static void VMS_TBT_Module_End () { char Local[2]; - /* - * End module - */ + /* End module. */ Local[0] = 1; Local[1] = DST_S_C_MODEND; - /* - * Put it into the object record - */ + /* Put it into the object record. */ VMS_Store_Immediate_Data (Local, 2, OBJ_S_C_TBT); } - -/* - * Write the Traceback Routine Begin record - */ -static +/* Write a Traceback Routine Begin record. */ + +static void VMS_TBT_Routine_Begin (symbolP, Psect) - struct symbol *symbolP; + symbolS *symbolP; int Psect; { register char *cp, *cp1; @@ -852,54 +972,29 @@ VMS_TBT_Routine_Begin (symbolP, Psect) int Size; char Local[512]; - /* - * Strip the leading "_" from the name - */ + /* Strip the leading "_" from the name. */ Name = S_GET_NAME (symbolP); if (*Name == '_') Name++; - /* - * Get the text psect offset - */ + /* Get the text psect offset. */ Offset = S_GET_VALUE (symbolP); - /* - * Calculate the record size - */ + /* Set the record size. */ Size = 1 + 1 + 4 + 1 + strlen (Name); - /* - * Record Size - */ Local[0] = Size; - /* - * Begin Routine - */ + /* DST type "routine begin". */ Local[1] = DST_S_C_RTNBEG; - /* - * Uses CallS/CallG - */ + /* Uses CallS/CallG. */ Local[2] = 0; - /* - * Store the data so far - */ + /* Store the data so far. */ VMS_Store_Immediate_Data (Local, 3, OBJ_S_C_TBT); - /* - * Make sure we are still generating a OBJ_S_C_TBT record - */ + /* Make sure we are still generating a OBJ_S_C_TBT record. */ if (Object_Record_Offset == 0) PUT_CHAR (OBJ_S_C_TBT); - /* - * Now get the symbol address - */ - PUT_CHAR (TIR_S_C_STA_WPL); - PUT_SHORT (Psect); - PUT_LONG (Offset); - /* - * Store the data reference - */ + /* Stack the address. */ + vms_tir_stack_psect (Psect, Offset, 0); + /* Store the data reference. */ PUT_CHAR (TIR_S_C_STO_PIDR); - /* - * Store the counted string as data - */ + /* Store the counted string as data. */ cp = Local; cp1 = Name; Size = strlen (cp1) + 1; @@ -908,25 +1003,24 @@ VMS_TBT_Routine_Begin (symbolP, Psect) *cp++ = *cp1++; VMS_Store_Immediate_Data (Local, Size, OBJ_S_C_TBT); } - -/* - * Write the Traceback Routine End record - * We *must* search the symbol table to find the next routine, since - * the assember has a way of reassembling the symbol table OUT OF ORDER - * Thus the next routine in the symbol list is not necessarily the - * next one in memory. For debugging to work correctly we must know the - * size of the routine. - */ -static +/* Write a Traceback Routine End record. + + We *must* search the symbol table to find the next routine, since the + assember has a way of reassembling the symbol table OUT OF ORDER Thus + the next routine in the symbol list is not necessarily the next one in + memory. For debugging to work correctly we must know the size of the + routine. */ + +static void VMS_TBT_Routine_End (Max_Size, sp) int Max_Size; symbolS *sp; { symbolS *symbolP; - int Size = 0x7fffffff; + unsigned long Size = 0x7fffffff; char Local[16]; - + valueT sym_value, sp_value = S_GET_VALUE (sp); for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP)) { @@ -934,49 +1028,43 @@ VMS_TBT_Routine_End (Max_Size, sp) { if (*S_GET_NAME (symbolP) == 'L') continue; - if ((S_GET_VALUE (symbolP) > S_GET_VALUE (sp)) && - (S_GET_VALUE (symbolP) < Size)) - Size = S_GET_VALUE (symbolP); + sym_value = S_GET_VALUE (symbolP); + if (sym_value > sp_value && sym_value < Size) + Size = sym_value; + + /* + * Dummy labels like "gcc_compiled." should no longer reach here. + */ +#if 0 + else /* check if gcc_compiled. has size of zero */ - if ((S_GET_VALUE (symbolP) == S_GET_VALUE (sp)) && + if (sym_value == sp_value && sp != symbolP && (!strcmp (S_GET_NAME (sp), "gcc_compiled.") || !strcmp (S_GET_NAME (sp), "gcc2_compiled."))) - Size = S_GET_VALUE (symbolP); - - }; - }; + Size = sym_value; +#endif + } + } if (Size == 0x7fffffff) Size = Max_Size; - Size -= S_GET_VALUE (sp); /* and get the size of the routine */ - /* - * Record Size - */ + Size -= sp_value; /* and get the size of the routine */ + /* Record Size. */ Local[0] = 6; - /* - * End of Routine - */ + /* DST type is "routine end". */ Local[1] = DST_S_C_RTNEND; - /* - * Unused - */ - Local[2] = 0; - /* - * Size of routine - */ + Local[2] = 0; /* unused */ + /* Size of routine. */ COPY_LONG (&Local[3], Size); - /* - * Store the record - */ + /* Store the record. */ VMS_Store_Immediate_Data (Local, 7, OBJ_S_C_TBT); } -/* - * Write the Traceback Block End record - */ -static +/* Write a Traceback Block Begin record. */ + +static void VMS_TBT_Block_Begin (symbolP, Psect, Name) - struct symbol *symbolP; + symbolS *symbolP; int Psect; char *Name; { @@ -984,48 +1072,28 @@ VMS_TBT_Block_Begin (symbolP, Psect, Name) int Offset; int Size; char Local[512]; - /* - * Begin block - */ + + /* Set the record size. */ Size = 1 + 1 + 4 + 1 + strlen (Name); - /* - * Record Size - */ Local[0] = Size; - /* - * Begin Block - We simulate with a phony routine - */ + /* DST type is "begin block"; we simulate with a phony routine. */ Local[1] = DST_S_C_BLKBEG; - /* - * Uses CallS/CallG - */ + /* Uses CallS/CallG. */ Local[2] = 0; - /* - * Store the data so far - */ + /* Store the data so far. */ VMS_Store_Immediate_Data (Local, 3, OBJ_S_C_DBG); - /* - * Make sure we are still generating a OBJ_S_C_DBG record - */ + /* Make sure we are still generating a debug record. */ if (Object_Record_Offset == 0) PUT_CHAR (OBJ_S_C_DBG); - /* - * Now get the symbol address - */ + /* Now get the symbol address. */ PUT_CHAR (TIR_S_C_STA_WPL); PUT_SHORT (Psect); - /* - * Get the text psect offset - */ + /* Get the text psect offset. */ Offset = S_GET_VALUE (symbolP); PUT_LONG (Offset); - /* - * Store the data reference - */ + /* Store the data reference. */ PUT_CHAR (TIR_S_C_STO_PIDR); - /* - * Store the counted string as data - */ + /* Store the counted string as data. */ cp = Local; cp1 = Name; Size = strlen (cp1) + 1; @@ -1034,36 +1102,27 @@ VMS_TBT_Block_Begin (symbolP, Psect, Name) *cp++ = *cp1++; VMS_Store_Immediate_Data (Local, Size, OBJ_S_C_DBG); } - -/* - * Write the Traceback Block End record - */ -static +/* Write a Traceback Block End record. */ + +static void VMS_TBT_Block_End (Size) - int Size; + valueT Size; { char Local[16]; - /* - * End block - simulate with a phony end routine - */ - Local[0] = 6; + Local[0] = 6; /* record length */ + /* DST type is "block end"; simulate with a phony end routine. */ Local[1] = DST_S_C_BLKEND; + Local[2] = 0; /* unused, must be zero */ COPY_LONG (&Local[3], Size); - /* - * Unused - */ - Local[2] = 0; VMS_Store_Immediate_Data (Local, 7, OBJ_S_C_DBG); } +/* Write a Line number <-> Program Counter correlation record. */ -/* - * Write a Line number / PC correlation record - */ -static +static void VMS_TBT_Line_PC_Correlation (Line_Number, Offset, Psect, Do_Delta) int Line_Number; int Offset; @@ -1073,49 +1132,43 @@ VMS_TBT_Line_PC_Correlation (Line_Number, Offset, Psect, Do_Delta) register char *cp; char Local[64]; - /* -* If not delta, set our PC/Line number correlation -*/ if (Do_Delta == 0) { /* - * Size - */ - Local[0] = 1 + 1 + 2 + 1 + 4; - /* - * Line Number/PC correlation - */ - Local[1] = DST_S_C_LINE_NUM; - /* - * Set Line number - */ - Local[2] = DST_S_C_SET_LINE_NUM; - COPY_SHORT (&Local[3], Line_Number - 1); - /* - * Set PC - */ - Local[5] = DST_S_C_SET_ABS_PC; - VMS_Store_Immediate_Data (Local, 6, OBJ_S_C_TBT); - /* - * Make sure we are still generating a OBJ_S_C_TBT record + * If not delta, set our PC/Line number correlation. */ - if (Object_Record_Offset == 0) - PUT_CHAR (OBJ_S_C_TBT); - if (Psect < 255) + cp = &Local[1]; /* Put size in Local[0] later. */ + /* DST type is "Line Number/PC correlation". */ + *cp++ = DST_S_C_LINE_NUM; + /* Set Line number. */ + if (Line_Number - 1 <= 255) { - PUT_CHAR (TIR_S_C_STA_PL); - PUT_CHAR (Psect); + *cp++ = DST_S_C_SET_LINUM_B; + *cp++ = (char) (Line_Number - 1); + } + else if (Line_Number - 1 <= 65535) + { + *cp++ = DST_S_C_SET_LINE_NUM; + COPY_SHORT (cp, Line_Number - 1), cp += 2; } else { - PUT_CHAR (TIR_S_C_STA_WPL); - PUT_SHORT (Psect); + *cp++ = DST_S_C_SET_LINUM_L; + COPY_LONG (cp, Line_Number - 1), cp += 4; } - PUT_LONG (Offset); + /* Set PC. */ + *cp++ = DST_S_C_SET_ABS_PC; + /* Store size now that we know it, then output the data. */ + Local[0] = cp - &Local[1]; + /* Account for the space that TIR_S_C_STO_PIDR will use for the PC. */ + Local[0] += 4; /* size includes length of another longword */ + VMS_Store_Immediate_Data (Local, cp - Local, OBJ_S_C_TBT); + /* Make sure we are still generating a OBJ_S_C_TBT record. */ + if (Object_Record_Offset == 0) + PUT_CHAR (OBJ_S_C_TBT); + vms_tir_stack_psect (Psect, Offset, 0); PUT_CHAR (TIR_S_C_STO_PIDR); - /* - * Do a PC offset of 0 to register the line number - */ + /* Do a PC offset of 0 to register the line number. */ Local[0] = 2; Local[1] = DST_S_C_LINE_NUM; Local[2] = 0; /* Increment PC by 0 and register line # */ @@ -1123,41 +1176,40 @@ VMS_TBT_Line_PC_Correlation (Line_Number, Offset, Psect, Do_Delta) } else { - /* - * If Delta is negative, terminate the line numbers - */ if (Do_Delta < 0) { + /* + * When delta is negative, terminate the line numbers. + */ Local[0] = 1 + 1 + 4; Local[1] = DST_S_C_LINE_NUM; Local[2] = DST_S_C_TERM_L; COPY_LONG (&Local[3], Offset); VMS_Store_Immediate_Data (Local, 7, OBJ_S_C_TBT); - /* - * Done - */ return; } /* - * Do a PC/Line delta + * Do a PC/Line delta. */ - cp = Local + 1; + cp = &Local[1]; *cp++ = DST_S_C_LINE_NUM; if (Line_Number > 1) { - /* - * We need to increment the line number - */ + /* We need to increment the line number. */ if (Line_Number - 1 <= 255) { *cp++ = DST_S_C_INCR_LINUM; *cp++ = Line_Number - 1; } - else + else if (Line_Number - 1 <= 65535) { *cp++ = DST_S_C_INCR_LINUM_W; - COPY_SHORT (cp, Line_Number - 1); - cp += sizeof (short); + COPY_SHORT (cp, Line_Number - 1), cp += 2; + } + else + { + *cp++ = DST_S_C_INCR_LINUM_L; + COPY_LONG (cp, Line_Number - 1), cp += 4; } } /* @@ -1165,279 +1217,223 @@ VMS_TBT_Line_PC_Correlation (Line_Number, Offset, Psect, Do_Delta) */ if (Offset <= 128) { - *cp++ = -Offset; + /* Small offsets are encoded as negative numbers, rather than the + usual non-negative type code followed by another data field. */ + *cp++ = (char) -Offset; + } + else if (Offset <= 65535) + { + *cp++ = DST_S_C_DELTA_PC_W; + COPY_SHORT (cp, Offset), cp += 2; } else { - if (Offset < 0x10000) - { - *cp++ = DST_S_C_DELTA_PC_W; - COPY_SHORT (cp, Offset); - cp += sizeof (short); - } - else - { - *cp++ = DST_S_C_DELTA_PC_L; - COPY_LONG (cp, Offset); - cp += sizeof (long); - } + *cp++ = DST_S_C_DELTA_PC_L; + COPY_LONG (cp, Offset), cp += 4; } - Local[0] = cp - (Local + 1); + /* Set size now that be know it, then output the data. */ + Local[0] = cp - &Local[1]; VMS_Store_Immediate_Data (Local, cp - Local, OBJ_S_C_TBT); } } -/* - * Describe a source file to the debugger - */ -static +/* Describe a source file to the debugger. */ + +static int VMS_TBT_Source_File (Filename, ID_Number) char *Filename; int ID_Number; { - register char *cp, *cp1; - int Status, i; + register char *cp; + int len, rfo, ffb, ebk; + char cdt[8]; char Local[512]; -#ifndef HO_VMS /* Used for cross-assembly */ - i = strlen (Filename); -#else /* HO_VMS */ - static struct FAB Fab; - static struct NAM Nam; - static struct XABDAT Date_Xab; - static struct XABFHC File_Header_Xab; - char Es_String[255], Rs_String[255]; - - /* - * Setup the Fab - */ - Fab.fab$b_bid = FAB$C_BID; - Fab.fab$b_bln = sizeof (Fab); - Fab.fab$l_nam = (&Nam); - Fab.fab$l_xab = (char *) &Date_Xab; - /* - * Setup the Nam block so we can find out the FULL name - * of the source file. - */ - Nam.nam$b_bid = NAM$C_BID; - Nam.nam$b_bln = sizeof (Nam); - Nam.nam$l_rsa = Rs_String; - Nam.nam$b_rss = sizeof (Rs_String); - Nam.nam$l_esa = Es_String; - Nam.nam$b_ess = sizeof (Es_String); - /* - * Setup the Date and File Header Xabs - */ - Date_Xab.xab$b_cod = XAB$C_DAT; - Date_Xab.xab$b_bln = sizeof (Date_Xab); - Date_Xab.xab$l_nxt = (char *) &File_Header_Xab; - File_Header_Xab.xab$b_cod = XAB$C_FHC; - File_Header_Xab.xab$b_bln = sizeof (File_Header_Xab); +#ifdef VMS /* Used for native assembly */ + unsigned Status; + struct FAB fab; /* RMS file access block */ + struct NAM nam; /* file name information */ + struct XABDAT xabdat; /* date+time fields */ + struct XABFHC xabfhc; /* file header characteristics */ + char resultant_string_buffer[255 + 1]; + + /* + * Set up RMS structures: + */ + /* FAB -- file access block */ + memset ((char *) &fab, 0, sizeof fab); + fab.fab$b_bid = FAB$C_BID; + fab.fab$b_bln = (unsigned char) sizeof fab; + fab.fab$l_fna = Filename; + fab.fab$b_fns = (unsigned char) strlen (Filename); + fab.fab$l_nam = (char *) &nam; + fab.fab$l_xab = (char *) &xabdat; + /* NAM -- file name block */ + memset ((char *) &nam, 0, sizeof nam); + nam.nam$b_bid = NAM$C_BID; + nam.nam$b_bln = (unsigned char) sizeof nam; + nam.nam$l_rsa = resultant_string_buffer; + nam.nam$b_rss = (unsigned char) (sizeof resultant_string_buffer - 1); + /* XABs -- extended attributes blocks */ + memset ((char *) &xabdat, 0, sizeof xabdat); + xabdat.xab$b_cod = XAB$C_DAT; + xabdat.xab$b_bln = (unsigned char) sizeof xabdat; + xabdat.xab$l_nxt = (char *) &xabfhc; + memset ((char *) &xabfhc, 0, sizeof xabfhc); + xabfhc.xab$b_cod = XAB$C_FHC; + xabfhc.xab$b_bln = (unsigned char) sizeof xabfhc; + xabfhc.xab$l_nxt = 0; /* * Get the file information */ - Fab.fab$l_fna = Filename; - Fab.fab$b_fns = strlen (Filename); - Status = sys$open (&Fab); + Status = sys$open (&fab); if (!(Status & 1)) { - printf ("gas: Couldn't find source file \"%s\", Error = %%X%x\n", - Filename, Status); - return (0); + as_tsktsk (_("Couldn't find source file \"%s\", status=%%X%x"), + Filename, Status); + return 0; } - sys$close (&Fab); - /* - * Calculate the size of the resultant string - */ - i = Nam.nam$b_rsl; -#endif /* HO_VMS */ - /* - * Size of record - */ - Local[0] = 1 + 1 + 1 + 1 + 1 + 2 + 8 + 4 + 2 + 1 + 1 + i + 1; - /* - * Source declaration - */ - Local[1] = DST_S_C_SOURCE; - /* - * Make formfeeds count as source records - */ - Local[2] = DST_S_C_SRC_FORMFEED; - /* - * Declare source file - */ - Local[3] = DST_S_C_SRC_DECLFILE; - Local[4] = 1 + 2 + 8 + 4 + 2 + 1 + 1 + i + 1; - cp = Local + 5; - /* - * Flags - */ - *cp++ = 0; - /* - * File ID - */ - COPY_SHORT (cp, ID_Number); - cp += sizeof (short); -#ifndef HO_VMS - /* - * Creation Date. Unknown, so we fill with zeroes. - */ - *(long *) cp = 0; - cp += sizeof (long); - *(long *) cp = 0; - cp += sizeof (long); - /* - * End of file block - */ - *(long *) cp = 0; - cp += sizeof (long); - /* - * First free byte - */ - *(short *) cp = 0; - cp += sizeof (short); - /* - * Record format - */ - *cp++ = 0; - /* - * Filename - */ - *cp++ = i; - cp1 = Filename; -#else /* Use this code when assembling for VMS on a VMS system */ - /* - * Creation Date - */ - *(long *) cp = ((long *) &Date_Xab.xab$q_cdt)[0]; - cp += sizeof (long); - *(long *) cp = ((long *) &Date_Xab.xab$q_cdt)[1]; - cp += sizeof (long); - /* - * End of file block - */ - *(long *) cp = File_Header_Xab.xab$l_ebk; - cp += sizeof (long); - /* - * First free byte - */ - *(short *) cp = File_Header_Xab.xab$w_ffb; - cp += sizeof (short); - /* - * Record format - */ - *cp++ = File_Header_Xab.xab$b_rfo; - /* - * Filename - */ - *cp++ = i; - cp1 = Rs_String; -#endif /* HO_VMS */ - while (--i >= 0) - *cp++ = *cp1++; - /* - * Library module name (none) - */ + sys$close (&fab); + /* Now extract fields of interest. */ + memcpy (cdt, (char *) &xabdat.xab$q_cdt, 8); /* creation date */ + ebk = xabfhc.xab$l_ebk; /* end-of-file block */ + ffb = xabfhc.xab$w_ffb; /* first free byte of last block */ + rfo = xabfhc.xab$b_rfo; /* record format */ + len = nam.nam$b_rsl; /* length of Filename */ + resultant_string_buffer[len] = '\0'; + Filename = resultant_string_buffer; /* full filename */ +#else /* Cross-assembly */ + /* [Perhaps we ought to use actual values derived from stat() here?] */ + memset (cdt, 0, 8); /* null VMS quadword binary time */ + ebk = ffb = rfo = 0; + len = strlen (Filename); + if (len > 255) /* a single byte is used as count prefix */ + { + Filename += (len - 255); /* tail end is more significant */ + len = 255; + } +#endif /* VMS */ + + cp = &Local[1]; /* fill in record length later */ + *cp++ = DST_S_C_SOURCE; /* DST type is "source file" */ + *cp++ = DST_S_C_SRC_FORMFEED; /* formfeeds count as source records */ + *cp++ = DST_S_C_SRC_DECLFILE; /* declare source file */ + know (cp == &Local[4]); + *cp++ = 0; /* fill in this length below */ + *cp++ = 0; /* flags; must be zero */ + COPY_SHORT (cp, ID_Number), cp += 2; /* file ID number */ + memcpy (cp, cdt, 8), cp += 8; /* creation date+time */ + COPY_LONG (cp, ebk), cp += 4; /* end-of-file block */ + COPY_SHORT (cp, ffb), cp += 2; /* first free byte of last block */ + *cp++ = (char) rfo; /* RMS record format */ + /* Filename. */ + *cp++ = (char) len; + while (--len >= 0) + *cp++ = *Filename++; + /* Library module name (none). */ *cp++ = 0; - /* - * Done - */ + /* Now that size is known, fill it in and write out the record. */ + Local[4] = cp - &Local[5]; /* source file declaration size */ + Local[0] = cp - &Local[1]; /* TBT record size */ VMS_Store_Immediate_Data (Local, cp - Local, OBJ_S_C_TBT); return 1; } - -/* - * Give the number of source lines to the debugger - */ -static +/* Traceback information is described in terms of lines from compiler + listing files, not lines from source files. We need to set up the + correlation between listing line numbers and source line numbers. + Since gcc's .stabn directives refer to the source lines, we just + need to describe a one-to-one correspondence. */ + +static void VMS_TBT_Source_Lines (ID_Number, Starting_Line_Number, Number_Of_Lines) int ID_Number; int Starting_Line_Number; int Number_Of_Lines; { - char *cp, *cp1; - char Local[16]; - - /* - * Size of record - */ - Local[0] = 1 + 1 + 2 + 1 + 4 + 1 + 2; - /* - * Source declaration - */ - Local[1] = DST_S_C_SOURCE; - /* - * Set Source File - */ - cp = Local + 2; - *cp++ = DST_S_C_SRC_SETFILE; - /* - * File ID Number - */ - COPY_SHORT (cp, ID_Number); - cp += sizeof (short); - /* - * Set record number - */ - *cp++ = DST_S_C_SRC_SETREC_L; - COPY_LONG (cp, Starting_Line_Number); - cp += sizeof (long); - /* - * Define lines - */ + char *cp; + int chunk_limit; + char Local[128]; /* room enough to describe 1310700 lines... */ + + cp = &Local[1]; /* Put size in Local[0] later. */ + *cp++ = DST_S_C_SOURCE; /* DST type is "source file". */ + *cp++ = DST_S_C_SRC_SETFILE; /* Set Source File. */ + COPY_SHORT (cp, ID_Number), cp += 2; /* File ID Number. */ + /* Set record number and define lines. Since no longword form of + SRC_DEFLINES is available, we need to be able to cope with any huge + files a chunk at a time. It doesn't matter for tracebacks, since + unspecified lines are mapped one-to-one and work out right, but it + does matter within the debugger. Without this explicit mapping, + it will complain about lines not existing in the module. */ + chunk_limit = (sizeof Local - 5) / 6; + if (Number_Of_Lines > 65535 * chunk_limit) /* avoid buffer overflow */ + Number_Of_Lines = 65535 * chunk_limit; + while (Number_Of_Lines > 65535) + { + *cp++ = DST_S_C_SRC_SETREC_L; + COPY_LONG (cp, Starting_Line_Number), cp += 4; + *cp++ = DST_S_C_SRC_DEFLINES_W; + COPY_SHORT (cp, 65535), cp += 2; + Starting_Line_Number += 65535; + Number_Of_Lines -= 65535; + } + /* Set record number and define lines, normal case. */ + if (Starting_Line_Number <= 65535) + { + *cp++ = DST_S_C_SRC_SETREC_W; + COPY_SHORT (cp, Starting_Line_Number), cp += 2; + } + else + { + *cp++ = DST_S_C_SRC_SETREC_L; + COPY_LONG (cp, Starting_Line_Number), cp += 4; + } *cp++ = DST_S_C_SRC_DEFLINES_W; - COPY_SHORT (cp, Number_Of_Lines); - cp += sizeof (short); - /* - * Done - */ + COPY_SHORT (cp, Number_Of_Lines), cp += 2; + /* Set size now that be know it, then output the data. */ + Local[0] = cp - &Local[1]; VMS_Store_Immediate_Data (Local, cp - Local, OBJ_S_C_TBT); } + /****** Debugger Information support routines ******/ +/* This routine locates a file in the list of files. If an entry does + not exist, one is created. For include files, a new entry is always + created such that inline functions can be properly debugged. */ -/* This routine locates a file in the list of files. If an entry does not - * exist, one is created. For include files, a new entry is always created - * such that inline functions can be properly debugged. */ static struct input_file * find_file (sp) symbolS *sp; { - struct input_file *same_file; - struct input_file *fpnt; - same_file = (struct input_file *) NULL; + struct input_file *same_file = 0; + struct input_file *fpnt, *last = 0; + char *sp_name; + for (fpnt = file_root; fpnt; fpnt = fpnt->next) { - if (fpnt == (struct input_file *) NULL) - break; if (fpnt->spnt == sp) return fpnt; - }; + last = fpnt; + } + sp_name = S_GET_NAME (sp); for (fpnt = file_root; fpnt; fpnt = fpnt->next) { - if (fpnt == (struct input_file *) NULL) - break; - if (strcmp (S_GET_NAME (sp), fpnt->name) == 0) + if (strcmp (sp_name, fpnt->name) == 0) { if (fpnt->flag == 1) return fpnt; same_file = fpnt; break; - }; - }; - fpnt = (struct input_file *) malloc (sizeof (struct input_file)); - if (file_root == (struct input_file *) NULL) + } + } + fpnt = (struct input_file *) xmalloc (sizeof (struct input_file)); + if (!file_root) file_root = fpnt; else - { - struct input_file *fpnt1; - for (fpnt1 = file_root; fpnt1->next; fpnt1 = fpnt1->next) ; - fpnt1->next = fpnt; - }; - fpnt->next = (struct input_file *) NULL; - fpnt->name = S_GET_NAME (sp); + last->next = fpnt; + fpnt->next = 0; + fpnt->name = sp_name; fpnt->min_line = 0x7fffffff; fpnt->max_line = 0; fpnt->offset = 0; @@ -1447,62 +1443,59 @@ find_file (sp) fpnt->same_file_fpnt = same_file; return fpnt; } - -/* - * The following functions and definitions are used to generate object records - * that will describe program variables to the VMS debugger. - * - * This file contains many of the routines needed to output debugging info into - * the object file that the VMS debugger needs to understand symbols. These - * routines are called very late in the assembly process, and thus we can be - * fairly lax about changing things, since the GSD and the TIR sections have - * already been output. - */ +/* This routine converts a number string into an integer, and stops when + it sees an invalid character. The return value is the address of the + character just past the last character read. No error is generated. */ -/* This routine converts a number string into an integer, and stops when it - * sees an invalid character the return value is the address of the character - * just past the last character read. No error is generated. - */ static char * cvt_integer (str, rtn) char *str; int *rtn; { - int ival, neg; - neg = *str == '-' ? ++str, -1 : 1; - ival = 0; /* first get the number of the type for dbx */ - while ((*str <= '9') && (*str >= '0')) + int ival = 0, sgn = 1; + + if (*str == '-') + sgn = -1, ++str; + while (*str >= '0' && *str <= '9') ival = 10 * ival + *str++ - '0'; - *rtn = neg * ival; + *rtn = sgn * ival; return str; } + -/* this routine fixes the names that are generated by C++, ".this" is a good - * example. The period does not work for the debugger, since it looks like - * the syntax for a structure element, and thus it gets mightily confused +/* + * The following functions and definitions are used to generate object + * records that will describe program variables to the VMS debugger. * - * We also use this to strip the PsectAttribute hack from the name before we - * write a debugger record */ + * This file contains many of the routines needed to output debugging info + * into the object file that the VMS debugger needs to understand symbols. + * These routines are called very late in the assembly process, and thus + * we can be fairly lax about changing things, since the GSD and the TIR + * sections have already been output. + */ + +/* This routine fixes the names that are generated by C++, ".this" is a good + example. The period does not work for the debugger, since it looks like + the syntax for a structure element, and thus it gets mightily confused. + + We also use this to strip the PsectAttribute hack from the name before we + write a debugger record. */ static char * fix_name (pnt) char *pnt; { char *pnt1; - /* - * Kill any leading "_" - */ + + /* Kill any leading "_". */ if (*pnt == '_') pnt++; - /* - * Is there a Psect Attribute to skip?? - */ + + /* Is there a Psect Attribute to skip?? */ if (HAS_PSECT_ATTRIBUTES (pnt)) { - /* - * Yes: Skip it - */ + /* Yes: Skip it. */ pnt += PSECT_ATTRIBUTES_STRING_LENGTH; while (*pnt) { @@ -1514,21 +1507,21 @@ fix_name (pnt) pnt++; } } -/* Here we fix the .this -> $this conversion */ + + /* Here we fix the .this -> $this conversion. */ for (pnt1 = pnt; *pnt1 != 0; pnt1++) - { - if (*pnt1 == '.') - *pnt1 = '$'; - }; + if (*pnt1 == '.') + *pnt1 = '$'; + return pnt; } /* When defining a structure, this routine is called to find the name of - * the actual structure. It is assumed that str points to the equal sign - * in the definition, and it moves backward until it finds the start of the - * name. If it finds a 0, then it knows that this structure def is in the - * outermost level, and thus symbol_name points to the symbol name. - */ + the actual structure. It is assumed that str points to the equal sign + in the definition, and it moves backward until it finds the start of the + name. If it finds a 0, then it knows that this structure def is in the + outermost level, and thus symbol_name points to the symbol name. */ + static char * get_struct_name (str) char *str; @@ -1538,7 +1531,7 @@ get_struct_name (str) while ((*pnt != ':') && (*pnt != '\0')) pnt--; if (*pnt == '\0') - return symbol_name; + return (char *) symbol_name; *pnt-- = '\0'; while ((*pnt != ';') && (*pnt != '=')) pnt--; @@ -1551,48 +1544,46 @@ get_struct_name (str) return pnt; } -/* search symbol list for type number dbx_type. Return a pointer to struct */ +/* Search symbol list for type number dbx_type. + Return a pointer to struct. */ + static struct VMS_DBG_Symbol * find_symbol (dbx_type) int dbx_type; { struct VMS_DBG_Symbol *spnt; - spnt = VMS_Symbol_type_list; - while (spnt != (struct VMS_DBG_Symbol *) NULL) + + spnt = VMS_Symbol_type_list[SYMTYP_HASH (dbx_type)]; + while (spnt) { if (spnt->dbx_type == dbx_type) break; spnt = spnt->next; - }; - if (spnt == (struct VMS_DBG_Symbol *) NULL) - return 0; /*Dunno what this is*/ - if(spnt->advanced == ALIAS) - return find_symbol(spnt->type2); - return spnt; + } + if (!spnt || spnt->advanced != ALIAS) + return spnt; + return find_symbol (spnt->type2); } - +#if 0 /* obsolete */ /* this routine puts info into either Local or Asuffix, depending on the sign * of size. The reason is that it is easier to build the variable descriptor * backwards, while the array descriptor is best built forwards. In the end * they get put together, if there is not a struct/union/enum along the way */ -static -push (value, size) - int value, size; +static void +push (value, size1) + int value, size1; { - int i; - int size1; - size1 = size; - if (size < 0) + if (size1 < 0) { - size1 = -size; + size1 = -size1; if (Lpnt < size1) { overflow = 1; Lpnt = 1; return; - }; + } Lpnt -= size1; md_number_to_chars (&Local[Lpnt + 1], value, size1); } @@ -1603,14 +1594,54 @@ push (value, size) overflow = 1; Apoint = MAX_DEBUG_RECORD - 1; return; - }; + } md_number_to_chars (&Asuffix[Apoint], value, size1); Apoint += size1; - }; + } } +#endif -/* this routine generates the array descriptor for a given array */ -static +static void +fpush (value, size) + int value, size; +{ + if (Apoint + size >= MAX_DEBUG_RECORD) + { + overflow = 1; + Apoint = MAX_DEBUG_RECORD - 1; + return; + } + if (size == 1) + Asuffix[Apoint++] = (char) value; + else + { + md_number_to_chars (&Asuffix[Apoint], value, size); + Apoint += size; + } +} + +static void +rpush (value, size) + int value, size; +{ + if (Lpnt < size) + { + overflow = 1; + Lpnt = 1; + return; + } + if (size == 1) + Local[Lpnt--] = (char) value; + else + { + Lpnt -= size; + md_number_to_chars (&Local[Lpnt + 1], value, size); + } +} + +/* This routine generates the array descriptor for a given array. */ + +static void array_suffix (spnt2) struct VMS_DBG_Symbol *spnt2; { @@ -1618,16 +1649,15 @@ array_suffix (spnt2) struct VMS_DBG_Symbol *spnt1; int rank; int total_size; - int i; + rank = 0; spnt = spnt2; while (spnt->advanced != ARRAY) { spnt = find_symbol (spnt->type2); - if (spnt == (struct VMS_DBG_Symbol *) NULL) + if (!spnt) return; - }; - spnt1 = spnt; + } spnt1 = spnt; total_size = 1; while (spnt1->advanced == ARRAY) @@ -1635,63 +1665,64 @@ array_suffix (spnt2) rank++; total_size *= (spnt1->index_max - spnt1->index_min + 1); spnt1 = find_symbol (spnt1->type2); - }; + } total_size = total_size * spnt1->data_size; - push (spnt1->data_size, 2); - if (spnt1->VMS_type == 0xa3) - push (0, 1); + fpush (spnt1->data_size, 2); /* element size */ + if (spnt1->VMS_type == DBG_S_C_ADVANCED_TYPE) + fpush (0, 1); else - push (spnt1->VMS_type, 1); - push (4, 1); - for (i = 0; i < 6; i++) - push (0, 1); - push (0xc0, 1); - push (rank, 1); - push (total_size, 4); - push (0, 4); + fpush (spnt1->VMS_type, 1); /* element type */ + fpush (DSC_K_CLASS_A, 1); /* descriptor class */ + fpush (0, 4); /* base address */ + fpush (0, 1); /* scale factor -- not applicable */ + fpush (0, 1); /* digit count -- not applicable */ + fpush (0xc0, 1); /* flags: multiplier block & bounds present */ + fpush (rank, 1); /* number of dimensions */ + fpush (total_size, 4); + fpush (0, 4); /* pointer to element [0][0]...[0] */ spnt1 = spnt; while (spnt1->advanced == ARRAY) { - push (spnt1->index_max - spnt1->index_min + 1, 4); + fpush (spnt1->index_max - spnt1->index_min + 1, 4); spnt1 = find_symbol (spnt1->type2); - }; + } spnt1 = spnt; while (spnt1->advanced == ARRAY) { - push (spnt1->index_min, 4); - push (spnt1->index_max, 4); + fpush (spnt1->index_min, 4); + fpush (spnt1->index_max, 4); spnt1 = find_symbol (spnt1->type2); - }; + } } -/* this routine generates the start of a variable descriptor based upon - * a struct/union/enum that has yet to be defined. We define this spot as - * a new location, and save four bytes for the address. When the struct is - * finally defined, then we can go back and plug in the correct address -*/ -static +/* This routine generates the start of a variable descriptor based upon + a struct/union/enum that has yet to be defined. We define this spot as + a new location, and save four bytes for the address. When the struct is + finally defined, then we can go back and plug in the correct address. */ + +static void new_forward_ref (dbx_type) int dbx_type; { struct forward_ref *fpnt; - fpnt = (struct forward_ref *) malloc (sizeof (struct forward_ref)); + fpnt = (struct forward_ref *) xmalloc (sizeof (struct forward_ref)); fpnt->next = f_ref_root; f_ref_root = fpnt; fpnt->dbx_type = dbx_type; fpnt->struc_numb = ++structure_count; fpnt->resolved = 'N'; - push (3, -1); + rpush (DST_K_TS_IND, 1); /* indirect type specification */ total_len = 5; - push (total_len, -2); + rpush (total_len, 2); struct_number = -fpnt->struc_numb; } -/* this routine generates the variable descriptor used to describe non-basic - * variables. It calls itself recursively until it gets to the bottom of it - * all, and then builds the descriptor backwards. It is easiest to do it this - *way since we must periodically write length bytes, and it is easiest if we know - *the value when it is time to write it. - */ +/* This routine generates the variable descriptor used to describe non-basic + variables. It calls itself recursively until it gets to the bottom of it + all, and then builds the descriptor backwards. It is easiest to do it + this way since we must periodically write length bytes, and it is easiest + if we know the value when it is time to write it. */ + static int gen1 (spnt, array_suffix_len) struct VMS_DBG_Symbol *spnt; @@ -1699,25 +1730,27 @@ gen1 (spnt, array_suffix_len) { struct VMS_DBG_Symbol *spnt1; int i; + switch (spnt->advanced) { case VOID: - push (DBG_S_C_VOID, -1); + rpush (DBG_S_C_VOID, 1); total_len += 1; - push (total_len, -2); + rpush (total_len, 2); return 0; case BASIC: case FUNCTION: if (array_suffix_len == 0) { - push (spnt->VMS_type, -1); - push (DBG_S_C_BASIC, -1); + rpush (spnt->VMS_type, 1); + rpush (DBG_S_C_BASIC, 1); total_len = 2; - push (total_len, -2); + rpush (total_len, 2); return 1; - }; - push (0, -4); - push (0xfa02, -2); + } + rpush (0, 4); + rpush (DST_K_VFLAGS_DSC, 1); + rpush (DST_K_TS_DSC, 1); /* descriptor type specification */ total_len = -2; return 1; case STRUCT: @@ -1729,40 +1762,39 @@ gen1 (spnt, array_suffix_len) new_forward_ref (spnt->dbx_type); return 1; } - push (DBG_S_C_STRUCT, -1); + rpush (DBG_S_C_STRUCT, 1); total_len = 5; - push (total_len, -2); + rpush (total_len, 2); return 1; case POINTER: spnt1 = find_symbol (spnt->type2); i = 1; - if (spnt1 == (struct VMS_DBG_Symbol *) NULL) + if (!spnt1) new_forward_ref (spnt->type2); else i = gen1 (spnt1, 0); if (i) - { /* (*void) is a special case, do not put pointer suffix*/ - push (DBG_S_C_POINTER, -1); + { /* (*void) is a special case, do not put pointer suffix */ + rpush (DBG_S_C_POINTER, 1); total_len += 3; - push (total_len, -2); - }; + rpush (total_len, 2); + } return 1; case ARRAY: spnt1 = spnt; while (spnt1->advanced == ARRAY) { spnt1 = find_symbol (spnt1->type2); - if (spnt1 == (struct VMS_DBG_Symbol *) NULL) + if (!spnt1) { - printf ("gcc-as warning(debugger output):"); - printf ("Forward reference error, dbx type %d\n", - spnt->type2); - return; + as_tsktsk (_("debugger forward reference error, dbx type %d"), + spnt->type2); + return 0; } - }; + } /* It is too late to generate forward references, so the user gets a message. * This should only happen on a compiler error */ - i = gen1 (spnt1, 1); + (void) gen1 (spnt1, 1); i = Apoint; array_suffix (spnt); array_suffix_len = Apoint - i; @@ -1772,84 +1804,94 @@ gen1 (spnt, array_suffix_len) case FUNCTION: break; default: - push (0, -2); + rpush (0, 2); total_len += 2; - push (total_len, -2); - push (0xfa, -1); - push (0x0101, -2); - push (DBG_S_C_COMPLEX_ARRAY, -1); - }; + rpush (total_len, 2); + rpush (DST_K_VFLAGS_DSC, 1); + rpush (1, 1); /* flags: element value spec included */ + rpush (1, 1); /* one dimension */ + rpush (DBG_S_C_COMPLEX_ARRAY, 1); + } total_len += array_suffix_len + 8; - push (total_len, -2); - }; + rpush (total_len, 2); + break; + default: /* lint suppression */ + break; + } + return 0; } /* This generates a suffix for a variable. If it is not a defined type yet, - * then dbx_type contains the type we are expecting so we can generate a - * forward reference. This calls gen1 to build most of the descriptor, and - * then it puts the icing on at the end. It then dumps whatever is needed - * to get a complete descriptor (i.e. struct reference, array suffix ). - */ -static + then dbx_type contains the type we are expecting so we can generate a + forward reference. This calls gen1 to build most of the descriptor, and + then it puts the icing on at the end. It then dumps whatever is needed + to get a complete descriptor (i.e. struct reference, array suffix). */ + +static void generate_suffix (spnt, dbx_type) struct VMS_DBG_Symbol *spnt; int dbx_type; { - int ilen; + static const char pvoid[6] = { + 5, /* record.length == 5 */ + DST_K_TYPSPEC, /* record.type == 1 (type specification) */ + 0, /* name.length == 0, no name follows */ + 1, 0, /* type.length == 1 {2 bytes, little endian} */ + DBG_S_C_VOID /* type.type == 5 (pointer to unspecified) */ + }; int i; - static CONST char pvoid[6] = {5, 0xaf, 0, 1, 0, 5}; - struct VMS_DBG_Symbol *spnt1; + Apoint = 0; Lpnt = MAX_DEBUG_RECORD - 1; total_len = 0; struct_number = 0; overflow = 0; - if (spnt == (struct VMS_DBG_Symbol *) NULL) + if (!spnt) new_forward_ref (dbx_type); else { - if (spnt->VMS_type != 0xa3) - return 0; /* no suffix needed */ + if (spnt->VMS_type != DBG_S_C_ADVANCED_TYPE) + return; /* no suffix needed */ gen1 (spnt, 0); - }; - push (0x00af, -2); + } + rpush (0, 1); /* no name (len==0) */ + rpush (DST_K_TYPSPEC, 1); total_len += 4; - push (total_len, -1); -/* if the variable descriptor overflows the record, output a descriptor for - * a pointer to void. - */ + rpush (total_len, 1); + /* If the variable descriptor overflows the record, output a descriptor + for a pointer to void. */ if ((total_len >= MAX_DEBUG_RECORD) || overflow) { - printf (" Variable descriptor %d too complicated. Defined as *void ", spnt->dbx_type); + as_warn (_("Variable descriptor %d too complicated. Defined as `void *'."), + spnt->dbx_type); VMS_Store_Immediate_Data (pvoid, 6, OBJ_S_C_DBG); return; - }; + } i = 0; while (Lpnt < MAX_DEBUG_RECORD - 1) Local[i++] = Local[++Lpnt]; Lpnt = i; -/* we use this for a reference to a structure that has already been defined */ + /* we use this for reference to structure that has already been defined */ if (struct_number > 0) { VMS_Store_Immediate_Data (Local, Lpnt, OBJ_S_C_DBG); Lpnt = 0; VMS_Store_Struct (struct_number); - }; -/* we use this for a forward reference to a structure that has yet to be -*defined. We store four bytes of zero to make room for the actual address once -* it is known -*/ + } + /* We use this for a forward reference to a structure that has yet to + be defined. We store four bytes of zero to make room for the actual + address once it is known. */ if (struct_number < 0) { struct_number = -struct_number; VMS_Store_Immediate_Data (Local, Lpnt, OBJ_S_C_DBG); Lpnt = 0; VMS_Def_Struct (struct_number); - for (i = 0; i < 4; i++) - Local[Lpnt++] = 0; + COPY_LONG (&Local[Lpnt], 0L); + Lpnt += 4; VMS_Store_Immediate_Data (Local, Lpnt, OBJ_S_C_DBG); Lpnt = 0; - }; + } i = 0; while (i < Apoint) Local[Lpnt++] = Asuffix[i++]; @@ -1858,47 +1900,124 @@ generate_suffix (spnt, dbx_type) Lpnt = 0; } -/* This routine generates a symbol definition for a C sybmol for the debugger. - * It takes a psect and offset for global symbols - if psect < 0, then this is - * a local variable and the offset is relative to FP. In this case it can - * be either a variable (Offset < 0) or a parameter (Offset > 0). - */ -static + /* "novel length" type doesn't work for simple atomic types */ +#define USE_BITSTRING_DESCRIPTOR(t) ((t)->advanced == BASIC) +#undef SETUP_BASIC_TYPES + +/* This routine generates a type description for a bitfield. */ + +static void +bitfield_suffix (spnt, width) + struct VMS_DBG_Symbol *spnt; + int width; +{ + Local[Lpnt++] = 13; /* rec.len==13 */ + Local[Lpnt++] = DST_K_TYPSPEC; /* a type specification record */ + Local[Lpnt++] = 0; /* not named */ + COPY_SHORT (&Local[Lpnt], 9); /* typ.len==9 */ + Lpnt += 2; + Local[Lpnt++] = DST_K_TS_NOV_LENG; /* This type is a "novel length" + incarnation of some other type. */ + COPY_LONG (&Local[Lpnt], width); /* size in bits == novel length */ + Lpnt += 4; + VMS_Store_Immediate_Data (Local, Lpnt, OBJ_S_C_DBG); + Lpnt = 0; + /* assert( spnt->struc_numb > 0 ); */ + VMS_Store_Struct (spnt->struc_numb); /* output 4 more bytes */ +} + +/* Formally define a builtin type, so that it can serve as the target of + an indirect reference. It makes bitfield_suffix() easier by avoiding + the need to use a forward reference for the first occurrence of each + type used in a bitfield. */ + +static void +setup_basic_type (spnt) + struct VMS_DBG_Symbol *spnt ATTRIBUTE_UNUSED; +{ +#ifdef SETUP_BASIC_TYPES + /* This would be very useful if "novel length" fields actually worked + with basic types like they do with enumerated types. However, + they do not, so this isn't worth doing just so that you can use + EXAMINE/TYPE=(__long_long_int) instead of EXAMINE/QUAD. */ + char *p; +#ifndef SETUP_SYNONYM_TYPES + /* This determines whether compatible things like `int' and `long int' + ought to have distinct type records rather than sharing one. */ + struct VMS_DBG_Symbol *spnt2; + + /* first check whether this type has already been seen by another name */ + for (spnt2 = VMS_Symbol_type_list[SYMTYP_HASH (spnt->VMS_type)]; + spnt2; + spnt2 = spnt2->next) + if (spnt2 != spnt && spnt2->VMS_type == spnt->VMS_type) + { + spnt->struc_numb = spnt2->struc_numb; + return; + } +#endif + + /* `structure number' doesn't really mean `structure'; it means an index + into a linker maintained set of saved locations which can be referenced + again later. */ + spnt->struc_numb = ++structure_count; + VMS_Def_Struct (spnt->struc_numb); /* remember where this type lives */ + /* define the simple scalar type */ + Local[Lpnt++] = 6 + strlen (symbol_name) + 2; /* rec.len */ + Local[Lpnt++] = DST_K_TYPSPEC; /* rec.typ==type specification */ + Local[Lpnt++] = strlen (symbol_name) + 2; + Local[Lpnt++] = '_'; /* prefix name with "__" */ + Local[Lpnt++] = '_'; + for (p = symbol_name; *p; p++) + Local[Lpnt++] = *p == ' ' ? '_' : *p; + COPY_SHORT (&Local[Lpnt], 2); /* typ.len==2 */ + Lpnt += 2; + Local[Lpnt++] = DST_K_TS_ATOM; /* typ.kind is simple type */ + Local[Lpnt++] = spnt->VMS_type; /* typ.type */ + VMS_Store_Immediate_Data (Local, Lpnt, OBJ_S_C_DBG); + Lpnt = 0; +#endif /* SETUP_BASIC_TYPES */ + return; +} + +/* This routine generates a symbol definition for a C symbol for the debugger. + It takes a psect and offset for global symbols; if psect < 0, then this is + a local variable and the offset is relative to FP. In this case it can + be either a variable (Offset < 0) or a parameter (Offset > 0). */ + +static void VMS_DBG_record (spnt, Psect, Offset, Name) struct VMS_DBG_Symbol *spnt; int Psect; int Offset; char *Name; { - char *pnt; char *Name_pnt; - int j; - int maxlen; + int len; int i = 0; - Name_pnt = fix_name (Name); /* if there are bad characters in name, convert them */ + + /* if there are bad characters in name, convert them */ + Name_pnt = fix_name (Name); + + len = strlen (Name_pnt); if (Psect < 0) { /* this is a local variable, referenced to SP */ - maxlen = 7 + strlen (Name_pnt); - Local[i++] = maxlen; + Local[i++] = 7 + len; Local[i++] = spnt->VMS_type; - if (Offset > 0) - Local[i++] = DBG_S_C_FUNCTION_PARAMETER; - else - Local[i++] = DBG_S_C_LOCAL_SYM; + Local[i++] = (Offset > 0) ? DBG_C_FUNCTION_PARAM : DBG_C_LOCAL_SYM; COPY_LONG (&Local[i], Offset); i += 4; } else { - maxlen = 7 + strlen (Name_pnt); /* symbols fixed in memory */ - Local[i++] = 7 + strlen (Name_pnt); + Local[i++] = 7 + len; Local[i++] = spnt->VMS_type; - Local[i++] = 1; + Local[i++] = DST_K_VALKIND_ADDR; VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG); i = 0; VMS_Set_Data (Psect, Offset, OBJ_S_C_DBG, 0); } - Local[i++] = strlen (Name_pnt); + Local[i++] = len; while (*Name_pnt != '\0') Local[i++] = *Name_pnt++; VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG); @@ -1906,29 +2025,28 @@ VMS_DBG_record (spnt, Psect, Offset, Name) generate_suffix (spnt, 0); } - /* This routine parses the stabs entries in order to make the definition - * for the debugger of local symbols and function parameters - */ -static int + for the debugger of local symbols and function parameters. */ + +static void VMS_local_stab_Parse (sp) symbolS *sp; { + struct VMS_DBG_Symbol *spnt; char *pnt; char *pnt1; char *str; - struct VMS_DBG_Symbol *spnt; - struct VMS_Symbol *vsp; int dbx_type; - int VMS_type; + dbx_type = 0; str = S_GET_NAME (sp); pnt = (char *) strchr (str, ':'); - if (pnt == (char *) NULL) + if (!pnt) return; /* no colon present */ pnt1 = pnt++; /* save this for later, and skip colon */ if (*pnt == 'c') - return 0; /* ignore static constants */ + return; /* ignore static constants */ + /* there is one little catch that we must be aware of. Sometimes function * parameters are optimized into registers, and the compiler, in its infiite * wisdom outputs stabs records for *both*. In general we want to use the @@ -1936,9 +2054,10 @@ VMS_local_stab_Parse (sp) * this function to see if this parameter is assigned to a register. */ { + symbolS *sp1; char *str1; char *pnt2; - symbolS *sp1; + if (*pnt == 'p') { for (sp1 = symbol_next (sp); sp1; sp1 = symbol_next (sp1)) @@ -1947,9 +2066,10 @@ VMS_local_stab_Parse (sp) continue; if (S_GET_RAW_TYPE (sp1) == N_FUN) { - char * pnt3=(char*) strchr (S_GET_NAME (sp1), ':') + 1; - if (*pnt3 == 'F' || *pnt3 == 'f') break; - }; + pnt2 = (char *) strchr (S_GET_NAME (sp1), ':') + 1; + if (*pnt2 == 'F' || *pnt2 == 'f') + break; + } if (S_GET_RAW_TYPE (sp1) != N_RSYM) continue; str1 = S_GET_NAME (sp1); /* and get the name */ @@ -1960,41 +2080,40 @@ VMS_local_stab_Parse (sp) break; pnt2++; str1++; - }; - if ((*str1 != ':') || (*pnt2 != ':')) - continue; - return; /* they are the same! lets skip this one */ - }; /* for */ -/* first find the dbx symbol type from list, and then find VMS type */ + } + if (*str1 == ':' && *pnt2 == ':') + return; /* They are the same! Let's skip this one. */ + } /* for */ pnt++; /* skip p in case no register */ - }; /* if */ - }; /* p block */ + } /* if */ + } /* p block */ + pnt = cvt_integer (pnt, &dbx_type); spnt = find_symbol (dbx_type); - if (spnt == (struct VMS_DBG_Symbol *) NULL) - return 0; /*Dunno what this is*/ + if (!spnt) + return; /*Dunno what this is*/ *pnt1 = '\0'; VMS_DBG_record (spnt, -1, S_GET_VALUE (sp), str); *pnt1 = ':'; /* and restore the string */ - return 1; + return; } -/* This routine parses a stabs entry to find the information required to define - * a variable. It is used for global and static variables. - * Basically we need to know the address of the symbol. With older versions - * of the compiler, const symbols are - * treated differently, in that if they are global they are written into the - * text psect. The global symbol entry for such a const is actually written - * as a program entry point (Yuk!!), so if we cannot find a symbol in the list - * of psects, we must search the entry points as well. static consts are even - * harder, since they are never assigned a memory address. The compiler passes - * a stab to tell us the value, but I am not sure what to do with it. - */ - -static +/* This routine parses a stabs entry to find the information required + to define a variable. It is used for global and static variables. + Basically we need to know the address of the symbol. With older + versions of the compiler, const symbols are treated differently, in + that if they are global they are written into the text psect. The + global symbol entry for such a const is actually written as a program + entry point (Yuk!!), so if we cannot find a symbol in the list of + psects, we must search the entry points as well. static consts are + even harder, since they are never assigned a memory address. The + compiler passes a stab to tell us the value, but I am not sure what + to do with it. */ + +static void VMS_stab_parse (sp, expected_type, type1, type2, Text_Psect) symbolS *sp; - char expected_type; + int expected_type; /* char */ int type1, type2, Text_Psect; { char *pnt; @@ -2004,11 +2123,11 @@ VMS_stab_parse (sp, expected_type, type1, type2, Text_Psect) struct VMS_DBG_Symbol *spnt; struct VMS_Symbol *vsp; int dbx_type; - int VMS_type; + dbx_type = 0; str = S_GET_NAME (sp); pnt = (char *) strchr (str, ':'); - if (pnt == (char *) NULL) + if (!pnt) return; /* no colon present */ pnt1 = pnt; /* save this for later*/ pnt++; @@ -2016,33 +2135,33 @@ VMS_stab_parse (sp, expected_type, type1, type2, Text_Psect) { pnt = cvt_integer (pnt + 1, &dbx_type); spnt = find_symbol (dbx_type); - if (spnt == (struct VMS_DBG_Symbol *) NULL) - return 0; /*Dunno what this is*/ -/* now we need to search the symbol table to find the psect and offset for - * this variable. - */ + if (!spnt) + return; /*Dunno what this is*/ + /* + * Now we need to search the symbol table to find the psect and + * offset for this variable. + */ *pnt1 = '\0'; vsp = VMS_Symbols; - while (vsp != (struct VMS_Symbol *) NULL) + while (vsp) { pnt = S_GET_NAME (vsp->Symbol); - if (pnt != (char *) NULL) - if (*pnt++ == '_') -/* make sure name is the same, and make sure correct symbol type */ - if ((strlen (pnt) == strlen (str)) && (strcmp (pnt, str) == 0) - && ((S_GET_RAW_TYPE (vsp->Symbol) == type1) || - (S_GET_RAW_TYPE (vsp->Symbol) == type2))) - break; + if (pnt && *pnt++ == '_' + /* make sure name is the same and symbol type matches */ + && strcmp (pnt, str) == 0 + && (S_GET_RAW_TYPE (vsp->Symbol) == type1 + || S_GET_RAW_TYPE (vsp->Symbol) == type2)) + break; vsp = vsp->Next; - }; - if (vsp != (struct VMS_Symbol *) NULL) + } + if (vsp) { VMS_DBG_record (spnt, vsp->Psect_Index, vsp->Psect_Offset, str); *pnt1 = ':'; /* and restore the string */ - return 1; - }; -/* the symbol was not in the symbol list, but it may be an "entry point" - if it was a constant */ + return; + } + /* The symbol was not in the symbol list, but it may be an + "entry point" if it was a constant. */ for (sp1 = symbol_rootP; sp1; sp1 = symbol_next (sp1)) { /* @@ -2057,32 +2176,38 @@ VMS_stab_parse (sp, expected_type, type1, type2, Text_Psect) { if (!gave_compiler_message && expected_type == 'G') { - printf ("***Warning - the assembly code generated by the compiler has placed\n"); - printf ("global constant(s) in the text psect. These will not be available to\n"); - printf ("other modules, since this is not the correct way to handle this. You\n"); - printf ("have two options: 1) get a patched compiler that does not put global\n"); - printf ("constants in the text psect, or 2) remove the 'const' keyword from\n"); - printf ("definitions of global variables in your source module(s). Don't say\n"); - printf ("I didn't warn you!"); + char *long_const_msg = _("\ +***Warning - the assembly code generated by the compiler has placed \n\ + global constant(s) in the text psect. These will not be available to \n\ + other modules, since this is not the correct way to handle this. You \n\ + have two options: 1) get a patched compiler that does not put global \n\ + constants in the text psect, or 2) remove the 'const' keyword from \n\ + definitions of global variables in your source module(s). Don't say \n\ + I didn't warn you! \n"); + + as_tsktsk (long_const_msg); gave_compiler_message = 1; - }; + } VMS_DBG_record (spnt, Text_Psect, S_GET_VALUE (sp1), str); *pnt1 = ':'; - *S_GET_NAME (sp1) = 'L'; - /* fool assembler to not output this - * as a routine in the TBT */ - return 1; - }; - }; - }; + /* fool assembler to not output this as a routine in the TBT */ + pnt1 = S_GET_NAME (sp1); + *pnt1 = 'L'; + S_SET_NAME (sp1, pnt1); + return; + } + } + } *pnt1 = ':'; /* and restore the string */ - return 0; + return; } -static +/* Simpler interfaces into VMS_stab_parse(). */ + +static void VMS_GSYM_Parse (sp, Text_Psect) symbolS *sp; int Text_Psect; @@ -2090,8 +2215,7 @@ VMS_GSYM_Parse (sp, Text_Psect) VMS_stab_parse (sp, 'G', (N_UNDF | N_EXT), (N_DATA | N_EXT), Text_Psect); } - -static +static void VMS_LCSYM_Parse (sp, Text_Psect) symbolS *sp; int Text_Psect; @@ -2099,7 +2223,7 @@ VMS_LCSYM_Parse (sp, Text_Psect) VMS_stab_parse (sp, 'S', N_BSS, -1, Text_Psect); } -static +static void VMS_STSYM_Parse (sp, Text_Psect) symbolS *sp; int Text_Psect; @@ -2107,31 +2231,31 @@ VMS_STSYM_Parse (sp, Text_Psect) VMS_stab_parse (sp, 'S', N_DATA, -1, Text_Psect); } +/* For register symbols, we must figure out what range of addresses + within the psect are valid. We will use the brackets in the stab + directives to give us guidance as to the PC range that this variable + is in scope. I am still not completely comfortable with this but + as I learn more, I seem to get a better handle on what is going on. + Caveat Emptor. */ -/* for register symbols, we must figure out what range of addresses within the - * psect are valid. We will use the brackets in the stab directives to give us - * guidance as to the PC range that this variable is in scope. I am still not - * completely comfortable with this but as I learn more, I seem to get a better - * handle on what is going on. - * Caveat Emptor. - */ -static +static void VMS_RSYM_Parse (sp, Current_Routine, Text_Psect) - symbolS *sp, *Current_Routine; + symbolS *sp; + symbolS *Current_Routine ATTRIBUTE_UNUSED; int Text_Psect; { + symbolS *symbolP; + struct VMS_DBG_Symbol *spnt; char *pnt; char *pnt1; char *str; int dbx_type; - struct VMS_DBG_Symbol *spnt; - int j; - int maxlen; + int len; int i = 0; int bcnt = 0; int Min_Offset = -1; /* min PC of validity */ int Max_Offset = 0; /* max PC of validity */ - symbolS *symbolP; + for (symbolP = sp; symbolP; symbolP = symbol_next (symbolP)) { /* @@ -2145,107 +2269,102 @@ VMS_RSYM_Parse (sp, Current_Routine, Text_Psect) break; case N_RBRAC: if (--bcnt == 0) - Max_Offset = - S_GET_VALUE (symbolP) - 1; + Max_Offset = S_GET_VALUE (symbolP) - 1; break; } if ((Min_Offset != -1) && (bcnt == 0)) break; if (S_GET_RAW_TYPE (symbolP) == N_FUN) { - pnt=(char*) strchr (S_GET_NAME (symbolP), ':') + 1; + pnt = (char *) strchr (S_GET_NAME (symbolP), ':') + 1; if (*pnt == 'F' || *pnt == 'f') break; - }; + } } -/* check to see that the addresses were defined. If not, then there were no - * brackets in the function, and we must try to search for the next function - * Since functions can be in any order, we should search all of the symbol list - * to find the correct ending address. */ + + /* Check to see that the addresses were defined. If not, then there + were no brackets in the function, and we must try to search for + the next function. Since functions can be in any order, we should + search all of the symbol list to find the correct ending address. */ if (Min_Offset == -1) { int Max_Source_Offset; int This_Offset; + Min_Offset = S_GET_VALUE (sp); + Max_Source_Offset = Min_Offset; /* just in case no N_SLINEs found */ for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP)) - { - /* - * Dispatch on STAB type - */ - This_Offset = S_GET_VALUE (symbolP); - switch (S_GET_RAW_TYPE (symbolP)) - { - case N_TEXT | N_EXT: - if ((This_Offset > Min_Offset) && (This_Offset < Max_Offset)) - Max_Offset = This_Offset; - break; - case N_SLINE: - if (This_Offset > Max_Source_Offset) - Max_Source_Offset = This_Offset; - } - } -/* if this is the last routine, then we use the PC of the last source line - * as a marker of the max PC for which this reg is valid */ + switch (S_GET_RAW_TYPE (symbolP)) + { + case N_TEXT | N_EXT: + This_Offset = S_GET_VALUE (symbolP); + if (This_Offset > Min_Offset && This_Offset < Max_Offset) + Max_Offset = This_Offset; + break; + case N_SLINE: + This_Offset = S_GET_VALUE (symbolP); + if (This_Offset > Max_Source_Offset) + Max_Source_Offset = This_Offset; + break; + } + /* If this is the last routine, then we use the PC of the last source + line as a marker of the max PC for which this reg is valid. */ if (Max_Offset == 0x7fffffff) Max_Offset = Max_Source_Offset; - }; + } + dbx_type = 0; str = S_GET_NAME (sp); - pnt = (char *) strchr (str, ':'); - if (pnt == (char *) NULL) + if ((pnt = (char *) strchr (str, ':')) == 0) return; /* no colon present */ pnt1 = pnt; /* save this for later*/ pnt++; if (*pnt != 'r') - return 0; + return; pnt = cvt_integer (pnt + 1, &dbx_type); spnt = find_symbol (dbx_type); - if (spnt == (struct VMS_DBG_Symbol *) NULL) - return 0; /*Dunno what this is yet*/ + if (!spnt) + return; /*Dunno what this is yet*/ *pnt1 = '\0'; pnt = fix_name (S_GET_NAME (sp)); /* if there are bad characters in name, convert them */ - maxlen = 25 + strlen (pnt); - Local[i++] = maxlen; + len = strlen (pnt); + Local[i++] = 25 + len; Local[i++] = spnt->VMS_type; - Local[i++] = 0xfb; - Local[i++] = strlen (pnt) + 1; - Local[i++] = 0x00; - Local[i++] = 0x00; - Local[i++] = 0x00; - Local[i++] = strlen (pnt); + Local[i++] = DST_K_VFLAGS_TVS; /* trailing value specified */ + COPY_LONG (&Local[i], 1 + len); /* relative offset, beyond name */ + i += 4; + Local[i++] = len; /* name length (ascic prefix) */ while (*pnt != '\0') Local[i++] = *pnt++; - Local[i++] = 0xfd; - Local[i++] = 0x0f; - Local[i++] = 0x00; - Local[i++] = 0x03; - Local[i++] = 0x01; + Local[i++] = DST_K_VS_FOLLOWS; /* value specification follows */ + COPY_SHORT (&Local[i], 15); /* length of rest of record */ + i += 2; + Local[i++] = DST_K_VS_ALLOC_SPLIT; /* split lifetime */ + Local[i++] = 1; /* one binding follows */ VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG); i = 0; VMS_Set_Data (Text_Psect, Min_Offset, OBJ_S_C_DBG, 1); VMS_Set_Data (Text_Psect, Max_Offset, OBJ_S_C_DBG, 1); - Local[i++] = 0x03; - Local[i++] = S_GET_VALUE (sp); - Local[i++] = 0x00; - Local[i++] = 0x00; - Local[i++] = 0x00; + Local[i++] = DST_K_VALKIND_REG; /* nested value spec */ + COPY_LONG (&Local[i], S_GET_VALUE (sp)); + i += 4; VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG); *pnt1 = ':'; if (spnt->VMS_type == DBG_S_C_ADVANCED_TYPE) generate_suffix (spnt, 0); } -/* this function examines a structure definition, checking all of the elements - * to make sure that all of them are fully defined. The only thing that we - * kick out are arrays of undefined structs, since we do not know how big - * they are. All others we can handle with a normal forward reference. - */ +/* This function examines a structure definition, checking all of the elements + to make sure that all of them are fully defined. The only thing that we + kick out are arrays of undefined structs, since we do not know how big + they are. All others we can handle with a normal forward reference. */ + static int forward_reference (pnt) char *pnt; { + struct VMS_DBG_Symbol *spnt, *spnt1; int i; - struct VMS_DBG_Symbol *spnt; - struct VMS_DBG_Symbol *spnt1; + pnt = cvt_integer (pnt + 1, &i); if (*pnt == ';') return 0; /* no forward references */ @@ -2254,144 +2373,129 @@ forward_reference (pnt) pnt = (char *) strchr (pnt, ':'); pnt = cvt_integer (pnt + 1, &i); spnt = find_symbol (i); - if(spnt != (struct VMS_DBG_Symbol*) NULL) { - while((spnt->advanced == POINTER) || (spnt->advanced == ARRAY)) + while (spnt && (spnt->advanced == POINTER || spnt->advanced == ARRAY)) { - i = spnt->type2; spnt1 = find_symbol (spnt->type2); - if ((spnt->advanced == ARRAY) && - (spnt1 == (struct VMS_DBG_Symbol *) NULL)) + if (spnt->advanced == ARRAY && !spnt1) return 1; - if (spnt1 == (struct VMS_DBG_Symbol *) NULL) - break; spnt = spnt1; - }; - }; + } pnt = cvt_integer (pnt + 1, &i); pnt = cvt_integer (pnt + 1, &i); - } while (*++pnt != ';'); + } while (*++pnt != ';'); return 0; /* no forward refences found */ } -/* Used to check a single element of a structure on the final pass*/ +/* Used to check a single element of a structure on the final pass. */ static int final_forward_reference (spnt) - struct VMS_DBG_Symbol * spnt; + struct VMS_DBG_Symbol *spnt; { - struct VMS_DBG_Symbol * spnt1; - if(spnt != (struct VMS_DBG_Symbol*) NULL) { - while((spnt->advanced == POINTER) || (spnt->advanced == ARRAY)){ - spnt1 = find_symbol(spnt->type2); - if((spnt->advanced == ARRAY) && - (spnt1 == (struct VMS_DBG_Symbol*) NULL))return 1; - if(spnt1 == (struct VMS_DBG_Symbol*) NULL) break; - spnt=spnt1; - }; - }; - return 0; /* no forward refences found */ + struct VMS_DBG_Symbol *spnt1; + + while (spnt && (spnt->advanced == POINTER || spnt->advanced == ARRAY)) + { + spnt1 = find_symbol (spnt->type2); + if (spnt->advanced == ARRAY && !spnt1) + return 1; + spnt = spnt1; + } + return 0; /* no forward refences found */ } -/* This routine parses the stabs directives to find any definitions of dbx type - * numbers. It makes a note of all of them, creating a structure element - * of VMS_DBG_Symbol that describes it. This also generates the info for the - * debugger that describes the struct/union/enum, so that further references - * to these data types will be by number - * We have to process pointers right away, since there can be references - * to them later in the same stabs directive. We cannot have forward - * references to pointers, (but we can have a forward reference to a pointer to - * a structure/enum/union) and this is why we process them immediately. - * After we process the pointer, then we search for defs that are nested even - * deeper. - * 8/15/92: We have to process arrays right away too, because there can - * be multiple references to identical array types in one structure - * definition, and only the first one has the definition. (We tend to - * parse from the back going forward. - */ +/* This routine parses the stabs directives to find any definitions of dbx + type numbers. It makes a note of all of them, creating a structure + element of VMS_DBG_Symbol that describes it. This also generates the + info for the debugger that describes the struct/union/enum, so that + further references to these data types will be by number + + We have to process pointers right away, since there can be references + to them later in the same stabs directive. We cannot have forward + references to pointers, (but we can have a forward reference to a + pointer to a structure/enum/union) and this is why we process them + immediately. After we process the pointer, then we search for defs + that are nested even deeper. + + 8/15/92: We have to process arrays right away too, because there can + be multiple references to identical array types in one structure + definition, and only the first one has the definition. */ + static int VMS_typedef_parse (str) char *str; { char *pnt; char *pnt1; - char *pnt2; + const char *pnt2; int i; int dtype; struct forward_ref *fpnt; - int i1, i2, i3; - int convert_integer; + int i1, i2, i3, len; struct VMS_DBG_Symbol *spnt; struct VMS_DBG_Symbol *spnt1; -/* check for any nested def's */ + + /* check for any nested def's */ pnt = (char *) strchr (str + 1, '='); - if ((pnt != (char *) NULL) && (*(str + 1) != '*') - && (str[1] != 'a' || str[2] != 'r')) - if (VMS_typedef_parse (pnt) == 1) - return 1; -/* now find dbx_type of entry */ + if (pnt && str[1] != '*' && (str[1] != 'a' || str[2] != 'r') + && VMS_typedef_parse (pnt) == 1) + return 1; + /* now find dbx_type of entry */ pnt = str - 1; if (*pnt == 'c') { /* check for static constants */ *str = '\0'; /* for now we ignore them */ return 0; - }; + } while ((*pnt <= '9') && (*pnt >= '0')) pnt--; pnt++; /* and get back to the number */ cvt_integer (pnt, &i1); spnt = find_symbol (i1); -/* first we see if this has been defined already, due to a forward reference*/ - if (spnt == (struct VMS_DBG_Symbol *) NULL) + /* first see if this has been defined already, due to forward reference */ + if (!spnt) { - if (VMS_Symbol_type_list == (struct VMS_DBG_Symbol *) NULL) - { - spnt = (struct VMS_DBG_Symbol *) malloc (sizeof (struct VMS_DBG_Symbol)); - spnt->next = (struct VMS_DBG_Symbol *) NULL; - VMS_Symbol_type_list = spnt; - } - else - { - spnt = (struct VMS_DBG_Symbol *) malloc (sizeof (struct VMS_DBG_Symbol)); - spnt->next = VMS_Symbol_type_list; - VMS_Symbol_type_list = spnt; - }; + i2 = SYMTYP_HASH (i1); + spnt = (struct VMS_DBG_Symbol *) xmalloc (sizeof (struct VMS_DBG_Symbol)); + spnt->next = VMS_Symbol_type_list[i2]; + VMS_Symbol_type_list[i2] = spnt; spnt->dbx_type = i1; /* and save the type */ - }; -/* for structs and unions, do a partial parse, otherwise we sometimes get - * circular definitions that are impossible to resolve. We read enough info - * so that any reference to this type has enough info to be resolved - */ + spnt->type2 = spnt->VMS_type = spnt->data_size = 0; + spnt->index_min = spnt->index_max = spnt->struc_numb = 0; + } + /* + * For structs and unions, do a partial parse, otherwise we sometimes get + * circular definitions that are impossible to resolve. We read enough + * info so that any reference to this type has enough info to be resolved. + */ pnt = str + 1; /* point to character past equal sign */ - if ((*pnt == 'u') || (*pnt == 's')) - { - }; - if ((*pnt <= '9') && (*pnt >= '0')) + if (*pnt >= '0' && *pnt <= '9') { if (type_check ("void")) { /* this is the void symbol */ *str = '\0'; spnt->advanced = VOID; return 0; - }; + } if (type_check ("unknown type")) - { /* this is the void symbol */ + { *str = '\0'; spnt->advanced = UNKNOWN; return 0; - }; - pnt1 = cvt_integer(pnt,&i1); - if(i1 != spnt->dbx_type) + } + pnt1 = cvt_integer (pnt, &i1); + if (i1 != spnt->dbx_type) { spnt->advanced = ALIAS; spnt->type2 = i1; - strcpy(str, pnt1); + strcpy (str, pnt1); return 0; } - printf ("gcc-as warning(debugger output):"); - printf (" %d is an unknown untyped variable.\n", spnt->dbx_type); + as_tsktsk (_("debugginer output: %d is an unknown untyped variable."), + spnt->dbx_type); return 1; /* do not know what this is */ - }; -/* now define this module*/ + } + pnt = str + 1; /* point to character past equal sign */ switch (*pnt) { @@ -2449,20 +2553,60 @@ VMS_typedef_parse (str) } else if (type_check ("double")) { - spnt->VMS_type = DBG_S_C_REAL8; + spnt->VMS_type = vax_g_doubles ? DBG_S_C_REAL8_G : DBG_S_C_REAL8; + spnt->data_size = 8; + } + else if (type_check ("long double")) + { + /* same as double, at least for now */ + spnt->VMS_type = vax_g_doubles ? DBG_S_C_REAL8_G : DBG_S_C_REAL8; + spnt->data_size = 8; + } + else if (type_check ("long long int")) + { + spnt->VMS_type = DBG_S_C_SQUAD; /* signed quadword */ + spnt->data_size = 8; + } + else if (type_check ("long long unsigned int")) + { + spnt->VMS_type = DBG_S_C_UQUAD; /* unsigned quadword */ spnt->data_size = 8; } + else if (type_check ("complex float")) + { + spnt->VMS_type = DBG_S_C_COMPLX4; + spnt->data_size = 2 * 4; + } + else if (type_check ("complex double")) + { + spnt->VMS_type = vax_g_doubles ? DBG_S_C_COMPLX8_G : DBG_S_C_COMPLX8; + spnt->data_size = 2 * 8; + } + else if (type_check ("complex long double")) + { + /* same as complex double, at least for now */ + spnt->VMS_type = vax_g_doubles ? DBG_S_C_COMPLX8_G : DBG_S_C_COMPLX8; + spnt->data_size = 2 * 8; + } + else + { + /* [pr] + * Shouldn't get here, but if we do, something + * more substantial ought to be done... + */ + spnt->VMS_type = 0; + spnt->data_size = 0; + } + if (spnt->VMS_type != 0) + setup_basic_type (spnt); pnt1 = (char *) strchr (str, ';') + 1; break; case 's': case 'u': - if (*pnt == 's') - spnt->advanced = STRUCT; - else - spnt->advanced = UNION; + spnt->advanced = (*pnt == 's') ? STRUCT : UNION; spnt->VMS_type = DBG_S_C_ADVANCED_TYPE; pnt1 = cvt_integer (pnt + 1, &spnt->data_size); - if (!final_pass && forward_reference(pnt)) + if (!final_pass && forward_reference (pnt)) { spnt->struc_numb = -1; return 1; @@ -2471,30 +2615,29 @@ VMS_typedef_parse (str) pnt1--; pnt = get_struct_name (str); VMS_Def_Struct (spnt->struc_numb); - fpnt = f_ref_root; - while (fpnt != (struct forward_ref *) NULL) - { - if (fpnt->dbx_type == spnt->dbx_type) - { - fpnt->resolved = 'Y'; - VMS_Set_Struct (fpnt->struc_numb); - VMS_Store_Struct (spnt->struc_numb); - }; - fpnt = fpnt->next; - }; - VMS_Set_Struct (spnt->struc_numb); + i = 0; + for (fpnt = f_ref_root; fpnt; fpnt = fpnt->next) + if (fpnt->dbx_type == spnt->dbx_type) + { + fpnt->resolved = 'Y'; + VMS_Set_Struct (fpnt->struc_numb); + VMS_Store_Struct (spnt->struc_numb); + i++; + } + if (i > 0) + VMS_Set_Struct (spnt->struc_numb); i = 0; Local[i++] = 11 + strlen (pnt); Local[i++] = DBG_S_C_STRUCT_START; - Local[i++] = 0x80; - for (i1 = 0; i1 < 4; i1++) - Local[i++] = 0x00; + Local[i++] = DST_K_VFLAGS_NOVAL; /* structure definition only */ + COPY_LONG (&Local[i], 0L); /* hence value is unused */ + i += 4; Local[i++] = strlen (pnt); pnt2 = pnt; while (*pnt2 != '\0') Local[i++] = *pnt2++; i2 = spnt->data_size * 8; /* number of bits */ - COPY_LONG(&Local[i], i2); + COPY_LONG (&Local[i], i2); i += 4; VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG); i = 0; @@ -2502,7 +2645,7 @@ VMS_typedef_parse (str) { pnt += strlen (pnt); *pnt = ':'; - }; /* replace colon for later */ + } /* replace colon for later */ while (*++pnt1 != ';') { pnt = (char *) strchr (pnt1, ':'); @@ -2511,52 +2654,81 @@ VMS_typedef_parse (str) pnt1 = cvt_integer (pnt + 1, &dtype); pnt1 = cvt_integer (pnt1 + 1, &i2); pnt1 = cvt_integer (pnt1 + 1, &i3); - if ((dtype == 1) && (i3 != 32)) + spnt1 = find_symbol (dtype); + len = strlen (pnt2); + if (spnt1 && (spnt1->advanced == BASIC || spnt1->advanced == ENUM) + && ((i3 != spnt1->data_size * 8) || (i2 % 8 != 0))) { /* bitfield */ - Apoint = 0; - push (19 + strlen (pnt2), 1); - push (0xfa22, 2); - push (1 + strlen (pnt2), 4); - push (strlen (pnt2), 1); - while (*pnt2 != '\0') - push (*pnt2++, 1); - push (i3, 2); /* size of bitfield */ - push (0x0d22, 2); - push (0x00, 4); - push (i2, 4); /* start position */ - VMS_Store_Immediate_Data (Asuffix, Apoint, OBJ_S_C_DBG); - Apoint = 0; + if (USE_BITSTRING_DESCRIPTOR (spnt1)) + { + /* This uses a type descriptor, which doesn't work if + the enclosing structure has been placed in a register. + Also, enum bitfields degenerate to simple integers. */ + int unsigned_type = (spnt1->VMS_type == DBG_S_C_ULINT + || spnt1->VMS_type == DBG_S_C_USINT + || spnt1->VMS_type == DBG_S_C_UCHAR + || spnt1->VMS_type == DBG_S_C_UQUAD + || spnt1->advanced == ENUM); /* (approximate) */ + Apoint = 0; + fpush (19 + len, 1); + fpush (unsigned_type ? DBG_S_C_UBITU : DBG_S_C_SBITU, 1); + fpush (DST_K_VFLAGS_DSC, 1); /* specified by descriptor */ + fpush (1 + len, 4); /* relative offset to descriptor */ + fpush (len, 1); /* length byte (ascic prefix) */ + while (*pnt2 != '\0') /* name bytes */ + fpush (*pnt2++, 1); + fpush (i3, 2); /* dsc length == size of bitfield */ + /* dsc type == un?signed bitfield */ + fpush (unsigned_type ? DBG_S_C_UBITU : DBG_S_C_SBITU, 1); + fpush (DSC_K_CLASS_UBS, 1); /* dsc class == unaligned bitstring */ + fpush (0x00, 4); /* dsc pointer == zeroes */ + fpush (i2, 4); /* start position */ + VMS_Store_Immediate_Data (Asuffix, Apoint, OBJ_S_C_DBG); + Apoint = 0; + } + else + { + /* Use a "novel length" type specification, which works + right for register structures and for enum bitfields + but results in larger object modules. */ + Local[i++] = 7 + len; + Local[i++] = DBG_S_C_ADVANCED_TYPE; /* type spec follows */ + Local[i++] = DBG_S_C_STRUCT_ITEM; /* value is a bit offset */ + COPY_LONG (&Local[i], i2); /* bit offset */ + i += 4; + Local[i++] = strlen (pnt2); + while (*pnt2 != '\0') + Local[i++] = *pnt2++; + VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG); + i = 0; + bitfield_suffix (spnt1, i3); + } } else - { - Local[i++] = 7 + strlen (pnt2); - spnt1 = find_symbol (dtype); + { /* not a bitfield */ /* check if this is a forward reference */ - if(final_pass && final_forward_reference(spnt1)) + if (final_pass && final_forward_reference (spnt1)) { - printf("gcc-as warning(debugger output):"); - printf("structure element %s has undefined type\n",pnt2); - i--; + as_tsktsk (_("debugger output: structure element `%s' has undefined type"), + pnt2); continue; } - if (spnt1 != (struct VMS_DBG_Symbol *) NULL) - Local[i++] = spnt1->VMS_type; - else - Local[i++] = DBG_S_C_ADVANCED_TYPE; + Local[i++] = 7 + len; + Local[i++] = spnt1 ? spnt1->VMS_type : DBG_S_C_ADVANCED_TYPE; Local[i++] = DBG_S_C_STRUCT_ITEM; - COPY_LONG (&Local[i], i2); + COPY_LONG (&Local[i], i2); /* bit offset */ i += 4; Local[i++] = strlen (pnt2); while (*pnt2 != '\0') Local[i++] = *pnt2++; VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG); i = 0; - if (spnt1 == (struct VMS_DBG_Symbol *) NULL) + if (!spnt1) generate_suffix (spnt1, dtype); else if (spnt1->VMS_type == DBG_S_C_ADVANCED_TYPE) generate_suffix (spnt1, 0); - }; - }; + } + } pnt1++; Local[i++] = 0x01; /* length byte */ Local[i++] = DBG_S_C_STRUCT_END; @@ -2569,23 +2741,23 @@ VMS_typedef_parse (str) spnt->struc_numb = ++structure_count; spnt->data_size = 4; VMS_Def_Struct (spnt->struc_numb); - fpnt = f_ref_root; - while (fpnt != (struct forward_ref *) NULL) - { - if (fpnt->dbx_type == spnt->dbx_type) - { - fpnt->resolved = 'Y'; - VMS_Set_Struct (fpnt->struc_numb); - VMS_Store_Struct (spnt->struc_numb); - }; - fpnt = fpnt->next; - }; - VMS_Set_Struct (spnt->struc_numb); i = 0; - Local[i++] = 3 + strlen (symbol_name); + for (fpnt = f_ref_root; fpnt; fpnt = fpnt->next) + if (fpnt->dbx_type == spnt->dbx_type) + { + fpnt->resolved = 'Y'; + VMS_Set_Struct (fpnt->struc_numb); + VMS_Store_Struct (spnt->struc_numb); + i++; + } + if (i > 0) + VMS_Set_Struct (spnt->struc_numb); + i = 0; + len = strlen (symbol_name); + Local[i++] = 3 + len; Local[i++] = DBG_S_C_ENUM_START; - Local[i++] = 0x20; - Local[i++] = strlen (symbol_name); + Local[i++] = 4 * 8; /* enum values are 32 bits */ + Local[i++] = len; pnt2 = symbol_name; while (*pnt2 != '\0') Local[i++] = *pnt2++; @@ -2596,19 +2768,20 @@ VMS_typedef_parse (str) pnt1 = (char *) strchr (pnt, ':'); *pnt1++ = '\0'; pnt1 = cvt_integer (pnt1, &i1); - Local[i++] = 7 + strlen (pnt); + len = strlen (pnt); + Local[i++] = 7 + len; Local[i++] = DBG_S_C_ENUM_ITEM; - Local[i++] = 0x00; + Local[i++] = DST_K_VALKIND_LITERAL; COPY_LONG (&Local[i], i1); i += 4; - Local[i++] = strlen (pnt); + Local[i++] = len; pnt2 = pnt; while (*pnt != '\0') Local[i++] = *pnt++; VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG); i = 0; pnt = pnt1; /* Skip final semicolon */ - }; + } Local[i++] = 0x01; /* len byte */ Local[i++] = DBG_S_C_ENUM_END; VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG); @@ -2619,14 +2792,14 @@ VMS_typedef_parse (str) spnt->advanced = ARRAY; spnt->VMS_type = DBG_S_C_ADVANCED_TYPE; pnt = (char *) strchr (pnt, ';'); - if (pnt == (char *) NULL) + if (!pnt) return 1; pnt1 = cvt_integer (pnt + 1, &spnt->index_min); pnt1 = cvt_integer (pnt1 + 1, &spnt->index_max); pnt1 = cvt_integer (pnt1 + 1, &spnt->type2); - pnt=(char*)strchr(str+1,'='); - if((pnt != (char*) NULL)) - if(VMS_typedef_parse(pnt) == 1 ) return 1; + pnt = (char *) strchr (str + 1, '='); + if (pnt && VMS_typedef_parse (pnt) == 1) + return 1; break; case 'f': spnt->advanced = FUNCTION; @@ -2641,19 +2814,18 @@ VMS_typedef_parse (str) spnt->data_size = 4; pnt1 = cvt_integer (pnt + 1, &spnt->type2); pnt = (char *) strchr (str + 1, '='); - if ((pnt != (char *) NULL)) - if (VMS_typedef_parse (pnt) == 1) - return 1; + if (pnt && VMS_typedef_parse (pnt) == 1) + return 1; break; default: spnt->advanced = UNKNOWN; spnt->VMS_type = 0; - printf ("gcc-as warning(debugger output):"); - printf (" %d is an unknown type of variable.\n", spnt->dbx_type); + as_tsktsk (_("debugger output: %d is an unknown type of variable."), + spnt->dbx_type); return 1; /* unable to decipher */ - }; -/* this removes the evidence of the definition so that the outer levels of -parsing do not have to worry about it */ + } + /* This removes the evidence of the definition so that the outer levels + of parsing do not have to worry about it. */ pnt = str; while (*pnt1 != '\0') *pnt++ = *pnt1++; @@ -2661,19 +2833,16 @@ parsing do not have to worry about it */ return 0; } +/* This is the root routine that parses the stabs entries for definitions. + it calls VMS_typedef_parse, which can in turn call itself. We need to + be careful, since sometimes there are forward references to other symbol + types, and these cannot be resolved until we have completed the parse. -/* - * This is the root routine that parses the stabs entries for definitions. - * it calls VMS_typedef_parse, which can in turn call itself. - * We need to be careful, since sometimes there are forward references to - * other symbol types, and these cannot be resolved until we have completed - * the parse. - * - * Also check and see if we are using continuation stabs, if we are, then - * paste together the entire contents of the stab before we pass it to - * VMS_typedef_parse. - */ -static int + Also check and see if we are using continuation stabs, if we are, then + paste together the entire contents of the stab before we pass it to + VMS_typedef_parse. */ + +static void VMS_LSYM_Parse () { char *pnt; @@ -2682,11 +2851,10 @@ VMS_LSYM_Parse () char *str; char *parse_buffer = 0; char fixit[10]; - int incomplete, i, pass, incom1; - struct VMS_DBG_Symbol *spnt; - struct VMS_Symbol *vsp; + int incomplete, pass, incom1; struct forward_ref *fpnt; symbolS *sp; + pass = 0; final_pass = 0; incomplete = 0; @@ -2715,218 +2883,212 @@ VMS_LSYM_Parse () case N_FUN: /*sometimes these contain typedefs*/ str = S_GET_NAME (sp); symbol_name = str; - pnt = str + strlen(str) -1; + pnt = str + strlen (str) - 1; if (*pnt == '?') /* Continuation stab. */ { symbolS *spnext; int tlen = 0; + spnext = sp; do { - tlen += strlen(str) - 1; + tlen += strlen (str) - 1; spnext = symbol_next (spnext); str = S_GET_NAME (spnext); - pnt = str + strlen(str) - 1; + pnt = str + strlen (str) - 1; } while (*pnt == '?'); - tlen += strlen(str); - parse_buffer = (char *) malloc (tlen + 1); - strcpy(parse_buffer, S_GET_NAME (sp)); - pnt2 = parse_buffer + strlen(S_GET_NAME (sp)) - 1; + tlen += strlen (str); + parse_buffer = (char *) xmalloc (tlen + 1); + strcpy (parse_buffer, S_GET_NAME (sp)); + pnt2 = parse_buffer + strlen (parse_buffer) - 1; *pnt2 = '\0'; spnext = sp; do { spnext = symbol_next (spnext); str = S_GET_NAME (spnext); - strcat (pnt2, S_GET_NAME (spnext)); - pnt2 += strlen(str) - 1; + strcat (pnt2, str); + pnt2 += strlen (str) - 1; *str = '\0'; /* Erase this string */ + /* S_SET_NAME (spnext, str); */ if (*pnt2 != '?') break; *pnt2 = '\0'; - } while (1 == 1); + } while (1); str = parse_buffer; symbol_name = str; - }; - pnt = (char *) strchr (str, ':'); - if (pnt != (char *) NULL) + } + if ((pnt = (char *) strchr (str, ':')) != 0) { *pnt = '\0'; pnt1 = pnt + 1; - pnt2 = (char *) strchr (pnt1, '='); - if (pnt2 != (char *) NULL) + if ((pnt2 = (char *) strchr (pnt1, '=')) != 0) incomplete += VMS_typedef_parse (pnt2); - if (parse_buffer){ - /* At this point the parse buffer should just contain name:nn. - If it does not, then we are in real trouble. Anyway, - this is always shorter than the original line. */ - strcpy(S_GET_NAME (sp), parse_buffer); - free (parse_buffer); - parse_buffer = 0; - }; - *pnt = ':'; /* put back colon so variable def code finds dbx_type*/ - }; + if (parse_buffer) + { + /* At this point the parse buffer should just + contain name:nn. If it does not, then we + are in real trouble. Anyway, this is always + shorter than the original line. */ + pnt2 = S_GET_NAME (sp); + strcpy (pnt2, parse_buffer); + /* S_SET_NAME (sp, pnt2); */ + free (parse_buffer), parse_buffer = 0; + } + *pnt = ':'; /* put back colon to restore dbx_type */ + } break; } /*switch*/ } /* if */ } /*for*/ pass++; -/* Make one last pass, if needed, and define whatever we can that is left */ - if(final_pass == 0 && incomplete == incom1) - { - final_pass = 1; - incom1 ++; /* Force one last pass through */ - }; - } while ((incomplete != 0) && (incomplete != incom1)); + /* + * Make one last pass, if needed, and define whatever we can + * that is left. + */ + if (final_pass == 0 && incomplete == incom1) + { + final_pass = 1; + incom1++; /* Force one last pass through */ + } + } while (incomplete != 0 && incomplete != incom1); /* repeat until all refs resolved if possible */ -/* if (pass > 1) printf(" Required %d passes\n",pass);*/ +/* if (pass > 1) printf (" Required %d passes\n", pass); */ if (incomplete != 0) { - printf ("gcc-as warning(debugger output):"); - printf ("Unable to resolve %d circular references.\n", incomplete); - }; + as_tsktsk (_("debugger output: Unable to resolve %d circular references."), + incomplete); + } fpnt = f_ref_root; symbol_name = "\0"; - while (fpnt != (struct forward_ref *) NULL) + while (fpnt) { if (fpnt->resolved != 'Y') { - if (find_symbol (fpnt->dbx_type) != - (struct VMS_DBG_Symbol *) NULL) + if (find_symbol (fpnt->dbx_type)) { - printf ("gcc-as warning(debugger output):"); - printf ("Forward reference error, dbx type %d\n", - fpnt->dbx_type); + as_tsktsk (_("debugger forward reference error, dbx type %d"), + fpnt->dbx_type); break; - }; + } fixit[0] = 0; sprintf (&fixit[1], "%d=s4;", fpnt->dbx_type); pnt2 = (char *) strchr (&fixit[1], '='); VMS_typedef_parse (pnt2); - }; + } fpnt = fpnt->next; - }; + } } -static -Define_Local_Symbols (s1, s2) - symbolS *s1, *s2; +static void +Define_Local_Symbols (s0P, s2P, Current_Routine, Text_Psect) + symbolS *s0P, *s2P; + symbolS *Current_Routine; + int Text_Psect; { - symbolS *symbolP1; - for (symbolP1 = symbol_next (s1); symbolP1 != s2; symbolP1 = symbol_next (symbolP1)) + symbolS *s1P; /* each symbol from s0P .. s2P (exclusive) */ + + for (s1P = symbol_next (s0P); s1P != s2P; s1P = symbol_next (s1P)) { - if (symbolP1 == (symbolS *) NULL) - return; - if (S_GET_RAW_TYPE (symbolP1) == N_FUN) + if (!s1P) + break; /* and return */ + if (S_GET_RAW_TYPE (s1P) == N_FUN) { - char * pnt=(char*) strchr (S_GET_NAME (symbolP1), ':') + 1; + char *pnt = (char *) strchr (S_GET_NAME (s1P), ':') + 1; if (*pnt == 'F' || *pnt == 'f') break; - }; + } + if (!S_IS_DEBUG (s1P)) + continue; /* - * Deal with STAB symbols + * Dispatch on STAB type */ - if (S_IS_DEBUG (symbolP1)) + switch (S_GET_RAW_TYPE (s1P)) { - /* - * Dispatch on STAB type - */ - switch (S_GET_RAW_TYPE (symbolP1)) - { - case N_LSYM: - case N_PSYM: - VMS_local_stab_Parse (symbolP1); - break; - case N_RSYM: - VMS_RSYM_Parse (symbolP1, Current_Routine, Text_Psect); - break; - } /*switch*/ - } /* if */ + default: + continue; /* not left or right brace */ + + case N_LSYM: + case N_PSYM: + VMS_local_stab_Parse (s1P); + break; + + case N_RSYM: + VMS_RSYM_Parse (s1P, Current_Routine, Text_Psect); + break; + } /*switch*/ } /* for */ } - -/* This function crawls the symbol chain searching for local symbols that need - * to be described to the debugger. When we enter a new scope with a "{", it - * creates a new "block", which helps the debugger keep track of which scope - * we are currently in. - */ +/* This function crawls the symbol chain searching for local symbols that + need to be described to the debugger. When we enter a new scope with + a "{", it creates a new "block", which helps the debugger keep track + of which scope we are currently in. */ static symbolS * -Define_Routine (symbolP, Level) - symbolS *symbolP; +Define_Routine (s0P, Level, Current_Routine, Text_Psect) + symbolS *s0P; int Level; + symbolS *Current_Routine; + int Text_Psect; { - symbolS *sstart; - symbolS *symbolP1; - char str[10]; + symbolS *s1P; + valueT Offset; int rcount = 0; - int Offset; - sstart = symbolP; - for (symbolP1 = symbol_next (symbolP); symbolP1; symbolP1 = symbol_next (symbolP1)) + + for (s1P = symbol_next (s0P); s1P != 0; s1P = symbol_next (s1P)) { - if (S_GET_RAW_TYPE (symbolP1) == N_FUN) + if (S_GET_RAW_TYPE (s1P) == N_FUN) { - char * pnt=(char*) strchr (S_GET_NAME (symbolP1), ':') + 1; + char *pnt = (char *) strchr (S_GET_NAME (s1P), ':') + 1; if (*pnt == 'F' || *pnt == 'f') break; - }; + } + if (!S_IS_DEBUG (s1P)) + continue; /* - * Deal with STAB symbols + * Dispatch on STAB type */ - if (S_IS_DEBUG (symbolP1)) + switch (S_GET_RAW_TYPE (s1P)) { - /* - * Dispatch on STAB type - */ - switch (S_GET_RAW_TYPE (symbolP1)) + default: + continue; /* not left or right brace */ + + case N_LBRAC: + if (Level != 0) { - case N_LBRAC: - if (Level != 0) - { - sprintf (str, "$%d", rcount++); - VMS_TBT_Block_Begin (symbolP1, Text_Psect, str); - }; - Offset = S_GET_VALUE (symbolP1); - Define_Local_Symbols (sstart, symbolP1); - symbolP1 = - Define_Routine (symbolP1, Level + 1); - if (Level != 0) - VMS_TBT_Block_End (S_GET_VALUE (symbolP1) - - Offset); - sstart = symbolP1; - break; - case N_RBRAC: - return symbolP1; - } /*switch*/ - } /* if */ + char str[10]; + sprintf (str, "$%d", rcount++); + VMS_TBT_Block_Begin (s1P, Text_Psect, str); + } + Offset = S_GET_VALUE (s1P); /* side-effect: fully resolve symbol */ + Define_Local_Symbols (s0P, s1P, Current_Routine, Text_Psect); + s1P = Define_Routine (s1P, Level + 1, Current_Routine, Text_Psect); + if (Level != 0) + VMS_TBT_Block_End (S_GET_VALUE (s1P) - Offset); + s0P = s1P; + break; + + case N_RBRAC: + return s1P; + } /*switch*/ } /* for */ - /* we end up here if there were no brackets in this function. Define -everything */ - Define_Local_Symbols (sstart, (symbolS *) 0); - return symbolP1; -} - -static -VMS_DBG_Define_Routine (symbolP, Curr_Routine, Txt_Psect) - symbolS *symbolP; - symbolS *Curr_Routine; - int Txt_Psect; -{ - Current_Routine = Curr_Routine; - Text_Psect = Txt_Psect; - Define_Routine (symbolP, 0); + /* We end up here if there were no brackets in this function. + Define everything. */ + Define_Local_Symbols (s0P, (symbolS *)0, Current_Routine, Text_Psect); + return s1P; } - - -#ifndef HO_VMS +#ifndef VMS #include #include +static void get_VMS_time_on_unix PARAMS ((char *)); -/* Manufacure a VMS like time on a unix based system. */ +/* Manufacture a VMS-like time string on a Unix based system. */ +static void get_VMS_time_on_unix (Now) char *Now; { char *pnt; time_t timeb; + time (&timeb); pnt = ctime (&timeb); pnt[3] = 0; @@ -2936,112 +3098,99 @@ get_VMS_time_on_unix (Now) pnt[24] = 0; sprintf (Now, "%2s-%3s-%s %s", pnt + 8, pnt + 4, pnt + 20, pnt + 11); } +#endif /* not VMS */ -#endif /* not HO_VMS */ -/* - * Write the MHD (Module Header) records - */ -static +/* Write the MHD (Module Header) records. */ + +static void Write_VMS_MHD_Records () { - register char *cp, *cp1; + register const char *cp; + register char *cp1; register int i; - struct - { - int Size; - char *Ptr; - } Descriptor; - char Module_Name[256]; - char Now[18]; +#ifdef VMS + struct { unsigned short len, mbz; char *ptr; } Descriptor; +#endif + char Now[17+1]; - /* - * We are writing a module header record - */ + /* We are writing a module header record. */ Set_VMS_Object_File_Record (OBJ_S_C_HDR); /* * *************************** * *MAIN MODULE HEADER RECORD* * *************************** - * - * Store record type and header type */ + /* Store record type and header type. */ PUT_CHAR (OBJ_S_C_HDR); PUT_CHAR (MHD_S_C_MHD); - /* - * Structure level is 0 - */ + /* Structure level is 0. */ PUT_CHAR (OBJ_S_C_STRLVL); - /* - * Maximum record size is size of the object record buffer - */ + /* Maximum record size is size of the object record buffer. */ PUT_SHORT (sizeof (Object_Record_Buffer)); - /* - * Get module name (the FILENAME part of the object file) - */ + + /* + * FIXME: module name and version should be user + * specifiable via `.ident' and/or `#pragma ident'. + */ + + /* Get module name (the FILENAME part of the object file). */ cp = out_file_name; cp1 = Module_Name; while (*cp) { - if ((*cp == ']') || (*cp == '>') || - (*cp == ':') || (*cp == '/')) + if (*cp == ']' || *cp == '>' || *cp == ':' || *cp == '/') { cp1 = Module_Name; cp++; continue; } - *cp1++ = islower (*cp) ? toupper (*cp++) : *cp++; + *cp1++ = TOUPPER (*cp++); } - *cp1 = 0; - /* - * Limit it to 31 characters and store in the object record - */ + *cp1 = '\0'; + + /* Limit it to 31 characters and store in the object record. */ while (--cp1 >= Module_Name) if (*cp1 == '.') - *cp1 = 0; + *cp1 = '\0'; if (strlen (Module_Name) > 31) { - if (flagseen['+']) - printf ("%s: Module name truncated: %s\n", myname, Module_Name); - Module_Name[31] = 0; + if (flag_hash_long_names) + as_tsktsk (_("Module name truncated: %s\n"), Module_Name); + Module_Name[31] = '\0'; } PUT_COUNTED_STRING (Module_Name); - /* - * Module Version is "V1.0" - */ + /* Module Version is "V1.0". */ PUT_COUNTED_STRING ("V1.0"); - /* - * Creation time is "now" (17 chars of time string) - */ -#ifndef HO_VMS - get_VMS_time_on_unix (&Now[0]); -#else /* HO_VMS */ - Descriptor.Size = 17; - Descriptor.Ptr = Now; - sys$asctim (0, &Descriptor, 0, 0); -#endif /* HO_VMS */ + /* Creation time is "now" (17 chars of time string): "dd-MMM-yyyy hh:mm". */ +#ifndef VMS + get_VMS_time_on_unix (Now); +#else /* VMS */ + Descriptor.len = sizeof Now - 1; + Descriptor.mbz = 0; /* type & class unspecified */ + Descriptor.ptr = Now; + (void) sys$asctim ((unsigned short *)0, &Descriptor, (long *)0, 0); +#endif /* VMS */ for (i = 0; i < 17; i++) PUT_CHAR (Now[i]); - /* - * Patch time is "never" (17 zeros) - */ + /* Patch time is "never" (17 zeros). */ for (i = 0; i < 17; i++) PUT_CHAR (0); - /* - * Flush the record - */ + /* Force this to be a separate output record. */ Flush_VMS_Object_Record_Buffer (); + /* * ************************* * *LANGUAGE PROCESSOR NAME* * ************************* - * - * Store record type and header type */ + /* Store record type and header type. */ PUT_CHAR (OBJ_S_C_HDR); PUT_CHAR (MHD_S_C_LNM); /* - * Store language processor name and version - * (not a counted string!) + * Store language processor name and version (not a counted string!). + * + * This is normally supplied by the gcc driver for the command line + * which invokes gas. If absent, we fall back to gas's version. */ cp = compiler_version_string; if (cp == 0) @@ -3049,57 +3198,39 @@ Write_VMS_MHD_Records () cp = "GNU AS V"; while (*cp) PUT_CHAR (*cp++); - cp = strchr (GAS_VERSION, '.'); - while (*cp != ' ') - cp--; - cp++; - }; - while (*cp >= 32) + cp = VERSION; + } + while (*cp >= ' ') PUT_CHAR (*cp++); - /* - * Flush the record - */ + /* Force this to be a separate output record. */ Flush_VMS_Object_Record_Buffer (); } - -/* - * Write the EOM (End Of Module) record - */ -static +/* Write the EOM (End Of Module) record. */ + +static void Write_VMS_EOM_Record (Psect, Offset) int Psect; - int Offset; + valueT Offset; { /* * We are writing an end-of-module record + * (this assumes that the entry point will always be in a psect + * represented by a single byte, which is the case for code in + * Text_Psect==0) */ Set_VMS_Object_File_Record (OBJ_S_C_EOM); - /* - * Store record Type - */ - PUT_CHAR (OBJ_S_C_EOM); - /* - * Store the error severity (0) - */ - PUT_CHAR (0); + PUT_CHAR (OBJ_S_C_EOM); /* Record type. */ + PUT_CHAR (0); /* Error severity level (we ignore it). */ /* * Store the entry point, if it exists */ if (Psect >= 0) { - /* - * Store the entry point Psect - */ PUT_CHAR (Psect); - /* - * Store the entry point Psect offset - */ PUT_LONG (Offset); } - /* - * Flush the record - */ + /* Flush the record; this will be our final output. */ Flush_VMS_Object_Record_Buffer (); } @@ -3108,10 +3239,10 @@ Write_VMS_EOM_Record (Psect, Offset) static int hash_string (ptr) - unsigned char *ptr; + const char *ptr; { - register unsigned char *p = ptr; - register unsigned char *end = p + strlen (ptr); + register const unsigned char *p = (unsigned char *) ptr; + register const unsigned char *end = p + strlen (ptr); register unsigned char c; register int hash = 0; @@ -3126,16 +3257,16 @@ hash_string (ptr) /* * Generate a Case-Hacked VMS symbol name (limited to 31 chars) */ -static +static void VMS_Case_Hack_Symbol (In, Out) - register char *In; + register const char *In; register char *Out; { - long int init = 0; + long int init; long int result; - char *pnt; + char *pnt = 0; char *new_name; - char *old_name; + const char *old_name; register int i; int destructor = 0; /*hack to allow for case sens in a destructor*/ int truncate = 0; @@ -3158,8 +3289,7 @@ VMS_Case_Hack_Symbol (In, Out) #endif /* We may need to truncate the symbol, save the hash for later*/ - if (strlen (In) > 23) - result = hash_string (In); + result = (strlen (In) > 23) ? hash_string (In) : 0; /* * Is there a Psect Attribute to skip?? */ @@ -3181,8 +3311,8 @@ VMS_Case_Hack_Symbol (In, Out) } old_name = In; -/* if (strlen(In) > 31 && flagseen['+']) - printf("%s: Symbol name truncated: %s\n",myname,In);*/ +/* if (strlen (In) > 31 && flag_hash_long_names) + as_tsktsk ("Symbol name truncated: %s\n", In); */ /* * Do the case conversion */ @@ -3197,28 +3327,28 @@ VMS_Case_Hack_Symbol (In, Out) switch (vms_name_mapping) { case 0: - if (isupper(*In)) { + if (ISUPPER (*In)) { *Out++ = *In++; Case_Hack_Bits |= 1; } else { - *Out++ = islower(*In) ? toupper(*In++) : *In++; + *Out++ = TOUPPER (*In++); } break; case 3: *Out++ = *In++; break; case 2: - if (islower(*In)) { + if (ISLOWER (*In)) { *Out++ = *In++; } else { - *Out++ = isupper(*In) ? tolower(*In++) : *In++; + *Out++ = TOLOWER (*In++); } break; - }; + } } /* * If we saw a dollar sign, we don't do case hacking */ - if (flagseen['h'] || Saw_Dollar) + if (flag_no_hash_mixed_case || Saw_Dollar) Case_Hack_Bits = 0; /* @@ -3241,7 +3371,7 @@ VMS_Case_Hack_Symbol (In, Out) * and ensure that they are lowercase */ for (i = 0; (In[i] != 0) && (i < 8); i++) - if (isupper(In[i]) && !Saw_Dollar && !flagseen['h']) + if (ISUPPER (In[i]) && !Saw_Dollar && !flag_no_hash_mixed_case) break; if (In[i] == 0) @@ -3256,17 +3386,13 @@ VMS_Case_Hack_Symbol (In, Out) i = 8; while ((--i >= 0) && (*In)) switch (vms_name_mapping){ - case 0: *Out++ = islower(*In) ? - toupper (*In++) : - *In++; + case 0: *Out++ = TOUPPER (*In++); break; case 3: *Out++ = *In++; break; - case 2: *Out++ = isupper(*In) ? - tolower(*In++) : - *In++; + case 2: *Out++ = TOLOWER (*In++); break; - }; + } } } } @@ -3276,7 +3402,7 @@ VMS_Case_Hack_Symbol (In, Out) */ /* Old behavior for regular GNU-C compiler */ - if (!flagseen['+']) + if (!flag_hash_long_names) truncate = 0; if ((Case_Hack_Bits != 0) || (truncate == 1)) { @@ -3297,10 +3423,7 @@ VMS_Case_Hack_Symbol (In, Out) for (i = 0; i < 7; i++) { init = result & 0x01f; - if (init < 10) - *Out++ = '0' + init; - else - *Out++ = 'A' + init - 10; + *Out++ = (init < 10) ? ('0' + init) : ('A' + init - 10); result = result >> 5; } } @@ -3309,8 +3432,8 @@ VMS_Case_Hack_Symbol (In, Out) * Done */ *Out = 0; - if (truncate == 1 && flagseen['+'] && flagseen['H']) - printf ("%s: Symbol %s replaced by %s\n", myname, old_name, new_name); + if (truncate == 1 && flag_hash_long_names && flag_show_after_trunc) + as_tsktsk (_("Symbol %s replaced by %s\n"), old_name, new_name); } @@ -3320,18 +3443,17 @@ VMS_Case_Hack_Symbol (In, Out) #define GLOBALSYMBOL_BIT 0x10000 #define GLOBALVALUE_BIT 0x20000 - -static +static void VMS_Modify_Psect_Attributes (Name, Attribute_Pointer) - char *Name; + const char *Name; int *Attribute_Pointer; { register int i; - register char *cp; + register const char *cp; int Negate; - static struct + static const struct { - char *Name; + const char *Name; int Value; } Attributes[] = { @@ -3425,14 +3547,21 @@ VMS_Modify_Psect_Attributes (Name, Attribute_Pointer) } +#define GBLSYM_REF 0 +#define GBLSYM_DEF 1 +#define GBLSYM_VAL 2 +#define GBLSYM_LCL 4 /* not GBL after all... */ +#define GBLSYM_WEAK 8 + /* - * Define a global symbol + * Define a global symbol (or possibly a local one). */ -static -VMS_Global_Symbol_Spec (Name, Psect_Number, Psect_Offset, Defined) - char *Name; +static void +VMS_Global_Symbol_Spec (Name, Psect_Number, Psect_Offset, Flags) + const char *Name; int Psect_Number; int Psect_Offset; + int Flags; { char Local[32]; @@ -3446,16 +3575,10 @@ VMS_Global_Symbol_Spec (Name, Psect_Number, Psect_Offset, Defined) if (Object_Record_Offset == 0) PUT_CHAR (OBJ_S_C_GSD); /* - * We are writing a Global symbol definition subrecord + * We are writing a Global (or local) symbol definition subrecord. */ - if (Psect_Number <= 255) - { - PUT_CHAR (GSD_S_C_SYM); - } - else - { - PUT_CHAR (GSD_S_C_SYMW); - } + PUT_CHAR ((Flags & GBLSYM_LCL) != 0 ? GSD_S_C_LSY : + ((unsigned) Psect_Number <= 255) ? GSD_S_C_SYM : GSD_S_C_SYMW); /* * Data type is undefined */ @@ -3463,53 +3586,43 @@ VMS_Global_Symbol_Spec (Name, Psect_Number, Psect_Offset, Defined) /* * Switch on Definition/Reference */ - if ((Defined & 1) != 0) + if ((Flags & GBLSYM_DEF) == 0) { /* - * Definition: - * Flags = "RELOCATABLE" and "DEFINED" for regular symbol - * = "DEFINED" for globalvalue (Defined & 2 == 1) + * Reference */ - if ((Defined & 2) == 0) - { - PUT_SHORT (GSY_S_M_DEF | GSY_S_M_REL); - } - else - { - PUT_SHORT (GSY_S_M_DEF); - }; + PUT_SHORT (((Flags & GBLSYM_VAL) == 0) ? GSY_S_M_REL : 0); + if ((Flags & GBLSYM_LCL) != 0) /* local symbols have extra field */ + PUT_SHORT (Current_Environment); + } + else + { + int sym_flags; + + /* + * Definition + *[ assert (LSY_S_M_DEF == GSY_S_M_DEF && LSY_S_M_REL == GSY_S_M_REL); ] + */ + sym_flags = GSY_S_M_DEF; + if (Flags & GBLSYM_WEAK) + sym_flags |= GSY_S_M_WEAK; + if ((Flags & GBLSYM_VAL) == 0) + sym_flags |= GSY_S_M_REL; + PUT_SHORT (sym_flags); + if ((Flags & GBLSYM_LCL) != 0) /* local symbols have extra field */ + PUT_SHORT (Current_Environment); /* * Psect Number */ - if (Psect_Number <= 255) - { - PUT_CHAR (Psect_Number); - } + if ((Flags & GBLSYM_LCL) == 0 && (unsigned) Psect_Number <= 255) + PUT_CHAR (Psect_Number); else - { - PUT_SHORT (Psect_Number); - } + PUT_SHORT (Psect_Number); /* * Offset */ PUT_LONG (Psect_Offset); } - else - { - /* - * Reference: - * Flags = "RELOCATABLE" for regular symbol, - * = "" for globalvalue (Defined & 2 == 1) - */ - if ((Defined & 2) == 0) - { - PUT_SHORT (GSY_S_M_REL); - } - else - { - PUT_SHORT (0); - }; - } /* * Finally, the global symbol name */ @@ -3518,8 +3631,40 @@ VMS_Global_Symbol_Spec (Name, Psect_Number, Psect_Offset, Defined) /* * Flush the buffer if it is more than 75% full */ - if (Object_Record_Offset > - (sizeof (Object_Record_Buffer) * 3 / 4)) + if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4)) + Flush_VMS_Object_Record_Buffer (); +} + +/* + * Define an environment to support local symbol references. + * This is just to mollify the linker; we don't actually do + * anything useful with it. + */ +static void +VMS_Local_Environment_Setup (Env_Name) + const char *Env_Name; +{ + /* We are writing a GSD record. */ + Set_VMS_Object_File_Record (OBJ_S_C_GSD); + /* If the buffer is empty we must insert the GSD record type. */ + if (Object_Record_Offset == 0) + PUT_CHAR (OBJ_S_C_GSD); + /* We are writing an ENV subrecord. */ + PUT_CHAR (GSD_S_C_ENV); + + ++Current_Environment; /* index of environment being defined */ + + /* ENV$W_FLAGS: we are defining the next environment. It's not nested. */ + PUT_SHORT (ENV_S_M_DEF); + /* ENV$W_ENVINDX: index is always 0 for non-nested definitions. */ + PUT_SHORT (0); + + /* ENV$B_NAMLNG + ENV$T_NAME: environment name in ASCIC format. */ + if (!Env_Name) Env_Name = ""; + PUT_COUNTED_STRING ((char *)Env_Name); + + /* Flush the buffer if it is more than 75% full. */ + if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4)) Flush_VMS_Object_Record_Buffer (); } @@ -3529,9 +3674,9 @@ VMS_Global_Symbol_Spec (Name, Psect_Number, Psect_Offset, Defined) */ static int VMS_Psect_Spec (Name, Size, Type, vsp) - char *Name; + const char *Name; int Size; - char *Type; + enum ps_type Type; struct VMS_Symbol *vsp; { char Local[32]; @@ -3540,50 +3685,46 @@ VMS_Psect_Spec (Name, Size, Type, vsp) /* * Generate the appropriate PSECT flags given the PSECT type */ - if (strcmp (Type, "COMMON") == 0) - { - /* - * Common block psects are: PIC,OVR,REL,GBL,SHR,RD,WRT - */ - Psect_Attributes = (GPS_S_M_PIC | GPS_S_M_OVR | GPS_S_M_REL | GPS_S_M_GBL | - GPS_S_M_SHR | GPS_S_M_RD | GPS_S_M_WRT); - } - else if (strcmp (Type, "CONST") == 0) - { - /* - * Common block psects are: PIC,OVR,REL,GBL,SHR,RD - */ - Psect_Attributes = (GPS_S_M_PIC | GPS_S_M_OVR | GPS_S_M_REL | GPS_S_M_GBL | - GPS_S_M_SHR | GPS_S_M_RD); - } - else if (strcmp (Type, "DATA") == 0) - { - /* - * The Data psects are PIC,REL,RD,WRT - */ - Psect_Attributes = - (GPS_S_M_PIC | GPS_S_M_REL | GPS_S_M_RD | GPS_S_M_WRT); - } - else if (strcmp (Type, "TEXT") == 0) - { - /* - * The Text psects are PIC,REL,SHR,EXE,RD - */ - Psect_Attributes = - (GPS_S_M_PIC | GPS_S_M_REL | GPS_S_M_SHR | - GPS_S_M_EXE | GPS_S_M_RD); - } - else + switch (Type) { - /* - * Error: Unknown psect type - */ - error ("Unknown VMS psect type"); + case ps_TEXT: + /* Text psects are PIC,noOVR,REL,noGBL,SHR,EXE,RD,noWRT. */ + Psect_Attributes = (GPS_S_M_PIC|GPS_S_M_REL|GPS_S_M_SHR|GPS_S_M_EXE + |GPS_S_M_RD); + break; + case ps_DATA: + /* Data psects are PIC,noOVR,REL,noGBL,noSHR,noEXE,RD,WRT. */ + Psect_Attributes = (GPS_S_M_PIC|GPS_S_M_REL|GPS_S_M_RD|GPS_S_M_WRT); + break; + case ps_COMMON: + /* Common block psects are: PIC,OVR,REL,GBL,noSHR,noEXE,RD,WRT. */ + Psect_Attributes = (GPS_S_M_PIC|GPS_S_M_OVR|GPS_S_M_REL|GPS_S_M_GBL + |GPS_S_M_RD|GPS_S_M_WRT); + break; + case ps_CONST: + /* Const data psects are: PIC,OVR,REL,GBL,noSHR,noEXE,RD,noWRT. */ + Psect_Attributes = (GPS_S_M_PIC|GPS_S_M_OVR|GPS_S_M_REL|GPS_S_M_GBL + |GPS_S_M_RD); + break; + case ps_CTORS: + /* Ctor psects are PIC,noOVR,REL,GBL,noSHR,noEXE,RD,noWRT. */ + Psect_Attributes = (GPS_S_M_PIC|GPS_S_M_REL|GPS_S_M_GBL|GPS_S_M_RD); + break; + case ps_DTORS: + /* Dtor psects are PIC,noOVR,REL,GBL,noSHR,noEXE,RD,noWRT. */ + Psect_Attributes = (GPS_S_M_PIC|GPS_S_M_REL|GPS_S_M_GBL|GPS_S_M_RD); + break; + default: + /* impossible */ + error (_("Unknown VMS psect type (%ld)"), (long) Type); + break; } /* * Modify the psect attributes according to any attribute string */ - if (HAS_PSECT_ATTRIBUTES (Name)) + if (vsp && S_GET_TYPE (vsp->Symbol) == N_ABS) + Psect_Attributes |= GLOBALVALUE_BIT; + else if (HAS_PSECT_ATTRIBUTES (Name)) VMS_Modify_Psect_Attributes (Name, &Psect_Attributes); /* * Check for globalref/def/val. @@ -3596,9 +3737,9 @@ VMS_Psect_Spec (Name, Size, Type, vsp) * fixup references are emitted correctly. */ vsp->Psect_Index = -1; /* to catch errors */ - S_GET_RAW_TYPE (vsp->Symbol) = N_UNDF; /* make refs work */ + S_SET_TYPE (vsp->Symbol, N_UNDF); /* make refs work */ return 1; /* decrement psect counter */ - }; + } if ((Psect_Attributes & GLOBALSYMBOL_BIT) != 0) { @@ -3606,26 +3747,21 @@ VMS_Psect_Spec (Name, Size, Type, vsp) { case N_UNDF | N_EXT: VMS_Global_Symbol_Spec (Name, vsp->Psect_Index, - vsp->Psect_Offset, 0); + vsp->Psect_Offset, GBLSYM_REF); vsp->Psect_Index = -1; - S_GET_RAW_TYPE (vsp->Symbol) = N_UNDF; + S_SET_TYPE (vsp->Symbol, N_UNDF); return 1; /* return and indicate no psect */ case N_DATA | N_EXT: VMS_Global_Symbol_Spec (Name, vsp->Psect_Index, - vsp->Psect_Offset, 1); + vsp->Psect_Offset, GBLSYM_DEF); /* In this case we still generate the psect */ break; default: - { - char Error_Line[256]; - sprintf (Error_Line, - "Globalsymbol attribute for symbol %s was unexpected.\n", - Name); - error (Error_Line); - break; - }; - }; /* switch */ - }; + as_fatal (_("Globalsymbol attribute for symbol %s was unexpected."), + Name); + break; + } /* switch */ + } Psect_Attributes &= 0xffff; /* clear out the globalref/def stuff */ /* @@ -3661,87 +3797,43 @@ VMS_Psect_Spec (Name, Size, Type, vsp) /* * Flush the buffer if it is more than 75% full */ - if (Object_Record_Offset > - (sizeof (Object_Record_Buffer) * 3 / 4)) + if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4)) Flush_VMS_Object_Record_Buffer (); return 0; } -/* - * Given the pointer to a symbol we calculate how big the data at the - * symbol is. We do this by looking for the next symbol (local or - * global) which will indicate the start of another datum. - */ -static int -VMS_Initialized_Data_Size (sp, End_Of_Data) - register struct symbol *sp; - int End_Of_Data; +/* Given the pointer to a symbol we calculate how big the data at the + symbol is. We do this by looking for the next symbol (local or global) + which will indicate the start of another datum. */ + +static offsetT +VMS_Initialized_Data_Size (s0P, End_Of_Data) + register symbolS *s0P; + unsigned End_Of_Data; { - register struct symbol *sp1, *Next_Symbol; + symbolS *s1P; + valueT s0P_val = S_GET_VALUE (s0P), s1P_val, + nearest_val = (valueT) End_Of_Data; - /* - * Find the next symbol - * it delimits this datum - */ - Next_Symbol = 0; - for (sp1 = symbol_rootP; sp1; sp1 = symbol_next (sp1)) + /* Find the nearest symbol what follows this one. */ + for (s1P = symbol_rootP; s1P; s1P = symbol_next (s1P)) { - /* - * The data type must match - */ - if (S_GET_TYPE (sp1) != N_DATA) - continue; - /* - * The symbol must be AFTER this symbol - */ - if (S_GET_VALUE (sp1) <= S_GET_VALUE (sp)) + /* The data type must match. */ + if (S_GET_TYPE (s1P) != N_DATA) continue; - /* - * We ignore THIS symbol - */ - if (sp1 == sp) - continue; - /* - * If there is already a candidate selected for the - * next symbol, see if we are a better candidate - */ - if (Next_Symbol) - { - /* - * We are a better candidate if we are "closer" - * to the symbol - */ - if (S_GET_VALUE (sp1) > - S_GET_VALUE (Next_Symbol)) - continue; - /* - * Win: Make this the candidate - */ - Next_Symbol = sp1; - } - else - { - /* - * This is the 1st candidate - */ - Next_Symbol = sp1; - } + s1P_val = S_GET_VALUE (s1P); + if (s1P_val > s0P_val && s1P_val < nearest_val) + nearest_val = s1P_val; } - /* - * Calculate its size - */ - return (Next_Symbol ? - (S_GET_VALUE (Next_Symbol) - - S_GET_VALUE (sp)) : - (End_Of_Data - S_GET_VALUE (sp))); + /* Calculate its size. */ + return (offsetT) (nearest_val - s0P_val); } - -/* - * Check symbol names for the Psect hack with a globalvalue, and then - * generate globalvalues for those that have it. - */ -static + +/* Check symbol names for the Psect hack with a globalvalue, and then + generate globalvalues for those that have it. */ + +static void VMS_Emit_Globalvalues (text_siz, data_siz, Data_Segment) unsigned text_siz; unsigned data_siz; @@ -3752,6 +3844,7 @@ VMS_Emit_Globalvalues (text_siz, data_siz, Data_Segment) int Size; int Psect_Attributes; int globalvalue; + int typ, abstyp; /* * Scan the symbol table for globalvalues, and emit def/ref when @@ -3760,51 +3853,77 @@ VMS_Emit_Globalvalues (text_siz, data_siz, Data_Segment) */ for (sp = symbol_rootP; sp; sp = sp->sy_next) { + typ = S_GET_RAW_TYPE (sp); + abstyp = ((typ & ~N_EXT) == N_ABS); /* * See if this is something we want to look at. */ - if ((S_GET_RAW_TYPE (sp) != (N_DATA | N_EXT)) && - (S_GET_RAW_TYPE (sp) != (N_UNDF | N_EXT))) + if (!abstyp && + typ != (N_DATA | N_EXT) && + typ != (N_UNDF | N_EXT)) continue; /* * See if this has globalvalue specification. */ Name = S_GET_NAME (sp); - if (!HAS_PSECT_ATTRIBUTES (Name)) + if (abstyp) + { + stripped_name = 0; + Psect_Attributes = GLOBALVALUE_BIT; + } + else if (HAS_PSECT_ATTRIBUTES (Name)) + { + stripped_name = (char *) xmalloc (strlen (Name) + 1); + strcpy (stripped_name, Name); + Psect_Attributes = 0; + VMS_Modify_Psect_Attributes (stripped_name, &Psect_Attributes); + } + else continue; - stripped_name = (char *) malloc (strlen (Name) + 1); - strcpy (stripped_name, Name); - Psect_Attributes = 0; - VMS_Modify_Psect_Attributes (stripped_name, &Psect_Attributes); - if ((Psect_Attributes & GLOBALVALUE_BIT) != 0) { - switch (S_GET_RAW_TYPE (sp)) + switch (typ) { + case N_ABS: + /* Local symbol references will want + to have an environment defined. */ + if (Current_Environment < 0) + VMS_Local_Environment_Setup (".N_ABS"); + VMS_Global_Symbol_Spec (Name, 0, + S_GET_VALUE (sp), + GBLSYM_DEF|GBLSYM_VAL|GBLSYM_LCL); + break; + case N_ABS | N_EXT: + VMS_Global_Symbol_Spec (Name, 0, + S_GET_VALUE (sp), + GBLSYM_DEF|GBLSYM_VAL); + break; case N_UNDF | N_EXT: - VMS_Global_Symbol_Spec (stripped_name, 0, 0, 2); + VMS_Global_Symbol_Spec (stripped_name, 0, 0, GBLSYM_VAL); break; case N_DATA | N_EXT: Size = VMS_Initialized_Data_Size (sp, text_siz + data_siz); if (Size > 4) - error ("Invalid data type for globalvalue"); - globalvalue = md_chars_to_number (Data_Segment + + error (_("Invalid data type for globalvalue")); + globalvalue = md_chars_to_number (Data_Segment + S_GET_VALUE (sp) - text_siz , Size); /* Three times for good luck. The linker seems to get confused if there are fewer than three */ - VMS_Global_Symbol_Spec (stripped_name, 0, 0, 2); - VMS_Global_Symbol_Spec (stripped_name, 0, globalvalue, 3); - VMS_Global_Symbol_Spec (stripped_name, 0, globalvalue, 3); + VMS_Global_Symbol_Spec (stripped_name, 0, 0, GBLSYM_VAL); + VMS_Global_Symbol_Spec (stripped_name, 0, globalvalue, + GBLSYM_DEF|GBLSYM_VAL); + VMS_Global_Symbol_Spec (stripped_name, 0, globalvalue, + GBLSYM_DEF|GBLSYM_VAL); break; default: - printf (" Invalid globalvalue of %s\n", stripped_name); + as_warn (_("Invalid globalvalue of %s"), stripped_name); break; - }; /* switch */ - }; /* if */ - free (stripped_name); /* clean up */ - }; /* for */ + } /* switch */ + } /* if */ + if (stripped_name) free (stripped_name); /* clean up */ + } /* for */ } @@ -3812,7 +3931,7 @@ VMS_Emit_Globalvalues (text_siz, data_siz, Data_Segment) /* * Define a procedure entry pt/mask */ -static +static void VMS_Procedure_Entry_Pt (Name, Psect_Number, Psect_Offset, Entry_Mask) char *Name; int Psect_Number; @@ -3833,14 +3952,7 @@ VMS_Procedure_Entry_Pt (Name, Psect_Number, Psect_Offset, Entry_Mask) /* * We are writing a Procedure Entry Pt/Mask subrecord */ - if (Psect_Number <= 255) - { - PUT_CHAR (GSD_S_C_EPM); - } - else - { - PUT_CHAR (GSD_S_C_EPMW); - } + PUT_CHAR (((unsigned) Psect_Number <= 255) ? GSD_S_C_EPM : GSD_S_C_EPMW); /* * Data type is undefined */ @@ -3852,14 +3964,10 @@ VMS_Procedure_Entry_Pt (Name, Psect_Number, Psect_Offset, Entry_Mask) /* * Psect Number */ - if (Psect_Number <= 255) - { - PUT_CHAR (Psect_Number); - } + if ((unsigned) Psect_Number <= 255) + PUT_CHAR (Psect_Number); else - { - PUT_SHORT (Psect_Number); - } + PUT_SHORT (Psect_Number); /* * Offset */ @@ -3876,8 +3984,7 @@ VMS_Procedure_Entry_Pt (Name, Psect_Number, Psect_Offset, Entry_Mask) /* * Flush the buffer if it is more than 75% full */ - if (Object_Record_Offset > - (sizeof (Object_Record_Buffer) * 3 / 4)) + if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4)) Flush_VMS_Object_Record_Buffer (); } @@ -3885,7 +3992,7 @@ VMS_Procedure_Entry_Pt (Name, Psect_Number, Psect_Offset, Entry_Mask) /* * Set the current location counter to a particular Psect and Offset */ -static +static void VMS_Set_Psect (Psect_Index, Offset, Record_Type) int Psect_Index; int Offset; @@ -3901,19 +4008,9 @@ VMS_Set_Psect (Psect_Index, Offset, Record_Type) if (Object_Record_Offset == 0) PUT_CHAR (Record_Type); /* - * Stack the Psect base + Longword Offset + * Stack the Psect base + Offset */ - if (Psect_Index < 255) - { - PUT_CHAR (TIR_S_C_STA_PL); - PUT_CHAR (Psect_Index); - } - else - { - PUT_CHAR (TIR_S_C_STA_WPL); - PUT_SHORT (Psect_Index); - } - PUT_LONG (Offset); + vms_tir_stack_psect (Psect_Index, Offset, 0); /* * Set relocation base */ @@ -3921,8 +4018,7 @@ VMS_Set_Psect (Psect_Index, Offset, Record_Type) /* * Flush the buffer if it is more than 75% full */ - if (Object_Record_Offset > - (sizeof (Object_Record_Buffer) * 3 / 4)) + if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4)) Flush_VMS_Object_Record_Buffer (); } @@ -3930,7 +4026,7 @@ VMS_Set_Psect (Psect_Index, Offset, Record_Type) /* * Store repeated immediate data in current Psect */ -static +static void VMS_Store_Repeated_Data (Repeat_Count, Pointer, Size, Record_Type) int Repeat_Count; register char *Pointer; @@ -3941,12 +4037,21 @@ VMS_Store_Repeated_Data (Repeat_Count, Pointer, Size, Record_Type) /* * Ignore zero bytes/words/longwords */ - if ((Size == sizeof (char)) && (*Pointer == 0)) - return; - if ((Size == sizeof (short)) && (*(short *) Pointer == 0)) - return; - if ((Size == sizeof (long)) && (*(long *) Pointer == 0)) - return; + switch (Size) + { + case 4: + if (Pointer[3] != 0 || Pointer[2] != 0) break; + /* else FALLTHRU */ + case 2: + if (Pointer[1] != 0) break; + /* else FALLTHRU */ + case 1: + if (Pointer[0] != 0) break; + /* zero value */ + return; + default: + break; + } /* * If the data is too big for a TIR_S_C_STO_RIVB sub-record * then we do it manually @@ -3981,8 +4086,7 @@ VMS_Store_Repeated_Data (Repeat_Count, Pointer, Size, Record_Type) /* * Flush the buffer if it is more than 75% full */ - if (Object_Record_Offset > - (sizeof (Object_Record_Buffer) * 3 / 4)) + if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4)) Flush_VMS_Object_Record_Buffer (); } @@ -3990,19 +4094,19 @@ VMS_Store_Repeated_Data (Repeat_Count, Pointer, Size, Record_Type) /* * Store a Position Independent Reference */ -static +static void VMS_Store_PIC_Symbol_Reference (Symbol, Offset, PC_Relative, Psect, Psect_Offset, Record_Type) - struct symbol *Symbol; + symbolS *Symbol; int Offset; int PC_Relative; int Psect; int Psect_Offset; int Record_Type; { - register struct VMS_Symbol *vsp = - (struct VMS_Symbol *) (Symbol->sy_number); + register struct VMS_Symbol *vsp = Symbol->sy_obj; char Local[32]; + int local_sym = 0; /* * We are writing a "Record_Type" record @@ -4014,23 +4118,14 @@ VMS_Store_PIC_Symbol_Reference (Symbol, Offset, PC_Relative, if (Object_Record_Offset == 0) PUT_CHAR (Record_Type); /* - * Set to the appropriate offset in the Psect + * Set to the appropriate offset in the Psect. + * For a Code reference we need to fix the operand + * specifier as well, so back up 1 byte; + * for a Data reference we just store HERE. */ - if (PC_Relative) - { - /* - * For a Code reference we need to fix the operand - * specifier as well (so back up 1 byte) - */ - VMS_Set_Psect (Psect, Psect_Offset - 1, Record_Type); - } - else - { - /* - * For a Data reference we just store HERE - */ - VMS_Set_Psect (Psect, Psect_Offset, Record_Type); - } + VMS_Set_Psect (Psect, + PC_Relative ? Psect_Offset - 1 : Psect_Offset, + Record_Type); /* * Make sure we are still generating a "Record Type" record */ @@ -4044,6 +4139,10 @@ VMS_Store_PIC_Symbol_Reference (Symbol, Offset, PC_Relative, /* * Global symbol */ + case N_ABS: + local_sym = 1; + /*FALLTHRU*/ + case N_ABS | N_EXT: #ifdef NOT_VAX_11_C_COMPATIBLE case N_UNDF | N_EXT: case N_DATA | N_EXT: @@ -4057,7 +4156,16 @@ VMS_Store_PIC_Symbol_Reference (Symbol, Offset, PC_Relative, /* * Stack the global symbol value */ - PUT_CHAR (TIR_S_C_STA_GBL); + if (!local_sym) + { + PUT_CHAR (TIR_S_C_STA_GBL); + } + else + { + /* Local symbols have an extra field. */ + PUT_CHAR (TIR_S_C_STA_LSY); + PUT_SHORT (Current_Environment); + } PUT_COUNTED_STRING (Local); if (Offset) { @@ -4079,17 +4187,9 @@ VMS_Store_PIC_Symbol_Reference (Symbol, Offset, PC_Relative, /* * Stack the Psect (+offset) */ - if (vsp->Psect_Index < 255) - { - PUT_CHAR (TIR_S_C_STA_PL); - PUT_CHAR (vsp->Psect_Index); - } - else - { - PUT_CHAR (TIR_S_C_STA_WPL); - PUT_SHORT (vsp->Psect_Index); - } - PUT_LONG (vsp->Psect_Offset + Offset); + vms_tir_stack_psect (vsp->Psect_Index, + vsp->Psect_Offset + Offset, + 0); break; /* * Local text @@ -4098,17 +4198,9 @@ VMS_Store_PIC_Symbol_Reference (Symbol, Offset, PC_Relative, /* * Stack the Psect (+offset) */ - if (vsp->Psect_Index < 255) - { - PUT_CHAR (TIR_S_C_STA_PL); - PUT_CHAR (vsp->Psect_Index); - } - else - { - PUT_CHAR (TIR_S_C_STA_WPL); - PUT_SHORT (vsp->Psect_Index); - } - PUT_LONG (S_GET_VALUE (Symbol) + Offset); + vms_tir_stack_psect (vsp->Psect_Index, + S_GET_VALUE (Symbol) + Offset, + 0); break; /* * Initialized local or global data @@ -4121,17 +4213,9 @@ VMS_Store_PIC_Symbol_Reference (Symbol, Offset, PC_Relative, /* * Stack the Psect (+offset) */ - if (vsp->Psect_Index < 255) - { - PUT_CHAR (TIR_S_C_STA_PL); - PUT_CHAR (vsp->Psect_Index); - } - else - { - PUT_CHAR (TIR_S_C_STA_WPL); - PUT_SHORT (vsp->Psect_Index); - } - PUT_LONG (vsp->Psect_Offset + Offset); + vms_tir_stack_psect (vsp->Psect_Index, + vsp->Psect_Offset + Offset, + 0); break; } /* @@ -4141,8 +4225,7 @@ VMS_Store_PIC_Symbol_Reference (Symbol, Offset, PC_Relative, /* * Flush the buffer if it is more than 75% full */ - if (Object_Record_Offset > - (sizeof (Object_Record_Buffer) * 3 / 4)) + if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4)) Flush_VMS_Object_Record_Buffer (); } @@ -4154,12 +4237,12 @@ VMS_Store_PIC_Symbol_Reference (Symbol, Offset, PC_Relative, * THIS SHOULD BE REPLACED BY THE USE OF TIR_S_C_STO_PIRR IN THE * PIC CODE GENERATING FIXUP ROUTINE. */ -static +static void VMS_Fix_Indirect_Reference (Text_Psect, Offset, fragP, text_frag_root) int Text_Psect; - int Offset; + addressT Offset; register fragS *fragP; - struct frag *text_frag_root; + fragS *text_frag_root; { /* * The addressing mode byte is 1 byte before the address @@ -4185,14 +4268,14 @@ VMS_Fix_Indirect_Reference (Text_Psect, Offset, fragP, text_frag_root) * If we couldn't find the frag, things are BAD!! */ if (fragP == 0) - error ("Couldn't find fixup fragment when checking for indirect reference"); + error (_("Couldn't find fixup fragment when checking for indirect reference")); } /* * Check for indirect PC relative addressing mode */ if (fragP->fr_literal[Offset - fragP->fr_address] == (char) 0xff) { - static char Address_Mode = 0xff; + static char Address_Mode = (char) 0xff; /* * Yes: Store the indirect mode back into the image @@ -4203,11 +4286,24 @@ VMS_Fix_Indirect_Reference (Text_Psect, Offset, fragP, text_frag_root) } } + /* * If the procedure "main()" exists we have to add the instruction * "jsb c$main_args" at the beginning to be compatible with VAX-11 "C". + * + * FIXME: the macro name `HACK_DEC_C_STARTUP' should be renamed + * to `HACK_VAXCRTL_STARTUP' because Digital's compiler + * named "DEC C" uses run-time library "DECC$SHR", but this + * startup code is for "VAXCRTL", the library for Digital's + * older "VAX C". Also, this extra code isn't needed for + * supporting gcc because it already generates the VAXCRTL + * startup call when compiling main(). The reference to + * `flag_hash_long_names' looks very suspicious too; + * probably an old-style command line option was inadvertently + * overloaded here, then blindly converted into the new one. */ -VMS_Check_For_Main () +void +vms_check_for_main () { register symbolS *symbolP; #ifdef HACK_DEC_C_STARTUP /* JF */ @@ -4219,12 +4315,12 @@ VMS_Check_For_Main () int i; #endif /* HACK_DEC_C_STARTUP */ - symbolP = (struct symbol *) symbol_find ("_main"); + symbolP = (symbolS *) symbol_find ("_main"); if (symbolP && !S_IS_DEBUG (symbolP) && S_IS_EXTERNAL (symbolP) && (S_GET_TYPE (symbolP) == N_TEXT)) { #ifdef HACK_DEC_C_STARTUP - if (!flagseen['+']) + if (!flag_hash_long_names) { #endif /* @@ -4364,18 +4460,20 @@ VMS_Check_For_Main () * JSB instruction. */ symbolP = (symbolS *) xmalloc (sizeof (*symbolP)); - S_GET_NAME (symbolP) = "_c$main_args"; + S_SET_NAME (symbolP, "_C$MAIN_ARGS"); S_SET_TYPE (symbolP, N_UNDF); - S_GET_OTHER (symbolP) = 0; - S_GET_DESC (symbolP) = 0; + S_SET_OTHER (symbolP, 0); + S_SET_DESC (symbolP, 0); S_SET_VALUE (symbolP, 0); symbolP->sy_name_offset = 0; symbolP->sy_number = 0; + symbolP->sy_obj = 0; symbolP->sy_frag = New_Frag; symbolP->sy_resolved = 0; symbolP->sy_resolving = 0; /* this actually inserts at the beginning of the list */ - symbol_append (symbol_rootP, symbolP, &symbol_rootP, &symbol_lastP); + symbol_append (symbol_rootP, symbolP, + &symbol_rootP, &symbol_lastP); symbol_rootP = symbolP; /* @@ -4389,7 +4487,7 @@ VMS_Check_For_Main () fixP->fx_addsy = symbolP; fixP->fx_subsy = 0; fixP->fx_offset = 0; - fixP->fx_size = sizeof (long); + fixP->fx_size = 4; fixP->fx_pcrel = 1; fixP->fx_next = text_fix_root; text_fix_root = fixP; @@ -4416,1030 +4514,1053 @@ VMS_Check_For_Main () } } + /* - * Write a VAX/VMS object file (everything else has been done!) + * Beginning of vms_write_object_file(). */ -VMS_write_object_file (text_siz, data_siz, bss_siz, text_frag_root, - data_frag_root) - unsigned text_siz; - unsigned data_siz; - unsigned bss_siz; + +static +struct vms_obj_state { + + /* Next program section index to use. */ + int psect_number; + + /* Psect index for code. Always ends up #0. */ + int text_psect; + + /* Psect index for initialized static variables. */ + int data_psect; + + /* Psect index for uninitialized static variables. */ + int bss_psect; + + /* Psect index for static constructors. */ + int ctors_psect; + + /* Psect index for static destructors. */ + int dtors_psect; + + /* Number of bytes used for local symbol data. */ + int local_initd_data_size; + + /* Dynamic buffer for initialized data. */ + char *data_segment; + +} vms_obj_state; + +#define Psect_Number vms_obj_state.psect_number +#define Text_Psect vms_obj_state.text_psect +#define Data_Psect vms_obj_state.data_psect +#define Bss_Psect vms_obj_state.bss_psect +#define Ctors_Psect vms_obj_state.ctors_psect +#define Dtors_Psect vms_obj_state.dtors_psect +#define Local_Initd_Data_Size vms_obj_state.local_initd_data_size +#define Data_Segment vms_obj_state.data_segment + +#define IS_GXX_VTABLE(symP) (strncmp (S_GET_NAME (symP), "__vt.", 5) == 0) +#define IS_GXX_XTOR(symP) (strncmp (S_GET_NAME (symP), "__GLOBAL_.", 10) == 0) +#define XTOR_SIZE 4 + + +/* Perform text segment fixups. */ + +static void +vms_fixup_text_section (text_siz, text_frag_root, data_frag_root) + unsigned text_siz ATTRIBUTE_UNUSED; struct frag *text_frag_root; struct frag *data_frag_root; { register fragS *fragP; - register symbolS *symbolP; - register symbolS *sp; register struct fix *fixP; - register struct VMS_Symbol *vsp; - char *Data_Segment; - int Local_Initialized_Data_Size = 0; - int Globalref; - int Psect_Number = 0; /* Psect Index Number */ - int Text_Psect = -1; /* Text Psect Index */ - int Data_Psect = -2; /* Data Psect Index JF: Was -1 */ - int Bss_Psect = -3; /* Bss Psect Index JF: Was -1 */ + offsetT dif; + + /* Scan the text fragments. */ + for (fragP = text_frag_root; fragP; fragP = fragP->fr_next) + { + /* Stop if we get to the data fragments. */ + if (fragP == data_frag_root) + break; + /* Ignore fragments with no data. */ + if ((fragP->fr_fix == 0) && (fragP->fr_var == 0)) + continue; + /* Go the the appropriate offset in the Text Psect. */ + VMS_Set_Psect (Text_Psect, fragP->fr_address, OBJ_S_C_TIR); + /* Store the "fixed" part. */ + if (fragP->fr_fix) + VMS_Store_Immediate_Data (fragP->fr_literal, + fragP->fr_fix, + OBJ_S_C_TIR); + /* Store the "variable" part. */ + if (fragP->fr_var && fragP->fr_offset) + VMS_Store_Repeated_Data (fragP->fr_offset, + fragP->fr_literal + fragP->fr_fix, + fragP->fr_var, + OBJ_S_C_TIR); + } /* text frag loop */ /* - * Create the VMS object file - */ - Create_VMS_Object_File (); - /* - * Write the module header records - */ - Write_VMS_MHD_Records (); - - /* - * Store the Data segment: - * - * Since this is REALLY hard to do any other way, - * we actually manufacture the data segment and - * the store the appropriate values out of it. - * We need to generate this early, so that globalvalues - * can be properly emitted. + * Now we go through the text segment fixups and generate + * TIR records to fix up addresses within the Text Psect. */ - if (data_siz > 0) + for (fixP = text_fix_root; fixP; fixP = fixP->fx_next) { - /* - * Allocate the data segment - */ - Data_Segment = (char *) xmalloc (data_siz); - /* - * Run through the data fragments, filling in the segment - */ - for (fragP = data_frag_root; fragP; fragP = fragP->fr_next) + /* We DO handle the case of "Symbol - Symbol" as + long as it is in the same segment. */ + if (fixP->fx_subsy && fixP->fx_addsy) { - register long int count; - register char *fill_literal; - register long int fill_size; - int i; - - i = fragP->fr_address - text_siz; - if (fragP->fr_fix) - memcpy (Data_Segment + i, - fragP->fr_literal, - fragP->fr_fix); - i += fragP->fr_fix; + /* They need to be in the same segment. */ + if (S_GET_RAW_TYPE (fixP->fx_subsy) != + S_GET_RAW_TYPE (fixP->fx_addsy)) + error (_("Fixup data addsy and subsy don't have the same type")); + /* And they need to be in one that we can check the psect on. */ + if ((S_GET_TYPE (fixP->fx_addsy) != N_DATA) && + (S_GET_TYPE (fixP->fx_addsy) != N_TEXT)) + error (_("Fixup data addsy and subsy don't have an appropriate type")); + /* This had better not be PC relative! */ + if (fixP->fx_pcrel) + error (_("Fixup data is erroneously \"pcrel\"")); + /* Subtract their values to get the difference. */ + dif = S_GET_VALUE (fixP->fx_addsy) - S_GET_VALUE (fixP->fx_subsy); + md_number_to_chars (Local, (valueT)dif, fixP->fx_size); + /* Now generate the fixup object records; + set the psect and store the data. */ + VMS_Set_Psect (Text_Psect, + fixP->fx_where + fixP->fx_frag->fr_address, + OBJ_S_C_TIR); + VMS_Store_Immediate_Data (Local, + fixP->fx_size, + OBJ_S_C_TIR); + continue; /* done with this fixup */ + } /* if fx_subsy && fx_addsy */ + /* Size will HAVE to be "long". */ + if (fixP->fx_size != 4) + error (_("Fixup datum is not a longword")); + /* Symbol must be "added" (if it is ever + subtracted we can fix this assumption). */ + if (fixP->fx_addsy == 0) + error (_("Fixup datum is not \"fixP->fx_addsy\"")); + /* Store the symbol value in a PIC fashion. */ + VMS_Store_PIC_Symbol_Reference (fixP->fx_addsy, + fixP->fx_offset, + fixP->fx_pcrel, + Text_Psect, + fixP->fx_where + fixP->fx_frag->fr_address, + OBJ_S_C_TIR); + /* + * Check for indirect address reference, which has to be fixed up + * (as the linker will screw it up with TIR_S_C_STO_PICR)... + */ + if (fixP->fx_pcrel) + VMS_Fix_Indirect_Reference (Text_Psect, + fixP->fx_where + fixP->fx_frag->fr_address, + fixP->fx_frag, + text_frag_root); + } /* text fix loop */ +} + + +/* Create a buffer holding the data segment. */ + +static void +synthesize_data_segment (data_siz, text_siz, data_frag_root) + unsigned data_siz; + unsigned text_siz; + struct frag *data_frag_root; +{ + register fragS *fragP; + char *fill_literal; + long fill_size, count, i; + + /* Allocate the data segment. */ + Data_Segment = (char *) xmalloc (data_siz); + /* Run through the data fragments, filling in the segment. */ + for (fragP = data_frag_root; fragP; fragP = fragP->fr_next) + { + i = fragP->fr_address - text_siz; + if (fragP->fr_fix) + memcpy (Data_Segment + i, fragP->fr_literal, fragP->fr_fix); + i += fragP->fr_fix; + if ((fill_size = fragP->fr_var) != 0) + { fill_literal = fragP->fr_literal + fragP->fr_fix; - fill_size = fragP->fr_var; for (count = fragP->fr_offset; count; count--) { - if (fill_size) - memcpy (Data_Segment + i, fill_literal, fill_size); + memcpy (Data_Segment + i, fill_literal, fill_size); i += fill_size; } } - } + } /* data frag loop */ + return; +} - /* - * Generate the VMS object file records - * 1st GSD then TIR records - */ +/* Perform data segment fixups. */ - /******* Global Symbol Dictionary *******/ - /* - * Emit globalvalues now. We must do this before the text psect - * is defined, or we will get linker warnings about multiply defined - * symbols. All of the globalvalues "reference" psect 0, although - * it really does not have anything to do with it. - */ - VMS_Emit_Globalvalues (text_siz, data_siz, Data_Segment); - /* - * Define the Text Psect - */ - Text_Psect = Psect_Number++; - VMS_Psect_Spec ("$code", text_siz, "TEXT", 0); - /* - * Define the BSS Psect - */ - if (bss_siz > 0) +static void +vms_fixup_data_section (data_siz, text_siz) + unsigned int data_siz ATTRIBUTE_UNUSED; + unsigned int text_siz; +{ + register struct VMS_Symbol *vsp; + register struct fix *fixP; + register symbolS *sp; + addressT fr_address; + offsetT dif; + valueT val; + + /* Run through all the data symbols and store the data. */ + for (vsp = VMS_Symbols; vsp; vsp = vsp->Next) { - Bss_Psect = Psect_Number++; - VMS_Psect_Spec ("$uninitialized_data", bss_siz, "DATA", 0); - } -#ifndef gxx_bug_fixed - /* - * The g++ compiler does not write out external references to vtables - * correctly. Check for this and holler if we see it happening. - * If that compiler bug is ever fixed we can remove this. - */ - for (sp = symbol_rootP; sp; sp = symbol_next (sp)) + /* Ignore anything other than data symbols. */ + if (S_GET_TYPE (vsp->Symbol) != N_DATA) + continue; + /* Set the Psect + Offset. */ + VMS_Set_Psect (vsp->Psect_Index, + vsp->Psect_Offset, + OBJ_S_C_TIR); + /* Store the data. */ + val = S_GET_VALUE (vsp->Symbol); + VMS_Store_Immediate_Data (Data_Segment + val - text_siz, + vsp->Size, + OBJ_S_C_TIR); + } /* N_DATA symbol loop */ + + /* + * Now we go through the data segment fixups and generate + * TIR records to fix up addresses within the Data Psects. + */ + for (fixP = data_fix_root; fixP; fixP = fixP->fx_next) { - /* - * Dispatch on symbol type - */ - switch (S_GET_RAW_TYPE (sp)) { - /* - * Global Reference - */ - case N_UNDF: - /* - * Make a GSD global symbol reference - * record. - */ - if (strncmp (S_GET_NAME (sp),"__vt.",5) == 0) - { - S_GET_RAW_TYPE (sp) = N_UNDF | N_EXT; - as_warn("g++ wrote an extern reference to %s as a routine.", - S_GET_NAME (sp)); - as_warn("I will fix it, but I hope that it was not really a routine"); - }; - break; - default: - break; - } + /* Find the symbol for the containing datum. */ + for (vsp = VMS_Symbols; vsp; vsp = vsp->Next) + { + /* Only bother with Data symbols. */ + sp = vsp->Symbol; + if (S_GET_TYPE (sp) != N_DATA) + continue; + /* Ignore symbol if After fixup. */ + val = S_GET_VALUE (sp); + fr_address = fixP->fx_frag->fr_address; + if (val > fixP->fx_where + fr_address) + continue; + /* See if the datum is here. */ + if (val + vsp->Size <= fixP->fx_where + fr_address) + continue; + /* We DO handle the case of "Symbol - Symbol" as + long as it is in the same segment. */ + if (fixP->fx_subsy && fixP->fx_addsy) + { + /* They need to be in the same segment. */ + if (S_GET_RAW_TYPE (fixP->fx_subsy) != + S_GET_RAW_TYPE (fixP->fx_addsy)) + error (_("Fixup data addsy and subsy don't have the same type")); + /* And they need to be in one that we can check the psect on. */ + if ((S_GET_TYPE (fixP->fx_addsy) != N_DATA) && + (S_GET_TYPE (fixP->fx_addsy) != N_TEXT)) + error (_("Fixup data addsy and subsy don't have an appropriate type")); + /* This had better not be PC relative! */ + if (fixP->fx_pcrel) + error (_("Fixup data is erroneously \"pcrel\"")); + /* Subtract their values to get the difference. */ + dif = S_GET_VALUE (fixP->fx_addsy) - S_GET_VALUE (fixP->fx_subsy); + md_number_to_chars (Local, (valueT)dif, fixP->fx_size); + /* + * Now generate the fixup object records; + * set the psect and store the data. + */ + VMS_Set_Psect (vsp->Psect_Index, + fr_address + fixP->fx_where + - val + vsp->Psect_Offset, + OBJ_S_C_TIR); + VMS_Store_Immediate_Data (Local, + fixP->fx_size, + OBJ_S_C_TIR); + break; /* done with this fixup */ + } + /* Size will HAVE to be "long". */ + if (fixP->fx_size != 4) + error (_("Fixup datum is not a longword")); + /* Symbol must be "added" (if it is ever + subtracted we can fix this assumption). */ + if (fixP->fx_addsy == 0) + error (_("Fixup datum is not \"fixP->fx_addsy\"")); + /* Store the symbol value in a PIC fashion. */ + VMS_Store_PIC_Symbol_Reference (fixP->fx_addsy, + fixP->fx_offset, + fixP->fx_pcrel, + vsp->Psect_Index, + fr_address + fixP->fx_where + - val + vsp->Psect_Offset, + OBJ_S_C_TIR); + /* Done with this fixup. */ + break; + } /* vms_symbol loop */ + + } /* data fix loop */ +} + +/* Perform ctors/dtors segment fixups. */ + +static void +vms_fixup_xtors_section (symbols, sect_no) + struct VMS_Symbol *symbols; + int sect_no ATTRIBUTE_UNUSED; +{ + register struct VMS_Symbol *vsp; + + /* Run through all the symbols and store the data. */ + for (vsp = symbols; vsp; vsp = vsp->Next) + { + register symbolS *sp; + + /* Set relocation base. */ + VMS_Set_Psect (vsp->Psect_Index, vsp->Psect_Offset, OBJ_S_C_TIR); + + sp = vsp->Symbol; + /* Stack the Psect base with its offset. */ + VMS_Set_Data (Text_Psect, S_GET_VALUE (sp), OBJ_S_C_TIR, 0); } -#endif /* gxx_bug_fixed */ + /* Flush the buffer if it is more than 75% full. */ + if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4)) + Flush_VMS_Object_Record_Buffer (); + + return; +} + + +/* Define symbols for the linker. */ + +static void +global_symbol_directory (text_siz, data_siz) + unsigned text_siz, data_siz; +{ + register fragS *fragP; + register symbolS *sp; + register struct VMS_Symbol *vsp; + int Globalref, define_as_global_symbol; + +#if 0 + /* The g++ compiler does not write out external references to + vtables correctly. Check for this and holler if we see it + happening. If that compiler bug is ever fixed we can remove + this. + + (Jun'95: gcc 2.7.0's cc1plus still exhibits this behavior.) + + This was reportedly fixed as of June 2, 1998. */ + + for (sp = symbol_rootP; sp; sp = symbol_next (sp)) + if (S_GET_RAW_TYPE (sp) == N_UNDF && IS_GXX_VTABLE (sp)) + { + S_SET_TYPE (sp, N_UNDF | N_EXT); + S_SET_OTHER (sp, 1); + as_warn (_("g++ wrote an extern reference to `%s' as a routine.\nI will fix it, but I hope that it was note really a routine."), + S_GET_NAME (sp)); + } +#endif + /* - * Now scan the symbols and emit the appropriate GSD records + * Now scan the symbols and emit the appropriate GSD records */ for (sp = symbol_rootP; sp; sp = symbol_next (sp)) { - /* - * Dispatch on symbol type - */ + define_as_global_symbol = 0; + vsp = 0; + /* Dispatch on symbol type. */ switch (S_GET_RAW_TYPE (sp)) { - /* - * Global uninitialized data - */ + + /* Global uninitialized data. */ case N_UNDF | N_EXT: - /* - * Make a VMS data symbol entry - */ - vsp = (struct VMS_Symbol *) - xmalloc (sizeof (*vsp)); + /* Make a VMS data symbol entry. */ + vsp = (struct VMS_Symbol *) xmalloc (sizeof *vsp); vsp->Symbol = sp; vsp->Size = S_GET_VALUE (sp); vsp->Psect_Index = Psect_Number++; vsp->Psect_Offset = 0; vsp->Next = VMS_Symbols; VMS_Symbols = vsp; - sp->sy_number = (int) vsp; - /* - * Make the psect for this data - */ - if (S_GET_OTHER (sp)) - Globalref = VMS_Psect_Spec ( - S_GET_NAME (sp), - vsp->Size, - "CONST", - vsp); - else - Globalref = VMS_Psect_Spec ( - S_GET_NAME (sp), - vsp->Size, - "COMMON", - vsp); + sp->sy_obj = vsp; + /* Make the psect for this data. */ + Globalref = VMS_Psect_Spec (S_GET_NAME (sp), + vsp->Size, + S_GET_OTHER (sp) ? ps_CONST : ps_COMMON, + vsp); if (Globalref) Psect_Number--; - -/* See if this is an external vtable. We want to help the linker find - these things in libraries, so we make a symbol reference. This - is not compatible with VAX-C usage for variables, but since vtables are - only used internally by g++, we can get away with this hack. */ - - if(strncmp (S_GET_NAME (sp), "__vt.", 5) == 0) - VMS_Global_Symbol_Spec (S_GET_NAME(sp), - vsp->Psect_Index, - 0, - 0); - #ifdef NOT_VAX_11_C_COMPATIBLE - /* - * Place a global symbol at the - * beginning of the Psect - */ - VMS_Global_Symbol_Spec (S_GET_NAME (sp), - vsp->Psect_Index, - 0, - 1); -#endif /* NOT_VAX_11_C_COMPATIBLE */ + define_as_global_symbol = 1; +#else + /* See if this is an external vtable. We want to help the + linker find these things in libraries, so we make a symbol + reference. This is not compatible with VAX-C usage for + variables, but since vtables are only used internally by + g++, we can get away with this hack. */ + define_as_global_symbol = IS_GXX_VTABLE (sp); +#endif break; - /* - * Local uninitialized data - */ + + /* Local uninitialized data. */ case N_BSS: - /* - * Make a VMS data symbol entry - */ - vsp = (struct VMS_Symbol *) - xmalloc (sizeof (*vsp)); + /* Make a VMS data symbol entry. */ + vsp = (struct VMS_Symbol *) xmalloc (sizeof *vsp); vsp->Symbol = sp; vsp->Size = 0; vsp->Psect_Index = Bss_Psect; - vsp->Psect_Offset = - S_GET_VALUE (sp) - - bss_address_frag.fr_address; + vsp->Psect_Offset = S_GET_VALUE (sp) - bss_address_frag.fr_address; vsp->Next = VMS_Symbols; VMS_Symbols = vsp; - sp->sy_number = (int) vsp; + sp->sy_obj = vsp; break; - /* - * Global initialized data - */ + + /* Global initialized data. */ case N_DATA | N_EXT: - /* - * Make a VMS data symbol entry - */ - vsp = (struct VMS_Symbol *) - xmalloc (sizeof (*vsp)); + /* Make a VMS data symbol entry. */ + vsp = (struct VMS_Symbol *) xmalloc (sizeof *vsp); vsp->Symbol = sp; - vsp->Size = VMS_Initialized_Data_Size (sp, - text_siz + data_siz); + vsp->Size = VMS_Initialized_Data_Size (sp, text_siz + data_siz); vsp->Psect_Index = Psect_Number++; vsp->Psect_Offset = 0; vsp->Next = VMS_Symbols; VMS_Symbols = vsp; - sp->sy_number = (int) vsp; - /* - * Make its psect - */ - if (S_GET_OTHER (sp)) - Globalref = VMS_Psect_Spec ( - S_GET_NAME (sp), - vsp->Size, - "CONST", - vsp); - else - Globalref = VMS_Psect_Spec ( - S_GET_NAME (sp), - vsp->Size, - "COMMON", - vsp); + sp->sy_obj = vsp; + /* Make its psect. */ + Globalref = VMS_Psect_Spec (S_GET_NAME (sp), + vsp->Size, + S_GET_OTHER (sp) ? ps_CONST : ps_COMMON, + vsp); if (Globalref) Psect_Number--; - -/* See if this is an external vtable. We want to help the linker find - these things in libraries, so we make a symbol definition. This - is not compatible with VAX-C usage for variables, but since vtables are - only used internally by g++, we can get away with this hack. */ - - if(strncmp (S_GET_NAME (sp), "__vt.", 5) == 0) - VMS_Global_Symbol_Spec (S_GET_NAME (sp), - vsp->Psect_Index, - 0, - 1); - #ifdef NOT_VAX_11_C_COMPATIBLE - /* - * Place a global symbol at the - * beginning of the Psect - */ - VMS_Global_Symbol_Spec (S_GET_NAME (sp), - vsp->Psect_Index, - 0, - 1); -#endif /* NOT_VAX_11_C_COMPATIBLE */ + define_as_global_symbol = 1; +#else + /* See N_UNDF|N_EXT above for explanation. */ + define_as_global_symbol = IS_GXX_VTABLE (sp); +#endif break; - /* - * Local initialized data - */ + + /* Local initialized data. */ case N_DATA: - /* - * Make a VMS data symbol entry - */ - vsp = (struct VMS_Symbol *) - xmalloc (sizeof (*vsp)); - vsp->Symbol = sp; - vsp->Size = - VMS_Initialized_Data_Size (sp, - text_siz + data_siz); - vsp->Psect_Index = Data_Psect; - vsp->Psect_Offset = - Local_Initialized_Data_Size; - Local_Initialized_Data_Size += vsp->Size; - vsp->Next = VMS_Symbols; - VMS_Symbols = vsp; - sp->sy_number = (int) vsp; + { + char *sym_name = S_GET_NAME (sp); + + /* Always suppress local numeric labels. */ + if (sym_name && strcmp (sym_name, FAKE_LABEL_NAME) == 0) + break; + + /* Make a VMS data symbol entry. */ + vsp = (struct VMS_Symbol *) xmalloc (sizeof *vsp); + vsp->Symbol = sp; + vsp->Size = VMS_Initialized_Data_Size (sp, text_siz + data_siz); + vsp->Psect_Index = Data_Psect; + vsp->Psect_Offset = Local_Initd_Data_Size; + Local_Initd_Data_Size += vsp->Size; + vsp->Next = VMS_Symbols; + VMS_Symbols = vsp; + sp->sy_obj = vsp; + } break; - /* - * Global Text definition - */ + + /* Global Text definition. */ case N_TEXT | N_EXT: { - unsigned short Entry_Mask; - - /* - * Get the entry mask - */ - fragP = sp->sy_frag; - Entry_Mask = (fragP->fr_literal[0] & 0xff) + - ((fragP->fr_literal[1] & 0xff) - << 8); - /* - * Define the Procedure entry pt. - */ - VMS_Procedure_Entry_Pt (S_GET_NAME (sp), + + if (IS_GXX_XTOR (sp)) + { + vsp = (struct VMS_Symbol *) xmalloc (sizeof *vsp); + vsp->Symbol = sp; + vsp->Size = XTOR_SIZE; + sp->sy_obj = vsp; + switch ((S_GET_NAME (sp))[10]) + { + case 'I': + vsp->Psect_Index = Ctors_Psect; + vsp->Psect_Offset = (Ctors_Symbols==0)?0:(Ctors_Symbols->Psect_Offset+XTOR_SIZE); + vsp->Next = Ctors_Symbols; + Ctors_Symbols = vsp; + break; + case 'D': + vsp->Psect_Index = Dtors_Psect; + vsp->Psect_Offset = (Dtors_Symbols==0)?0:(Dtors_Symbols->Psect_Offset+XTOR_SIZE); + vsp->Next = Dtors_Symbols; + Dtors_Symbols = vsp; + break; + case 'G': + as_warn (_("Can't handle global xtors symbols yet.")); + break; + default: + as_warn (_("Unknown %s"), S_GET_NAME (sp)); + break; + } + } + else + { + unsigned short Entry_Mask; + + /* Get the entry mask. */ + fragP = sp->sy_frag; + /* First frag might be empty if we're generating listings. + So skip empty rs_fill frags. */ + while (fragP && fragP->fr_type == rs_fill && fragP->fr_fix == 0) + fragP = fragP->fr_next; + + /* If first frag doesn't contain the data, what do we do? + If it's possibly smaller than two bytes, that would + imply that the entry mask is not stored where we're + expecting it. + + If you can find a test case that triggers this, report + it (and tell me what the entry mask field ought to be), + and I'll try to fix it. KR */ + if (fragP->fr_fix < 2) + abort (); + + Entry_Mask = (fragP->fr_literal[0] & 0x00ff) | + ((fragP->fr_literal[1] & 0x00ff) << 8); + /* Define the procedure entry point. */ + VMS_Procedure_Entry_Pt (S_GET_NAME (sp), Text_Psect, S_GET_VALUE (sp), Entry_Mask); + } break; } - /* - * Local Text definition - */ + + /* Local Text definition. */ case N_TEXT: - /* - * Make a VMS data symbol entry - */ + /* Make a VMS data symbol entry. */ if (Text_Psect != -1) { - vsp = (struct VMS_Symbol *) - xmalloc (sizeof (*vsp)); + vsp = (struct VMS_Symbol *) xmalloc (sizeof *vsp); vsp->Symbol = sp; vsp->Size = 0; vsp->Psect_Index = Text_Psect; vsp->Psect_Offset = S_GET_VALUE (sp); vsp->Next = VMS_Symbols; VMS_Symbols = vsp; - sp->sy_number = (int) vsp; + sp->sy_obj = vsp; } break; - /* - * Global Reference - */ + + /* Global Reference. */ case N_UNDF: - /* - * Make a GSD global symbol reference - * record. - */ + /* Make a GSD global symbol reference record. */ VMS_Global_Symbol_Spec (S_GET_NAME (sp), 0, 0, - 0); + GBLSYM_REF); break; - /* - * Anything else - */ + + /* Absolute symbol. */ + case N_ABS: + case N_ABS | N_EXT: + /* gcc doesn't generate these; + VMS_Emit_Globalvalue handles them though. */ + vsp = (struct VMS_Symbol *) xmalloc (sizeof *vsp); + vsp->Symbol = sp; + vsp->Size = 4; /* always assume 32 bits */ + vsp->Psect_Index = 0; + vsp->Psect_Offset = S_GET_VALUE (sp); + vsp->Next = VMS_Symbols; + VMS_Symbols = vsp; + sp->sy_obj = vsp; + break; + + /* Anything else. */ default: - /* - * Ignore STAB symbols - * Including .stabs emitted by g++ - */ + /* Ignore STAB symbols, including .stabs emitted by g++. */ if (S_IS_DEBUG (sp) || (S_GET_TYPE (sp) == 22)) break; /* - * Error + * Error otherwise. */ - if (S_GET_TYPE (sp) != 22) - printf (" ERROR, unknown type (%d)\n", - S_GET_TYPE (sp)); + as_tsktsk (_("unhandled stab type %d"), S_GET_TYPE (sp)); break; } + + /* Global symbols have different linkage than external variables. */ + if (define_as_global_symbol) + VMS_Global_Symbol_Spec (S_GET_NAME (sp), + vsp->Psect_Index, + 0, + GBLSYM_DEF); + } + + return; +} + + +/* Output debugger symbol table information for symbols which + are local to a specific routine. */ + +static void +local_symbols_DST (s0P, Current_Routine) + symbolS *s0P, *Current_Routine; +{ + symbolS *s1P; + char *s0P_name, *pnt0, *pnt1; + + s0P_name = S_GET_NAME (s0P); + if (*s0P_name++ != '_') + return; + + for (s1P = Current_Routine; s1P; s1P = symbol_next (s1P)) + { +#if 0 /* redundant; RAW_TYPE != N_FUN suffices */ + if (!S_IS_DEBUG (s1P)) + continue; +#endif + if (S_GET_RAW_TYPE (s1P) != N_FUN) + continue; + pnt0 = s0P_name; + pnt1 = S_GET_NAME (s1P); + /* We assume the two strings are never exactly equal... */ + while (*pnt0++ == *pnt1++) + { + } + /* Found it if s0P name is exhausted and s1P name has ":F" or ":f" next. + Note: both pointers have advanced one past the non-matching char. */ + if ((*pnt1 == 'F' || *pnt1 == 'f') && *--pnt1 == ':' && *--pnt0 == '\0') + { + Define_Routine (s1P, 0, Current_Routine, Text_Psect); + return; + } } +} + +/* Construct and output the debug symbol table. */ + +static void +vms_build_DST (text_siz) + unsigned text_siz; +{ + register symbolS *symbolP; + symbolS *Current_Routine = 0; + struct input_file *Cur_File = 0; + offsetT Cur_Offset = -1; + int Cur_Line_Number = 0; + int File_Number = 0; + int Debugger_Offset = 0; + int file_available; + int dsc; + offsetT val; + + /* Write the Traceback Begin Module record. */ + VMS_TBT_Module_Begin (); + /* - * Define the Data Psect + * Output debugging info for global variables and static variables + * that are not specific to one routine. We also need to examine + * all stabs directives, to find the definitions to all of the + * advanced data types, and this is done by VMS_LSYM_Parse. This + * needs to be done before any definitions are output to the object + * file, since there can be forward references in the stabs + * directives. When through with parsing, the text of the stabs + * directive is altered, with the definitions removed, so that later + * passes will see directives as they would be written if the type + * were already defined. + * + * We also look for files and include files, and make a list of + * them. We examine the source file numbers to establish the actual + * lines that code was generated from, and then generate offsets. */ - if ((data_siz > 0) && (Local_Initialized_Data_Size > 0)) + VMS_LSYM_Parse (); + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP)) { + /* Only deal with STAB symbols here. */ + if (!S_IS_DEBUG (symbolP)) + continue; /* - * Do it - */ - Data_Psect = Psect_Number++; - VMS_Psect_Spec ("$data", - Local_Initialized_Data_Size, - "DATA", 0); - /* - * Scan the VMS symbols and fill in the data psect + * Dispatch on STAB type. */ - for (vsp = VMS_Symbols; vsp; vsp = vsp->Next) + switch (S_GET_RAW_TYPE (symbolP)) { - /* - * Only look for undefined psects - */ - if (vsp->Psect_Index < 0) + case N_SLINE: + dsc = S_GET_DESC (symbolP); + if (dsc > Cur_File->max_line) + Cur_File->max_line = dsc; + if (dsc < Cur_File->min_line) + Cur_File->min_line = dsc; + break; + case N_SO: + Cur_File = find_file (symbolP); + Cur_File->flag = 1; + Cur_File->min_line = 1; + break; + case N_SOL: + Cur_File = find_file (symbolP); + break; + case N_GSYM: + VMS_GSYM_Parse (symbolP, Text_Psect); + break; + case N_LCSYM: + VMS_LCSYM_Parse (symbolP, Text_Psect); + break; + case N_FUN: /* For static constant symbols */ + case N_STSYM: + VMS_STSYM_Parse (symbolP, Text_Psect); + break; + default: + break; + } /* switch */ + } /* for */ + + /* + * Now we take a quick sweep through the files and assign offsets + * to each one. This will essentially be the starting line number to + * the debugger for each file. Output the info for the debugger to + * specify the files, and then tell it how many lines to use. + */ + for (Cur_File = file_root; Cur_File; Cur_File = Cur_File->next) + { + if (Cur_File->max_line == 0) + continue; + if ((strncmp (Cur_File->name, "GNU_GXX_INCLUDE:", 16) == 0) && + !flag_debug) + continue; + if ((strncmp (Cur_File->name, "GNU_CC_INCLUDE:", 15) == 0) && + !flag_debug) + continue; + /* show a few extra lines at the start of the region selected */ + if (Cur_File->min_line > 2) + Cur_File->min_line -= 2; + Cur_File->offset = Debugger_Offset - Cur_File->min_line + 1; + Debugger_Offset += Cur_File->max_line - Cur_File->min_line + 1; + if (Cur_File->same_file_fpnt) + { + Cur_File->file_number = Cur_File->same_file_fpnt->file_number; + } + else + { + Cur_File->file_number = ++File_Number; + file_available = VMS_TBT_Source_File (Cur_File->name, + Cur_File->file_number); + if (!file_available) { - /* - * And only initialized data - */ - if ((S_GET_TYPE (vsp->Symbol) == N_DATA) && !S_IS_EXTERNAL (vsp->Symbol)) - vsp->Psect_Index = Data_Psect; + Cur_File->file_number = 0; + File_Number--; + continue; } } - } - - /******* Text Information and Relocation Records *******/ + VMS_TBT_Source_Lines (Cur_File->file_number, + Cur_File->min_line, + Cur_File->max_line - Cur_File->min_line + 1); + } /* for */ + Cur_File = (struct input_file *) NULL; + /* - * Write the text segment data + * Scan the symbols and write out the routines + * (this makes the assumption that symbols are in + * order of ascending text segment offset) */ - if (text_siz > 0) + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP)) { /* - * Scan the text fragments + * Deal with text symbols. */ - for (fragP = text_frag_root; fragP; fragP = fragP->fr_next) + if (!S_IS_DEBUG (symbolP) && S_GET_TYPE (symbolP) == N_TEXT) { /* - * Stop if we get to the data fragments + * Ignore symbols starting with "L", as they are local symbols. */ - if (fragP == data_frag_root) - break; - /* - * Ignore fragments with no data - */ - if ((fragP->fr_fix == 0) && (fragP->fr_var == 0)) + if (*S_GET_NAME (symbolP) == 'L') continue; /* - * Go the the appropriate offset in the - * Text Psect. - */ - VMS_Set_Psect (Text_Psect, fragP->fr_address, OBJ_S_C_TIR); - /* - * Store the "fixed" part + * If there is a routine start defined, terminate it. */ - if (fragP->fr_fix) - VMS_Store_Immediate_Data (fragP->fr_literal, - fragP->fr_fix, - OBJ_S_C_TIR); - /* - * Store the "variable" part - */ - if (fragP->fr_var && fragP->fr_offset) - VMS_Store_Repeated_Data (fragP->fr_offset, - fragP->fr_literal + - fragP->fr_fix, - fragP->fr_var, - OBJ_S_C_TIR); - } - /* - * Now we go through the text segment fixups and - * generate TIR records to fix up addresses within - * the Text Psect - */ - for (fixP = text_fix_root; fixP; fixP = fixP->fx_next) - { - /* - * We DO handle the case of "Symbol - Symbol" as - * long as it is in the same segment. - */ - if (fixP->fx_subsy && fixP->fx_addsy) - { - int i; + if (Current_Routine) + VMS_TBT_Routine_End (text_siz, Current_Routine); - /* - * They need to be in the same segment - */ - if (S_GET_RAW_TYPE (fixP->fx_subsy) != - S_GET_RAW_TYPE (fixP->fx_addsy)) - error ("Fixup data addsy and subsy didn't have the same type"); - /* - * And they need to be in one that we - * can check the psect on - */ - if ((S_GET_TYPE (fixP->fx_addsy) != N_DATA) && - (S_GET_TYPE (fixP->fx_addsy) != N_TEXT)) - error ("Fixup data addsy and subsy didn't have an appropriate type"); - /* - * This had better not be PC relative! - */ - if (fixP->fx_pcrel) - error ("Fixup data was erroneously \"pcrel\""); - /* - * Subtract their values to get the - * difference. - */ - i = S_GET_VALUE (fixP->fx_addsy) - - S_GET_VALUE (fixP->fx_subsy); - /* - * Now generate the fixup object records - * Set the psect and store the data - */ - VMS_Set_Psect (Text_Psect, - fixP->fx_where + - fixP->fx_frag->fr_address, - OBJ_S_C_TIR); - VMS_Store_Immediate_Data (&i, - fixP->fx_size, - OBJ_S_C_TIR); - /* - * Done - */ - continue; - } /* - * Size will HAVE to be "long" + * Check for & skip dummy labels like "gcc_compiled.". + * They're identified by the IN_DEFAULT_SECTION flag. */ - if (fixP->fx_size != sizeof (long)) - error ("Fixup datum was not a longword"); + if ((S_GET_OTHER (symbolP) & IN_DEFAULT_SECTION) != 0 && + S_GET_VALUE (symbolP) == 0) + continue; /* - * Symbol must be "added" (if it is ever - * subtracted we can - * fix this assumption) + * Store the routine begin traceback info. */ - if (fixP->fx_addsy == 0) - error ("Fixup datum was not \"fixP->fx_addsy\""); + VMS_TBT_Routine_Begin (symbolP, Text_Psect); + Current_Routine = symbolP; /* - * Store the symbol value in a PIC fashion + * Define symbols local to this routine. */ - VMS_Store_PIC_Symbol_Reference (fixP->fx_addsy, - fixP->fx_offset, - fixP->fx_pcrel, - Text_Psect, - fixP->fx_where + - fixP->fx_frag->fr_address, - OBJ_S_C_TIR); + local_symbols_DST (symbolP, Current_Routine); /* - * Check for indirect address reference, - * which has to be fixed up (as the linker - * will screw it up with TIR_S_C_STO_PICR). + * Done */ - if (fixP->fx_pcrel) - VMS_Fix_Indirect_Reference (Text_Psect, - fixP->fx_where + - fixP->fx_frag->fr_address, - fixP->fx_frag, - text_frag_root); - } - } - /* - * Store the Data segment: - * - * Since this is REALLY hard to do any other way, - * we actually manufacture the data segment and - * the store the appropriate values out of it. - * The segment was manufactured before, now we just - * dump it into the appropriate psects. - */ - if (data_siz > 0) - { + continue; - /* - * Now we can run through all the data symbols - * and store the data - */ - for (vsp = VMS_Symbols; vsp; vsp = vsp->Next) - { - /* - * Ignore anything other than data symbols - */ - if (S_GET_TYPE (vsp->Symbol) != N_DATA) - continue; - /* - * Set the Psect + Offset - */ - VMS_Set_Psect (vsp->Psect_Index, - vsp->Psect_Offset, - OBJ_S_C_TIR); - /* - * Store the data - */ - VMS_Store_Immediate_Data (Data_Segment + - S_GET_VALUE (vsp->Symbol) - - text_siz, - vsp->Size, - OBJ_S_C_TIR); } /* - * Now we go through the data segment fixups and - * generate TIR records to fix up addresses within - * the Data Psects + * Deal with STAB symbols. */ - for (fixP = data_fix_root; fixP; fixP = fixP->fx_next) + else if (S_IS_DEBUG (symbolP)) { /* - * Find the symbol for the containing datum + * Dispatch on STAB type. */ - for (vsp = VMS_Symbols; vsp; vsp = vsp->Next) + switch (S_GET_RAW_TYPE (symbolP)) { + /* + * Line number + */ + case N_SLINE: + /* Offset the line into the correct portion of the file. */ + if (Cur_File->file_number == 0) + break; + val = S_GET_VALUE (symbolP); + /* Sometimes the same offset gets several source lines + assigned to it. We should be selective about which + lines we allow, we should prefer lines that are in + the main source file when debugging inline functions. */ + if (val == Cur_Offset && Cur_File->file_number != 1) + break; + + /* calculate actual debugger source line */ + dsc = S_GET_DESC (symbolP) + Cur_File->offset; + S_SET_DESC (symbolP, dsc); /* - * Only bother with Data symbols - */ - sp = vsp->Symbol; - if (S_GET_TYPE (sp) != N_DATA) - continue; - /* - * Ignore symbol if After fixup - */ - if (S_GET_VALUE (sp) > - (fixP->fx_where + - fixP->fx_frag->fr_address)) - continue; - /* - * See if the datum is here - */ - if ((S_GET_VALUE (sp) + vsp->Size) <= - (fixP->fx_where + - fixP->fx_frag->fr_address)) - continue; - /* - * We DO handle the case of "Symbol - Symbol" as - * long as it is in the same segment. + * Define PC/Line correlation. */ - if (fixP->fx_subsy && fixP->fx_addsy) + if (Cur_Offset == -1) { - int i; - - /* - * They need to be in the same segment - */ - if (S_GET_RAW_TYPE (fixP->fx_subsy) != - S_GET_RAW_TYPE (fixP->fx_addsy)) - error ("Fixup data addsy and subsy didn't have the same type"); - /* - * And they need to be in one that we - * can check the psect on - */ - if ((S_GET_TYPE (fixP->fx_addsy) != N_DATA) && - (S_GET_TYPE (fixP->fx_addsy) != N_TEXT)) - error ("Fixup data addsy and subsy didn't have an appropriate type"); /* - * This had better not be PC relative! + * First N_SLINE; set up initial correlation. */ - if (fixP->fx_pcrel) - error ("Fixup data was erroneously \"pcrel\""); - /* - * Subtract their values to get the - * difference. - */ - i = S_GET_VALUE (fixP->fx_addsy) - - S_GET_VALUE (fixP->fx_subsy); + VMS_TBT_Line_PC_Correlation (dsc, + val, + Text_Psect, + 0); + } + else if ((dsc - Cur_Line_Number) <= 0) + { /* - * Now generate the fixup object records - * Set the psect and store the data + * Line delta is not +ve, we need to close the line and + * start a new PC/Line correlation. */ - VMS_Set_Psect (vsp->Psect_Index, - fixP->fx_frag->fr_address + - fixP->fx_where - - S_GET_VALUE (vsp->Symbol) + - vsp->Psect_Offset, - OBJ_S_C_TIR); - VMS_Store_Immediate_Data (&i, - fixP->fx_size, - OBJ_S_C_TIR); + VMS_TBT_Line_PC_Correlation (0, + val - Cur_Offset, + 0, + -1); + VMS_TBT_Line_PC_Correlation (dsc, + val, + Text_Psect, + 0); + } + else + { /* - * Done + * Line delta is +ve, all is well. */ - break; + VMS_TBT_Line_PC_Correlation (dsc - Cur_Line_Number, + val - Cur_Offset, + 0, + 1); } - /* - * Size will HAVE to be "long" - */ - if (fixP->fx_size != sizeof (long)) - error ("Fixup datum was not a longword"); - /* - * Symbol must be "added" (if it is ever - * subtracted we can - * fix this assumption) - */ - if (fixP->fx_addsy == 0) - error ("Fixup datum was not \"fixP->fx_addsy\""); - /* - * Store the symbol value in a PIC fashion - */ - VMS_Store_PIC_Symbol_Reference ( - fixP->fx_addsy, - fixP->fx_offset, - fixP->fx_pcrel, - vsp->Psect_Index, - fixP->fx_frag->fr_address + - fixP->fx_where - - S_GET_VALUE (vsp->Symbol) + - vsp->Psect_Offset, - OBJ_S_C_TIR); - /* - * Done - */ + /* Update the current line/PC info. */ + Cur_Line_Number = dsc; + Cur_Offset = val; break; - } - - } - } - - /* - * Write the Traceback Begin Module record - */ - VMS_TBT_Module_Begin (); - /* - * Scan the symbols and write out the routines - * (this makes the assumption that symbols are in - * order of ascending text segment offset) - */ - { - struct symbol *Current_Routine = 0; - int Current_Line_Number = 0; - int Current_Offset = -1; - struct input_file *Current_File; - -/* Output debugging info for global variables and static variables that are not - * specific to one routine. We also need to examine all stabs directives, to - * find the definitions to all of the advanced data types, and this is done by - * VMS_LSYM_Parse. This needs to be done before any definitions are output to - * the object file, since there can be forward references in the stabs - * directives. When through with parsing, the text of the stabs directive - * is altered, with the definitions removed, so that later passes will see - * directives as they would be written if the type were already defined. - * - * We also look for files and include files, and make a list of them. We - * examine the source file numbers to establish the actual lines that code was - * generated from, and then generate offsets. - */ - VMS_LSYM_Parse (); - for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP)) - { - /* - * Deal with STAB symbols - */ - if (S_IS_DEBUG (symbolP)) - { - /* - * Dispatch on STAB type - */ - switch ((unsigned char) S_GET_RAW_TYPE (symbolP)) - { - case N_SLINE: - if (S_GET_DESC (symbolP) > Current_File->max_line) - Current_File->max_line = S_GET_DESC (symbolP); - if (S_GET_DESC (symbolP) < Current_File->min_line) - Current_File->min_line = S_GET_DESC (symbolP); - break; - case N_SO: - Current_File = find_file (symbolP); - Current_File->flag = 1; - Current_File->min_line = 1; - break; - case N_SOL: - Current_File = find_file (symbolP); - break; - case N_GSYM: - VMS_GSYM_Parse (symbolP, Text_Psect); - break; - case N_LCSYM: - VMS_LCSYM_Parse (symbolP, Text_Psect); - break; - case N_FUN: /* For static constant symbols */ - case N_STSYM: - VMS_STSYM_Parse (symbolP, Text_Psect); - break; - } - } - } - /* now we take a quick sweep through the files and assign offsets - to each one. This will essentially be the starting line number to the - debugger for each file. Output the info for the debugger to specify the - files, and then tell it how many lines to use */ - { - int File_Number = 0; - int Debugger_Offset = 0; - int file_available; - Current_File = file_root; - for (Current_File = file_root; Current_File; Current_File = Current_File->next) - { - if (Current_File == (struct input_file *) NULL) - break; - if (Current_File->max_line == 0) - continue; - if ((strncmp (Current_File->name, "GNU_GXX_INCLUDE:", 16) == 0) && - !flagseen['D']) - continue; - if ((strncmp (Current_File->name, "GNU_CC_INCLUDE:", 15) == 0) && - !flagseen['D']) - continue; -/* show a few extra lines at the start of the region selected */ - if (Current_File->min_line > 2) - Current_File->min_line -= 2; - Current_File->offset = Debugger_Offset - Current_File->min_line + 1; - Debugger_Offset += Current_File->max_line - Current_File->min_line + 1; - if (Current_File->same_file_fpnt != (struct input_file *) NULL) - Current_File->file_number = Current_File->same_file_fpnt->file_number; - else - { - Current_File->file_number = ++File_Number; - file_available = VMS_TBT_Source_File (Current_File->name, - Current_File->file_number); - if (!file_available) - { - Current_File->file_number = 0; - File_Number--; - continue; - }; - }; - VMS_TBT_Source_Lines (Current_File->file_number, - Current_File->min_line, - Current_File->max_line - Current_File->min_line + 1); - }; /* for */ - }; /* scope */ - Current_File = (struct input_file *) NULL; - - for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP)) - { - /* - * Deal with text symbols - */ - if (!S_IS_DEBUG (symbolP) && (S_GET_TYPE (symbolP) == N_TEXT)) - { - /* - * Ignore symbols starting with "L", - * as they are local symbols - */ - if (*S_GET_NAME (symbolP) == 'L') - continue; - /* - * If there is a routine start defined, - * terminate it. - */ - if (Current_Routine) - { - /* - * End the routine - */ - VMS_TBT_Routine_End (text_siz, Current_Routine); - } - /* - * Store the routine begin traceback info - */ - if (Text_Psect != -1) - { - VMS_TBT_Routine_Begin (symbolP, Text_Psect); - Current_Routine = symbolP; - } -/* Output local symbols, i.e. all symbols that are associated with a specific - * routine. We output them now so the debugger recognizes them as local to - * this routine. - */ - { - symbolS *symbolP1; - char *pnt; - char *pnt1; - for (symbolP1 = Current_Routine; symbolP1; symbolP1 = symbol_next (symbolP1)) - { - if (!S_IS_DEBUG (symbolP1)) - continue; - if (S_GET_RAW_TYPE (symbolP1) != N_FUN) - continue; - pnt = S_GET_NAME (symbolP); - pnt1 = S_GET_NAME (symbolP1); - if (*pnt++ != '_') - continue; - while (*pnt++ == *pnt1++) - { - }; - if (*pnt1 != 'F' && *pnt1 != 'f') continue; - if ((*(--pnt) == '\0') && (*(--pnt1) == ':')) - break; - }; - if (symbolP1 != (symbolS *) NULL) - VMS_DBG_Define_Routine (symbolP1, Current_Routine, Text_Psect); - } /* local symbol block */ - /* - * Done - */ - continue; - } - /* - * Deal with STAB symbols - */ - if (S_IS_DEBUG (symbolP)) - { - /* - * Dispatch on STAB type - */ - switch ((unsigned char) S_GET_RAW_TYPE (symbolP)) - { - /* - * Line number - */ - case N_SLINE: - /* Offset the line into the correct portion - * of the file */ - if (Current_File->file_number == 0) - break; - /* Sometimes the same offset gets several source - * lines assigned to it. - * We should be selective about which lines - * we allow, we should prefer lines that are - * in the main source file when debugging - * inline functions. */ - if ((Current_File->file_number != 1) && - S_GET_VALUE (symbolP) == - Current_Offset) - break; - /* calculate actual debugger source line */ - S_GET_DESC (symbolP) - += Current_File->offset; - /* - * If this is the 1st N_SLINE, setup - * PC/Line correlation. Otherwise - * do the delta PC/Line. If the offset - * for the line number is not +ve we need - * to do another PC/Line correlation - * setup - */ - if (Current_Offset == -1) - { - VMS_TBT_Line_PC_Correlation ( - S_GET_DESC (symbolP), - S_GET_VALUE (symbolP), - Text_Psect, - 0); - } - else - { - if ((S_GET_DESC (symbolP) - - Current_Line_Number) <= 0) - { - /* - * Line delta is not +ve, we - * need to close the line and - * start a new PC/Line - * correlation. - */ - VMS_TBT_Line_PC_Correlation (0, - S_GET_VALUE (symbolP) - - Current_Offset, - 0, - -1); - VMS_TBT_Line_PC_Correlation ( - S_GET_DESC (symbolP), - S_GET_VALUE (symbolP), - Text_Psect, - 0); - } - else - { - /* - * Line delta is +ve, all is well - */ - VMS_TBT_Line_PC_Correlation ( - S_GET_DESC (symbolP) - - Current_Line_Number, - S_GET_VALUE (symbolP) - - Current_Offset, - 0, - 1); - } - } - /* - * Update the current line/PC - */ - Current_Line_Number = S_GET_DESC (symbolP); - Current_Offset = S_GET_VALUE (symbolP); - /* - * Done - */ - break; /* * Source file */ - case N_SO: - /* - * Remember that we had a source file - * and emit the source file debugger - * record - */ - Current_File = - find_file (symbolP); - break; -/* We need to make sure that we are really in the actual source file when - * we compute the maximum line number. Otherwise the debugger gets really - * confused */ - case N_SOL: - Current_File = - find_file (symbolP); - break; - } - } - } + case N_SO: + /* Remember that we had a source file and emit + the source file debugger record. */ + Cur_File = find_file (symbolP); + break; + + case N_SOL: + /* We need to make sure that we are really in the actual + source file when we compute the maximum line number. + Otherwise the debugger gets really confused. */ + Cur_File = find_file (symbolP); + break; + + default: + break; + } /* switch */ + } /* if (IS_DEBUG) */ + } /* for */ + /* - * If there is a routine start defined, - * terminate it (and the line numbers) + * If there is a routine start defined, terminate it + * (and the line numbers). */ if (Current_Routine) { - /* - * Terminate the line numbers - */ + /* Terminate the line numbers. */ VMS_TBT_Line_PC_Correlation (0, - text_siz - S_GET_VALUE (Current_Routine), + text_siz - S_GET_VALUE (Current_Routine), 0, -1); - /* - * Terminate the routine - */ + /* Terminate the routine. */ VMS_TBT_Routine_End (text_siz, Current_Routine); } - } - /* - * Write the Traceback End Module TBT record - */ + + /* Write the Traceback End Module TBT record. */ VMS_TBT_Module_End (); +} + +/* Write a VAX/VMS object file (everything else has been done!). */ + +void +vms_write_object_file (text_siz, data_siz, bss_siz, text_frag_root, + data_frag_root) + unsigned text_siz; + unsigned data_siz; + unsigned bss_siz; + fragS *text_frag_root; + fragS *data_frag_root; +{ + register struct VMS_Symbol *vsp; + + /* + * Initialize program section indices; values get updated later. + */ + Psect_Number = 0; /* next Psect Index to use */ + Text_Psect = -1; /* Text Psect Index */ + Data_Psect = -2; /* Data Psect Index JF: Was -1 */ + Bss_Psect = -3; /* Bss Psect Index JF: Was -1 */ + Ctors_Psect = -4; /* Ctors Psect Index */ + Dtors_Psect = -5; /* Dtors Psect Index */ + /* Initialize other state variables. */ + Data_Segment = 0; + Local_Initd_Data_Size = 0; + + /* + * Create the actual output file and populate it with required + * "module header" information. + */ + Create_VMS_Object_File (); + Write_VMS_MHD_Records (); + + /* + * Create the Data segment: + * + * Since this is REALLY hard to do any other way, + * we actually manufacture the data segment and + * then store the appropriate values out of it. + * We need to generate this early, so that globalvalues + * can be properly emitted. + */ + if (data_siz > 0) + synthesize_data_segment (data_siz, text_siz, data_frag_root); + + /******* Global Symbol Directory *******/ + + /* + * Emit globalvalues now. We must do this before the text psect is + * defined, or we will get linker warnings about multiply defined + * symbols. All of the globalvalues "reference" psect 0, although + * it really does not have anything to do with it. + */ + VMS_Emit_Globalvalues (text_siz, data_siz, Data_Segment); + /* + * Define the Text Psect + */ + Text_Psect = Psect_Number++; + VMS_Psect_Spec ("$code", text_siz, ps_TEXT, 0); + /* + * Define the BSS Psect + */ + if (bss_siz > 0) + { + Bss_Psect = Psect_Number++; + VMS_Psect_Spec ("$uninitialized_data", bss_siz, ps_DATA, 0); + } + /* + * Define symbols to the linker. + */ + global_symbol_directory (text_siz, data_siz); + /* + * Define the Data Psect + */ + if (data_siz > 0 && Local_Initd_Data_Size > 0) + { + Data_Psect = Psect_Number++; + VMS_Psect_Spec ("$data", Local_Initd_Data_Size, ps_DATA, 0); + /* + * Local initialized data (N_DATA) symbols need to be updated to the + * proper value of Data_Psect now that it's actually been defined. + * (A dummy value was used in global_symbol_directory() above.) + */ + for (vsp = VMS_Symbols; vsp; vsp = vsp->Next) + if (vsp->Psect_Index < 0 && S_GET_RAW_TYPE (vsp->Symbol) == N_DATA) + vsp->Psect_Index = Data_Psect; + } + + if (Ctors_Symbols != 0) + { + char *ps_name = "$ctors"; + Ctors_Psect = Psect_Number++; + VMS_Psect_Spec (ps_name, Ctors_Symbols->Psect_Offset + XTOR_SIZE, + ps_CTORS, 0); + VMS_Global_Symbol_Spec (ps_name, Ctors_Psect, + 0, GBLSYM_DEF|GBLSYM_WEAK); + for (vsp = Ctors_Symbols; vsp; vsp = vsp->Next) + vsp->Psect_Index = Ctors_Psect; + } + + if (Dtors_Symbols != 0) + { + char *ps_name = "$dtors"; + Dtors_Psect = Psect_Number++; + VMS_Psect_Spec (ps_name, Dtors_Symbols->Psect_Offset + XTOR_SIZE, + ps_DTORS, 0); + VMS_Global_Symbol_Spec (ps_name, Dtors_Psect, + 0, GBLSYM_DEF|GBLSYM_WEAK); + for (vsp = Dtors_Symbols; vsp; vsp = vsp->Next) + vsp->Psect_Index = Dtors_Psect; + } + + /******* Text Information and Relocation Records *******/ + + /* + * Write the text segment data + */ + if (text_siz > 0) + vms_fixup_text_section (text_siz, text_frag_root, data_frag_root); + /* + * Write the data segment data, then discard it. + */ + if (data_siz > 0) + { + vms_fixup_data_section (data_siz, text_siz); + free (Data_Segment), Data_Segment = 0; + } + + if (Ctors_Symbols != 0) + { + vms_fixup_xtors_section (Ctors_Symbols, Ctors_Psect); + } + + if (Dtors_Symbols != 0) + { + vms_fixup_xtors_section (Dtors_Symbols, Dtors_Psect); + } + + /******* Debugger Symbol Table Records *******/ + + vms_build_DST (text_siz); + + /******* Wrap things up *******/ + /* * Write the End Of Module record */ - if (Entry_Point_Symbol == 0) - Write_VMS_EOM_Record (-1, 0); + if (Entry_Point_Symbol) + Write_VMS_EOM_Record (Text_Psect, S_GET_VALUE (Entry_Point_Symbol)); else - Write_VMS_EOM_Record (Text_Psect, - S_GET_VALUE (Entry_Point_Symbol)); - + Write_VMS_EOM_Record (-1, (valueT) 0); + /* * All done, close the object file */ Close_VMS_Object_File (); } - -/* end of obj-vms.c */