Checkpoint. Can now read relocs.

This commit is contained in:
Ian Lance Taylor 1993-01-19 17:38:13 +00:00
parent 74e8194991
commit b6bef86226
1 changed files with 509 additions and 80 deletions

View File

@ -43,6 +43,9 @@ typedef struct ecoff_tdata
/* The symbol table file position, set by ecoff_mkobject_hook. */ /* The symbol table file position, set by ecoff_mkobject_hook. */
file_ptr sym_filepos; file_ptr sym_filepos;
/* The cached gp value. This is used when relocating. */
bfd_vma gp;
/* The size of the unswapped ECOFF symbolic information. */ /* The size of the unswapped ECOFF symbolic information. */
bfd_size_type raw_size; bfd_size_type raw_size;
@ -340,79 +343,6 @@ DEFUN (styp_to_sec_flags, (abfd, hdr),
return sec_flags; return sec_flags;
} }
/* Reloc handling. MIPS ECOFF relocs are packed into 8 bytes in
external form. They use a bit which indicates whether the symbol
is external. */
/* Swap a reloc in. */
static void
DEFUN (ecoff_swap_reloc_in, (abfd, ext, intern),
bfd *abfd AND
RELOC *ext AND
struct internal_reloc *intern)
{
intern->r_vaddr = bfd_h_get_32 (abfd, (bfd_byte *) ext->r_vaddr);
if (abfd->xvec->header_byteorder_big_p != false)
{
intern->r_symndx = ((ext->r_bits[0]
<< RELOC_BITS0_SYMNDX_SH_LEFT_BIG)
| (ext->r_bits[1]
<< RELOC_BITS1_SYMNDX_SH_LEFT_BIG)
| (ext->r_bits[2]
<< RELOC_BITS2_SYMNDX_SH_LEFT_BIG));
intern->r_type = ((ext->r_bits[3] & RELOC_BITS3_TYPE_BIG)
>> RELOC_BITS3_TYPE_SH_BIG);
intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_BIG) != 0;
}
else
{
intern->r_symndx = ((ext->r_bits[0]
<< RELOC_BITS0_SYMNDX_SH_LEFT_LITTLE)
| (ext->r_bits[1]
<< RELOC_BITS1_SYMNDX_SH_LEFT_LITTLE)
| (ext->r_bits[2]
<< RELOC_BITS2_SYMNDX_SH_LEFT_LITTLE));
intern->r_type = ((ext->r_bits[3] & RELOC_BITS3_TYPE_LITTLE)
>> RELOC_BITS3_TYPE_SH_LITTLE);
intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_LITTLE) != 0;
}
}
/* Swap a reloc out. */
static unsigned int
DEFUN (ecoff_swap_reloc_out, (abfd, src, dst),
bfd *abfd AND
PTR src AND
PTR dst)
{
struct internal_reloc *intern = (struct internal_reloc *) src;
RELOC *ext = (RELOC *) dst;
bfd_h_put_32 (abfd, intern->r_vaddr, (bfd_byte *) ext->r_vaddr);
if (abfd->xvec->header_byteorder_big_p != false)
{
ext->r_bits[0] = intern->r_symndx >> RELOC_BITS0_SYMNDX_SH_LEFT_BIG;
ext->r_bits[1] = intern->r_symndx >> RELOC_BITS1_SYMNDX_SH_LEFT_BIG;
ext->r_bits[2] = intern->r_symndx >> RELOC_BITS2_SYMNDX_SH_LEFT_BIG;
ext->r_bits[3] = (((intern->r_type << RELOC_BITS3_TYPE_SH_BIG)
& RELOC_BITS3_TYPE_BIG)
| (intern->r_extern ? RELOC_BITS3_EXTERN_BIG : 0));
}
else
{
ext->r_bits[0] = intern->r_symndx >> RELOC_BITS0_SYMNDX_SH_LEFT_LITTLE;
ext->r_bits[1] = intern->r_symndx >> RELOC_BITS1_SYMNDX_SH_LEFT_LITTLE;
ext->r_bits[2] = intern->r_symndx >> RELOC_BITS2_SYMNDX_SH_LEFT_LITTLE;
ext->r_bits[3] = (((intern->r_type << RELOC_BITS3_TYPE_SH_LITTLE)
& RELOC_BITS3_TYPE_LITTLE)
| (intern->r_extern ? RELOC_BITS3_EXTERN_LITTLE : 0));
}
return RELSZ;
}
/* Read in and swap the important symbolic information for an ECOFF /* Read in and swap the important symbolic information for an ECOFF
object file. */ object file. */
@ -1280,9 +1210,10 @@ DEFUN (ecoff_print_symbol, (abfd, filep, symbol, how),
type_to_string (abfd, aux_base, indx + 1, type_to_string (abfd, aux_base, indx + 1,
bigendian)); bigendian));
else else
printf ("\n Type: %s", printf ("\n Local symbol: %d",
type_to_string (abfd, aux_base, indx, bigendian)); (indx
+ sym_base
+ ecoff_data (abfd)->symbolic_header.iextMax));
break; break;
default: default:
@ -1297,6 +1228,507 @@ DEFUN (ecoff_print_symbol, (abfd, filep, symbol, how),
} }
} }
/* Reloc handling. MIPS ECOFF relocs are packed into 8 bytes in
external form. They use a bit which indicates whether the symbol
is external. */
/* Swap a reloc in. */
static void
DEFUN (ecoff_swap_reloc_in, (abfd, ext, intern),
bfd *abfd AND
RELOC *ext AND
struct internal_reloc *intern)
{
intern->r_vaddr = bfd_h_get_32 (abfd, (bfd_byte *) ext->r_vaddr);
if (abfd->xvec->header_byteorder_big_p != false)
{
intern->r_symndx = ((ext->r_bits[0]
<< RELOC_BITS0_SYMNDX_SH_LEFT_BIG)
| (ext->r_bits[1]
<< RELOC_BITS1_SYMNDX_SH_LEFT_BIG)
| (ext->r_bits[2]
<< RELOC_BITS2_SYMNDX_SH_LEFT_BIG));
intern->r_type = ((ext->r_bits[3] & RELOC_BITS3_TYPE_BIG)
>> RELOC_BITS3_TYPE_SH_BIG);
intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_BIG) != 0;
}
else
{
intern->r_symndx = ((ext->r_bits[0]
<< RELOC_BITS0_SYMNDX_SH_LEFT_LITTLE)
| (ext->r_bits[1]
<< RELOC_BITS1_SYMNDX_SH_LEFT_LITTLE)
| (ext->r_bits[2]
<< RELOC_BITS2_SYMNDX_SH_LEFT_LITTLE));
intern->r_type = ((ext->r_bits[3] & RELOC_BITS3_TYPE_LITTLE)
>> RELOC_BITS3_TYPE_SH_LITTLE);
intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_LITTLE) != 0;
}
}
/* Swap a reloc out. */
static unsigned int
DEFUN (ecoff_swap_reloc_out, (abfd, src, dst),
bfd *abfd AND
PTR src AND
PTR dst)
{
struct internal_reloc *intern = (struct internal_reloc *) src;
RELOC *ext = (RELOC *) dst;
bfd_h_put_32 (abfd, intern->r_vaddr, (bfd_byte *) ext->r_vaddr);
if (abfd->xvec->header_byteorder_big_p != false)
{
ext->r_bits[0] = intern->r_symndx >> RELOC_BITS0_SYMNDX_SH_LEFT_BIG;
ext->r_bits[1] = intern->r_symndx >> RELOC_BITS1_SYMNDX_SH_LEFT_BIG;
ext->r_bits[2] = intern->r_symndx >> RELOC_BITS2_SYMNDX_SH_LEFT_BIG;
ext->r_bits[3] = (((intern->r_type << RELOC_BITS3_TYPE_SH_BIG)
& RELOC_BITS3_TYPE_BIG)
| (intern->r_extern ? RELOC_BITS3_EXTERN_BIG : 0));
}
else
{
ext->r_bits[0] = intern->r_symndx >> RELOC_BITS0_SYMNDX_SH_LEFT_LITTLE;
ext->r_bits[1] = intern->r_symndx >> RELOC_BITS1_SYMNDX_SH_LEFT_LITTLE;
ext->r_bits[2] = intern->r_symndx >> RELOC_BITS2_SYMNDX_SH_LEFT_LITTLE;
ext->r_bits[3] = (((intern->r_type << RELOC_BITS3_TYPE_SH_LITTLE)
& RELOC_BITS3_TYPE_LITTLE)
| (intern->r_extern ? RELOC_BITS3_EXTERN_LITTLE : 0));
}
return RELSZ;
}
/* Do a REFHI relocation. The next reloc must be the corresponding
REFLO. This has to be done in a function so that carry is handled
correctly. */
static bfd_reloc_status_type
DEFUN (ecoff_refhi_reloc, (abfd,
reloc_entry,
symbol,
data,
input_section,
output_bfd),
bfd *abfd AND
arelent *reloc_entry AND
asymbol *symbol AND
PTR data AND
asection *input_section AND
bfd *output_bfd)
{
bfd_reloc_status_type ret;
arelent *rello;
bfd_vma relocation;
asection *reloc_target_output_section;
unsigned long val;
unsigned long insn;
ret = bfd_reloc_ok;
if (symbol->section == &bfd_und_section
&& output_bfd == (bfd *) NULL)
ret = bfd_reloc_undefined;
rello = reloc_entry + 1;
BFD_ASSERT (rello->howto->type == ECOFF_R_REFLO
&& *rello->sym_ptr_ptr == *reloc_entry->sym_ptr_ptr);
if (symbol->section == &bfd_com_section)
relocation = 0;
else
relocation = symbol->value;
relocation += symbol->section->output_section->vma;
relocation += symbol->section->output_offset;
if (reloc_entry->address > input_section->_cooked_size)
return bfd_reloc_outofrange;
if (output_bfd != (bfd *) NULL)
reloc_entry->address += input_section->output_offset;
insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
val = (((insn & 0xffff) << 16)
+ (bfd_get_32 (abfd, (bfd_byte *) data + rello->address) & 0xffff));
insn = (insn &~ 0xffff) | (((val + symbol->value) >> 16) & 0xffff);
bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address);
return ret;
}
/* Do a GPREL relocation. This is a 16 bit value which must become
the offset from the gp register. */
static bfd_reloc_status_type
DEFUN (ecoff_gprel_reloc, (abfd,
reloc_entry,
symbol,
data,
input_section,
output_bfd),
bfd *abfd AND
arelent *reloc_entry AND
asymbol *symbol AND
PTR data AND
asection *input_section AND
bfd *output_bfd)
{
bfd_reloc_status_type ret;
bfd_vma relocation;
unsigned long val;
unsigned long insn;
/* If this is a partial link, we don't need to do anything unusual
here. */
if (output_bfd != (bfd *) NULL)
return bfd_reloc_continue;
ret = bfd_reloc_ok;
if (symbol->section == &bfd_und_section)
ret = bfd_reloc_undefined;
/* Otherwise we have to figure out the gp value, so that we can
adjust the symbol value correctly. We look up the symbol _gp in
the output BFD. If we can't find it, we're stuck. We cache it
in the ECOFF target data. */
output_bfd = symbol->section->output_section->owner;
if (ecoff_data (output_bfd)->gp == 0)
{
unsigned int count;
asymbol **sym;
unsigned int i;
count = bfd_get_symcount (output_bfd);
sym = bfd_get_outsymbols (output_bfd);
/* We should do something more friendly here, but we don't have
a good reloc status to return. */
if (sym == (asymbol **) NULL)
abort ();
for (i = 0; i < count; i++, sym++)
{
register CONST char *name;
name = bfd_asymbol_name (*sym);
if (*name == '_' && strcmp (name, "_gp") == 0)
{
ecoff_data (output_bfd)->gp = bfd_asymbol_value (*sym);
break;
}
}
/* We should do something more friendly here, but we don't have
a good reloc status to return. */
if (i >= count)
abort ();
}
if (symbol->section == &bfd_com_section)
relocation = 0;
else
relocation = symbol->value;
relocation += symbol->section->output_section->vma;
relocation += symbol->section->output_offset;
if (reloc_entry->address > input_section->_cooked_size)
return bfd_reloc_outofrange;
insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
val = insn & 0xffff;
if ((val & 0x8000) != 0)
val -= 0x10000;
val -= ecoff_data (output_bfd)->gp;
insn = (insn &~ 0xffff) | (val & 0xffff);
bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address);
return ret;
}
/* How to process the various relocs types. */
static reloc_howto_type ecoff_howto_table[] =
{
/* Reloc type 0 is ignored. The reloc reading code ensures that
this is a reference to the .abs section, which will cause
bfd_perform_relocation to do nothing. */
HOWTO (ECOFF_R_IGNORE, /* type */
0, /* rightshift */
0, /* size (0 = byte, 1 = short, 2 = long) */
8, /* bitsize (obsolete) */
false, /* pc_relative */
0, /* bitpos */
false, /* absolute (obsolete) */
false, /* complain_on_overflow */
0, /* special_function */
"IGNORE", /* name */
false, /* partial_inplace */
0, /* src_mask */
0, /* dst_mask */
false), /* pcrel_offset */
/* A 16 bit reference to a symbol, normally from a data section. */
HOWTO (ECOFF_R_REFHALF, /* type */
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize (obsolete) */
false, /* pc_relative */
0, /* bitpos */
false, /* absolute (obsolete) */
true, /* complain_on_overflow */
0, /* special_function */
"REFHALF", /* name */
true, /* partial_inplace */
0xffff, /* src_mask */
0xffff, /* dst_mask */
false), /* pcrel_offset */
/* A 32 bit reference to a symbol, normally from a data section. */
HOWTO (ECOFF_R_REFWORD, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize (obsolete) */
false, /* pc_relative */
0, /* bitpos */
false, /* absolute (obsolete) */
true, /* complain_on_overflow */
0, /* special_function */
"REFWORD", /* name */
true, /* partial_inplace */
0xffffffff, /* src_mask */
0xffffffff, /* dst_mask */
false), /* pcrel_offset */
/* A 26 bit absolute jump address. */
HOWTO (ECOFF_R_JMPADDR, /* type */
2, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize (obsolete) */
false, /* pc_relative */
0, /* bitpos */
false, /* absolute (obsolete) */
true, /* complain_on_overflow */
0, /* special_function */
"JMPADDR", /* name */
true, /* partial_inplace */
0x3ffffff, /* src_mask */
0x3ffffff, /* dst_mask */
false), /* pcrel_offset */
/* The high 16 bits of a symbol value. Handled by the function
ecoff_refhi_reloc. */
HOWTO (ECOFF_R_REFHI, /* type */
16, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize (obsolete) */
false, /* pc_relative */
0, /* bitpos */
false, /* absolute (obsolete) */
true, /* complain_on_overflow */
ecoff_refhi_reloc, /* special_function */
"REFHI", /* name */
true, /* partial_inplace */
0xffff, /* src_mask */
0xffff, /* dst_mask */
false), /* pcrel_offset */
/* The low 16 bits of a symbol value. */
HOWTO (ECOFF_R_REFLO, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize (obsolete) */
false, /* pc_relative */
0, /* bitpos */
false, /* absolute (obsolete) */
true, /* complain_on_overflow */
0, /* special_function */
"REFLO", /* name */
true, /* partial_inplace */
0xffff, /* src_mask */
0xffff, /* dst_mask */
false), /* pcrel_offset */
/* A reference to an offset from the gp register. Handled by the
function ecoff_gprel_reloc. */
HOWTO (ECOFF_R_GPREL, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize (obsolete) */
false, /* pc_relative */
0, /* bitpos */
false, /* absolute (obsolete) */
true, /* complain_on_overflow */
ecoff_gprel_reloc, /* special_function */
"GPREL", /* name */
true, /* partial_inplace */
0xffff, /* src_mask */
0xffff, /* dst_mask */
false), /* pcrel_offset */
/* A reference to a literal using an offset from the gp register.
Handled by the function ecoff_gprel_reloc. */
HOWTO (ECOFF_R_LITERAL, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize (obsolete) */
false, /* pc_relative */
0, /* bitpos */
false, /* absolute (obsolete) */
true, /* complain_on_overflow */
ecoff_gprel_reloc, /* special_function */
"LITERAL", /* name */
true, /* partial_inplace */
0xffff, /* src_mask */
0xffff, /* dst_mask */
false) /* pcrel_offset */
};
/* Read in the relocs for a section. */
static boolean
DEFUN (ecoff_slurp_reloc_table, (abfd, section, symbols),
bfd *abfd AND
asection *section AND
asymbol **symbols)
{
RELOC *external_relocs;
arelent *internal_relocs;
arelent *rptr;
unsigned int i;
if (section->relocation != (arelent *) NULL
|| section->reloc_count == 0
|| (section->flags & SEC_CONSTRUCTOR) != 0)
return true;
if (ecoff_slurp_symbol_table (abfd) == false)
return false;
internal_relocs = (arelent *) bfd_alloc (abfd,
(sizeof (arelent)
* section->reloc_count));
external_relocs = (RELOC *) bfd_alloc (abfd, RELSZ * section->reloc_count);
if (internal_relocs == (arelent *) NULL
|| external_relocs == (RELOC *) NULL)
{
bfd_error = no_memory;
return false;
}
if (bfd_seek (abfd, section->rel_filepos, SEEK_SET) != 0)
return false;
if (bfd_read (external_relocs, 1, RELSZ * section->reloc_count, abfd)
!= RELSZ * section->reloc_count)
{
bfd_error = system_call_error;
return false;
}
for (i = 0, rptr = internal_relocs; i < section->reloc_count; i++, rptr++)
{
struct internal_reloc intern;
ecoff_swap_reloc_in (abfd, external_relocs + i, &intern);
if (intern.r_type < 0 || intern.r_type > ECOFF_R_LITERAL)
abort ();
if (intern.r_extern)
{
/* r_symndx is an index into the external symbols. */
BFD_ASSERT (intern.r_symndx >= 0
&& (intern.r_symndx
< ecoff_data (abfd)->symbolic_header.iextMax));
rptr->sym_ptr_ptr = symbols + intern.r_symndx;
}
else
{
CONST char *sec_name;
asection *sec;
/* r_symndx is a section key. */
switch (intern.r_symndx)
{
case RELOC_SECTION_TEXT: sec_name = ".text"; break;
case RELOC_SECTION_RDATA: sec_name = ".rdata"; break;
case RELOC_SECTION_DATA: sec_name = ".data"; break;
case RELOC_SECTION_SDATA: sec_name = ".sdata"; break;
case RELOC_SECTION_SBSS: sec_name = ".sbss"; break;
case RELOC_SECTION_BSS: sec_name = ".bss"; break;
case RELOC_SECTION_INIT: sec_name = ".init"; break;
case RELOC_SECTION_LIT8: sec_name = ".lit8"; break;
case RELOC_SECTION_LIT4: sec_name = ".lit4"; break;
default: abort ();
}
sec = bfd_get_section_by_name (abfd, sec_name);
if (sec == (asection *) NULL)
abort ();
rptr->sym_ptr_ptr = sec->symbol_ptr_ptr;
}
rptr->address = intern.r_vaddr - bfd_get_section_vma (abfd, section);
rptr->addend = 0;
rptr->howto = &ecoff_howto_table[intern.r_type];
/* If the type is ECOFF_R_IGNORE, make sure this is a reference
to the absolute section so that the reloc is ignored. */
if (intern.r_type == ECOFF_R_IGNORE)
rptr->sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr;
}
bfd_release (abfd, external_relocs);
section->relocation = internal_relocs;
return true;
}
/* Get a canonical list of relocs. */
static unsigned int
DEFUN (ecoff_canonicalize_reloc, (abfd, section, relptr, symbols),
bfd *abfd AND
asection *section AND
arelent **relptr AND
asymbol **symbols)
{
unsigned int count;
if (section->flags & SEC_CONSTRUCTOR)
{
arelent_chain *chain;
/* This section has relocs made up by us, not the file, so take
them out of their chain and place them into the data area
provided. */
for (count = 0, chain = section->constructor_chain;
count < section->reloc_count;
count++, chain = chain->next)
*relptr++ = &chain->relent;
}
else
{
arelent *tblptr;
if (ecoff_slurp_reloc_table (abfd, section, symbols) == false)
return 0;
tblptr = section->relocation;
if (tblptr == (arelent *) NULL)
return 0;
for (count = 0; count < section->reloc_count; count++)
*relptr++ = tblptr++;
}
*relptr = (arelent *) NULL;
return section->reloc_count;
}
/* Provided a BFD, a section and an offset into the section, calculate /* Provided a BFD, a section and an offset into the section, calculate
and return the name of the source file and the line nearest to the and return the name of the source file and the line nearest to the
wanted location. */ wanted location. */
@ -2246,7 +2678,7 @@ DEFUN (ecoff_compute_section_file_positions, (abfd),
static boolean static boolean
DEFUN (ecoff_set_section_contents, (abfd, section, location, offset, count), DEFUN (ecoff_set_section_contents, (abfd, section, location, offset, count),
bfd *abfd AND bfd *abfd AND
sec_ptr section AND asection *section AND
PTR location AND PTR location AND
file_ptr offset AND file_ptr offset AND
bfd_size_type count) bfd_size_type count)
@ -2518,9 +2950,6 @@ static CONST bfd_coff_backend_data bfd_ecoff_std_swap_table = {
ecoff_slurp_symbol_table ecoff_slurp_symbol_table
}; };
/* Routines that need to be written. */
#define ecoff_canonicalize_reloc (unsigned int (*) PARAMS ((bfd *, sec_ptr, arelent **, struct symbol_cache_entry **))) bfd_0
/* get_lineno could be written for ECOFF, but it would currently only /* get_lineno could be written for ECOFF, but it would currently only
be useful for linking ECOFF and COFF files together, which doesn't be useful for linking ECOFF and COFF files together, which doesn't
seem too likely. */ seem too likely. */