Mon Jul 3 13:55:18 1995 Steve Chamberlain <sac@slash.cygnus.com>
[deliverable/binutils-gdb.git] / bfd / coff-sh.c
index 00b16025dfb8fb7aaa06e4d9348d1257b3e02ad3..960d9ac6dee1bcb008377e0e699e46594b7f0ed4 100644 (file)
@@ -1,5 +1,5 @@
 /* BFD back-end for Hitachi Super-H COFF binaries.
-   Copyright 1993, 1994 Free Software Foundation, Inc.
+   Copyright 1993, 1994, 1995 Free Software Foundation, Inc.
    Contributed by Cygnus Support.
    Written by Steve Chamberlain, <sac@cygnus.com>.
 
@@ -28,23 +28,15 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "coff/internal.h"
 #include "libcoff.h"
 
-static reloc_howto_type r_imm32 =
-HOWTO (R_SH_IMM32, 0,2, 32, false, 0,
-       complain_overflow_bitfield, 0, "r_imm32", false, 0x0, 0xffffffff,
-       false);
-
-
+static bfd_reloc_status_type sh_reloc();
 
-/* Turn a howto into a reloc number */
+#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
 
-static int 
-coff_SH_select_reloc (howto)
-     reloc_howto_type *howto;
-{
-  return howto->type;
-}
+/*#define COFF_LONG_FILENAMES*/
 
-#define SELECT_RELOC(x,howto) x.r_type = coff_SH_select_reloc(howto)
+static reloc_howto_type r_imm32 =
+  {R_SH_IMM32,  0, 2, 32, false, 0, 
+     complain_overflow_bitfield, sh_reloc,"r_imm32",    true, 0xffffffff,0xffffffff, false};
 
 
 #define BADMAG(x) SHBADMAG(x)
@@ -53,107 +45,226 @@ coff_SH_select_reloc (howto)
 #define __A_MAGIC_SET__
 
 /* Code to swap in the reloc */
-#define SWAP_IN_RELOC_OFFSET   bfd_h_get_32
-#define SWAP_OUT_RELOC_OFFSET bfd_h_put_32
 #define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) \
   dst->r_stuff[0] = 'S'; \
   dst->r_stuff[1] = 'C';
 
-/* Code to turn a r_type into a howto ptr, uses the above howto table
-   */
-
-static void
-rtype2howto (internal, dst)
-     arelent * internal;
-     struct internal_reloc *dst;
-{
-  switch (dst->r_type)
-    {
-    default:
-      fprintf (stderr, "BAD 0x%x\n", dst->r_type);
-    case R_SH_IMM32:
-      internal->howto = &r_imm32;
-      break;
-    }
+/* Code to turn a r_type into a howto ptr, uses the above howto table.  */
+static long
+get_symbol_value (symbol)       
+     asymbol *symbol;
+{                                             
+  long relocation = 0;
+
+  if (bfd_is_com_section (symbol->section))
+  {
+    relocation = 0;                           
+  }
+  else 
+  {                                      
+    relocation = symbol->value +
+     symbol->section->output_section->vma +
+      symbol->section->output_offset;
+  }                                           
+
+  return(relocation);
 }
 
-#define RTYPE2HOWTO(internal, relocentry) rtype2howto(internal,relocentry)
-
-
-/* Perform any necessaru magic to the addend in a reloc entry */
-
-
-#define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \
- cache_ptr->addend =  ext_reloc.r_offset;
-
-
-#define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \
- reloc_processing(relent, reloc, symbols, abfd, section)
-
-static void 
-reloc_processing (relent, reloc, symbols, abfd, section)
-     arelent * relent;
-     struct internal_reloc *reloc;
-     asymbol ** symbols;
-     bfd * abfd;
-     asection * section;
+#define RTYPE2HOWTO(x,y) ((x)->howto = &r_imm32)
+
+
+/* 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;                                   \
+  }
+
+/* this function is in charge of performing all the 29k relocations */
+
+static bfd_reloc_status_type
+sh_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
+           error_message)
+     bfd *abfd;
+     arelent *reloc_entry;
+     asymbol *symbol_in;
+     PTR data;
+     asection *input_section;
+     bfd *output_bfd;
+     char **error_message;
 {
-  relent->address = reloc->r_vaddr;
-  rtype2howto (relent, reloc);
-
-  if (reloc->r_symndx > 0)
+  /* the consth relocation comes in two parts, we have to remember
+     the state between calls, in these variables */
+  unsigned long insn;
+  unsigned long sym_value;
+  unsigned short r_type;
+
+  unsigned long addr = reloc_entry->address ; /*+ input_section->vma*/
+  bfd_byte  *hit_data =addr + (bfd_byte *)(data);
+       
+  r_type = reloc_entry->howto->type;
+
+  if (output_bfd) {
+    /* Partial linking - do nothing */
+    reloc_entry->address += input_section->output_offset;
+    return bfd_reloc_ok;
+  }
+
+  if (symbol_in != NULL
+      && bfd_is_und_section (symbol_in->section))
     {
-      relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx];
-    }
-  else
-    {
-      relent->sym_ptr_ptr = &(bfd_abs_symbol);
+      /* Keep the state machine happy in case we're called again */
+      return (bfd_reloc_undefined);
     }
 
 
