Changes to 68k-lynx to make it handle symbols in common sections "properly",
authorMark Eichin <eichin@cygnus>
Sat, 12 Mar 1994 05:37:38 +0000 (05:37 +0000)
committerMark Eichin <eichin@cygnus>
Sat, 12 Mar 1994 05:37:38 +0000 (05:37 +0000)
ie. the way "real" 68k coff implementations seem to do it, rather than like
the way it's traditionally done. Fixes lifted from the i386-coff version.

bfd/cf-m68klynx.c

index be52e41..f056503 100644 (file)
@@ -25,6 +25,146 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #define COFF_LONG_FILENAMES
 
-#define ONLY_DECLARE_RELOCS
+#define _bfd_m68kcoff_howto_table _bfd_m68klynx_howto_table    
+#define _bfd_m68kcoff_rtype2howto _bfd_m68klynx_rtype2howto    
+#define _bfd_m68kcoff_howto2rtype _bfd_m68klynx_howto2rtype    
+
+#define LYNX_SPECIAL_FN _bfd_m68klynx_special_fn
+
+#include "bfd.h"
+
+static bfd_reloc_status_type _bfd_m68klynx_special_fn PARAMS ((bfd *abfd,
+                                                     arelent *reloc_entry,
+                                                     asymbol *symbol,
+                                                     PTR data,
+                                                     asection *input_section,
+                                                     bfd *output_bfd,
+                                                     char **error_message));
+
+/* For some reason when using m68k COFF the value stored in the .text
+   section for a reference to a common symbol is the value itself plus
+   any desired offset.  (taken from work done by Ian Taylor, Cygnus Support,
+   for I386 COFF).  */
+
+/* If we are producing relocateable output, we need to do some
+   adjustments to the object file that are not done by the
+   bfd_perform_relocation function.  This function is called by every
+   reloc type to make any required adjustments.  */
+
+static bfd_reloc_status_type
+_bfd_m68klynx_special_fn (abfd, reloc_entry, symbol, data, input_section, output_bfd,
+                         error_message)
+     bfd *abfd;
+     arelent *reloc_entry;
+     asymbol *symbol;
+     PTR data;
+     asection *input_section;
+     bfd *output_bfd;
+     char **error_message;
+{
+  symvalue diff;
+
+  if (output_bfd == (bfd *) NULL)
+    return bfd_reloc_continue;
+
+  if (bfd_is_com_section (symbol->section))
+    {
+      /* We are relocating a common symbol.  The current value in the
+        object file is ORIG + OFFSET, where ORIG is the value of the
+        common symbol as seen by the object file when it was compiled
+        (this may be zero if the symbol was undefined) and OFFSET is
+        the offset into the common symbol (normally zero, but may be
+        non-zero when referring to a field in a common structure).
+        ORIG is the negative of reloc_entry->addend, which is set by
+        the CALC_ADDEND macro below.  We want to replace the value in
+        the object file with NEW + OFFSET, where NEW is the value of
+        the common symbol which we are going to put in the final
+        object file.  NEW is symbol->value.  */
+      diff = symbol->value + reloc_entry->addend;
+    }
+  else
+    {
+      /* For some reason bfd_perform_relocation always effectively
+        ignores the addend for a COFF target when producing
+        relocateable output.  This seems to be always wrong for 386
+        COFF, so we handle the addend here instead.  */
+      diff = reloc_entry->addend;
+    }
+
+#define DOIT(x) \
+  x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask))
+
+  if (diff != 0)
+    {
+      const reloc_howto_type *howto = reloc_entry->howto;
+      unsigned char *addr = (unsigned char *) data + reloc_entry->address;
+
+      switch (howto->size)
+       {
+       case 0:
+         {
+           char x = bfd_get_8 (abfd, addr);
+           DOIT (x);
+           bfd_put_8 (abfd, x, addr);
+         }
+         break;
+
+       case 1:
+         {
+           short x = bfd_get_16 (abfd, addr);
+           DOIT (x);
+           bfd_put_16 (abfd, x, addr);
+         }
+         break;
+
+       case 2:
+         {
+           long x = bfd_get_32 (abfd, addr);
+           DOIT (x);
+           bfd_put_32 (abfd, x, addr);
+         }
+         break;
+
+       default:
+         abort ();
+       }
+    }
+
+  /* Now let bfd_perform_relocation finish everything up.  */
+  return bfd_reloc_continue;
+}
+/* Compute the addend of a reloc.  If the reloc is to a common symbol,
+   the object file contains the value of the common symbol.  By the
+   time this is called, the linker may be using a different symbol
+   from a different object file with a different value.  Therefore, we
+   hack wildly to locate the original symbol from this file so that we
+   can make the correct adjustment.  This macro sets coffsym to the
+   symbol from the original file, and uses it to set the addend value
+   correctly.  If this is not a common symbol, the usual addend
+   calculation is done, except that an additional tweak is needed for
+   PC relative relocs.
+   FIXME: This macro refers to symbols and asect; these are from the
+   calling function, not the macro arguments.  */
+
+#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr)               \
+  {                                                            \
+    coff_symbol_type *coffsym = (coff_symbol_type *) NULL;     \
+    if (ptr && bfd_asymbol_bfd (ptr) != abfd)                  \
+      coffsym = (obj_symbols (abfd)                            \
+                + (cache_ptr->sym_ptr_ptr - symbols));         \
+    else if (ptr)                                              \
+      coffsym = coff_symbol_from (abfd, ptr);                  \
+    if (coffsym != (coff_symbol_type *) NULL                   \
+       && coffsym->native->u.syment.n_scnum == 0)              \
+      cache_ptr->addend = - coffsym->native->u.syment.n_value; \
+    else if (ptr && bfd_asymbol_bfd (ptr) == abfd              \
+            && ptr->section != (asection *) NULL)              \
+      cache_ptr->addend = - (ptr->section->vma + ptr->value);  \
+    else                                                       \
+      cache_ptr->addend = 0;                                   \
+    if (ptr && howto_table[reloc.r_type].pc_relative)          \
+      cache_ptr->addend += asect->vma;                         \
+  }
+
 
 #include "coff-m68k.c"