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. */
file_ptr sym_filepos;
/* The cached gp value. This is used when relocating. */
bfd_vma gp;
/* The size of the unswapped ECOFF symbolic information. */
bfd_size_type raw_size;
@ -340,79 +343,6 @@ DEFUN (styp_to_sec_flags, (abfd, hdr),
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
object file. */
@ -1280,9 +1210,10 @@ DEFUN (ecoff_print_symbol, (abfd, filep, symbol, how),
type_to_string (abfd, aux_base, indx + 1,
bigendian));
else
printf ("\n Type: %s",
type_to_string (abfd, aux_base, indx, bigendian));
printf ("\n Local symbol: %d",
(indx
+ sym_base
+ ecoff_data (abfd)->symbolic_header.iextMax));
break;
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
and return the name of the source file and the line nearest to the
wanted location. */
@ -2246,7 +2678,7 @@ DEFUN (ecoff_compute_section_file_positions, (abfd),
static boolean
DEFUN (ecoff_set_section_contents, (abfd, section, location, offset, count),
bfd *abfd AND
sec_ptr section AND
asection *section AND
PTR location AND
file_ptr offset AND
bfd_size_type count)
@ -2518,9 +2950,6 @@ static CONST bfd_coff_backend_data bfd_ecoff_std_swap_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
be useful for linking ECOFF and COFF files together, which doesn't
seem too likely. */