* elf32-i386.c (elf_i386_adjust_dynamic_symbol): Correct
authorIan Lance Taylor <ian@airs.com>
Mon, 3 Jul 1995 17:05:56 +0000 (17:05 +0000)
committerIan Lance Taylor <ian@airs.com>
Mon, 3 Jul 1995 17:05:56 +0000 (17:05 +0000)
BFD_ASSERT to handle __start_SECNAME symbols automatically defined
by the linker.
* elf32-sparc.c (elf32_sparc_adjust_dynamic_symbol): Likewise.
* elf32-m68k.c (elf_m68k_adjust_dynamic_symbol): Likewise.

bfd/ChangeLog
bfd/elf32-i386.c
bfd/elf32-m68k.c [new file with mode: 0644]
bfd/elf32-sparc.c

index 79f4571..6cb306e 100644 (file)
@@ -1,5 +1,11 @@
 Mon Jul  3 11:30:45 1995  Ian Lance Taylor  <ian@cygnus.com>
 
+       * elf32-i386.c (elf_i386_adjust_dynamic_symbol): Correct
+       BFD_ASSERT to handle __start_SECNAME symbols automatically defined
+       by the linker.
+       * elf32-sparc.c (elf32_sparc_adjust_dynamic_symbol): Likewise.
+       * elf32-m68k.c (elf_m68k_adjust_dynamic_symbol): Likewise.
+
        * Makefile.in: Rebuild dependencies.
        (BFD32_BACKENDS): Add versados.o.
        (CFILES): Add pe-i386.c, pei-i386.c, and versados.c.
index 844138f..3d56995 100644 (file)
@@ -1,5 +1,5 @@
 /* Intel 80386/80486-specific support for 32-bit ELF
-   Copyright 1993 Free Software Foundation, Inc.
+   Copyright 1993, 1994, 1995 Free Software Foundation, Inc.
 
 This file is part of BFD, the Binary File Descriptor library.
 
@@ -23,7 +23,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "libbfd.h"
 #include "libelf.h"
 
-static CONST struct reloc_howto_struct *elf_i386_reloc_type_lookup
+static reloc_howto_type *elf_i386_reloc_type_lookup
   PARAMS ((bfd *, bfd_reloc_code_real_type));
 static void elf_i386_info_to_howto
   PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *));
@@ -105,7 +105,7 @@ static reloc_howto_type elf_howto_table[]=
 #define TRACE(str)
 #endif
 
-static CONST struct reloc_howto_struct *
+static reloc_howto_type *
 elf_i386_reloc_type_lookup (abfd, code)
      bfd *abfd;
      bfd_reloc_code_real_type code;
@@ -607,20 +607,22 @@ elf_i386_adjust_dynamic_symbol (info, h)
   dynobj = elf_hash_table (info)->dynobj;
 
   /* Make sure we know what is going on here.  */
-  BFD_ASSERT (dynobj != NULL
-             && ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT)
-                 || ((h->elf_link_hash_flags
-                      & ELF_LINK_HASH_DEF_DYNAMIC) != 0
-                     && (h->elf_link_hash_flags
-                         & ELF_LINK_HASH_REF_REGULAR) != 0
-                     && (h->elf_link_hash_flags
-                         & ELF_LINK_HASH_DEF_REGULAR) == 0
-                     && (elf_elfheader (h->root.u.def.section->owner)->e_type
-                         == ET_DYN)
-                     && h->root.type == bfd_link_hash_defined
-                     && (bfd_get_flavour (h->root.u.def.section->owner)
-                         == bfd_target_elf_flavour)
-                     && h->root.u.def.section->output_section == NULL)));
+  BFD_ASSERT (dynobj != NULL);
+  BFD_ASSERT ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT)
+             || ((h->elf_link_hash_flags
+                  & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+                 && (h->elf_link_hash_flags
+                     & ELF_LINK_HASH_REF_REGULAR) != 0
+                 && (h->elf_link_hash_flags
+                     & ELF_LINK_HASH_DEF_REGULAR) == 0
+                 && (h->root.type == bfd_link_hash_defined
+                     || h->root.type == bfd_link_hash_defweak)
+                 && (h->root.u.def.section->owner == NULL
+                     || ((elf_elfheader (h->root.u.def.section->owner)->e_type
+                          == ET_DYN)
+                         && (bfd_get_flavour (h->root.u.def.section->owner)
+                             == bfd_target_elf_flavour)
+                         && h->root.u.def.section->output_section == NULL))));
 
   /* If this is a function, put it in the procedure linkage table.  We
      will fill in the contents of the procedure linkage table later,
@@ -685,7 +687,8 @@ elf_i386_adjust_dynamic_symbol (info, h)
      real definition first, and we can just use the same value.  */
   if (h->weakdef != NULL)
     {
-      BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined);
+      BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined
+                 || h->weakdef->root.type == bfd_link_hash_defweak);
       h->root.u.def.section = h->weakdef->root.u.def.section;
       h->root.u.def.value = h->weakdef->root.u.def.value;
       return true;
@@ -980,6 +983,7 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
       asection *sec;
       bfd_vma relocation;
       bfd_reloc_status_type r;
+      char *shared_name;
 
       r_type = ELF32_R_TYPE (rel->r_info);
       if (r_type < 0 || r_type >= (int) R_386_max)
@@ -1018,6 +1022,8 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
       h = NULL;
       sym = NULL;
       sec = NULL;
+      shared_name = NULL;
+
       if (r_symndx < symtab_hdr->sh_info)
        {
          sym = local_syms + r_symndx;
@@ -1029,7 +1035,8 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
       else
        {
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-         if (h->root.type == bfd_link_hash_defined)
+         if (h->root.type == bfd_link_hash_defined
+             || h->root.type == bfd_link_hash_defweak)
            {
              sec = h->root.u.def.section;
              if (r_type == R_386_GOTPC
@@ -1052,7 +1059,7 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
                              + sec->output_section->vma
                              + sec->output_offset);
            }
-         else if (h->root.type == bfd_link_hash_weak)
+         else if (h->root.type == bfd_link_hash_undefweak)
            relocation = 0;
          else if (info->shared)
            relocation = 0;
@@ -1225,21 +1232,19 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
 
              if (sreloc == NULL)
                {
-                 const char *name;
-
-                 name = (elf_string_from_elf_section
+                 shared_name = (elf_string_from_elf_section
                          (input_bfd,
                           elf_elfheader (input_bfd)->e_shstrndx,
                           elf_section_data (input_section)->rel_hdr.sh_name));
-                 if (name == NULL)
+                 if (shared_name == NULL)
                    return false;
 
-                 BFD_ASSERT (strncmp (name, ".rel", 4) == 0
+                 BFD_ASSERT (strncmp (shared_name, ".rel", 4) == 0
                              && strcmp (bfd_get_section_name (input_bfd,
                                                               input_section),
-                                        name + 4) == 0);
+                                        shared_name + 4) == 0);
 
-                 sreloc = bfd_get_section_by_name (dynobj, name);
+                 sreloc = bfd_get_section_by_name (dynobj, shared_name);
                  BFD_ASSERT (sreloc != NULL);
                }
 
@@ -1248,8 +1253,18 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
                                 + input_section->output_offset);
              if (r_type == R_386_PC32)
                {
-                 BFD_ASSERT (h != NULL && h->dynindx != -1);
-                 outrel.r_info = ELF32_R_INFO (h->dynindx, R_386_PC32);
+                 if (!h)
+                   {
+                     if (! ((*info->callbacks->undefined_symbol)
+                            (info, shared_name ? shared_name : sec->name, input_bfd,
+                             input_section, rel->r_offset)))
+                       bfd_set_error (bfd_error_bad_value);
+                     return false;
+                   }
+                 else {
+                   BFD_ASSERT (h->dynindx != -1);
+                   outrel.r_info = ELF32_R_INFO (h->dynindx, R_386_PC32);
+                 }
                }
              else
                {
@@ -1450,7 +1465,8 @@ elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym)
       /* This symbol needs a copy reloc.  Set it up.  */
 
       BFD_ASSERT (h->dynindx != -1
-                 && h->root.type == bfd_link_hash_defined);
+                 && (h->root.type == bfd_link_hash_defined
+                     || h->root.type == bfd_link_hash_defweak));
 
       s = bfd_get_section_by_name (h->root.u.def.section->owner,
                                   ".rel.bss");
