* coff-a29k.c (a29k_reloc): Change handling of R_IREL reloc to be
authorIan Lance Taylor <ian@airs.com>
Thu, 9 Nov 1995 02:30:33 +0000 (02:30 +0000)
committerIan Lance Taylor <ian@airs.com>
Thu, 9 Nov 1995 02:30:33 +0000 (02:30 +0000)
compatible with AMD generated COFF files.  Try to support both AMD
and GNU formats simultaneously.
(coff_a29k_relocate_section): Likewise.

bfd/ChangeLog
bfd/coff-a29k.c

index 0f1dda4..48f9a90 100644 (file)
@@ -5,6 +5,11 @@ Wed Nov  8 20:03:44 1995  Eric Freudenthal <freudenthal@nyu.edu>
 
 Wed Nov  8 11:31:11 1995  Ian Lance Taylor  <ian@cygnus.com>
 
+       * coff-a29k.c (a29k_reloc): Change handling of R_IREL reloc to be
+       compatible with AMD generated COFF files.  Try to support both AMD
+       and GNU formats simultaneously.
+       (coff_a29k_relocate_section): Likewise.
+
        * libbfd.c (bfd_get_file_window): Change writable parameter from
        int to boolean; update all callers.  Pass MAP_SHARED if not
        writable--it's required on Solaris.  Cast fprintf argument to
index 633899d..7b0f8e8 100644 (file)
@@ -134,18 +134,23 @@ a29k_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
     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);
@@ -422,8 +427,29 @@ coff_a29k_relocate_section (output_bfd, info, input_bfd, input_section,
          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)
            {