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