1991-04-04 18:19:56 +00:00
|
|
|
|
/* 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
|
1991-06-14 13:59:44 +00:00
|
|
|
|
the Free Software Foundation; either version 2, or (at your option)
|
1991-04-04 18:19:56 +00:00
|
|
|
|
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 */
|