-  relent->addend = reloc->r_offset;
-  relent->address -= section->vma;
-}
+  sym_value = get_symbol_value(symbol_in);
 
-static void
-extra_case (in_abfd, link_info, link_order, reloc, data, src_ptr, dst_ptr)
-     bfd *in_abfd;
-     struct bfd_link_info *link_info;
-     struct bfd_link_order *link_order;
-     arelent *reloc;
-     bfd_byte *data;
-     unsigned int *src_ptr;
-     unsigned int *dst_ptr;
-{
-  switch (reloc->howto->type)
+  switch (r_type) 
     {
     case R_SH_IMM32:
-      {
-       int v = bfd_coff_reloc16_get_value(reloc, link_info,
-                                          link_order->u.indirect.section);
-       bfd_put_32 (in_abfd, v, data  + *dst_ptr);
-       (*dst_ptr) +=4;
-       (*src_ptr)+=4;;
-      }
+      insn = sym_value + reloc_entry->addend;  
+      insn += bfd_get_32 (abfd, hit_data);
+      bfd_put_32(abfd, insn, hit_data);
       break;
-
     default:
-      abort ();
+      *error_message = "Unrecognized reloc";
+      return (bfd_reloc_dangerous);
     }
+
+
+  return(bfd_reloc_ok);        
 }
 
-#define coff_reloc16_extra_cases extra_case
+/* The reloc processing routine for the optimized COFF linker.  */
+
+static boolean
+coff_sh_relocate_section (output_bfd, info, input_bfd, input_section,
+                           contents, relocs, syms, sections)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+     bfd *input_bfd;
+     asection *input_section;
+     bfd_byte *contents;
+     struct internal_reloc *relocs;
+     struct internal_syment *syms;
+     asection **sections;
+{
+  struct internal_reloc *rel;
+  struct internal_reloc *relend;
 
-#include "coffcode.h"
+  /* If we are performing a relocateable link, we don't need to do a
+     thing.  The caller will take care of adjusting the reloc
+     addresses and symbol indices.  */
+  if (info->relocateable)
+    return true;
 
 
-#undef  coff_bfd_get_relocated_section_contents
-#undef coff_bfd_relax_section
-#define coff_bfd_get_relocated_section_contents \
-  bfd_coff_reloc16_get_relocated_section_contents
-#define coff_bfd_relax_section bfd_coff_reloc16_relax_section
+  rel = relocs;
+  relend = rel + input_section->reloc_count;
+  for (; rel < relend; rel++)
+    {
+      long symndx;
+      bfd_byte *loc;
+      struct coff_link_hash_entry *h;
+      struct internal_syment *sym;
+      asection *sec;
+      bfd_vma val;
+
+      symndx = rel->r_symndx;
+      loc = contents + rel->r_vaddr - input_section->vma;
+
+      if (symndx == -1)
+       h = NULL;
+      else
+       h = obj_coff_sym_hashes (input_bfd)[symndx];
+
+      sym = NULL;
+      sec = NULL;
+      val = 0;
+
+
+      if (h == NULL)
+       {
+         if (symndx == -1)
+           sec = bfd_abs_section_ptr;
+         else
+           {
+             sym = syms + symndx;
+             sec = sections[symndx];
+             val = (sec->output_section->vma
+                    + sec->output_offset
+                    + sym->n_value
+                    - sec->vma);
+           }
+       }
+      else
+       {
+         if (h->root.type == bfd_link_hash_defined)
+           {
+             sec = h->root.u.def.section;
+             val = (h->root.u.def.value
+                    + sec->output_section->vma
+                    + sec->output_offset);
+           }
+         else
+           {
+             if (! ((*info->callbacks->undefined_symbol)
+                    (info, h->root.root.string, input_bfd, input_section,
+                     rel->r_vaddr - input_section->vma)))
+               return false;
+           }
+       }
+
+      switch (rel->r_type)
+       {
+       default:
+         bfd_set_error (bfd_error_bad_value);
+         return false;
+
+       case R_SH_IMM32:
+         {
+           long x = bfd_get_32 (input_bfd, loc);
+           x += val;
+           bfd_put_32 (input_bfd, x, loc);
+
+         }
+
+         break;
+       }
+    }     
+
+  return true;
+}
 
