diff options
Diffstat (limited to 'gas/config/vms/vms.c')
-rw-r--r-- | gas/config/vms/vms.c | 3741 |
1 files changed, 3741 insertions, 0 deletions
diff --git a/gas/config/vms/vms.c b/gas/config/vms/vms.c new file mode 100644 index 0000000..cd3bb59 --- /dev/null +++ b/gas/config/vms/vms.c @@ -0,0 +1,3741 @@ +/* vms.c -- Write out a VAX/VMS object file + Copyright (C) 1987, 1988 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +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. */ + +/* Written by David L. Kashtan */ +#include <ctype.h> +#include <stdio.h> + +#include "as.h" +#include "subsegs.h" +#include "obstack.h" +#include "struc-symbol.h" +#include "write.h" +#include "symbols.h" + +#ifdef VMS /* THIS MODULE IS FOR VMS ONLY */ + +#include <stab.h> +#include "objrecdef.h" /* Define VMS Object record lang. */ +#include <vms/fabdef.h> /* Define File Access Block */ +#include <vms/namdef.h> /* Define NAM Block */ +#include <vms/xabdef.h> /* Define XAB */ +#include <vms/xabdatdef.h> /* Define Date XAB */ +#include <vms/xabfhcdef.h> /* Define File Header XAB */ + +const pseudo_typeS obj_pseudo_table[] = { + { "const", s_const, 0 }, + +}; /* obj_pseudo_table */ + +/* + * Version string of the compiler that produced the code we are + * assembling. (And this assembler, if we do not have compiler info.) + */ +extern char version_string[]; +char *compiler_version_string; + +extern char *myname; +static symbolS *Entry_Point_Symbol = 0; /* Pointer to "_main" */ + +/* + * We augment the "gas" symbol structure with this + */ +struct VMS_Symbol { + struct VMS_Symbol *Next; + struct symbol *Symbol; + int Size; + int Psect_Index; + int Psect_Offset; + }; +struct VMS_Symbol *VMS_Symbols = 0; + +/* we need this to keep track of the various input files, so that we can + * give the debugger the correct source line + */ + +struct input_file{ + struct input_file* next; + struct input_file* same_file_fpnt; + int file_number; + int max_line; + int min_line; + int offset; + char flag; + char * name; + symbolS * spnt; + }; + +static struct input_file * file_root = (struct input_file*)NULL; + +struct input_file * find_file(symbolS *); + + +/* + * 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". + */ +VMS_Check_For_Main() +{ + register symbolS *symbolP; +#ifdef HACK_DEC_C_STARTUP /* JF */ + register struct frchain *frchainP; + register fragS *fragP; + register fragS **prev_fragPP; + register struct fix *fixP; + register fragS *New_Frag; + int i; +#endif HACK_DEC_C_STARTUP + + symbolP = (struct symbol *)symbol_find("_main"); + if (symbolP && (symbolP->sy_nlist.n_type == (N_TEXT | N_EXT))) { +#ifdef HACK_DEC_C_STARTUP + if( !flagseen['+']) { +#endif + /* + * Remember the entry point symbol + */ + Entry_Point_Symbol = symbolP; +#ifdef HACK_DEC_C_STARTUP + } else { + /* + * Scan all the fragment chains for the one with "_main" + * (Actually we know the fragment from the symbol, but we need + * the previous fragment so we can change its pointer) + */ + frchainP = frchain_root; + while(frchainP) { + /* + * Scan all the fragments in this chain, remembering + * the "previous fragment" + */ + prev_fragPP = &frchainP->frch_root; + fragP = frchainP->frch_root; + while(fragP && (fragP != frchainP->frch_last)) { + /* + * Is this the fragment? + */ + if (fragP == symbolP->sy_frag) { + /* + * Yes: Modify the fragment by replacing + * it with a new fragment. + */ + New_Frag = (fragS *) + xmalloc(sizeof(*New_Frag) + + fragP->fr_fix + + fragP->fr_var + + 5); + /* + * The fragments are the same except + * that the "fixed" area is larger + */ + *New_Frag = *fragP; + New_Frag->fr_fix += 6; + /* + * Copy the literal data opening a hole + * 2 bytes after "_main" (i.e. just after + * the entry mask). Into which we place + * the JSB instruction. + */ + New_Frag->fr_literal[0] = fragP->fr_literal[0]; + New_Frag->fr_literal[1] = fragP->fr_literal[1]; + New_Frag->fr_literal[2] = 0x16; /* Jsb */ + New_Frag->fr_literal[3] = 0xef; + New_Frag->fr_literal[4] = 0; + New_Frag->fr_literal[5] = 0; + New_Frag->fr_literal[6] = 0; + New_Frag->fr_literal[7] = 0; + for(i = 2; i < fragP->fr_fix + fragP->fr_var; i++) + New_Frag->fr_literal[i+6] = + fragP->fr_literal[i]; + /* + * Now replace the old fragment with the + * newly generated one. + */ + *prev_fragPP = New_Frag; + /* + * Remember the entry point symbol + */ + Entry_Point_Symbol = symbolP; + /* + * Scan the text area fixup structures + * as offsets in the fragment may have + * changed + */ + for(fixP = text_fix_root; fixP; fixP = fixP->fx_next) { + /* + * Look for references to this + * fragment. + */ + if (fixP->fx_frag == fragP) { + /* + * Change the fragment + * pointer + */ + fixP->fx_frag = New_Frag; + /* + * If the offset is after + * the entry mask we need + * to account for the JSB + * instruction we just + * inserted. + */ + if (fixP->fx_where >= 2) + fixP->fx_where += 6; + } + } + /* + * Scan the symbols as offsets in the + * fragment may have changed + */ + for(symbolP = symbol_rootP; + symbolP; + symbolP = symbol_next(symbolP)) { + /* + * Look for references to this + * fragment. + */ + if (symbolP->sy_frag == fragP) { + /* + * Change the fragment + * pointer + */ + symbolP->sy_frag = New_Frag; + /* + * If the offset is after + * the entry mask we need + * to account for the JSB + * instruction we just + * inserted. + */ + if (symbolP->sy_nlist.n_value >= 2) + symbolP->sy_nlist.n_value += 6; + } + } + /* + * Make a symbol reference to + * "_c$main_args" so we can get + * its address inserted into the + * JSB instruction. + */ + symbolP = (symbolS *)xmalloc(sizeof(*symbolP)); + symbolP->sy_nlist.n_un.n_name = "_c$main_args"; + symbolP->sy_nlist.n_type = N_UNDF; + symbolP->sy_nlist.n_other = 0; + symbolP->sy_nlist.n_desc = 0; + symbolP->sy_nlist.n_value = 0; + symbolP->sy_name_offset = 0; + symbolP->sy_number = 0; + symbolP->sy_frag = New_Frag; + symbolP->sy_forward = 0; + /* this actually inserts at the beginning of the list */ + symbol_append(symbol_rootP, symbolP, &symbol_rootP, &symbol_lastP); + + symbol_rootP = symbolP; + /* + * Generate a text fixup structure + * to get "_c$main_args" stored into the + * JSB instruction. + */ + fixP = (struct fix *)xmalloc(sizeof(*fixP)); + fixP->fx_frag = New_Frag; + fixP->fx_where = 4; + fixP->fx_addsy = symbolP; + fixP->fx_subsy = 0; + fixP->fx_offset = 0; + fixP->fx_size = sizeof(long); + fixP->fx_pcrel = 1; + fixP->fx_next = text_fix_root; + text_fix_root = fixP; + /* + * Now make sure we exit from the loop + */ + frchainP = 0; + break; + } + /* + * Try the next fragment + */ + prev_fragPP = &fragP->fr_next; + fragP = fragP->fr_next; + } + /* + * Try the next fragment chain + */ + if (frchainP) frchainP=frchainP->frch_next; + } + } +#endif /* HACK_DEC_C_STARTUP */ + } +} + +/* + * Write a VAX/VMS object file (everything else has been done!) + */ +VMS_write_object_file(text_siz, data_siz, text_frag_root, data_frag_root) +unsigned text_siz; +unsigned data_siz; +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; + int Local_Initialized_Data_Size = 0; + 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 */ + + /* + * Create the VMS object file + */ + Create_VMS_Object_File(); + /* + * Write the module header records + */ + Write_VMS_MHD_Records(); + + /* + * Generate the VMS object file records + * 1st GSD then TIR records + */ + + /******* Global Symbol Dictionary *******/ + /* + * Define the Text Psect + */ + if (text_siz > 0) { + Text_Psect = Psect_Number++; + VMS_Psect_Spec("$code",text_siz,"TEXT"); + } + /* + * Define the BSS Psect + */ + if (local_bss_counter > 0) { + Bss_Psect = Psect_Number++; + VMS_Psect_Spec("$uninitialized_data",local_bss_counter,"DATA"); + } + /* + * Now scan the symbols and emit the appropriate GSD records + */ + for (sp = symbol_rootP; sp; sp = symbol_next(sp)) { + /* + * Dispatch on symbol type + */ + switch(sp->sy_type) { + /* + * Global uninitialized data + */ + case N_UNDF | N_EXT: + /* + * Make a VMS data symbol entry + */ + vsp = (struct VMS_Symbol *) + xmalloc(sizeof(*vsp)); + vsp->Symbol = sp; + vsp->Size = sp->sy_nlist.n_value; + 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(sp->sy_nlist.n_other) + VMS_Psect_Spec(sp->sy_nlist.n_un.n_name, + vsp->Size, + "CONST"); + else + VMS_Psect_Spec(sp->sy_nlist.n_un.n_name, + vsp->Size, + "COMMON"); +#ifdef NOT_VAX_11_C_COMPATIBLE + /* + * Place a global symbol at the + * beginning of the Psect + */ + VMS_Global_Symbol_Spec(sp->sy_nlist.n_un.n_name, + vsp->Psect_Index, + 0, + 1); +#endif NOT_VAX_11_C_COMPATIBLE + break; + /* + * Local uninitialized data + */ + case N_BSS: + /* + * 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 = + sp->sy_nlist.n_value - + bss_address_frag . fr_address; + vsp->Next = VMS_Symbols; + VMS_Symbols = vsp; + sp->sy_number = (int)vsp; + break; + /* + * Global initialized data + */ + case N_DATA | N_EXT: + /* + * 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 = Psect_Number++; + vsp->Psect_Offset = 0; + vsp->Next = VMS_Symbols; + VMS_Symbols = vsp; + sp->sy_number = (int)vsp; + /* + * Make its psect + */ + if(sp->sy_nlist.n_other) + VMS_Psect_Spec(sp->sy_nlist.n_un.n_name, + vsp->Size, + "CONST"); + else + VMS_Psect_Spec(sp->sy_nlist.n_un.n_name, + vsp->Size, + "COMMON"); +#ifdef NOT_VAX_11_C_COMPATIBLE + /* + * Place a global symbol at the + * beginning of the Psect + */ + VMS_Global_Symbol_Spec(sp->sy_nlist.n_un.n_name, + vsp->Psect_Index, + 0, + 1); +#endif NOT_VAX_11_C_COMPATIBLE + break; + /* + * 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; + break; + /* + * 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(sp->sy_nlist.n_un.n_name, + Text_Psect, + sp->sy_nlist.n_value, + Entry_Mask); + break; + } + /* + * Local Text definition + */ + case N_TEXT: + /* + * Make a VMS data symbol entry + */ + if(Text_Psect != -1) { + vsp = (struct VMS_Symbol *) + xmalloc(sizeof(*vsp)); + vsp->Symbol = sp; + vsp->Size = 0; + vsp->Psect_Index = Text_Psect; + vsp->Psect_Offset = sp->sy_nlist.n_value; + vsp->Next = VMS_Symbols; + VMS_Symbols = vsp; + sp->sy_number = (int)vsp; + } + break; + /* + * Global Reference + */ + case N_UNDF: + /* + * Make a GSD global symbol reference + * record. + */ + VMS_Global_Symbol_Spec(sp->sy_nlist.n_un.n_name, + 0, + 0, + 0); + break; + /* + * Anything else + */ + default: + /* + * Ignore STAB symbols + * Including .stabs emitted by g++ + */ + if ((sp->sy_type & N_STAB) != 0 || sp->sy_nlist.n_type==22) + break; + /* + * Error + */ + if(sp->sy_nlist.n_type !=22) + printf(" ERROR, unknown type (%d)\n", + sp->sy_nlist.n_type); + break; + } + } + /* + * Define the Data Psect + */ + if ((data_siz > 0) && (Local_Initialized_Data_Size > 0)) { + /* + * Do it + */ + Data_Psect = Psect_Number++; + VMS_Psect_Spec("$data", + Local_Initialized_Data_Size, + "DATA"); + /* + * Scan the VMS symbols and fill in the data psect + */ + for (vsp = VMS_Symbols; vsp; vsp = vsp->Next) { + /* + * Only look for undefined psects + */ + if (vsp->Psect_Index < 0) { + /* + * And only initialized data + */ + if (vsp->Symbol->sy_nlist.n_type == N_DATA) + vsp->Psect_Index = Data_Psect; + } + } + } + + /******* Text Information and Relocation Records *******/ + /* + * Write the text segment data + */ + if (text_siz > 0) { + /* + * 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$C_TIR); + /* + * Store the "fixed" part + */ + if (fragP->fr_fix) + VMS_Store_Immediate_Data(fragP->fr_literal, + fragP->fr_fix, + OBJ$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$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; + + /* + * They need to be in the same segment + */ + if (fixP->fx_subsy->sy_type != + fixP->fx_addsy->sy_type) + 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 (((fixP->fx_addsy->sy_type & ~N_EXT) != N_DATA) && + ((fixP->fx_addsy->sy_type & ~N_EXT) != 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 = fixP->fx_addsy->sy_value - + fixP->fx_subsy->sy_value; + /* + * 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$C_TIR); + VMS_Store_Immediate_Data(&i, + fixP->fx_size, + OBJ$C_TIR); + /* + * Done + */ + continue; + } + /* + * 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, + Text_Psect, + fixP->fx_where + + fixP->fx_frag->fr_address, + OBJ$C_TIR); + /* + * Check for indirect address reference, + * which has to be fixed up (as the linker + * will screw it up with TIR$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); + } + } + /* + * 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. + */ + if (data_siz > 0) { + char *Data_Segment; + + /* + * 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) { + 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) + bcopy(fragP->fr_literal, + Data_Segment + i, + fragP->fr_fix); + i += fragP->fr_fix; + + fill_literal= fragP -> fr_literal + fragP -> fr_fix; + fill_size = fragP -> fr_var; + for (count = fragP -> fr_offset; count; count --) { + if (fill_size) + bcopy(fill_literal, + Data_Segment + i, + fill_size); + i += fill_size; + } + } + /* + * 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 ((vsp->Symbol->sy_nlist.n_type & ~N_EXT) != N_DATA) + continue; + /* + * Set the Psect + Offset + */ + VMS_Set_Psect(vsp->Psect_Index, + vsp->Psect_Offset, + OBJ$C_TIR); + /* + * Store the data + */ + VMS_Store_Immediate_Data(Data_Segment + + vsp->Symbol->sy_nlist.n_value - + text_siz, + vsp->Size, + OBJ$C_TIR); + } + /* + * 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) { + /* + * Find the symbol for the containing datum + */ + for(vsp = VMS_Symbols; vsp; vsp = vsp->Next) { + /* + * Only bother with Data symbols + */ + sp = vsp->Symbol; + if ((sp->sy_nlist.n_type & ~N_EXT) != N_DATA) + continue; + /* + * Ignore symbol if After fixup + */ + if (sp->sy_nlist.n_value > + (fixP->fx_where + + fixP->fx_frag->fr_address)) + continue; + /* + * See if the datum is here + */ + if ((sp->sy_nlist.n_value + 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. + */ + if (fixP->fx_subsy && fixP->fx_addsy) { + int i; + + /* + * They need to be in the same segment + */ + if (fixP->fx_subsy->sy_type != + fixP->fx_addsy->sy_type) + 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 (((fixP->fx_addsy->sy_type & ~N_EXT) != N_DATA) && + ((fixP->fx_addsy->sy_type & ~N_EXT) != 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 = fixP->fx_addsy->sy_value - + fixP->fx_subsy->sy_value; + /* + * Now generate the fixup object records + * Set the psect and store the data + */ + VMS_Set_Psect(vsp->Psect_Index, + fixP->fx_frag->fr_address + + fixP->fx_where - + vsp->Symbol->sy_value + + vsp->Psect_Offset, + OBJ$C_TIR); + VMS_Store_Immediate_Data(&i, + fixP->fx_size, + OBJ$C_TIR); + /* + * Done + */ + break; + } + /* + * 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 - + vsp->Symbol->sy_value + + vsp->Psect_Offset, + OBJ$C_TIR); + /* + * Done + */ + 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 ((symbolP->sy_nlist.n_type & N_STAB) != 0) { + /* + * Dispatch on STAB type + */ + switch((unsigned char)symbolP->sy_nlist.n_type) { + case N_SLINE: + if(symbolP->sy_nlist.n_desc > Current_File->max_line) + Current_File->max_line = symbolP->sy_nlist.n_desc; + if(symbolP->sy_nlist.n_desc < Current_File->min_line) + Current_File->min_line = symbolP->sy_nlist.n_desc; + 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 ((symbolP->sy_nlist.n_type & ~N_EXT) == N_TEXT) { + /* + * Ignore symbols starting with "L", + * as they are local symbols + */ + if (symbolP->sy_nlist.n_un.n_name[0] == '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 ((symbolP1->sy_nlist.n_type & N_STAB) == 0) continue; + if (symbolP1->sy_nlist.n_type != N_FUN) continue; + pnt=symbolP->sy_nlist.n_un.n_name; + pnt1=symbolP1->sy_nlist.n_un.n_name; + if(*pnt++ != '_') continue; + while(*pnt++ == *pnt1++) {}; + 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 ((symbolP->sy_nlist.n_type & N_STAB) != 0) { + /* + * Dispatch on STAB type + */ + switch((unsigned char)symbolP->sy_nlist.n_type) { + /* + * 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) && + symbolP->sy_nlist.n_value == + Current_Offset) break; + /* calculate actual debugger source line */ + symbolP->sy_nlist.n_desc + += 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( + symbolP->sy_nlist.n_desc, + symbolP->sy_nlist.n_value, + Text_Psect, + 0); + } else { + if ((symbolP->sy_nlist.n_desc - + 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, + symbolP->sy_nlist.n_value - + Current_Offset, + 0, + -1); + VMS_TBT_Line_PC_Correlation( + symbolP->sy_nlist.n_desc, + symbolP->sy_nlist.n_value, + Text_Psect, + 0); + } else { + /* + * Line delta is +ve, all is well + */ + VMS_TBT_Line_PC_Correlation( + symbolP->sy_nlist.n_desc - + Current_Line_Number, + symbolP->sy_nlist.n_value - + Current_Offset, + 0, + 1); + } + } + /* + * Update the current line/PC + */ + Current_Line_Number = symbolP->sy_nlist.n_desc; + Current_Offset = symbolP->sy_nlist.n_value; + /* + * 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; + } + } + } + /* + * If there is a routine start defined, + * terminate it (and the line numbers) + */ + if (Current_Routine) { + /* + * Terminate the line numbers + */ + VMS_TBT_Line_PC_Correlation(0, + text_siz - Current_Routine->sy_nlist.n_value, + 0, + -1); + /* + * Terminate the routine + */ + VMS_TBT_Routine_End(text_siz,Current_Routine); + } + } + /* + * Write the Traceback End Module TBT record + */ + VMS_TBT_Module_End(); + + /* + * Write the End Of Module record + */ + if (Entry_Point_Symbol == 0) + Write_VMS_EOM_Record(-1,0); + else + Write_VMS_EOM_Record(Text_Psect, + Entry_Point_Symbol->sy_nlist.n_value); + + /* + * All done, close the object file + */ + Close_VMS_Object_File(); +} + + + /****** VMS OBJECT FILE HACKING ROUTINES *******/ + + +/* + * 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 char Object_Record_Buffer[512]; /* Buffer for object file records */ +static int Object_Record_Offset; /* Offset to end of data */ +static int Current_Object_Record_Type; /* Type of record in above */ + +/* + * Macros for placing data into the object record buffer + */ +#define PUT_LONG(val) *((long *)(Object_Record_Buffer + \ + Object_Record_Offset)) = val; \ + Object_Record_Offset += sizeof(long) + +#define PUT_SHORT(val) *((short *)(Object_Record_Buffer + \ + Object_Record_Offset)) = val; \ + Object_Record_Offset += sizeof(short) + +#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++);} + +/* + * Macro for determining if a Name has psect attributes attached + * to it. + */ +#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) + + +/* + * Create the VMS object file + */ +Create_VMS_Object_File() +{ +#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"); +#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 + */ + Object_Record_Offset = 0; + Current_Object_Record_Type = -1; +} + + +/* + * Declare a particular type of object file record + */ +Set_VMS_Object_File_Record(Type) +int Type; +{ + /* + * If the type matches, we are done + */ + if (Type == Current_Object_Record_Type) return; + /* + * Otherwise: flush the buffer + */ + Flush_VMS_Object_Record_Buffer(); + /* + * Set the new type + */ + Current_Object_Record_Type = Type; +} + + +/* + * Flush the object record buffer to the object file + */ +Flush_VMS_Object_Record_Buffer() +{ + int i; + + /* + * If the buffer is empty, we are done + */ + if (Object_Record_Offset == 0) return; + /* + * Write the data to the file + */ + 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"); + /* + * The buffer is now empty + */ + Object_Record_Offset = 0; +} + + +/* + * Close the VMS Object file + */ +Close_VMS_Object_File() +{ + close(VMS_Object_File_FD); +} + + +/* + * Write the MHD (Module Header) records + */ +Write_VMS_MHD_Records() +{ + register char *cp,*cp1; + register int i; + struct {int Size; char *Ptr;} Descriptor; + char Module_Name[256]; + char Now[17]; + + /* + * We are writing a module header record + */ + Set_VMS_Object_File_Record(OBJ$C_HDR); + /* + * *************************** + * *MAIN MODULE HEADER RECORD* + * *************************** + * + * Store record type and header type + */ + PUT_CHAR(OBJ$C_HDR); + PUT_CHAR(MHD$C_MHD); + /* + * Structure level is 0 + */ + PUT_CHAR(OBJ$C_STRLVL); + /* + * 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) + */ + 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 and store in the object record + */ + 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; + } + PUT_COUNTED_STRING(Module_Name); + /* + * Module Version is "V1.0" + */ + PUT_COUNTED_STRING("V1.0"); + /* + * Creation time is "now" (17 chars of time string) + */ + Descriptor.Size = 17; + Descriptor.Ptr = Now; + sys$asctim(0,&Descriptor,0,0); + for(i = 0; i < 17; i++) PUT_CHAR(Now[i]); + /* + * Patch time is "never" (17 zeros) + */ + for(i = 0; i < 17; i++) PUT_CHAR(0); + /* + * Flush the record + */ + Flush_VMS_Object_Record_Buffer(); + /* + * ************************* + * *LANGUAGE PROCESSOR NAME* + * ************************* + * + * Store record type and header type + */ + PUT_CHAR(OBJ$C_HDR); + PUT_CHAR(MHD$C_LNM); + /* + * Store language processor name and version + * (not a counted string!) + */ + cp = compiler_version_string; + if (cp == 0) { + cp ="GNU AS V"; + while(*cp) PUT_CHAR(*cp++); + cp = strchr(&version_string,'.'); + while(*cp != ' ') cp--; cp++; + }; + while(*cp >= 32) PUT_CHAR(*cp++); + /* + * Flush the record + */ + Flush_VMS_Object_Record_Buffer(); +} + + +/* + * Write the EOM (End Of Module) record + */ +Write_VMS_EOM_Record(Psect, Offset) +int Psect; +int Offset; +{ + /* + * We are writing an end-of-module record + */ + Set_VMS_Object_File_Record(OBJ$C_EOM); + /* + * Store record Type + */ + PUT_CHAR(OBJ$C_EOM); + /* + * Store the error severity (0) + */ + PUT_CHAR(0); + /* + * 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_VMS_Object_Record_Buffer(); +} + + +/* this hash routine borrowed from GNU-EMACS, and strengthened slightly ERY*/ + +static int +hash_string (ptr) + unsigned char *ptr; +{ + register unsigned char *p = ptr; + register unsigned char *end = p + strlen(ptr); + register unsigned char c; + register int hash = 0; + + while (p != end) + { + c = *p++; + hash = ((hash<<3) + (hash<<15) + (hash>>28) + c); + } + return hash; +} + +/* + * Generate a Case-Hacked VMS symbol name (limited to 31 chars) + */ +VMS_Case_Hack_Symbol(In,Out) +register char *In; +register char *Out; +{ + long int init = 0; + long int result; + char *pnt; + char *new_name; + char *old_name; + register int i; + int destructor = 0; /*hack to allow for case sens in a destructor*/ + int truncate = 0; + int Case_Hack_Bits = 0; + int Saw_Dollar = 0; + static char Hex_Table[16] = + {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + + /* + * Kill any leading "_" + */ + if (*In == '_') In++; + + new_name=Out; /* save this for later*/ + + if((In[0]=='_')&&(In[1]=='$')&&(In[2]=='_')) + destructor=1; + + /* We may need to truncate the symbol, save the hash for later*/ + if(strlen(In)>23) result = hash_string(In); + /* + * Is there a Psect Attribute to skip?? + */ + if (HAS_PSECT_ATTRIBUTES(In)) { + /* + * Yes: Skip it + */ + In += PSECT_ATTRIBUTES_STRING_LENGTH; + while(*In) { + if ((In[0] == '$') && (In[1] == '$')) { + In += 2; + break; + } + In++; + } + } + + old_name=In; +/* if(strlen(In) > 31 && flagseen['+']) + printf("%s: Symbol name truncated: %s\n",myname,In);*/ + /* + * Do the case conversion + */ + i = 23; /* Maximum of 23 chars */ + while(*In && (--i >= 0)) { + Case_Hack_Bits <<= 1; + if (*In == '$') Saw_Dollar = 1; + if ((destructor==1)&&(i==21)) Saw_Dollar = 0; + if (isupper(*In)) { + *Out++ = *In++; + Case_Hack_Bits |= 1; + } else { + *Out++ = islower(*In) ? toupper(*In++) : *In++; + } + } + /* + * If we saw a dollar sign, we don't do case hacking + */ + if(flagseen['h'] || Saw_Dollar) + Case_Hack_Bits = 0; + + /* + * If we have more than 23 characters and everything is lowercase + * we can insert the full 31 characters + */ + if (*In) { + /* + * We have more than 23 characters + * If we must add the case hack, then we have truncated the str + */ + pnt=Out; + truncate=1; + if (Case_Hack_Bits == 0) { + /* + * And so far they are all lower case: + * Check up to 8 more characters + * and ensure that they are lowercase + */ + if(flagseen['h']) + i=8; + else + for(i = 0; (In[i] != 0) && (i < 8); i++) + if (isupper(In[i]) && !Saw_Dollar) + break; + if(In[i]==0) + truncate=0; + + if ((i >= 8) || (In[i] == 0)) { + /* + * They are: Copy up to 31 characters + * to the output string + */ + i = 8; + while((--i >= 0) && (*In)) + *Out++ = islower(*In) ? + toupper(*In++) : + *In++; + } + } + } + /* + * If there were any uppercase characters in the name we + * take on the case hacking string + */ + + /* Old behavior for regular GNU-C compiler */ + if (!flagseen['+']) + truncate=0; + if ((Case_Hack_Bits != 0)||(truncate==1)) { + if(truncate==0) { + *Out++ = '_'; + for(i = 0; i < 6; i++) { + *Out++ = Hex_Table[Case_Hack_Bits & 0xf]; + Case_Hack_Bits >>= 4; + } + *Out++ = 'X'; + } else { + Out=pnt; /*Cut back to 23 characters maximum */ + *Out++ = '_'; + for( i=0; i < 7; i++) { + init = result & 0x01f; + if (init < 10) + *Out++='0'+init; + else + *Out++ = 'A'+init-10; + result = result >> 5; + } + } + } /*Case Hack */ + /* + * Done + */ + *Out = 0; + if( truncate==1 && flagseen['+'] && flagseen['H']) + printf("%s: Symbol %s replaced by %s\n",myname,old_name,new_name); +} + + +/* + * Scan a symbol name for a psect attribute specification + */ +VMS_Modify_Psect_Attributes(Name, Attribute_Pointer) +char *Name; +int *Attribute_Pointer; +{ + register int i; + register char *cp; + int Negate; + static struct { + char *Name; + int Value; + } Attributes[] = { + {"PIC", GPS$M_PIC}, + {"LIB", GPS$M_LIB}, + {"OVR", GPS$M_OVR}, + {"REL", GPS$M_REL}, + {"GBL", GPS$M_GBL}, + {"SHR", GPS$M_SHR}, + {"EXE", GPS$M_EXE}, + {"RD", GPS$M_RD}, + {"WRT", GPS$M_WRT}, + {"VEC", GPS$M_VEC}, + {0, 0}}; + + /* + * Kill leading "_" + */ + if (*Name == '_') Name++; + /* + * Check for a PSECT attribute list + */ + if (!HAS_PSECT_ATTRIBUTES(Name)) return; /* If not, return */ + /* + * Skip the attribute list indicator + */ + Name += PSECT_ATTRIBUTES_STRING_LENGTH; + /* + * Process the attributes ("_" separated, "$" terminated) + */ + while(*Name != '$') { + /* + * Assume not negating + */ + Negate = 0; + /* + * Check for "NO" + */ + if ((Name[0] == 'N') && (Name[1] == 'O')) { + /* + * We are negating (and skip the NO) + */ + Negate = 1; + Name += 2; + } + /* + * Find the token delimiter + */ + cp = Name; + while(*cp && (*cp != '_') && (*cp != '$')) cp++; + /* + * Look for the token in the attribute list + */ + for(i = 0; Attributes[i].Name; i++) { + /* + * If the strings match, set/clear the attr. + */ + if (strncmp(Name, Attributes[i].Name, cp - Name) == 0) { + /* + * Set or clear + */ + if (Negate) + *Attribute_Pointer &= + ~Attributes[i].Value; + else + *Attribute_Pointer |= + Attributes[i].Value; + /* + * Done + */ + break; + } + } + /* + * Now skip the attribute + */ + Name = cp; + if (*Name == '_') Name++; + } + /* + * Done + */ + return; +} + + +/* + * Define a psect + */ +VMS_Psect_Spec(Name, Size, Type) +char *Name; +int Size; +char *Type; +{ + char Local[32]; + int Psect_Attributes; + + /* + * We are writing a GSD record + */ + Set_VMS_Object_File_Record(OBJ$C_GSD); + /* + * If the buffer is empty we must insert the GSD record type + */ + if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_GSD); + /* + * We are writing a PSECT definition subrecord + */ + PUT_CHAR(GSD$C_PSC); + /* + * Psects are always LONGWORD aligned + */ + PUT_CHAR(2); + /* + * 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$M_PIC|GPS$M_OVR|GPS$M_REL|GPS$M_GBL| + GPS$M_SHR|GPS$M_RD|GPS$M_WRT); + } else if (strcmp(Type,"CONST") == 0) { + /* + * Common block psects are: PIC,OVR,REL,GBL,SHR,RD + */ + Psect_Attributes = (GPS$M_PIC|GPS$M_OVR|GPS$M_REL|GPS$M_GBL| + GPS$M_SHR|GPS$M_RD); + } else if (strcmp(Type,"DATA") == 0) { + /* + * The Data psects are PIC,REL,RD,WRT + */ + Psect_Attributes = + (GPS$M_PIC|GPS$M_REL|GPS$M_RD|GPS$M_WRT); + } else if (strcmp(Type,"TEXT") == 0) { + /* + * The Text psects are PIC,REL,SHR,EXE,RD + */ + Psect_Attributes = + (GPS$M_PIC|GPS$M_REL|GPS$M_SHR| + GPS$M_EXE|GPS$M_RD); + } else { + /* + * Error: Unknown psect type + */ + error("Unknown VMS psect type"); + } + /* + * Modify the psect attributes according to any attribute string + */ + if (HAS_PSECT_ATTRIBUTES(Name)) + VMS_Modify_Psect_Attributes(Name,&Psect_Attributes); + /* + * Specify the psect attributes + */ + PUT_SHORT(Psect_Attributes); + /* + * Specify the allocation + */ + PUT_LONG(Size); + /* + * Finally, the psect name + */ + VMS_Case_Hack_Symbol(Name,Local); + PUT_COUNTED_STRING(Local); + /* + * 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(); +} + + +/* + * Define a global symbol + */ +VMS_Global_Symbol_Spec(Name, Psect_Number, Psect_Offset, Defined) +char *Name; +int Psect_Number; +int Psect_Offset; +{ + char Local[32]; + + /* + * We are writing a GSD record + */ + Set_VMS_Object_File_Record(OBJ$C_GSD); + /* + * If the buffer is empty we must insert the GSD record type + */ + if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_GSD); + /* + * We are writing a Global symbol definition subrecord + */ + if (Psect_Number <= 255) { + PUT_CHAR(GSD$C_SYM); + } else { + PUT_CHAR(GSD$C_SYMW); + } + /* + * Data type is undefined + */ + PUT_CHAR(0); + /* + * Switch on Definition/Reference + */ + if (Defined) { + /* + * Definition: + * Flags = "RELOCATABLE" and "DEFINED" + */ + PUT_SHORT(GSY$M_DEF|GSY$M_REL); + /* + * Psect Number + */ + if (Psect_Number <= 255) { + PUT_CHAR(Psect_Number); + } else { + PUT_SHORT(Psect_Number); + } + /* + * Offset + */ + PUT_LONG(Psect_Offset); + } else { + /* + * Reference: + * Flags = "RELOCATABLE" + */ + PUT_SHORT(GSY$M_REL); + } + /* + * Finally, the global symbol name + */ + VMS_Case_Hack_Symbol(Name,Local); + PUT_COUNTED_STRING(Local); + /* + * 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(); +} + + +/* + * Define a procedure entry pt/mask + */ +VMS_Procedure_Entry_Pt(Name, Psect_Number, Psect_Offset, Entry_Mask) +char *Name; +int Psect_Number; +int Psect_Offset; +int Entry_Mask; +{ + char Local[32]; + + /* + * We are writing a GSD record + */ + Set_VMS_Object_File_Record(OBJ$C_GSD); + /* + * If the buffer is empty we must insert the GSD record type + */ + if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_GSD); + /* + * We are writing a Procedure Entry Pt/Mask subrecord + */ + if (Psect_Number <= 255) { + PUT_CHAR(GSD$C_EPM); + } else { + PUT_CHAR(GSD$C_EPMW); + } + /* + * Data type is undefined + */ + PUT_CHAR(0); + /* + * Flags = "RELOCATABLE" and "DEFINED" + */ + PUT_SHORT(GSY$M_DEF|GSY$M_REL); + /* + * Psect Number + */ + if (Psect_Number <= 255) { + PUT_CHAR(Psect_Number); + } else { + PUT_SHORT(Psect_Number); + } + /* + * Offset + */ + PUT_LONG(Psect_Offset); + /* + * Entry mask + */ + PUT_SHORT(Entry_Mask); + /* + * Finally, the global symbol name + */ + VMS_Case_Hack_Symbol(Name,Local); + PUT_COUNTED_STRING(Local); + /* + * 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(); +} + + +/* + * Set the current location counter to a particular Psect and Offset + */ +VMS_Set_Psect(Psect_Index, Offset, Record_Type) +int Psect_Index; +int Offset; +int Record_Type; +{ + /* + * 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 (Object_Record_Offset == 0) PUT_CHAR(Record_Type); + /* + * Stack the Psect base + Longword Offset + */ + if (Psect_Index < 255) { + PUT_CHAR(TIR$C_STA_PL); + PUT_CHAR(Psect_Index); + } else { + PUT_CHAR(TIR$C_STA_WPL); + PUT_SHORT(Psect_Index); + } + PUT_LONG(Offset); + /* + * Set relocation base + */ + PUT_CHAR(TIR$C_CTL_SETRB); + /* + * 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 + */ +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 (Object_Record_Offset == 0) PUT_CHAR(Record_Type); + /* + * Stack the Psect base + Longword Offset + */ + if(Force==1){ + if(Psect_Index>127){ + PUT_CHAR(TIR$C_STA_WPL); + PUT_SHORT(Psect_Index); + PUT_LONG(Offset);} + else { + PUT_CHAR(TIR$C_STA_PL); + PUT_CHAR(Psect_Index); + PUT_LONG(Offset);} + } else {if(Offset>32767){ + PUT_CHAR(TIR$C_STA_WPL); + PUT_SHORT(Psect_Index); + PUT_LONG(Offset);} + else if(Offset>127){ + PUT_CHAR(TIR$C_STA_WPW); + PUT_SHORT(Psect_Index); + PUT_SHORT(Offset);} + else{ + PUT_CHAR(TIR$C_STA_WPB); + PUT_SHORT(Psect_Index); + PUT_CHAR(Offset);};}; + /* + * Set relocation base + */ + PUT_CHAR(TIR$C_STO_PIDR); + /* + * 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. + */ +VMS_Store_Struct(int Struct_Index) +{ + /* + * We are writing a "OBJ$C_DBG" record + */ + Set_VMS_Object_File_Record(OBJ$C_DBG); + /* + * If the buffer is empty we must insert the record type + */ + if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_DBG); + PUT_CHAR(TIR$C_STA_UW); + PUT_SHORT(Struct_Index); + PUT_CHAR(TIR$C_CTL_STKDL); + PUT_CHAR(TIR$C_STO_L); + /* + * 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. + */ +VMS_Def_Struct(int Struct_Index) +{ + /* + * We are writing a "OBJ$C_DBG" record + */ + Set_VMS_Object_File_Record(OBJ$C_DBG); + /* + * If the buffer is empty we must insert the record type + */ + if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_DBG); + PUT_CHAR(TIR$C_STA_UW); + PUT_SHORT(Struct_Index); + PUT_CHAR(TIR$C_CTL_DFLOC); + /* + * 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(); +} + +VMS_Set_Struct(int Struct_Index) +{/* see previous functions for comments */ + Set_VMS_Object_File_Record(OBJ$C_DBG); + if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_DBG); + PUT_CHAR(TIR$C_STA_UW); + PUT_SHORT(Struct_Index); + PUT_CHAR(TIR$C_CTL_STLOC); + if (Object_Record_Offset > + (sizeof(Object_Record_Buffer)*3/4)) + Flush_VMS_Object_Record_Buffer(); +} + +/* + * Store immediate data in current Psect + */ +VMS_Store_Immediate_Data(Pointer, Size, Record_Type) +register 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 + */ + 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)) + Flush_VMS_Object_Record_Buffer(); + /* + * 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 + */ + 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(); + } +} + + +/* + * Store repeated immediate data in current Psect + */ +VMS_Store_Repeated_Data(Repeat_Count,Pointer, Size, Record_Type) +int Repeat_Count; +register char *Pointer; +int Size; +int 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; + /* + * If the data is too big for a TIR$C_STO_RIVB sub-record + * then we do it manually + */ + if (Size > 255) { + while(--Repeat_Count >= 0) + VMS_Store_Immediate_Data(Pointer,Size,Record_Type); + return; + } + /* + * We are writing a "Record_Type" record + */ + Set_VMS_Object_File_Record(Record_Type); + /* + * If the buffer is empty we must insert record type + */ + if (Object_Record_Offset == 0) PUT_CHAR(Record_Type); + /* + * Stack the repeat count + */ + PUT_CHAR(TIR$C_STA_LW); + PUT_LONG(Repeat_Count); + /* + * And now the command and its data + */ + PUT_CHAR(TIR$C_STO_RIVB); + PUT_CHAR(Size); + while(--Size >= 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(); +} + + +/* + * Store a Position Independent Reference + */ +VMS_Store_PIC_Symbol_Reference(Symbol, Offset, PC_Relative, + Psect, Psect_Offset, Record_Type) +struct symbol *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); + char Local[32]; + + /* + * We are writing a "Record_Type" record + */ + Set_VMS_Object_File_Record(Record_Type); + /* + * If the buffer is empty we must insert record type + */ + if (Object_Record_Offset == 0) PUT_CHAR(Record_Type); + /* + * Set to the appropriate offset in the Psect + */ + 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); + } + /* + * Make sure we are still generating a "Record Type" record + */ + if (Object_Record_Offset == 0) PUT_CHAR(Record_Type); + /* + * Dispatch on symbol type (so we can stack its value) + */ + switch(Symbol->sy_nlist.n_type) { + /* + * Global symbol + */ +#ifdef NOT_VAX_11_C_COMPATIBLE + case N_UNDF | N_EXT: + case N_DATA | N_EXT: +#endif NOT_VAX_11_C_COMPATIBLE + case N_UNDF: + case N_TEXT | N_EXT: + /* + * Get the symbol name (case hacked) + */ + VMS_Case_Hack_Symbol(Symbol->sy_nlist.n_un.n_name,Local); + /* + * Stack the global symbol value + */ + PUT_CHAR(TIR$C_STA_GBL); + PUT_COUNTED_STRING(Local); + if (Offset) { + /* + * Stack the longword offset + */ + PUT_CHAR(TIR$C_STA_LW); + PUT_LONG(Offset); + /* + * Add the two, leaving the result on the stack + */ + PUT_CHAR(TIR$C_OPR_ADD); + } + break; + /* + * Uninitialized local data + */ + case N_BSS: + /* + * Stack the Psect (+offset) + */ + if (vsp->Psect_Index < 255) { + PUT_CHAR(TIR$C_STA_PL); + PUT_CHAR(vsp->Psect_Index); + } else { + PUT_CHAR(TIR$C_STA_WPL); + PUT_SHORT(vsp->Psect_Index); + } + PUT_LONG(vsp->Psect_Offset + Offset); + break; + /* + * Local text + */ + case N_TEXT: + /* + * Stack the Psect (+offset) + */ + if (vsp->Psect_Index < 255) { + PUT_CHAR(TIR$C_STA_PL); + PUT_CHAR(vsp->Psect_Index); + } else { + PUT_CHAR(TIR$C_STA_WPL); + PUT_SHORT(vsp->Psect_Index); + } + PUT_LONG(Symbol->sy_nlist.n_value); + break; + /* + * Initialized local or global data + */ + case N_DATA: +#ifndef NOT_VAX_11_C_COMPATIBLE + case N_UNDF | N_EXT: + case N_DATA | N_EXT: +#endif NOT_VAX_11_C_COMPATIBLE + /* + * Stack the Psect (+offset) + */ + if (vsp->Psect_Index < 255) { + PUT_CHAR(TIR$C_STA_PL); + PUT_CHAR(vsp->Psect_Index); + } else { + PUT_CHAR(TIR$C_STA_WPL); + PUT_SHORT(vsp->Psect_Index); + } + PUT_LONG(vsp->Psect_Offset + Offset); + break; + } + /* + * Store either a code or data reference + */ + PUT_CHAR(PC_Relative ? TIR$C_STO_PICR : TIR$C_STO_PIDR); + /* + * 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(); +} + + +/* + * Check in the text area for an indirect pc-relative reference + * and fix it up with addressing mode 0xff [PC indirect] + * + * THIS SHOULD BE REPLACED BY THE USE OF TIR$C_STO_PIRR IN THE + * PIC CODE GENERATING FIXUP ROUTINE. + */ +VMS_Fix_Indirect_Reference(Text_Psect, Offset, fragP, text_frag_root) +int Text_Psect; +int Offset; +register fragS *fragP; +struct frag *text_frag_root; +{ + /* + * The addressing mode byte is 1 byte before the address + */ + Offset--; + /* + * Is it in THIS frag?? + */ + if ((Offset < fragP->fr_address) || + (Offset >= (fragP->fr_address + fragP->fr_fix))) { + /* + * We need to search for the fragment containing this + * Offset + */ + for(fragP = text_frag_root; fragP; fragP = fragP->fr_next) { + if ((Offset >= fragP->fr_address) && + (Offset < (fragP->fr_address + fragP->fr_fix))) + break; + } + /* + * If we couldn't find the frag, things are BAD!! + */ + if (fragP == 0) + 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; + + /* + * Yes: Store the indirect mode back into the image + * to fix up the damage done by STO_PICR + */ + VMS_Set_Psect(Text_Psect,Offset,OBJ$C_TIR); + VMS_Store_Immediate_Data(&Address_Mode,1,OBJ$C_TIR); + } +} + + +/* + * Write the Traceback Module Begin record + */ +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 + */ + *cp++ = DST$C_MODBEG; + /* + * Unused + */ + *cp++ = 0; + /* + * Language type == "C" + */ + *(long *)cp = DST$C_C; + cp += sizeof(long); + /* + * Store the module name + */ + *cp++ = strlen(Module_Name); + cp1 = Module_Name; + while(*cp1) *cp++ = *cp1++; + /* + * Now we can store the record size + */ + Size = (cp - Local); + Local[0] = Size-1; + /* + * Put it into the object record + */ + VMS_Store_Immediate_Data(Local, Size, OBJ$C_TBT); +} + + +/* + * Write the Traceback Module End record +*/ +VMS_TBT_Module_End() +{ + char Local[2]; + + /* + * End module + */ + Local[0] = 1; + Local[1] = DST$C_MODEND; + /* + * Put it into the object record + */ + VMS_Store_Immediate_Data(Local, 2, OBJ$C_TBT); +} + + +/* + * Write the Traceback Routine Begin record + */ +VMS_TBT_Routine_Begin(symbolP, Psect) +struct symbol *symbolP; +int Psect; +{ + register char *cp,*cp1; + char *Name; + int Offset; + int Size; + char Local[512]; + + /* + * Strip the leading "_" from the name + */ + Name = symbolP->sy_nlist.n_un.n_name; + if (*Name == '_') Name++; + /* + * Get the text psect offset + */ + Offset = symbolP->sy_nlist.n_value; + /* + * Calculate the record size + */ + Size = 1+1+4+1+strlen(Name); + /* + * Record Size + */ + Local[0] = Size; + /* + * Begin Routine + */ + Local[1] = DST$C_RTNBEG; + /* + * Uses CallS/CallG + */ + Local[2] = 0; + /* + * Store the data so far + */ + VMS_Store_Immediate_Data(Local, 3, OBJ$C_TBT); + /* + * Make sure we are still generating a OBJ$C_TBT record + */ + if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_TBT); + /* + * Now get the symbol address + */ + PUT_CHAR(TIR$C_STA_WPL); + PUT_SHORT(Psect); + PUT_LONG(Offset); + /* + * Store the data reference + */ + PUT_CHAR(TIR$C_STO_PIDR); + /* + * Store the counted string as data + */ + cp = Local; + cp1 = Name; + Size = strlen(cp1) + 1; + *cp++ = Size - 1; + while(*cp1) *cp++ = *cp1++; + VMS_Store_Immediate_Data(Local, Size, OBJ$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. + */ +VMS_TBT_Routine_End(Max_Size,sp) +int Max_Size; +symbolS *sp; +{ + symbolS *symbolP; + int Size = 0x7fffffff; + char Local[16]; + + + for(symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) { + if ((symbolP->sy_nlist.n_type & ~N_EXT) == N_TEXT) { + if (symbolP->sy_nlist.n_un.n_name[0] == 'L') continue; + if((symbolP->sy_nlist.n_value > sp->sy_nlist.n_value) && + (symbolP->sy_nlist.n_value < Size )) + Size = symbolP->sy_nlist.n_value; + /* check if gcc_compiled. has size of zero */ + if((symbolP->sy_nlist.n_value == sp->sy_nlist.n_value) && + sp != symbolP && + !strcmp(sp->sy_nlist.n_un.n_name,"gcc_compiled.")) + Size = symbolP->sy_nlist.n_value; + + }; + }; + if(Size == 0x7fffffff) Size = Max_Size; + Size -= sp->sy_nlist.n_value; /* and get the size of the routine */ + /* + * Record Size + */ + Local[0] = 6; + /* + * End of Routine + */ + Local[1] = DST$C_RTNEND; + /* + * Unused + */ + Local[2] = 0; + /* + * Size of routine + */ + *((long *)(Local+3)) = Size; + /* + * Store the record + */ + VMS_Store_Immediate_Data(Local,7, OBJ$C_TBT); +} +/* + * Write the Traceback Block End record + */ +VMS_TBT_Block_Begin(symbolP, Psect, Name) +struct symbol *symbolP; +int Psect; +char* Name; +{ + register char *cp,*cp1; + int Offset; + int Size; + char Local[512]; + /* + * Begin block + */ + Size = 1+1+4+1+strlen(Name); + /* + * Record Size + */ + Local[0] = Size; + /* + * Begin Block - We simulate with a phony routine + */ + Local[1] = DST$C_BLKBEG; + /* + * Uses CallS/CallG + */ + Local[2] = 0; + /* + * Store the data so far + */ + VMS_Store_Immediate_Data(Local, 3, OBJ$C_DBG); + /* + * Make sure we are still generating a OBJ$C_DBG record + */ + if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_DBG); + /* + * Now get the symbol address + */ + PUT_CHAR(TIR$C_STA_WPL); + PUT_SHORT(Psect); + /* + * Get the text psect offset + */ + Offset = symbolP->sy_nlist.n_value; + PUT_LONG(Offset); + /* + * Store the data reference + */ + PUT_CHAR(TIR$C_STO_PIDR); + /* + * Store the counted string as data + */ + cp = Local; + cp1 = Name; + Size = strlen(cp1) + 1; + *cp++ = Size - 1; + while(*cp1) *cp++ = *cp1++; + VMS_Store_Immediate_Data(Local, Size, OBJ$C_DBG); +} + + +/* + * Write the Traceback Block End record + */ +VMS_TBT_Block_End(int Size) +{ + char Local[16]; + + /* + * End block - simulate with a phony end routine + */ + Local[0] = 6; + Local[1] = DST$C_BLKEND; + *((long *)(Local+3)) = Size; + /* + * Unused + */ + Local[2] = 0; + VMS_Store_Immediate_Data(Local,7, OBJ$C_DBG); +} + + + +/* + * Write a Line number / PC correlation record + */ +VMS_TBT_Line_PC_Correlation(Line_Number, Offset, Psect, Do_Delta) +int Line_Number; +int Offset; +int Psect; +int 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$C_LINE_NUM; + /* + * Set Line number + */ + Local[2] = DST$C_SET_LINE_NUM; + *((unsigned short *)(Local+3)) = Line_Number-1; + /* + * Set PC + */ + Local[5] = DST$C_SET_ABS_PC; + VMS_Store_Immediate_Data(Local, 6, OBJ$C_TBT); + /* + * Make sure we are still generating a OBJ$C_TBT record + */ + if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_TBT); + if (Psect < 255) { + PUT_CHAR(TIR$C_STA_PL); + PUT_CHAR(Psect); + } else { + PUT_CHAR(TIR$C_STA_WPL); + PUT_SHORT(Psect); + } + PUT_LONG(Offset); + PUT_CHAR(TIR$C_STO_PIDR); + /* + * Do a PC offset of 0 to register the line number + */ + Local[0] = 2; + Local[1] = DST$C_LINE_NUM; + Local[2] = 0; /* Increment PC by 0 and register line # */ + VMS_Store_Immediate_Data(Local, 3, OBJ$C_TBT); + } else { + /* + * If Delta is negative, terminate the line numbers + */ + if (Do_Delta < 0) { + Local[0] = 1+1+4; + Local[1] = DST$C_LINE_NUM; + Local[2] = DST$C_TERM_L; + *((long *)(Local+3)) = Offset; + VMS_Store_Immediate_Data(Local, 7, OBJ$C_TBT); + /* + * Done + */ + return; + } + /* + * Do a PC/Line delta + */ + cp = Local+1; + *cp++ = DST$C_LINE_NUM; + if (Line_Number > 1) { + /* + * We need to increment the line number + */ + if (Line_Number-1 <= 255) { + *cp++ = DST$C_INCR_LINUM; + *cp++ = Line_Number-1; + } else { + *cp++ = DST$C_INCR_LINUM_W; + *(short *)cp = Line_Number-1; + cp += sizeof(short); + } + } + /* + * Increment the PC + */ + if (Offset <= 128) { + *cp++ = -Offset; + } else { + if (Offset < 0x10000) { + *cp++ = DST$C_DELTA_PC_W; + *(short *)cp = Offset; + cp += sizeof(short); + } else { + *cp++ = DST$C_DELTA_PC_L; + *(long *)cp = Offset; + cp += sizeof(long); + } + } + Local[0] = cp - (Local+1); + VMS_Store_Immediate_Data(Local,cp - Local, OBJ$C_TBT); + } +} + + +/* + * Describe a source file to the debugger + */ +VMS_TBT_Source_File(Filename, ID_Number) +char *Filename; +int ID_Number; +{ + register char *cp,*cp1; + int Status,i; + char Local[512]; + 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 = (struct XAB *)&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); +/* ((struct XAB *)&Date_Xab)->xab$b_cod = XAB$C_DAT; */ +/* ((struct XAB *)&Date_Xab)->xab$b_bln = sizeof(Date_Xab); */ +/* ((struct XAB *)&Date_Xab)->xab$l_nxt = (struct XAB *)&File_Header_Xab; */ +/* ((struct XAB *)&File_Header_Xab)->xab$b_cod = XAB$C_FHC; */ +/* ((struct XAB *)&File_Header_Xab)->xab$b_bln = sizeof(File_Header_Xab); */ + /* + * Get the file information + */ + Fab.fab$l_fna = Filename; + Fab.fab$b_fns = strlen(Filename); + Status = sys$open(&Fab); + if (!(Status & 1)) { + printf("gas: Couldn't find source file \"%s\", Error = %%X%x\n", + Filename, Status); + return(0); + } + sys$close(&Fab); + /* + * Calculate the size of the resultant string + */ + i = Nam.nam$b_rsl; + /* + * Size of record + */ + Local[0] = 1+1+1+1+1+2+8+4+2+1+1+i+1; + /* + * Source declaration + */ + Local[1] = DST$C_SOURCE; + /* + * Make formfeeds count as source records + */ + Local[2] = DST$C_SRC_FORMFEED; + /* + * Declare source file + */ + Local[3] = DST$C_SRC_DECLFILE; + Local[4] = 1+2+8+4+2+1+1+i+1; + cp = Local+5; + /* + * Flags + */ + *cp++ = 0; + /* + * File ID + */ + *(short *)cp = ID_Number; + cp += sizeof(short); + /* + * 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; + while(--i >= 0) *cp++ = *cp1++; + /* + * Library module name (none) + */ + *cp++ = 0; + /* + * Done + */ + VMS_Store_Immediate_Data(Local,cp - Local, OBJ$C_TBT); +} + + +/* + * Give the number of source lines to the debugger + */ +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$C_SOURCE; + /* + * Set Source File + */ + cp = Local+2; + *cp++ = DST$C_SRC_SETFILE; + /* + * File ID Number + */ + *(short *)cp = ID_Number; + cp += sizeof(short); + /* + * Set record number + */ + *cp++ = DST$C_SRC_SETREC_L; + *(long *)cp = Starting_Line_Number; + cp += sizeof(long); + /* + * Define lines + */ + *cp++ = DST$C_SRC_DEFLINES_W; + *(short *)cp = Number_Of_Lines; + cp += sizeof(short); + /* + * Done + */ + VMS_Store_Immediate_Data(Local, cp-Local, OBJ$C_TBT); +} + + +/* + * 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. + */ +int VMS_Initialized_Data_Size(sp, End_Of_Data) +register struct symbol *sp; +int End_Of_Data; +{ + register struct symbol *sp1,*Next_Symbol; + + /* + * Find the next symbol + * it delimits this datum + */ + Next_Symbol = 0; + for (sp1 = symbol_rootP; sp1; sp1 = symbol_next(sp1)) { + /* + * The data type must match + */ + if ((sp1->sy_nlist.n_type & ~N_EXT) != N_DATA) continue; + /* + * The symbol must be AFTER this symbol + */ + if (sp1->sy_nlist.n_value <= sp->sy_nlist.n_value) 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 (sp1->sy_nlist.n_value > + Next_Symbol->sy_nlist.n_value) + continue; + /* + * Win: Make this the candidate + */ + Next_Symbol = sp1; + } else { + /* + * This is the 1st candidate + */ + Next_Symbol = sp1; + } + } + /* + * Calculate its size + */ + return(Next_Symbol ? + (Next_Symbol->sy_nlist.n_value - + sp->sy_nlist.n_value) : + (End_Of_Data - sp->sy_nlist.n_value)); +} + + + +/* 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 */ +struct input_file * +find_file(sp) +symbolS * sp; +{ + struct input_file * same_file; + struct input_file * fpnt; + same_file = (struct input_file*) NULL; + for(fpnt = file_root; fpnt; fpnt = fpnt->next){ + if(fpnt == (struct input_file*) NULL) break; + if(fpnt->spnt == sp) return fpnt; + }; + for(fpnt = file_root; fpnt; fpnt = fpnt->next){ + if(fpnt == (struct input_file*) NULL) break; + if (strcmp(sp->sy_nlist.n_un.n_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) 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 = sp->sy_nlist.n_un.n_name; + fpnt->min_line = 0x7fffffff; + fpnt->max_line = 0; + fpnt->offset = 0; + fpnt->flag = 0; + fpnt->file_number = 0; + fpnt->spnt = sp; + fpnt->same_file_fpnt = same_file; + return fpnt; +} + + +/* + * This is a hacked _doprnt() for VAX-11 "C". It understands that + * it is ONLY called by as_fatal(Format, Args) with a pointer to the + * "Args" argument. From this we can make it all work right! + */ +#ifndef eunice +_doprnt(Format, a, f) +char *Format; +FILE *f; +char **a; +{ + int Nargs = ((int *)a)[-2]; /* This understands as_fatal() */ + + switch(Nargs) { + default: fprintf(f,"_doprnt error on \"%s\"!!",Format); break; + case 1: fprintf(f,Format); break; + case 2: fprintf(f,Format,a[0]); break; + case 3: fprintf(f,Format,a[0],a[1]); break; + case 4: fprintf(f,Format,a[0],a[1],a[2]); break; + case 5: fprintf(f,Format,a[0],a[1],a[2],a[3]); break; + case 6: fprintf(f,Format,a[0],a[1],a[2],a[3],a[4]); break; + case 7: fprintf(f,Format,a[0],a[1],a[2],a[3],a[4],a[5]); break; + case 8: fprintf(f,Format,a[0],a[1],a[2],a[3],a[4],a[5],a[6]); break; + case 9: fprintf(f,Format,a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7]); break; + case 10: fprintf(f,Format,a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]); break; + } +} + +#endif /* eunice */ + +#endif /* VMS */ + +char const_flag = 0; +void s_const(); + +void +s_const() +{ + register int temp; + + temp = get_absolute_expression (); + subseg_new (SEG_DATA, (subsegT)temp); + const_flag = 1; + demand_empty_rest_of_line(); +} + +obj_crawl_symbol_chain() { + /* JF deal with forward references first. . . */ + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) { + if (symbolP->sy_forward) { + symbolP->sy_value += symbolP->sy_forward->sy_value + symbolP->sy_forward->sy_frag->fr_address; +#ifdef OBJ_COFF + if(SF_GET_GET_SEGMENT(symbolP) && + S_GET_SEGMENT(symbolP) == SEG_UNKNOWN) + S_SET_SEGMENT(symbolP, S_GET_SEGMENT(symbolP->sy_forward)); +#endif /* OBJ_COFF */ + symbolP->sy_forward=0; + } /* if it has a forward reference */ + } /* walk the symbol chain */ + + { /* crawl symbol table */ + register int symbol_number = 0; + +#if defined(OBJ_COFF) + { /* OBJ_COFF version */ + lineno* lineP; + symbolS* symbol_externP = (symbolS*)0; + symbolS* symbol_extern_lastP = (symbolS*)0; + + /* The symbol list should be ordered according to the following sequence + * order : + * . .file symbol + * . debug entries for functions + * . fake symbols for .text .data and .bss + * . defined symbols + * . undefined symbols + * But this is not mandatory. The only important point is to put the + * undefined symbols at the end of the list. + */ + + if (symbol_rootP == NULL + || S_GET_STORAGE_CLASS(symbol_rootP) != C_FILE) { + c_dot_file_symbol("fake"); + } /* Is there a .file symbol ? If not insert one at the beginning. */ + + /* + * Build up static symbols for .text, .data and .bss + */ + dot_text_symbol = (symbolS*) + c_section_symbol(".text", + 0, + H_GET_TEXT_SIZE(&headers), + 0/*text_relocation_number*/, + 0/*text_lineno_number*/); + + dot_data_symbol = (symbolS*) + c_section_symbol(".data", + H_GET_TEXT_SIZE(&headers), + H_GET_DATA_SIZE(&headers), + 0/*data_relocation_number*/, + 0); /* There are no data lineno + entries */ + + dot_bss_symbol = (symbolS*) + c_section_symbol(".bss", + H_GET_TEXT_SIZE(&headers) + H_GET_DATA_SIZE(&headers), + H_GET_BSS_SIZE(&headers), + 0, /* No relocation for a bss section. */ + 0); /* There are no bss lineno entries */ + + /* FIXME late night before delivery, I don't know why the chain is + broken, but I can guess. So! Let's force them to be knit properly + at this point. */ + +/* as john pointed out, this wasn't right. Instead, we'll check here to + make sure that the list is doubly linked. */ + +#if defined(DEBUG) && defined(SYMBOLS_NEED_BACKPOINTERS) + for (symbolP = symbol_rootP; symbol_next(symbolP); symbolP = symbol_next(symbolP)) { + know(symbolP->sy_next->sy_previous == symbolP); + } /* walk the symbol chain */ +#endif /* DEBUG and SYMBOLS_NEED_BACKPOINTERS */ + symbolP = symbol_rootP; + + if (symbolP) { + while(symbolP) { + /* If the symbol has a tagndx entry, resolve it */ + if(SF_GET_TAGGED(symbolP)) { + SA_SET_SYM_TAGNDX(symbolP, + ((symbolS*)SA_GET_SYM_TAGNDX(symbolP))->sy_number); + } + /* Debug symbol do not need all this rubbish */ + if(!SF_GET_DEBUG(symbolP)) { + symbolS* real_symbolP; + /* L* and C_EFCN symbols never merge. */ + if(!SF_GET_LOCAL(symbolP) && + (real_symbolP = + symbol_find_base(S_GET_NAME(symbolP), DO_NOT_STRIP)) && + real_symbolP != symbolP) { + /* FIXME where do dups come from? xoxorich. */ + /* Move the debug data from the debug symbol to the + real symbol. Do NOT do the oposite (i.e. move from + real symbol to symbol and remove real symbol from the + list.) Because some pointers refer to the real symbol + whereas no pointers refer to the symbol. */ + c_symbol_merge(symbolP, real_symbolP); + /* Replace the current symbol by the real one */ + /* The symbols will never be the last or the first + because : 1st symbol is .file and 3 last symbols are + .text, .data, .bss */ + symbol_remove(real_symbolP, &symbol_rootP, &symbol_lastP); + symbol_insert(real_symbolP, symbolP, &symbol_rootP, &symbol_lastP); + symbol_remove(symbolP, &symbol_rootP, &symbol_lastP); + symbolP = real_symbolP; + } + if(flagseen['R'] && S_IS_DATA(symbolP)) + S_SET_TEXT(symbolP); + + symbolP->sy_value += symbolP->sy_frag->fr_address; + + if(!S_IS_DEFINED(symbolP)) + S_SET_EXTERNAL(symbolP); + else if(S_GET_STORAGE_CLASS(symbolP) == C_NULL) + S_SET_STORAGE_CLASS(symbolP, C_STAT); + + /* Mainly to speed up if not -g */ + if(SF_GET_PROCESS(symbolP)) { + /* Handle the nested blocks auxiliary info. */ + if(S_GET_STORAGE_CLASS(symbolP) == C_BLOCK) { + if(!strcmp(S_GET_NAME(symbolP), ".bb")) + stack_push(block_stack, (char *) &symbolP); + else { /* .eb */ + register symbolS* begin_symbolP; + begin_symbolP = *(symbolS**)stack_pop(block_stack); + if(begin_symbolP == (symbolS*)0) + as_warn("mismatched .eb"); + else + SA_SET_SYM_ENDNDX(begin_symbolP, symbol_number); + } + } + /* If we are able to identify the type of a function, and we + are out of a function (last_functionP == 0) then, the + function symbol will be associated with an auxiliary + entry. */ + if(last_functionP == (symbolS*)0 && + SF_GET_FUNCTION(symbolP)) { + last_functionP = symbolP; + S_SET_NUMBER_AUXILIARY(symbolP, 1); + /* Clobber possible stale .dim information. */ + memset(&symbolP->sy_auxent[0], '\0', sizeof(union auxent)); + } + /* The C_FCN doesn't need any additional information. + I don't even know if this is needed for sdb. But the + standard assembler generates it, so... + */ + if(S_GET_STORAGE_CLASS(symbolP) == C_EFCN) { + if(last_functionP == (symbolS*)0) + as_fatal("C_EFCN symbol out of scope"); + SA_SET_SYM_FSIZE(last_functionP, + (long)(symbolP->sy_value - + last_functionP->sy_value)); + SA_SET_SYM_ENDNDX(last_functionP, symbol_number); + last_functionP = (symbolS*)0; + } + } + } else { + /* First descriptor of a structure must point to the next + slot outside the structure description. */ + if(SF_GET_TAG(symbolP)) + last_tagP = symbolP; + else if(S_GET_STORAGE_CLASS(symbolP) == C_EOS) + /* +2 take in account the current symbol */ + SA_SET_SYM_ENDNDX(last_tagP, symbol_number+2); + } + + /* We must put the external symbols apart. The loader + does not bomb if we do not. But the references in + the endndx field for a .bb symbol are not corrected + if an external symbol is removed between .bb and .be. + I.e in the following case : + [20] .bb endndx = 22 + [21] foo external + [22] .be + ld will move the symbol 21 to the end of the list but + endndx will still be 22 instead of 21. */ + { + register symbolS* thisP = symbolP; + + symbolP = symbol_next(thisP); + /* remove C_EFCN and LOCAL (L...) symbols */ + if (SF_GET_LOCAL(thisP)) { + symbol_remove(thisP, &symbol_rootP, &symbol_lastP); + } else { + if(S_GET_STORAGE_CLASS(thisP) == C_EXT && + !SF_GET_FUNCTION(thisP)) { + /* Remove from the list */ + symbol_remove(thisP, &symbol_rootP, &symbol_lastP); + symbol_clear_list_pointers(thisP); + /* Move at the end of the list */ + if (symbol_extern_lastP == (symbolS*)0) + symbol_externP = thisP; + else + symbol_append(thisP, symbol_extern_lastP); + symbol_extern_lastP = thisP; + } else { + if(SF_GET_STRING(thisP)) { + thisP->sy_name_offset = string_byte_count; + string_byte_count += strlen(S_GET_NAME(thisP)) + 1; + } else + thisP->sy_name_offset = 0; + thisP->sy_number = symbol_number; + symbol_number += 1 + S_GET_NUMBER_AUXILIARY(thisP); + } + } + } + } + + /* this actually appends the entire extern chain */ + symbol_append(symbol_externP, symbol_lastP); + symbolP = symbol_externP; + while(symbolP) { + if(SF_GET_STRING(symbolP)) { + symbolP->sy_name_offset = string_byte_count; + string_byte_count += strlen(S_GET_NAME(symbolP)) + 1; + } else + symbolP->sy_name_offset = 0; + symbolP->sy_number = symbol_number; + symbol_number += 1 + S_GET_NUMBER_AUXILIARY(symbolP); + symbolP = symbol_next(symbolP); + } + } + + /* FIXME I'm counting line no's here so we know what to put in the section + headers, and I'm resolving the addresses since I'm not sure how to + do it later. I am NOT resolving the linno's representing functions. + Their symbols need a fileptr pointing to this linno when emitted. + Thus, I resolve them on emit. xoxorich. */ + + for (lineP = lineno_rootP; lineP; lineP = lineP->next) { + if (lineP->line.l_lnno) { + lineP->line.l_addr.l_paddr += ((fragS*)lineP->frag)->fr_address; + } else { + ; + } + text_lineno_number++; + } /* for each line number */ + } /* OBJ_COFF version */ +#elif defined(OBJ_AOUT) | defined(OBJ_BOUT) + { /* OBJ_AOUT version */ + symbolPP = & symbol_rootP; /* -> last symbol chain link. */ + while ((symbolP = *symbolPP) != NULL) + { + if (flagseen['R'] && S_IS_DATA(symbolP)) { + S_SET_TEXT(symbolP); + } /* if pusing data into text */ + + symbolP -> sy_value += symbolP -> sy_frag -> fr_address; + + /* 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 (1 + && !S_IS_REGISTER(symbolP) +#ifndef VMS /* Under VMS we need to keep local symbols */ + && ( !S_GET_NAME(symbolP) + || S_IS_DEBUG(symbolP) +#ifdef TC_I960 + /* FIXME this ifdef seems highly dubious to me. xoxorich. */ + || !S_IS_DEFINED(symbolP) + || S_IS_EXTERNAL(symbolP) +#endif /* TC_I960 */ + || (S_GET_NAME(symbolP)[0] != '\001' && (flagseen ['L'] || ! S_LOCAL_NAME(symbolP)))) +#endif /* not VMS */ + ) + { +#ifndef VMS + symbolP->sy_number = symbol_number++; + + /* The + 1 after strlen account for the \0 at the + end of each string */ + if (!S_IS_STABD(symbolP)) { + /* Ordinary case. */ + symbolP->sy_name_offset = string_byte_count; + string_byte_count += strlen(S_GET_NAME(symbolP)) + 1; + } + else /* .Stabd case. */ +#endif /* not VMS */ + symbolP->sy_name_offset = 0; + symbolPP = &(symbol_next(symbolP)); + } else { + if (S_IS_EXTERNAL(symbolP) || !S_IS_DEFINED(symbolP)) { + as_bad ("Local symbol %s never defined", name); + } /* oops. */ + +#ifndef VMS + /* Unhook it from the chain */ + *symbolPP = symbol_next(symbolP); +#endif /* VMS */ + } /* if this symbol should be in the output */ + } /* for each symbol */ + } /* OBJ_AOUT version */ +#else + cant_crawl_symbol_table(); +#endif + H_SET_STRING_SIZE(&headers,string_byte_count); + H_SET_SYMBOL_TABLE_SIZE(&headers, symbol_number); + } /* crawl symbol table */ + + /* JF deal with forward references first. . . */ + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) { + if (symbolP->sy_forward) { + symbolP->sy_value += symbolP->sy_forward->sy_value + symbolP->sy_forward->sy_frag->fr_address; +#ifdef OBJ_COFF + if(SF_GET_GET_SEGMENT(symbolP) && + S_GET_SEGMENT(symbolP) == SEG_UNKNOWN) + S_SET_SEGMENT(symbolP, S_GET_SEGMENT(symbolP->sy_forward)); +#endif /* OBJ_COFF */ + symbolP->sy_forward=0; + } /* if it has a forward reference */ + } /* walk the symbol chain */ + + { /* crawl symbol table */ + register int symbol_number = 0; + +#if defined(OBJ_COFF) + { /* OBJ_COFF version */ + lineno* lineP; + symbolS* symbol_externP = (symbolS*)0; + symbolS* symbol_extern_lastP = (symbolS*)0; + + /* The symbol list should be ordered according to the following sequence + * order : + * . .file symbol + * . debug entries for functions + * . fake symbols for .text .data and .bss + * . defined symbols + * . undefined symbols + * But this is not mandatory. The only important point is to put the + * undefined symbols at the end of the list. + */ + + if (symbol_rootP == NULL + || S_GET_STORAGE_CLASS(symbol_rootP) != C_FILE) { + c_dot_file_symbol("fake"); + } /* Is there a .file symbol ? If not insert one at the beginning. */ + + /* + * Build up static symbols for .text, .data and .bss + */ + dot_text_symbol = (symbolS*) + c_section_symbol(".text", + 0, + H_GET_TEXT_SIZE(&headers), + 0/*text_relocation_number*/, + 0/*text_lineno_number*/); + + dot_data_symbol = (symbolS*) + c_section_symbol(".data", + H_GET_TEXT_SIZE(&headers), + H_GET_DATA_SIZE(&headers), + 0/*data_relocation_number*/, + 0); /* There are no data lineno + entries */ + + dot_bss_symbol = (symbolS*) + c_section_symbol(".bss", + H_GET_TEXT_SIZE(&headers) + H_GET_DATA_SIZE(&headers), + H_GET_BSS_SIZE(&headers), + 0, /* No relocation for a bss section. */ + 0); /* There are no bss lineno entries */ + + /* FIXME late night before delivery, I don't know why the chain is + broken, but I can guess. So! Let's force them to be knit properly + at this point. */ + +/* as john pointed out, this wasn't right. Instead, we'll check here to + make sure that the list is doubly linked. */ + +#if defined(DEBUG) && defined(SYMBOLS_NEED_BACKPOINTERS) + for (symbolP = symbol_rootP; symbol_next(symbolP); symbolP = symbol_next(symbolP)) { + know(symbolP->sy_next->sy_previous == symbolP); + } /* walk the symbol chain */ +#endif /* DEBUG and SYMBOLS_NEED_BACKPOINTERS */ + symbolP = symbol_rootP; + + if (symbolP) { + while(symbolP) { + /* If the symbol has a tagndx entry, resolve it */ + if(SF_GET_TAGGED(symbolP)) { + SA_SET_SYM_TAGNDX(symbolP, + ((symbolS*)SA_GET_SYM_TAGNDX(symbolP))->sy_number); + } + /* Debug symbol do not need all this rubbish */ + if(!SF_GET_DEBUG(symbolP)) { + symbolS* real_symbolP; + /* L* and C_EFCN symbols never merge. */ + if(!SF_GET_LOCAL(symbolP) && + (real_symbolP = + symbol_find_base(S_GET_NAME(symbolP), DO_NOT_STRIP)) && + real_symbolP != symbolP) { + /* FIXME where do dups come from? xoxorich. */ + /* Move the debug data from the debug symbol to the + real symbol. Do NOT do the oposite (i.e. move from + real symbol to symbol and remove real symbol from the + list.) Because some pointers refer to the real symbol + whereas no pointers refer to the symbol. */ + c_symbol_merge(symbolP, real_symbolP); + /* Replace the current symbol by the real one */ + /* The symbols will never be the last or the first + because : 1st symbol is .file and 3 last symbols are + .text, .data, .bss */ + symbol_remove(real_symbolP, &symbol_rootP, &symbol_lastP); + symbol_insert(real_symbolP, symbolP, &symbol_rootP, &symbol_lastP); + symbol_remove(symbolP, &symbol_rootP, &symbol_lastP); + symbolP = real_symbolP; + } + if(flagseen['R'] && S_IS_DATA(symbolP)) + S_SET_TEXT(symbolP); + + symbolP->sy_value += symbolP->sy_frag->fr_address; + + if(!S_IS_DEFINED(symbolP)) + S_SET_EXTERNAL(symbolP); + else if(S_GET_STORAGE_CLASS(symbolP) == C_NULL) + S_SET_STORAGE_CLASS(symbolP, C_STAT); + + /* Mainly to speed up if not -g */ + if(SF_GET_PROCESS(symbolP)) { + /* Handle the nested blocks auxiliary info. */ + if(S_GET_STORAGE_CLASS(symbolP) == C_BLOCK) { + if(!strcmp(S_GET_NAME(symbolP), ".bb")) + stack_push(block_stack, (char *) &symbolP); + else { /* .eb */ + register symbolS* begin_symbolP; + begin_symbolP = *(symbolS**)stack_pop(block_stack); + if(begin_symbolP == (symbolS*)0) + as_warn("mismatched .eb"); + else + SA_SET_SYM_ENDNDX(begin_symbolP, symbol_number); + } + } + /* If we are able to identify the type of a function, and we + are out of a function (last_functionP == 0) then, the + function symbol will be associated with an auxiliary + entry. */ + if(last_functionP == (symbolS*)0 && + SF_GET_FUNCTION(symbolP)) { + last_functionP = symbolP; + S_SET_NUMBER_AUXILIARY(symbolP, 1); + /* Clobber possible stale .dim information. */ + memset(&symbolP->sy_auxent[0], '\0', sizeof(union auxent)); + } + /* The C_FCN doesn't need any additional information. + I don't even know if this is needed for sdb. But the + standard assembler generates it, so... + */ + if(S_GET_STORAGE_CLASS(symbolP) == C_EFCN) { + if(last_functionP == (symbolS*)0) + as_fatal("C_EFCN symbol out of scope"); + SA_SET_SYM_FSIZE(last_functionP, + (long)(symbolP->sy_value - + last_functionP->sy_value)); + SA_SET_SYM_ENDNDX(last_functionP, symbol_number); + last_functionP = (symbolS*)0; + } + } + } else { + /* First descriptor of a structure must point to the next + slot outside the structure description. */ + if(SF_GET_TAG(symbolP)) + last_tagP = symbolP; + else if(S_GET_STORAGE_CLASS(symbolP) == C_EOS) + /* +2 take in account the current symbol */ + SA_SET_SYM_ENDNDX(last_tagP, symbol_number+2); + } + + /* We must put the external symbols apart. The loader + does not bomb if we do not. But the references in + the endndx field for a .bb symbol are not corrected + if an external symbol is removed between .bb and .be. + I.e in the following case : + [20] .bb endndx = 22 + [21] foo external + [22] .be + ld will move the symbol 21 to the end of the list but + endndx will still be 22 instead of 21. */ + { + register symbolS* thisP = symbolP; + + symbolP = symbol_next(thisP); + /* remove C_EFCN and LOCAL (L...) symbols */ + if (SF_GET_LOCAL(thisP)) { + symbol_remove(thisP, &symbol_rootP, &symbol_lastP); + } else { + if(S_GET_STORAGE_CLASS(thisP) == C_EXT && + !SF_GET_FUNCTION(thisP)) { + /* Remove from the list */ + symbol_remove(thisP, &symbol_rootP, &symbol_lastP); + symbol_clear_list_pointers(thisP); + /* Move at the end of the list */ + if (symbol_extern_lastP == (symbolS*)0) + symbol_externP = thisP; + else + symbol_append(thisP, symbol_extern_lastP); + symbol_extern_lastP = thisP; + } else { + if(SF_GET_STRING(thisP)) { + thisP->sy_name_offset = string_byte_count; + string_byte_count += strlen(S_GET_NAME(thisP)) + 1; + } else + thisP->sy_name_offset = 0; + thisP->sy_number = symbol_number; + symbol_number += 1 + S_GET_NUMBER_AUXILIARY(thisP); + } + } + } + } + + /* this actually appends the entire extern chain */ + symbol_append(symbol_externP, symbol_lastP); + symbolP = symbol_externP; + while(symbolP) { + if(SF_GET_STRING(symbolP)) { + symbolP->sy_name_offset = string_byte_count; + string_byte_count += strlen(S_GET_NAME(symbolP)) + 1; + } else + symbolP->sy_name_offset = 0; + symbolP->sy_number = symbol_number; + symbol_number += 1 + S_GET_NUMBER_AUXILIARY(symbolP); + symbolP = symbol_next(symbolP); + } + } + + /* FIXME I'm counting line no's here so we know what to put in the section + headers, and I'm resolving the addresses since I'm not sure how to + do it later. I am NOT resolving the linno's representing functions. + Their symbols need a fileptr pointing to this linno when emitted. + Thus, I resolve them on emit. xoxorich. */ + + for (lineP = lineno_rootP; lineP; lineP = lineP->next) { + if (lineP->line.l_lnno) { + lineP->line.l_addr.l_paddr += ((fragS*)lineP->frag)->fr_address; + } else { + ; + } + text_lineno_number++; + } /* for each line number */ + } /* OBJ_COFF version */ +#elif defined(OBJ_AOUT) | defined(OBJ_BOUT) + { /* OBJ_AOUT version */ + symbolPP = & symbol_rootP; /* -> last symbol chain link. */ + while ((symbolP = *symbolPP) != NULL) + { + if (flagseen['R'] && S_IS_DATA(symbolP)) { + S_SET_TEXT(symbolP); + } /* if pusing data into text */ + + symbolP -> sy_value += symbolP -> sy_frag -> fr_address; + + /* 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 (1 + && !S_IS_REGISTER(symbolP) +#ifndef VMS /* Under VMS we need to keep local symbols */ + && ( !S_GET_NAME(symbolP) + || S_IS_DEBUG(symbolP) +#ifdef TC_I960 + /* FIXME this ifdef seems highly dubious to me. xoxorich. */ + || !S_IS_DEFINED(symbolP) + || S_IS_EXTERNAL(symbolP) +#endif /* TC_I960 */ + || (S_GET_NAME(symbolP)[0] != '\001' && (flagseen ['L'] || ! S_LOCAL_NAME(symbolP)))) +#endif /* not VMS */ + ) + { +#ifndef VMS + symbolP->sy_number = symbol_number++; + + /* The + 1 after strlen account for the \0 at the + end of each string */ + if (!S_IS_STABD(symbolP)) { + /* Ordinary case. */ + symbolP->sy_name_offset = string_byte_count; + string_byte_count += strlen(S_GET_NAME(symbolP)) + 1; + } + else /* .Stabd case. */ +#endif /* not VMS */ + symbolP->sy_name_offset = 0; + symbolPP = &(symbol_next(symbolP)); + } else { + if (S_IS_EXTERNAL(symbolP) || !S_IS_DEFINED(symbolP)) { + as_bad ("Local symbol %s never defined", name); + } /* oops. */ + +#ifndef VMS + /* Unhook it from the chain */ + *symbolPP = symbol_next(symbolP); +#endif /* VMS */ + } /* if this symbol should be in the output */ + } /* for each symbol */ + } /* OBJ_AOUT version */ +#else + cant_crawl_symbol_table(); +#endif + H_SET_STRING_SIZE(&headers,string_byte_count); + H_SET_SYMBOL_TABLE_SIZE(&headers, symbol_number); + } /* crawl symbol table */ + +} /* obj_crawl_symbol_chain() */ + +/* end of obj-vms.c */ |