diff --git a/bfd/elf32-m68k.c b/bfd/elf32-m68k.c
new file mode 100644 (file)
index 0000000..5ba6527
--- /dev/null
@@ -0,0 +1,1697 @@
+/* Motorola 68k series support for 32-bit ELF
+   Copyright 1993 Free Software Foundation, Inc.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "bfdlink.h"
+#include "libbfd.h"
+#include "libelf.h"
+
+static reloc_howto_type *reloc_type_lookup
+  PARAMS ((bfd *, bfd_reloc_code_real_type));
+static void rtype_to_howto
+  PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *));
+static void rtype_to_howto_rel
+  PARAMS ((bfd *, arelent *, Elf32_Internal_Rel *));
+static boolean elf_m68k_create_dynamic_sections
+  PARAMS ((bfd *, struct bfd_link_info *));
+static boolean elf_m68k_create_got_section
+  PARAMS ((bfd *, struct bfd_link_info *));
+static boolean elf_m68k_check_relocs
+  PARAMS ((bfd *, struct bfd_link_info *, asection *,
+          const Elf_Internal_Rela *));
+static boolean elf_m68k_adjust_dynamic_symbol
+  PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
+static boolean elf_m68k_adjust_dynindx
+  PARAMS ((struct elf_link_hash_entry *, PTR));
+static boolean elf_m68k_size_dynamic_sections
+  PARAMS ((bfd *, struct bfd_link_info *));
+static boolean elf_m68k_relocate_section
+  PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
+          Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
+static boolean elf_m68k_finish_dynamic_symbol
+  PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
+          Elf_Internal_Sym *));
+static boolean elf_m68k_finish_dynamic_sections
+  PARAMS ((bfd *, struct bfd_link_info *));
+
+/* elf32 m68k code, generated by elf.el */
+enum reloc_type {
+  R_68K_NONE        =   0,
+  R_68K_32          =   1,
+  R_68K_16          =   2,
+  R_68K_8           =   3,
+  R_68K_PC32        =   4,
+  R_68K_PC16        =   5,
+  R_68K_PC8         =   6,
+  R_68K_GOT32       =   7,
+  R_68K_GOT16       =   8,
+  R_68K_GOT8        =   9,
+  R_68K_GOT32O      =  10,
+  R_68K_GOT16O      =  11,
+  R_68K_GOT8O       =  12,
+  R_68K_PLT32       =  13,
+  R_68K_PLT16       =  14,
+  R_68K_PLT8        =  15,
+  R_68K_PLT32O      =  16,
+  R_68K_PLT16O      =  17,
+  R_68K_PLT8O       =  18,
+  R_68K_COPY        =  19,
+  R_68K_GLOB_DAT    =  20,
+  R_68K_JMP_SLOT    =  21,
+  R_68K_RELATIVE    =  22,
+  R_68K__max
+};
+
+static reloc_howto_type howto_table[] = {
+  HOWTO(R_68K_NONE,       0, 0, 0, false,0, complain_overflow_dont,     bfd_elf_generic_reloc, "R_68K_NONE",      false, 0x00000000, 0x00000000,false),
+  HOWTO(R_68K_32,         0, 2,32, false,0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_68K_32",        false, 0xffffffff, 0xffffffff,false),
+  HOWTO(R_68K_16,         0, 1,16, false,0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_68K_16",        false, 0x0000ffff, 0x0000ffff,false),
+  HOWTO(R_68K_8,          0, 0, 8, false,0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_68K_8",         false, 0x000000ff, 0x000000ff,false),
+  HOWTO(R_68K_PC32,       0, 2,32, true, 0, complain_overflow_signed,   bfd_elf_generic_reloc, "R_68K_PC32",      false, 0xffffffff, 0xffffffff,true),
+  HOWTO(R_68K_PC16,       0, 1,16, true, 0, complain_overflow_signed,   bfd_elf_generic_reloc, "R_68K_PC16",      false, 0x0000ffff, 0x0000ffff,true),
+  HOWTO(R_68K_PC8,        0, 0, 8, true, 0, complain_overflow_signed,   bfd_elf_generic_reloc, "R_68K_PC8",       false, 0x000000ff, 0x000000ff,true),
+  HOWTO(R_68K_GOT32,      0, 2,32, true, 0, complain_overflow_signed,   bfd_elf_generic_reloc, "R_68K_GOT32",     false, 0xffffffff, 0xffffffff,true),
+  HOWTO(R_68K_GOT16,      0, 1,16, true, 0, complain_overflow_signed,   bfd_elf_generic_reloc, "R_68K_GOT16",     false, 0x0000ffff, 0x0000ffff,true),
+  HOWTO(R_68K_GOT8,       0, 0, 8, true, 0, complain_overflow_signed,   bfd_elf_generic_reloc, "R_68K_GOT8",      false, 0x000000ff, 0x000000ff,true),
+  HOWTO(R_68K_GOT32O,     0, 2,32, false,0, complain_overflow_signed,   bfd_elf_generic_reloc, "R_68K_GOT32O",    false, 0xffffffff, 0xffffffff,false),
+  HOWTO(R_68K_GOT16O,     0, 1,16, false,0, complain_overflow_signed,   bfd_elf_generic_reloc, "R_68K_GOT16O",    false, 0x0000ffff, 0x0000ffff,false),
+  HOWTO(R_68K_GOT8O,      0, 0, 8, false,0, complain_overflow_signed,   bfd_elf_generic_reloc, "R_68K_GOT8O",     false, 0x000000ff, 0x000000ff,false),
+  HOWTO(R_68K_PLT32,      0, 2,32, true, 0, complain_overflow_signed,   bfd_elf_generic_reloc, "R_68K_PLT32",     false, 0xffffffff, 0xffffffff,true),
+  HOWTO(R_68K_PLT16,      0, 1,16, true, 0, complain_overflow_signed,   bfd_elf_generic_reloc, "R_68K_PLT16",     false, 0x0000ffff, 0x0000ffff,true),
+  HOWTO(R_68K_PLT8,       0, 0, 8, true, 0, complain_overflow_signed,   bfd_elf_generic_reloc, "R_68K_PLT8",      false, 0x000000ff, 0x000000ff,true),
+  HOWTO(R_68K_PLT32O,     0, 2,32, false,0, complain_overflow_signed,   bfd_elf_generic_reloc, "R_68K_PLT32O",    false, 0xffffffff, 0xffffffff,false),
+  HOWTO(R_68K_PLT16O,     0, 1,16, false,0, complain_overflow_signed,   bfd_elf_generic_reloc, "R_68K_PLT16O",    false, 0x0000ffff, 0x0000ffff,false),
+  HOWTO(R_68K_PLT8O,      0, 0, 8, false,0, complain_overflow_signed,   bfd_elf_generic_reloc, "R_68K_PLT8O",     false, 0x000000ff, 0x000000ff,false),
+  HOWTO(R_68K_COPY,       0, 0, 0, false,0, complain_overflow_dont,     bfd_elf_generic_reloc, "R_68K_COPY",      false, 0xffffffff, 0xffffffff,false),
+  HOWTO(R_68K_GLOB_DAT,   0, 2,32, false,0, complain_overflow_dont,     bfd_elf_generic_reloc, "R_68K_GLOB_DAT",  false, 0xffffffff, 0xffffffff,false),
+  HOWTO(R_68K_JMP_SLOT,   0, 2,32, false,0, complain_overflow_dont,     bfd_elf_generic_reloc, "R_68K_JMP_SLOT",  false, 0xffffffff, 0xffffffff,false),
+  HOWTO(R_68K_RELATIVE,   0, 2,32, false,0, complain_overflow_dont,     bfd_elf_generic_reloc, "R_68K_RELATIVE",  false, 0xffffffff, 0xffffffff,false),
+};
+
+static void
+rtype_to_howto (abfd, cache_ptr, dst)
+     bfd *abfd;
+     arelent *cache_ptr;
+     Elf_Internal_Rela *dst;
+{
+  BFD_ASSERT (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_68K__max);
+  cache_ptr->howto = &howto_table[ELF32_R_TYPE(dst->r_info)];
+}
+
+static void
+rtype_to_howto_rel (abfd, cache_ptr, dst)
+     bfd *abfd;
+     arelent *cache_ptr;
+     Elf_Internal_Rel *dst;
+{
+  BFD_ASSERT (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_68K__max);
+  cache_ptr->howto = &howto_table[ELF32_R_TYPE(dst->r_info)];
+}
+
+#define elf_info_to_howto rtype_to_howto
+#define elf_info_to_howto_rel rtype_to_howto_rel
+
+static const struct { unsigned char bfd_val, elf_val; } reloc_map[] = {
+  { BFD_RELOC_NONE, R_68K_NONE },
+  { BFD_RELOC_32, R_68K_32 },
+  { BFD_RELOC_16, R_68K_16 },
+  { BFD_RELOC_8, R_68K_8 },
+  { BFD_RELOC_32_PCREL, R_68K_PC32 },
+  { BFD_RELOC_16_PCREL, R_68K_PC16 },
+  { BFD_RELOC_8_PCREL, R_68K_PC8 },
+  { BFD_RELOC_32_GOT_PCREL, R_68K_GOT32 },
+  { BFD_RELOC_16_GOT_PCREL, R_68K_GOT16 },
+  { BFD_RELOC_8_GOT_PCREL, R_68K_GOT8 },
+  { BFD_RELOC_32_GOTOFF, R_68K_GOT32O },
+  { BFD_RELOC_16_GOTOFF, R_68K_GOT16O },
+  { BFD_RELOC_8_GOTOFF, R_68K_GOT8O },
+  { BFD_RELOC_32_PLT_PCREL, R_68K_PLT32 },
+  { BFD_RELOC_16_PLT_PCREL, R_68K_PLT16 },
+  { BFD_RELOC_8_PLT_PCREL, R_68K_PLT8 },
+  { BFD_RELOC_32_PLTOFF, R_68K_PLT32O },
+  { BFD_RELOC_16_PLTOFF, R_68K_PLT16O },
+  { BFD_RELOC_8_PLTOFF, R_68K_PLT8O },
+  { BFD_RELOC_NONE, R_68K_COPY },
+  { BFD_RELOC_68K_GLOB_DAT, R_68K_GLOB_DAT },
+  { BFD_RELOC_68K_JMP_SLOT, R_68K_JMP_SLOT },
+  { BFD_RELOC_68K_RELATIVE, R_68K_RELATIVE },
+  { BFD_RELOC_CTOR, R_68K_32 },
+};
+
+static reloc_howto_type *
+reloc_type_lookup (abfd, code)
+     bfd *abfd;
+     bfd_reloc_code_real_type code;
+{
+  int i;
+  for (i = 0; i < sizeof (reloc_map) / sizeof (reloc_map[0]); i++)
+    {
+      if (reloc_map[i].bfd_val == code)
+       return &howto_table[(int) reloc_map[i].elf_val];
+    }
+  return 0;
+}
+
+#define bfd_elf32_bfd_reloc_type_lookup reloc_type_lookup
+#define ELF_ARCH bfd_arch_m68k
+/* end code generated by elf.el */
+
+#define USE_RELA
+
+\f
+/* Functions for the m68k ELF linker.  */
+
+/* The name of the dynamic interpreter.  This is put in the .interp
+   section.  */
+
+#define ELF_DYNAMIC_INTERPRETER "/usr/lib/libc.so.1"
+
+/* The size in bytes of an entry in the procedure linkage table.  */
+
+#define PLT_ENTRY_SIZE 20
+
+/* The first entry in a procedure linkage table looks like this.  See
+   the SVR4 ABI m68k supplement to see how this works.  */
+
+static const bfd_byte elf_m68k_plt0_entry[PLT_ENTRY_SIZE] =
+{
+  0x2f, 0x3b, 0x01, 0x70, /* move.l (%pc,addr),-(%sp) */
+  0, 0, 0, 0,            /* replaced with address of .got + 4.  */
+  0x4e, 0xfb, 0x01, 0x71, /* jmp ([%pc,addr]) */
+  0, 0, 0, 0,            /* replaced with address of .got + 8.  */
+  0, 0, 0, 0             /* pad out to 20 bytes.  */
+};
+
+/* Subsequent entries in a procedure linkage table look like this.  */
+
+static const bfd_byte elf_m68k_plt_entry[PLT_ENTRY_SIZE] =
+{
+  0x4e, 0xfb, 0x01, 0x71, /* jmp ([addr]) */
+  0, 0, 0, 0,            /* replaced with address of this symbol in .got.  */
+  0x2f, 0x3c,            /* move.l #offset,-(%sp) */
+  0, 0, 0, 0,            /* replaced with offset into relocation table.  */
+  0x60, 0xff,            /* bra.l .plt */
+  0, 0, 0, 0             /* replaced with offset to start of .plt.  */
+};
+
+/* Create dynamic sections when linking against a dynamic object.  */
+
+static boolean
+elf_m68k_create_dynamic_sections (abfd, info)
+     bfd *abfd;
+     struct bfd_link_info *info;
+{
+  flagword flags;
+  register asection *s;
+
+  /* We need to create .plt, .rela.plt, .got, .got.plt, .dynbss, and
+     .rela.bss sections.  */
+
+  flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
+
+  s = bfd_make_section (abfd, ".plt");
+  if (s == NULL
+      || !bfd_set_section_flags (abfd, s, flags | SEC_READONLY | SEC_CODE)
+      || !bfd_set_section_alignment (abfd, s, 2))
+    return false;
+
+  s = bfd_make_section (abfd, ".rela.plt");
+  if (s == NULL
+      || !bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
+      || !bfd_set_section_alignment (abfd, s, 2))
+    return false;
+
+  if (!elf_m68k_create_got_section (abfd, info))
+    return false;
+
+  /* The .dynbss section is a place to put symbols which are defined
+     by dynamic objects, are referenced by regular objects, and are
+     not functions.  We must allocate space for them in the process
+     image and use a R_68K_COPY reloc to tell the dynamic linker to
+     initialize them at run time.  The linker script puts the .dynbss
+     section into the .bss section of the final image.  */
+  s = bfd_make_section (abfd, ".dynbss");
+  if (s == NULL
+      || !bfd_set_section_flags (abfd, s, SEC_ALLOC))
+    return false;
+
+  /* The .rela.bss section holds copy relocs.  This section is not
+     normally needed.  We need to create it here, though, so that the
+     linker will map it to an output section.  We can't just create it
+     only if we need it, because we will not know whether we need it
+     until we have seen all the input files, and the first time the
+     main linker code calls BFD after examining all the input files
+     (size_dynamic_sections) the input sections have already been
+     mapped to the output sections.  If the section turns out not to
+     be needed, we can discard it later.  We will never need this
+     section when generating a shared object, since they do not use
+     copy relocs.  */
+  if (!info->shared)
+    {
+      s = bfd_make_section (abfd, ".rela.bss");
+      if (s == NULL
+         || !bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
+         || !bfd_set_section_alignment (abfd, s, 2))
+       return false;
+    }
+
+  return true;
+}
+
+/* Create the .got section to hold the global offset table, and the
+   .got.plt section to hold procedure linkage table GOT entries.  The
+   linker script will put .got.plt into the output .got section.  */
+
+static boolean
+elf_m68k_create_got_section (abfd, info)
+     bfd *abfd;
+     struct bfd_link_info *info;
+{
+  flagword flags;
+  register asection *s;
+  struct elf_link_hash_entry *h;
+
+  /* This function may be called more than once.  */
+  if (bfd_get_section_by_name (abfd, ".got") != NULL)
+    return true;
+
+  flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
+
+  s = bfd_make_section (abfd, ".got");
+  if (s == NULL
+      || !bfd_set_section_flags (abfd, s, flags)
+      || !bfd_set_section_alignment (abfd, s, 2))
+    return false;
+
+  s = bfd_make_section (abfd, ".got.plt");
+  if (s == NULL
+      || !bfd_set_section_flags (abfd, s, flags)
+      || !bfd_set_section_alignment (abfd, s, 2))
+    return false;
+
+  /* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the
+     .got.plt section, which will be placed at the start of the output
+     .got section.  We don't do this in the linker script because we
+     don't want to define the symbol if we are not creating a global
+     offset table.  */
+  h = NULL;
+  if (!(_bfd_generic_link_add_one_symbol
+       (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s, (bfd_vma) 0,
+        (const char *) NULL, false, get_elf_backend_data (abfd)->collect,
+        (struct bfd_link_hash_entry **) &h)))
+    return false;
+  h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+  h->type = STT_OBJECT;
+
+  if (info->shared
+      && !bfd_elf32_link_record_dynamic_symbol (info, h))
+    return false;
+
+  /* The first three global offset table entries are reserved.  */
+  s->_raw_size += 3 * 4;
+
+  return true;
+}
+
+/* Look through the relocs for a section during the first phase, and
+   allocate space in the global offset table or procedure linkage
+   table.  */
+
+static boolean
+elf_m68k_check_relocs (abfd, info, sec, relocs)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     asection *sec;
+     const Elf_Internal_Rela *relocs;
+{
+  bfd *dynobj;
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes;
+  bfd_vma *local_got_offsets;
+  const Elf_Internal_Rela *rel;
+  const Elf_Internal_Rela *rel_end;
+  asection *sgot;
+  asection *srelgot;
+  asection *sreloc;
+
+  if (info->relocateable)
+    return true;
+
+  dynobj = elf_hash_table (info)->dynobj;
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  sym_hashes = elf_sym_hashes (abfd);
+  local_got_offsets = elf_local_got_offsets (abfd);
+
+  sgot = NULL;
+  srelgot = NULL;
+  sreloc = NULL;
+
+  rel_end = relocs + sec->reloc_count;
+  for (rel = relocs; rel < rel_end; rel++)
+    {
+      long r_symndx;
+      struct elf_link_hash_entry *h;
+
+      r_symndx = ELF32_R_SYM (rel->r_info);
+
+      if (r_symndx < symtab_hdr->sh_info)
+       h = NULL;
+      else
+       h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+
+      switch (ELF32_R_TYPE (rel->r_info))
+       {
+       case R_68K_GOT8:
+       case R_68K_GOT16:
+       case R_68K_GOT32:
+       case R_68K_GOT8O:
+       case R_68K_GOT16O:
+       case R_68K_GOT32O:
+         /* This symbol requires a global offset table entry.  */
+
+         if (h != NULL
+             && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+           break;
+
+         if (dynobj == NULL)
+           {
+             /* Create the .got section.  */
+             elf_hash_table (info)->dynobj = dynobj = abfd;
+             if (!elf_m68k_create_got_section (dynobj, info))
+               return false;
+           }
+
+         if (sgot == NULL)
+           {
+             sgot = bfd_get_section_by_name (dynobj, ".got");
+             BFD_ASSERT (sgot != NULL);
+           }
+
+         if (srelgot == NULL
+             && (h != NULL || info->shared))
+           {
+             srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+             if (srelgot == NULL)
+               {
+                 srelgot = bfd_make_section (dynobj, ".rela.got");
+                 if (srelgot == NULL
+                     || !bfd_set_section_flags (dynobj, srelgot,
+                                                (SEC_ALLOC
+                                                 | SEC_LOAD
+                                                 | SEC_HAS_CONTENTS
+                                                 | SEC_IN_MEMORY
+                                                 | SEC_READONLY))
+                     || !bfd_set_section_alignment (dynobj, srelgot, 2))
+                   return false;
+               }
+           }
+
+         if (h != NULL)
+           {
+             if (h->got_offset != (bfd_vma) -1)
+               {
+                 /* We have already allocated space in the .got.  */
+                 break;
+               }
+             h->got_offset = sgot->_raw_size;
+
+             /* Make sure this symbol is output as a dynamic symbol.  */
+             if (h->dynindx == -1)
+               {
+                 if (!bfd_elf32_link_record_dynamic_symbol (info, h))
+                   return false;
+               }
+
+             srelgot->_raw_size += sizeof (Elf32_External_Rela);
+           }
+         else
+           {
+             /* This is a global offset table entry for a local
+                symbol.  */
+             if (local_got_offsets == NULL)
+               {
+                 size_t size;
+                 register int i;
+
+                 size = symtab_hdr->sh_info * sizeof (bfd_vma);
+                 local_got_offsets = (bfd_vma *) bfd_alloc (abfd, size);
+                 if (local_got_offsets == NULL)
+                   {
+                     bfd_set_error (bfd_error_no_memory);
+                     return false;
+                   }
+                 elf_local_got_offsets (abfd) = local_got_offsets;
+                 for (i = 0; i < symtab_hdr->sh_info; i++)
+                   local_got_offsets[i] = (bfd_vma) -1;
+               }
+             if (local_got_offsets[r_symndx] != (bfd_vma) -1)
+               {
+                 /* We have already allocated space in the .got.  */
+                 break;
+               }
+             local_got_offsets[r_symndx] = sgot->_raw_size;
+
+             if (info->shared)
+               {
+                 /* If we are generating a shared object, we need to
+                    output a R_68K_RELATIVE reloc so that the dynamic
+                    linker can adjust this GOT entry.  */
+                 srelgot->_raw_size += sizeof (Elf32_External_Rela);
+               }
+           }
+
+         sgot->_raw_size += 4;
+         break;
+
+       case R_68K_PLT8:
+       case R_68K_PLT16:
+       case R_68K_PLT32:
+       case R_68K_PLT8O:
+       case R_68K_PLT16O:
+       case R_68K_PLT32O:
+         /* This symbol requires a procedure linkage table entry.  We
+            actually build the entry in adjust_dynamic_symbol,
+            because this might be a case of linking PIC code without
+            linking in any dynamic objects, in which case we don't
+            need to generate a procedure linkage table after all.  */
+         
+         /* If this is a local symbol, we resolve it directly without
+            creating a procedure linkage table entry.  */
+         if (h == NULL)
+           continue;
+
+         /* Make sure this symbol is output as a dynamic symbol.  */
+         if (h->dynindx == -1)
+           {
+             if (!bfd_elf32_link_record_dynamic_symbol (info, h))
+               return false;
+           }
+
+         h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+         break;
+
+       case R_68K_8:
+       case R_68K_16:
+       case R_68K_32:
+       case R_68K_PC8:
+       case R_68K_PC16:
+       case R_68K_PC32:
+         if (info->shared
+             && (sec->flags & SEC_ALLOC) != 0)
+           {
+             /* When creating a shared object, we must copy these
+                reloc types into the output file.  We create a reloc
+                section in dynobj and make room for this reloc.  */
+             if (sreloc == NULL)
+               {
+                 const char *name;
+
+                 name = (elf_string_from_elf_section
+                         (abfd,
+                          elf_elfheader (abfd)->e_shstrndx,
+                          elf_section_data (sec)->rel_hdr.sh_name));
+                 if (name == NULL)
+                   return false;
+
+                 BFD_ASSERT (strncmp (name, ".rela", 5) == 0
+                             && strcmp (bfd_get_section_name (abfd, sec),
+                                        name + 5) == 0);
+
+                 sreloc = bfd_get_section_by_name (dynobj, name);
+                 if (sreloc == NULL)
+                   {
+                     sreloc = bfd_make_section (dynobj, name);
+                     if (sreloc == NULL
+                         || !bfd_set_section_flags (dynobj, sreloc,
+                                                    (SEC_ALLOC
+                                                     | SEC_LOAD
+                                                     | SEC_HAS_CONTENTS
+                                                     | SEC_IN_MEMORY
+                                                     | SEC_READONLY))
+                         || !bfd_set_section_alignment (dynobj, sreloc, 2))
+                       return false;
+                   }
+               }
+
+             sreloc->_raw_size += sizeof (Elf32_External_Rela);
+           }
+
+         break;
+
+       default:
+         break;
+       }
+    }
+
+  return true;
+}
+
+/* Adjust a symbol defined by a dynamic object and referenced by a
+   regular object.  The current definition is in some section of the
+   dynamic object, but we're not including those sections.  We have to
+   change the definition to something the rest of the link can
+   understand.  */
+
+static boolean
+elf_m68k_adjust_dynamic_symbol (info, h)
+     struct bfd_link_info *info;
+     struct elf_link_hash_entry *h;
+{
+  bfd *dynobj;
+  asection *s;
+  unsigned int power_of_two;
+
+  dynobj = elf_hash_table (info)->dynobj;
+
+  /* Make sure we know what is going on here.  */
+  BFD_ASSERT (dynobj != NULL);
+  BFD_ASSERT ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT)
+             || ((h->elf_link_hash_flags
+                  & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+                 && (h->elf_link_hash_flags
+                     & ELF_LINK_HASH_REF_REGULAR) != 0
+                 && (h->elf_link_hash_flags
+                     & ELF_LINK_HASH_DEF_REGULAR) == 0
+                 && (h->root.type == bfd_link_hash_defined
+                     || h->root.type == bfd_link_hash_defweak)
+                 && (h->root.u.def.section->owner == NULL
+                     || ((elf_elfheader (h->root.u.def.section->owner)->e_type
+                          == ET_DYN)
+                         && (bfd_get_flavour (h->root.u.def.section->owner)
+                             == bfd_target_elf_flavour)
+                         && h->root.u.def.section->output_section == NULL))));
+
+  /* If this is a function, put it in the procedure linkage table.  We
+     will fill in the contents of the procedure linkage table later,
+     when we know the address of the .got section.  */
+  if (h->type == STT_FUNC
+      || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
+    {
+      if (!elf_hash_table (info)->dynamic_sections_created)
+       {
+         /* This case can occur if we saw a PLT32 reloc in an input
+            file, but none of the input files were dynamic objects.
+            In such a case, we don't actually need to build a
+            procedure linkage table, and we can just do a PC32 reloc
+            instead.  */
+         BFD_ASSERT ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0);
+         return true;
+       }
+
+      s = bfd_get_section_by_name (dynobj, ".plt");
+      BFD_ASSERT (s != NULL);
+
+      /* If this is the first .plt entry, make room for the special
+        first entry.  */
+      if (s->_raw_size == 0)
+       s->_raw_size += PLT_ENTRY_SIZE;
+
+      /* If this symbol is not defined in a regular file, and we are
+        not generating a shared library, then set the symbol to this
+        location in the .plt.  This is required to make function
+        pointers compare as equal between the normal executable and
+        the shared library.  */
+      if (!info->shared
+         && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+       {
+         h->root.u.def.section = s;
+         h->root.u.def.value = s->_raw_size;
+       }
+
+      h->plt_offset = s->_raw_size;
+
+      /* Make room for this entry.  */
+      s->_raw_size += PLT_ENTRY_SIZE;
+
+      /* We also need to make an entry in the .got.plt section, which
+        will be placed in the .got section by the linker script.  */
+
+      s = bfd_get_section_by_name (dynobj, ".got.plt");
+      BFD_ASSERT (s != NULL);
+      s->_raw_size += 4;
+
+      /* We also need to make an entry in the .rela.plt section.  */
+
+      s = bfd_get_section_by_name (dynobj, ".rela.plt");
+      BFD_ASSERT (s != NULL);
+      s->_raw_size += sizeof (Elf32_External_Rela);
+
+      return true;
+    }
+
+  /* If this is a weak symbol, and there is a real definition, the
+     processor independent code will have arranged for us to see the
+     real definition first, and we can just use the same value.  */
+  if (h->weakdef != NULL)
+    {
+      BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined
+                 || h->weakdef->root.type == bfd_link_hash_defweak);
+      h->root.u.def.section = h->weakdef->root.u.def.section;
+      h->root.u.def.value = h->weakdef->root.u.def.value;
+      return true;
+    }
+
+  /* This is a reference to a symbol defined by a dynamic object which
+     is not a function.  */
+
+  /* If we are creating a shared library, we must presume that the
+     only references to the symbol are via the global offset table.
+     For such cases we need not do anything here; the relocations will
+     be handled correctly by relocate_section.  */
+  if (info->shared)
+    return true;
+
+  /* We must allocate the symbol in our .dynbss section, which will
+     become part of the .bss section of the executable.  There will be
+     an entry for this symbol in the .dynsym section.  The dynamic
+     object will contain position independent code, so all references
+     from the dynamic object to this symbol will go through the global
+     offset table.  The dynamic linker will use the .dynsym entry to
+     determine the address it must put in the global offset table, so
+     both the dynamic object and the regular object will refer to the
+     same memory location for the variable.  */
+
+  s = bfd_get_section_by_name (dynobj, ".dynbss");
+  BFD_ASSERT (s != NULL);
+
+  /* If the symbol is currently defined in the .bss section of the
+     dynamic object, then it is OK to simply initialize it to zero.
+     If the symbol is in some other section, we must generate a
+     R_68K_COPY reloc to tell the dynamic linker to copy the initial
+     value out of the dynamic object and into the runtime process
+     image.  We need to remember the offset into the .rela.bss section
+     we are going to use.  */
+  if ((h->root.u.def.section->flags & SEC_LOAD) != 0)
+    {
+      asection *srel;
+
+      srel = bfd_get_section_by_name (dynobj, ".rela.bss");
+      BFD_ASSERT (srel != NULL);
+      srel->_raw_size += sizeof (Elf32_External_Rela);
+      h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY;
+    }
+
+  /* We need to figure out the alignment required for this symbol.  I
+     have no idea how ELF linkers handle this.  */
+  power_of_two = bfd_log2 (h->size);
+  if (power_of_two > 3)
+    power_of_two = 3;
+
+  /* Apply the required alignment.  */
+  s->_raw_size = BFD_ALIGN (s->_raw_size,
+                           (bfd_size_type) (1 << power_of_two));
+  if (power_of_two > bfd_get_section_alignment (dynobj, s))
+    {
+      if (!bfd_set_section_alignment (dynobj, s, power_of_two))
+       return false;
+    }
+
+  /* Define the symbol as being at this point in the section.  */
+  h->root.u.def.section = s;
+  h->root.u.def.value = s->_raw_size;
+
+  /* Increment the section size to make room for the symbol.  */
+  s->_raw_size += h->size;
+
+  return true;
+}
+
+/* Set the sizes of the dynamic sections.  */
+
+static boolean
+elf_m68k_size_dynamic_sections (output_bfd, info)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+{
+  bfd *dynobj;
+  asection *s;
+  boolean plt;
+  boolean relocs;
+  boolean reltext;
+
+  dynobj = elf_hash_table (info)->dynobj;
+  BFD_ASSERT (dynobj != NULL);
+
+  if (elf_hash_table (info)->dynamic_sections_created)
+    {
+      /* Set the contents of the .interp section to the interpreter.  */
+      if (!info->shared)
+       {
+         s = bfd_get_section_by_name (dynobj, ".interp");
+         BFD_ASSERT (s != NULL);
+         s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER;
+         s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
+       }
+    }
+  else
+    {
+      /* We may have created entries in the .rela.got section.
+        However, if we are not creating the dynamic sections, we will
+        not actually use these entries.  Reset the size of .rela.got,
+        which will cause it to get stripped from the output file
+        below.  */
+      s = bfd_get_section_by_name (dynobj, ".rela.got");
+      if (s != NULL)
+       s->_raw_size = 0;
+    }
+
+  /* The check_relocs and adjust_dynamic_symbol entry points have
+     determined the sizes of the various dynamic sections.  Allocate
+     memory for them.  */
+  plt = false;
+  relocs = false;
+  reltext = false;
+  for (s = dynobj->sections; s != NULL; s = s->next)
+    {
+      const char *name;
+      boolean strip;
+
+      if ((s->flags & SEC_IN_MEMORY) == 0)
+       continue;
+
+      /* It's OK to base decisions on the section name, because none
+        of the dynobj section names depend upon the input files.  */
+      name = bfd_get_section_name (dynobj, s);
+
+      strip = false;
+
+      if (strcmp (name, ".plt") == 0)
+       {
+         if (s->_raw_size == 0)
+           {
+             /* Strip this section if we don't need it; see the
+                 comment below.  */
+             strip = true;
+           }
+         else
+           {
+             /* Remember whether there is a PLT.  */
+             plt = true;
+           }
+       }
+      else if (strncmp (name, ".rela", 5) == 0)
+       {
+         if (s->_raw_size == 0)
+           {
+             /* If we don't need this section, strip it from the
+                output file.  This is mostly to handle .rela.bss and
+                .rela.plt.  We must create both sections in
+                create_dynamic_sections, because they must be created
+                before the linker maps input sections to output
+                sections.  The linker does that before
+                adjust_dynamic_symbol is called, and it is that
+                function which decides whether anything needs to go
+                into these sections.  */
+             strip = true;
+           }
+         else
+           {
+             asection *target;
+
+             /* Remember whether there are any reloc sections other
+                 than .rela.plt.  */
+             if (strcmp (name, ".rela.plt") != 0)
+               {
+                 relocs = true;
+
+                 /* If this relocation section applies to a read only
+                    section, then we probably need a DT_TEXTREL
+                    entry.  .rela.plt is actually associated with
+                    .got.plt, which is never readonly.  */
+                 target = bfd_get_section_by_name (output_bfd, name + 5);
+                 if (target != NULL
+                     && (target->flags & SEC_READONLY) != 0)
+                   reltext = true;
+               }
+
+             /* We use the reloc_count field as a counter if we need
+                to copy relocs into the output file.  */
+             s->reloc_count = 0;
+           }
+       }
+      else if (strncmp (name, ".got", 4) != 0)
+       {
+         /* It's not one of our sections, so don't allocate space.  */
+         continue;
+       }
+
+      if (strip)
+       {
+         asection **spp;
+
+         for (spp = &s->output_section->owner->sections;
+              *spp != s->output_section;
+              spp = &(*spp)->next)
+           ;
+         *spp = s->output_section->next;
+         --s->output_section->owner->section_count;
+
+         continue;
+       }
+
+      /* Allocate memory for the section contents.  */
+      s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size);
+      if (s->contents == NULL && s->_raw_size != 0)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         return false;
+       }
+    }
+
+  if (elf_hash_table (info)->dynamic_sections_created)
+    {
+      /* Add some entries to the .dynamic section.  We fill in the
+        values later, in elf_m68k_finish_dynamic_sections, but we
+        must add the entries now so that we get the correct size for
+        the .dynamic section.  The DT_DEBUG entry is filled in by the
+        dynamic linker and used by the debugger.  */
+      if (!info->shared)
+       {
+         if (!bfd_elf32_add_dynamic_entry (info, DT_DEBUG, 0))
+           return false;
+       }
+
+      if (plt)
+       {
+         if (!bfd_elf32_add_dynamic_entry (info, DT_PLTGOT, 0)
+             || !bfd_elf32_add_dynamic_entry (info, DT_PLTRELSZ, 0)
+             || !bfd_elf32_add_dynamic_entry (info, DT_PLTREL, DT_RELA)
+             || !bfd_elf32_add_dynamic_entry (info, DT_JMPREL, 0))
+           return false;
+       }
+
+      if (relocs)
+       {
+         if (!bfd_elf32_add_dynamic_entry (info, DT_RELA, 0)
+             || !bfd_elf32_add_dynamic_entry (info, DT_RELASZ, 0)
+             || !bfd_elf32_add_dynamic_entry (info, DT_RELAENT,
+                                              sizeof (Elf32_External_Rela)))
+           return false;
+       }
+
+      if (reltext)
+       {
+         if (!bfd_elf32_add_dynamic_entry (info, DT_TEXTREL, 0))
+           return false;
+       }
+    }
+
+  /* If we are generating a shared library, we generate a section
+     symbol for each output section.  These are local symbols, which
+     means that they must come first in the dynamic symbol table.
+     That means we must increment the dynamic symbol index of every
+     other dynamic symbol.  */
+  if (info->shared)
+    {
+      int c, i;
+
+      c = bfd_count_sections (output_bfd);
+      elf_link_hash_traverse (elf_hash_table (info),
+                             elf_m68k_adjust_dynindx,
+                             (PTR) &c);
+      elf_hash_table (info)->dynsymcount += c;
+
+      for (i = 1, s = output_bfd->sections; s != NULL; s = s->next, i++)
+       {
+         elf_section_data (s)->dynindx = i;
+         /* These symbols will have no names, so we don't need to
+             fiddle with dynstr_index.  */
+       }
+    }
+
+  return true;
+}
+
+/* Increment the index of a dynamic symbol by a given amount.  Called
+   via elf_link_hash_traverse.  */
+
+static boolean
+elf_m68k_adjust_dynindx (h, cparg)
+     struct elf_link_hash_entry *h;
+     PTR cparg;
+{
+  int *cp = (int *) cparg;
+
+  if (h->dynindx != -1)
+    h->dynindx += *cp;
+  return true;
+}
+
+/* Relocate an M68K ELF section.  */
+
+static boolean
+elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section,
+                          contents, relocs, local_syms, local_sections)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+     bfd *input_bfd;
+     asection *input_section;
+     bfd_byte *contents;
+     Elf_Internal_Rela *relocs;
+     Elf_Internal_Sym *local_syms;
+     asection **local_sections;
+{
+  bfd *dynobj;
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes;
+  bfd_vma *local_got_offsets;
+  asection *sgot;
+  asection *sgotplt;
+  asection *splt;
+  asection *sreloc;
+  Elf_Internal_Rela *rel;
+  Elf_Internal_Rela *relend;
+
+  dynobj = elf_hash_table (info)->dynobj;
+  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+  sym_hashes = elf_sym_hashes (input_bfd);
+  local_got_offsets = elf_local_got_offsets (input_bfd);
+
+  sgot = NULL;
+  sgotplt = NULL;
+  splt = NULL;
+  sreloc = NULL;
+
+  rel = relocs;
+  relend = relocs + input_section->reloc_count;
+  for (; rel < relend; rel++)
+    {
+      int r_type;
+      reloc_howto_type *howto;
+      long r_symndx;
+      struct elf_link_hash_entry *h;
+      Elf_Internal_Sym *sym;
+      asection *sec;
+      bfd_vma relocation;
+      bfd_reloc_status_type r;
+
+      r_type = ELF32_R_TYPE (rel->r_info);
+      if (r_type < 0 || r_type >= (int) R_68K__max)
+       {
+         bfd_set_error (bfd_error_bad_value);
+         return false;
+       }
+      howto = howto_table + r_type;
+
+      r_symndx = ELF32_R_SYM (rel->r_info);
+
+      if (info->relocateable)
+       {
+         /* This is a relocateable link.  We don't have to change
+            anything, unless the reloc is against a section symbol,
+            in which case we have to adjust according to where the
+            section symbol winds up in the output section.  */
+         if (r_symndx < symtab_hdr->sh_info)
+           {
+             sym = local_syms + r_symndx;
+             if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+               {
+                 sec = local_sections[r_symndx];
+                 rel->r_addend += sec->output_offset + sym->st_value;
+               }
+           }
+
+         continue;
+       }
+
+      /* This is a final link.  */
+      h = NULL;
+      sym = NULL;
+      sec = NULL;
+      if (r_symndx < symtab_hdr->sh_info)
+       {
+         sym = local_syms + r_symndx;
+         sec = local_sections[r_symndx];
+         relocation = (sec->output_section->vma
+                       + sec->output_offset
+                       + sym->st_value);
+       }
+      else
+       {
+         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+         if (h->root.type == bfd_link_hash_defined
+             || h->root.type == bfd_link_hash_defweak)
+           {
+             sec = h->root.u.def.section;
+             if (((r_type == R_68K_PLT8
+                   || r_type == R_68K_PLT16
+                   || r_type == R_68K_PLT32
+                   || r_type == R_68K_PLT8O
+                   || r_type == R_68K_PLT16O
+                   || r_type == R_68K_PLT32O)
+                  && h->plt_offset != (bfd_vma) -1)
+                 || ((r_type == R_68K_GOT8O
+                      || r_type == R_68K_GOT16O
+                      || r_type == R_68K_GOT32O
+                      || ((r_type == R_68K_GOT8
+                           || r_type == R_68K_GOT16
+                           || r_type == R_68K_GOT32)
+                          && strcmp (h->root.root.string,
+                                     "_GLOBAL_OFFSET_TABLE_") != 0))
+                     && elf_hash_table (info)->dynamic_sections_created)
+                 || (info->shared
+                     && (input_section->flags & SEC_ALLOC) != 0
+                     && (r_type == R_68K_8
+                         || r_type == R_68K_16
+                         || r_type == R_68K_32
+                         || r_type == R_68K_PC8
+                         || r_type == R_68K_PC16
+                         || r_type == R_68K_PC32)))
+               {
+                 /* In these cases, we don't need the relocation
+                    value.  We check specially because in some
+                    obscure cases sec->output_section will be NULL.  */
+                 relocation = 0;
+               }
+             else
+               relocation = (h->root.u.def.value
+                             + sec->output_section->vma
+                             + sec->output_offset);
+           }
+         else if (h->root.type == bfd_link_hash_undefweak)
+           relocation = 0;
+         else if (info->shared)
+           relocation = 0;
+         else
+           {
+             if (!(info->callbacks->undefined_symbol
+                   (info, h->root.root.string, input_bfd,
+                    input_section, rel->r_offset)))
+               return false;
+             relocation = 0;
+           }
+       }
+
+      switch (r_type)
+       {
+       case R_68K_GOT8:
+       case R_68K_GOT16:
+       case R_68K_GOT32:
+         /* Relocation is to the entry for this symbol in the global
+            offset table.  */
+         if (h != NULL
+             && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+           break;
+         /* Fall through.  */
+       case R_68K_GOT8O:
+       case R_68K_GOT16O:
+       case R_68K_GOT32O:
+         /* Relocation is the offset of the entry for this symbol in
+            the global offset table.  */
+
+         if (sgot == NULL)
+           {
+             sgot = bfd_get_section_by_name (dynobj, ".got");
+             BFD_ASSERT (sgot != NULL);
+           }
+
+         if (sgotplt == NULL)
+           {
+             sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
+             BFD_ASSERT (sgotplt != NULL);
+           }
+
+         if (h != NULL)
+           {
+             bfd_vma off;
+
+             off = h->got_offset;
+             BFD_ASSERT (off != (bfd_vma) -1);
+
+             if (!elf_hash_table (info)->dynamic_sections_created)
+               {
+                 /* This is actually a static link.  We must
+                    initialize this entry in the global offset table.
+                    Since the offset must always be a multiple of 4,
+                    we use the least significant bit to record
+                    whether we have initialized it already.
+
+                    When doing a dynamic link, we create a .rela.got
+                    relocation entry to initialize the value.  This
+                    is done in the finish_dynamic_symbol routine.  */
+                 if ((off & 1) != 0)
+                   off &= ~1;
+                 else
+                   {
+                     bfd_put_32 (output_bfd, relocation,
+                                 sgot->contents + off);
+                     h->got_offset |= 1;
+                   }
+               }
+
+             relocation = sgot->output_offset + off;
+             if (r_type == R_68K_GOT8O
+                 || r_type == R_68K_GOT16O
+                 || r_type == R_68K_GOT32O)
+               relocation -= sgotplt->output_offset;
+           }
+         else
+           {
+             bfd_vma off;
+
+             BFD_ASSERT (local_got_offsets != NULL
+                         && local_got_offsets[r_symndx] != (bfd_vma) -1);
+
+             off = local_got_offsets[r_symndx];
+
+             /* The offset must always be a multiple of 4.  We use
+                the least significant bit to record whether we have
+                already generated the necessary reloc.  */
+             if ((off & 1) != 0)
+               off &= ~1;
+             else
+               {
+                 bfd_put_32 (output_bfd, relocation, sgot->contents + off);
+
+                 if (info->shared)
+                   {
+                     asection *srelgot;
+                     Elf_Internal_Rela outrel;
+
+                     srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+                     BFD_ASSERT (srelgot != NULL);
+
+                     outrel.r_offset = (sgot->output_section->vma
+                                        + sgot->output_offset
+                                        + off);
+                     outrel.r_info = ELF32_R_INFO (0, R_68K_RELATIVE);
+                     outrel.r_addend = 0;
+                     bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+                                                (((Elf32_External_Rela *)
+                                                  srelgot->contents)
+                                                 + srelgot->reloc_count));
+                     ++srelgot->reloc_count;
+                   }
+
+                 local_got_offsets[r_symndx] |= 1;
+               }
+
+             relocation = sgot->output_offset + off;
+             if (r_type == R_68K_GOT8O
+                 || r_type == R_68K_GOT16O
+                 || r_type == R_68K_GOT32O)
+               relocation -= sgotplt->output_offset;
+           }
+
+         break;
+
+       case R_68K_PLT8:
+       case R_68K_PLT16:
+       case R_68K_PLT32:
+         /* Relocation is to the entry for this symbol in the
+            procedure linkage table.  */
+
+         /* Resolve a PLT32 reloc against a local symbol directly,
+            without using the procedure linkage table.  */
+         if (h == NULL)
+           break;
+
+         if (h->plt_offset == (bfd_vma) -1)
+           {
+             /* We didn't make a PLT entry for this symbol.  This
+                happens when statically linking PIC code.  */
+             break;
+           }
+
+         if (splt == NULL)
+           {
+             splt = bfd_get_section_by_name (dynobj, ".plt");
+             BFD_ASSERT (splt != NULL);
+           }
+
+         relocation = (splt->output_section->vma
+                       + splt->output_offset
+                       + h->plt_offset);
+         break;
+
+       case R_68K_PLT8O:
+       case R_68K_PLT16O:
+       case R_68K_PLT32O:
+         /* Relocation is the offset of the entry for this symbol in
+            the procedure linkage table.  */
+         BFD_ASSERT (h != NULL);
+
+         if (h->plt_offset == (bfd_vma) -1)
+           {
+             /* We didn't make a PLT entry for this symbol.  This
+                happens when statically linking PIC code.  */
+             break;
+           }
+
+         if (splt == NULL)
+           {
+             splt = bfd_get_section_by_name (dynobj, ".plt");
+             BFD_ASSERT (splt != NULL);
+           }
+
+         relocation = h->plt_offset;
+         break;
+
+       case R_68K_8:
+       case R_68K_16:
+       case R_68K_32:
+       case R_68K_PC8:
+       case R_68K_PC16:
+       case R_68K_PC32:
+         if (info->shared
+             && (input_section->flags & SEC_ALLOC) != 0)
+           {
+             Elf_Internal_Rela outrel;
+
+             /* When generating a shared object, these relocations
+                are copied into the output file to be resolved at run
+                time.  */
+
+             if (sreloc == NULL)
+               {
+                 const char *name;
+
+                 name = (elf_string_from_elf_section
+                         (input_bfd,
+                          elf_elfheader (input_bfd)->e_shstrndx,
+                          elf_section_data (input_section)->rel_hdr.sh_name));
+                 if (name == NULL)
+                   return false;
+
+                 BFD_ASSERT (strncmp (name, ".rela", 5) == 0
+                             && strcmp (bfd_get_section_name (input_bfd,
+                                                              input_section),
+                                        name + 5) == 0);
+
+                 sreloc = bfd_get_section_by_name (dynobj, name);
+                 BFD_ASSERT (sreloc != NULL);
+               }
+
+             outrel.r_offset = (rel->r_offset
+                                + input_section->output_section->vma
+                                + input_section->output_offset);
+             if (h != NULL)
+               {
+                 BFD_ASSERT (h->dynindx != -1);
+                 outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
+                 outrel.r_addend = rel->r_addend;
+               }
+             else
+               {
+                 if (r_type == R_68K_32)
+                   {
+                     outrel.r_info = ELF32_R_INFO (0, R_68K_RELATIVE);
+                     outrel.r_addend = relocation + rel->r_addend;
+                   }
+                 else
+                   {
+                     long indx;
+
+                     sym = local_syms + r_symndx;
+
+                     BFD_ASSERT (ELF_ST_TYPE (sym->st_info) == STT_SECTION);
+
+                     sec = local_sections[r_symndx];
+                     if (sec != NULL && bfd_is_abs_section (sec))
+                       indx = 0;
+                     else if (sec == NULL || sec->owner == NULL)
+                       {
+                         bfd_set_error (bfd_error_bad_value);
+                         return false;
+                       }
+                     else
+                       {
+                         asection *osec;
+
+                         osec = sec->output_section;
+                         indx = elf_section_data (osec)->dynindx;
+                         if (indx == 0)
+                           abort ();
+                       }
+
+                     outrel.r_info = ELF32_R_INFO (indx, r_type);
+                     outrel.r_addend = relocation + rel->r_addend;
+                   }
+               }
+
+             bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+                                        (((Elf32_External_Rela *)
+                                          sreloc->contents)
+                                         + sreloc->reloc_count));
+             ++sreloc->reloc_count;
+
+             /* This reloc will be computed at runtime, so there's no
+                 need to do anything now.  */
+             continue;
+           }
+
+         break;
+
+       default:
+         break;
+       }
+
+      r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+                                   contents, rel->r_offset,
+                                   relocation, rel->r_addend);
+
+      if (r != bfd_reloc_ok)
+       {
+         switch (r)
+           {
+           default:
+           case bfd_reloc_outofrange:
+             abort ();
+           case bfd_reloc_overflow:
+             {
+               const char *name;
+
+               if (h != NULL)
+                 name = h->root.root.string;
+               else
+                 {
+                   name = elf_string_from_elf_section (input_bfd,
+                                                       symtab_hdr->sh_link,
+                                                       sym->st_name);
+                   if (name == NULL)
+                     return false;
+                   if (*name == '\0')
+                     name = bfd_section_name (input_bfd, sec);
+                 }
+               if (!(info->callbacks->reloc_overflow
+                     (info, name, howto->name, (bfd_vma) 0,
+                      input_bfd, input_section, rel->r_offset)))
+                 return false;
+             }
+             break;
+           }
+       }
+    }
+
+  return true;
+}
+
+/* Finish up dynamic symbol handling.  We set the contents of various
+   dynamic sections here.  */
+
+static boolean
+elf_m68k_finish_dynamic_symbol (output_bfd, info, h, sym)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+     struct elf_link_hash_entry *h;
+     Elf_Internal_Sym *sym;
+{
+  bfd *dynobj;
+
+  dynobj = elf_hash_table (info)->dynobj;
+
+  if (h->plt_offset != (bfd_vma) -1)
+    {
+      asection *splt;
+      asection *sgot;
+      asection *srela;
+      bfd_vma plt_index;
+      bfd_vma got_offset;
+      Elf_Internal_Rela rela;
+
+      /* This symbol has an entry in the procedure linkage table.  Set
+        it up.  */
+
+      BFD_ASSERT (h->dynindx != -1);
+
+      splt = bfd_get_section_by_name (dynobj, ".plt");
+      sgot = bfd_get_section_by_name (dynobj, ".got.plt");
+      srela = bfd_get_section_by_name (dynobj, ".rela.plt");
+      BFD_ASSERT (splt != NULL && sgot != NULL && srela != NULL);
+
+      /* Get the index in the procedure linkage table which
+        corresponds to this symbol.  This is the index of this symbol
+        in all the symbols for which we are making plt entries.  The
+        first entry in the procedure linkage table is reserved.  */
+      plt_index = h->plt_offset / PLT_ENTRY_SIZE - 1;
+
+      /* Get the offset into the .got table of the entry that
+        corresponds to this function.  Each .got entry is 4 bytes.
+        The first three are reserved.  */
+      got_offset = (plt_index + 3) * 4;
+
+      /* Fill in the entry in the procedure linkage table.  */
+      memcpy (splt->contents + h->plt_offset, elf_m68k_plt_entry,
+             PLT_ENTRY_SIZE);
+      /* The offset is relative to the first extension word.  */
+      bfd_put_32 (output_bfd,
+                 (sgot->output_section->vma
+                  + sgot->output_offset
+                  + got_offset
+                  - (splt->output_section->vma
+                     + h->plt_offset + 2)),
+                 splt->contents + h->plt_offset + 4);
+
+      bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rela),
+                 splt->contents + h->plt_offset + 10);
+      bfd_put_32 (output_bfd, - (h->plt_offset + 16),
+                 splt->contents + h->plt_offset + 16);
+
+      /* Fill in the entry in the global offset table.  */
+      bfd_put_32 (output_bfd,
+                 (splt->output_section->vma
+                  + splt->output_offset
+                  + h->plt_offset
+                  + 8),
+                 sgot->contents + got_offset);
+
+      /* Fill in the entry in the .rela.plt section.  */
+      rela.r_offset = (sgot->output_section->vma
+                      + sgot->output_offset
+                      + got_offset);
+      rela.r_info = ELF32_R_INFO (h->dynindx, R_68K_JMP_SLOT);
+      rela.r_addend = 0;
+      bfd_elf32_swap_reloca_out (output_bfd, &rela,
+                                ((Elf32_External_Rela *) srela->contents
+                                 + plt_index));
+
+      if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+       {
+         /* Mark the symbol as undefined, rather than as defined in
+            the .plt section.  Leave the value alone.  */
+         sym->st_shndx = SHN_UNDEF;
+       }
+    }
+
+  if (h->got_offset != (bfd_vma) -1)
+    {
+      asection *sgot;
+      asection *srela;
+      Elf_Internal_Rela rela;
+
+      /* This symbol has an entry in the global offset table.  Set it
+        up.  */
+      
+      BFD_ASSERT (h->dynindx != -1);
+
+      sgot = bfd_get_section_by_name (dynobj, ".got");
+      srela = bfd_get_section_by_name (dynobj, ".rela.got");
+      BFD_ASSERT (sgot != NULL && srela != NULL);
+
+      bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got_offset);
+
+      rela.r_offset = (sgot->output_section->vma
+                      + sgot->output_offset
+                      + h->got_offset);
+      rela.r_info = ELF32_R_INFO (h->dynindx, R_68K_GLOB_DAT);
+      rela.r_addend = 0;
+      bfd_elf32_swap_reloca_out (output_bfd, &rela,
+                                ((Elf32_External_Rela *) srela->contents
+                                 + srela->reloc_count));
+      ++srela->reloc_count;
+    }
+
+  if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0)
+    {
+      asection *s;
+      Elf_Internal_Rela rela;
+
+      /* This symbol needs a copy reloc.  Set it up.  */
+
+      BFD_ASSERT (h->dynindx != -1
+                 && (h->root.type == bfd_link_hash_defined
+                     || h->root.type == bfd_link_hash_defweak));
+
+      s = bfd_get_section_by_name (h->root.u.def.section->owner,
+                                  ".rela.bss");
+      BFD_ASSERT (s != NULL);
+
+      rela.r_offset = (h->root.u.def.value
+                      + h->root.u.def.section->output_section->vma
+                      + h->root.u.def.section->output_offset);
+      rela.r_info = ELF32_R_INFO (h->dynindx, R_68K_COPY);
+      rela.r_addend = 0;
+      bfd_elf32_swap_reloca_out (output_bfd, &rela,
+                                ((Elf32_External_Rela *) s->contents
+                                 + s->reloc_count));
+      ++s->reloc_count;
+    }
+
+  /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute.  */
+  if (strcmp (h->root.root.string, "_DYNAMIC") == 0
+      || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+    sym->st_shndx = SHN_ABS;
+
+  return true;
+}
+
+/* Finish up the dynamic sections.  */
+
+static boolean
+elf_m68k_finish_dynamic_sections (output_bfd, info)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+{
+  bfd *dynobj;
+  asection *sgot;
+  asection *sdyn;
+
+  dynobj = elf_hash_table (info)->dynobj;
+
+  sgot = bfd_get_section_by_name (dynobj, ".got.plt");
+  BFD_ASSERT (sgot != NULL);
+  sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
+
+  if (elf_hash_table (info)->dynamic_sections_created)
+    {
+      asection *splt;
+      Elf32_External_Dyn *dyncon, *dynconend;
+
+      splt = bfd_get_section_by_name (dynobj, ".plt");
+      BFD_ASSERT (splt != NULL && sdyn != NULL);
+
+      dyncon = (Elf32_External_Dyn *) sdyn->contents;
+      dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size);
+      for (; dyncon < dynconend; dyncon++)
+       {
+         Elf_Internal_Dyn dyn;
+         const char *name;
+         asection *s;
+
+         bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn);
+
+         switch (dyn.d_tag)
+           {
+           default:
+             break;
+
+           case DT_PLTGOT:
+             name = ".got";
+             goto get_vma;
+           case DT_JMPREL:
+             name = ".rela.plt";
+           get_vma:
+             s = bfd_get_section_by_name (output_bfd, name);
+             BFD_ASSERT (s != NULL);
+             dyn.d_un.d_ptr = s->vma;
+             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+             break;
+
+           case DT_PLTRELSZ:
+             s = bfd_get_section_by_name (output_bfd, ".rela.plt");
+             BFD_ASSERT (s != NULL);
+             if (s->_cooked_size != 0)
+               dyn.d_un.d_val = s->_cooked_size;
+             else
+               dyn.d_un.d_val = s->_raw_size;
+             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+             break;
+
+           case DT_RELASZ:
+             /* My reading of the SVR4 ABI indicates that the
+                procedure linkage table relocs (DT_JMPREL) should be
+                included in the overall relocs (DT_RELA).  This is
+                what Solaris does.  However, UnixWare can not handle
+                that case.  Therefore, we override the DT_RELASZ entry
+                here to make it not include the JMPREL relocs.  Since
+                the linker script arranges for .rela.plt to follow all
+                other relocation sections, we don't have to worry
+                about changing the DT_RELA entry.  */
+             /* FIXME: This comment is from elf32-i386.c, what about
+                the SVR4/m68k implementations? */
+             s = bfd_get_section_by_name (output_bfd, ".rela.plt");
+             if (s != NULL)
+               {
+                 if (s->_cooked_size != 0)
+                   dyn.d_un.d_val -= s->_cooked_size;
+                 else
+                   dyn.d_un.d_val -= s->_raw_size;
+               }
+             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+             break;
+           }
+       }
+
+      /* Fill in the first entry in the procedure linkage table.  */
+      if (splt->_raw_size > 0)
+       {
+         memcpy (splt->contents, elf_m68k_plt0_entry, PLT_ENTRY_SIZE);
+         bfd_put_32 (output_bfd,
+                     (sgot->output_section->vma
+                      + sgot->output_offset + 4
+                      - (splt->output_section->vma + 2)),
+                     splt->contents + 4);
+         bfd_put_32 (output_bfd,
+                     (sgot->output_section->vma
+                      + sgot->output_offset + 8
+                      - (splt->output_section->vma + 10)),
+                     splt->contents + 12);
+       }
+
+      elf_section_data (splt->output_section)->this_hdr.sh_entsize
+       = PLT_ENTRY_SIZE;
+    }
+
+  /* Fill in the first three entries in the global offset table.  */
+  if (sgot->_raw_size > 0)
+    {
+      if (sdyn == NULL)
+       bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents);
+      else
+       bfd_put_32 (output_bfd,
+                   sdyn->output_section->vma + sdyn->output_offset,
+                   sgot->contents);
+      bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4);
+      bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8);
+    }
+
+  elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
+
+  return true;
+}
+
+#define TARGET_BIG_SYM                 bfd_elf32_m68k_vec
+#define TARGET_BIG_NAME                        "elf32-m68k"
+#define ELF_MACHINE_CODE               EM_68K
+#define ELF_MAXPAGESIZE                        0x2000
+#define elf_backend_create_dynamic_sections \
+                                       elf_m68k_create_dynamic_sections
+#define elf_backend_check_relocs       elf_m68k_check_relocs
+#define elf_backend_adjust_dynamic_symbol \
+                                       elf_m68k_adjust_dynamic_symbol
+#define elf_backend_size_dynamic_sections \
+                                       elf_m68k_size_dynamic_sections
+#define elf_backend_relocate_section   elf_m68k_relocate_section
+#define elf_backend_finish_dynamic_symbol \
+                                       elf_m68k_finish_dynamic_symbol
+#define elf_backend_finish_dynamic_sections \
+                                       elf_m68k_finish_dynamic_sections
+
+#include "elf32-target.h"
index 3d007c4..9bf032f 100644 (file)
@@ -102,7 +102,7 @@ static reloc_howto_type elf_sparc_howto_table[] =
   HOWTO(R_SPARC_13,      0,2,13,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_13",      false,0,0x00001fff,true),
   HOWTO(R_SPARC_LO10,    0,2,10,false,0,complain_overflow_dont,    bfd_elf_generic_reloc,"R_SPARC_LO10",    false,0,0x000003ff,true),
   HOWTO(R_SPARC_GOT10,   0,2,10,false,0,complain_overflow_dont,    bfd_elf_generic_reloc,"R_SPARC_GOT10",   false,0,0x000003ff,true),
-  HOWTO(R_SPARC_GOT13,   0,2,13,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_GOT13",   false,0,0x00001fff,true),
+  HOWTO(R_SPARC_GOT13,   0,2,13,false,0,complain_overflow_signed,  bfd_elf_generic_reloc,"R_SPARC_GOT13",   false,0,0x00001fff,true),
   HOWTO(R_SPARC_GOT22,  10,2,22,false,0,complain_overflow_dont,    bfd_elf_generic_reloc,"R_SPARC_GOT22",   false,0,0x003fffff,true),
   HOWTO(R_SPARC_PC10,    0,2,10,true, 0,complain_overflow_dont,    bfd_elf_generic_reloc,"R_SPARC_PC10",    false,0,0x000003ff,true),
   HOWTO(R_SPARC_PC22,   10,2,22,true, 0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_PC22",    false,0,0x003fffff,true),
@@ -573,21 +573,22 @@ elf32_sparc_adjust_dynamic_symbol (info, h)
   dynobj = elf_hash_table (info)->dynobj;
 
   /* Make sure we know what is going on here.  */
-  BFD_ASSERT (dynobj != NULL
-             && ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT)
-                 || ((h->elf_link_hash_flags
-                      & ELF_LINK_HASH_DEF_DYNAMIC) != 0
-                     && (h->elf_link_hash_flags
-                         & ELF_LINK_HASH_REF_REGULAR) != 0
-                     && (h->elf_link_hash_flags
-                         & ELF_LINK_HASH_DEF_REGULAR) == 0
-                     && (h->root.type == bfd_link_hash_defined
-                         || h->root.type == bfd_link_hash_defweak)
-                     && (bfd_get_flavour (h->root.u.def.section->owner)
-                         == bfd_target_elf_flavour)
-                     && (elf_elfheader (h->root.u.def.section->owner)->e_type
-                         == ET_DYN)
-                     && h->root.u.def.section->output_section == NULL)));
+  BFD_ASSERT (dynobj != NULL);
+  BFD_ASSERT ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT)
+             || ((h->elf_link_hash_flags
+                  & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+                 && (h->elf_link_hash_flags
+                     & ELF_LINK_HASH_REF_REGULAR) != 0
+                 && (h->elf_link_hash_flags
+                     & ELF_LINK_HASH_DEF_REGULAR) == 0
+                 && (h->root.type == bfd_link_hash_defined
+                     || h->root.type == bfd_link_hash_defweak)
+                 && (h->root.u.def.section->owner == NULL
+                     || ((elf_elfheader (h->root.u.def.section->owner)->e_type
+                          == ET_DYN)
+                         && (bfd_get_flavour (h->root.u.def.section->owner)
+                             == bfd_target_elf_flavour)
+                         && h->root.u.def.section->output_section == NULL))));
 
   /* If this is a function, put it in the procedure linkage table.  We
      will fill in the contents of the procedure linkage table later