-bfd_target shcoff_vec =
+#define coff_relocate_section coff_sh_relocate_section
+#include "coffcode.h"
+
+const bfd_target shcoff_vec =
 {
   "coff-sh",                   /* name */
   bfd_target_coff_flavour,
@@ -169,10 +280,10 @@ bfd_target shcoff_vec =
   '/',                         /* ar_pad_char */
   15,                          /* ar_max_namelen */
   2,                           /* minimum section alignment */
-bfd_getb64, bfd_getb_signed_64, bfd_putb64,
+     bfd_getb64, bfd_getb_signed_64, bfd_putb64,
      bfd_getb32, bfd_getb_signed_32, bfd_putb32,
      bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
-bfd_getb64, bfd_getb_signed_64, bfd_putb64,
+     bfd_getb64, bfd_getb_signed_64, bfd_putb64,
      bfd_getb32, bfd_getb_signed_32, bfd_putb32,
      bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
 
@@ -191,6 +302,54 @@ bfd_getb64, bfd_getb_signed_64, bfd_putb64,
      BFD_JUMP_TABLE_RELOCS (coff),
      BFD_JUMP_TABLE_WRITE (coff),
      BFD_JUMP_TABLE_LINK (coff),
+     BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
+
+    COFF_SWAP_TABLE,
+};
+
+const bfd_target shlcoff_vec =
+{
+  "coff-shl",                  /* name */
+  bfd_target_coff_flavour,
+  false,                       /* data byte order is little */
+  false,                       /* header byte order is little endian too*/
+
+  (HAS_RELOC | EXEC_P |                /* object flags */
+   HAS_LINENO | HAS_DEBUG |
+   HAS_SYMS | HAS_LOCALS | WP_TEXT | BFD_IS_RELAXABLE ),
+
+  (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC),       /* section flags */
+  '_',                         /* leading symbol underscore */
+  '/',                         /* ar_pad_char */
+  15,                          /* ar_max_namelen */
+  2,                           /* minimum section alignment */
+     bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+     bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+     bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
+     bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+     bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+     bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
+
+/* Note that we use a special archive recognizer.
+   This is so that we only use one archive format for both
+   object file types */
+  {_bfd_dummy_target, coff_object_p, /* bfd_check_format */
+     _bfd_dummy_target, _bfd_dummy_target},   
+  {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */
+     bfd_false},
+  {bfd_false, coff_write_object_contents,      /* bfd_write_contents */
+     _bfd_write_archive_contents, bfd_false},
+
+     BFD_JUMP_TABLE_GENERIC (coff),
+     BFD_JUMP_TABLE_COPY (coff),
+     BFD_JUMP_TABLE_CORE (_bfd_nocore),
+     BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
+     BFD_JUMP_TABLE_SYMBOLS (coff),
+     BFD_JUMP_TABLE_RELOCS (coff),
+     BFD_JUMP_TABLE_WRITE (coff),
+     BFD_JUMP_TABLE_LINK (coff),
+     BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
 
     COFF_SWAP_TABLE,
 };
+
This page took 0.026598 seconds and 4 git commands to generate.