/* BFD back-end for AMD 29000 COFF binaries.
- Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Copyright 1990, 91, 92, 93, 94, 95, 1997 Free Software Foundation, Inc.
Contributed by David Wood at New York University 7/8/91.
This file is part of BFD, the Binary File Descriptor library.
#include "bfd.h"
#include "sysdep.h"
#include "libbfd.h"
-#include "obstack.h"
#include "coff/a29k.h"
#include "coff/internal.h"
#include "libcoff.h"
#define EXTRACT_HWORD(WORD) \
((((WORD) & 0x00ff0000) >> 8) | ((WORD)& 0xff))
#define SIGN_EXTEND_HWORD(HWORD) \
- ((HWORD) & 0x8000 ? (HWORD)|0xffff0000 : (HWORD))
+ ((HWORD) & 0x8000 ? (HWORD)|(~0xffffL) : (HWORD))
/* Provided the symbol, returns the value reffed */
static long
signed_value = EXTRACT_HWORD(insn);
signed_value = SIGN_EXTEND_HWORD(signed_value);
signed_value <<= 2;
- signed_value += sym_value + reloc_entry->addend;
- if (((signed_value + reloc_entry->address) & ~0x3ffff) == 0)
+
+ /* See the note on the R_IREL reloc in coff_a29k_relocate_section. */
+ if (signed_value == - (long) reloc_entry->address)
+ signed_value = 0;
+
+ signed_value += sym_value + reloc_entry->addend;
+ if ((signed_value & ~0x3ffff) == 0)
{ /* Absolute jmp/call */
insn |= (1<<24); /* Make it absolute */
- signed_value += reloc_entry->address;
/* FIXME: Should we change r_type to R_IABS */
}
else
{
/* Relative jmp/call, so subtract from the value the
address of the place we're coming from */
- signed_value -= (input_section->output_section->vma
+ signed_value -= (reloc_entry->address
+ + input_section->output_section->vma
+ input_section->output_offset);
if (signed_value>0x1ffff || signed_value<-0x20000)
return(bfd_reloc_overflow);
symndx = rel->r_symndx;
loc = contents + rel->r_vaddr - input_section->vma;
- if (symndx == -1)
+ if (symndx == -1 || rel->r_type == R_IHCONST)
h = NULL;
else
h = obj_coff_sym_hashes (input_bfd)[symndx];
signed_value = SIGN_EXTEND_HWORD (signed_value);
signed_value <<= 2;
+ /* Unfortunately, there are two different versions of COFF
+ a29k. In the original AMD version, the value stored in
+ the field for the R_IREL reloc is a simple addend. In
+ the GNU version, the value is the negative of the address
+ of the reloc within section. We try to cope here by
+ assuming the AMD version, unless the addend is exactly
+ the negative of the address; in the latter case we assume
+ the GNU version. This means that something like
+ .text
+ nop
+ jmp i-4
+ will fail, because the addend of -4 will happen to equal
+ the negative of the address within the section. The
+ compiler will never generate code like this.
+
+ At some point in the future we may want to take out this
+ check. */
+
+ if (signed_value == - (long) (rel->r_vaddr - input_section->vma))
+ signed_value = 0;
+
/* Determine the destination of the jump. */
- signed_value += val + rel->r_vaddr - input_section->vma;
+ signed_value += val;
if ((signed_value & ~0x3ffff) == 0)
{
{
"coff-a29k-big", /* name */
bfd_target_coff_flavour,
- true, /* data byte order is big */
- true, /* header byte order is big */
+ BFD_ENDIAN_BIG, /* data byte order is big */
+ BFD_ENDIAN_BIG, /* header byte order is big */
(HAS_RELOC | EXEC_P | /* object flags */
HAS_LINENO | HAS_DEBUG |