Fri Jan 3 16:58:31 1997 Richard Henderson <rth@tamu.edu>
authorIan Lance Taylor <ian@airs.com>
Fri, 3 Jan 1997 22:09:40 +0000 (22:09 +0000)
committerIan Lance Taylor <ian@airs.com>
Fri, 3 Jan 1997 22:09:40 +0000 (22:09 +0000)
elf64-alpha multiple .got rewrite:

* elf-bfd.h (struct elf_backend_data): Add always_size_sections entry.
(bfd_elf*_mkobject): Don't define here ...
* elfxx-target.h: ... but rather here.  Default always_size_sections
hook to NULL.
* elf.c (elf_mkobject): Rename to bfd_elf_mkobject, since that was
what the #defines in elf-bfd.h transmuted it to anyway.

* section.c: Add SEC_LINKER_CREATED flag.
* bfd-in2.h: Rebuild.
* elf32-i386.c (elf_i386_check_relocs): Add SEC_LINKER_CREATED to
relocation section flags.
(elf_i386_size_dynamic_sections): Use SEC_LINKER_CREATED instead of
SEC_IN_MEMORY to recognize generated bits.
* elf32-m68k.c (elf_m68k_check_relocs, elf_m68k_size_dynamic_sections):
Likewise.
* elf32-mips.c (mips_elf_final_link, mips_elf_create_dynamic_sections,
mips_elf_create_compact_rel_section, mips_elf_create_got_section,
mips_elf_check_relocs, mips_elf_size_dynamic_sections): Likewise.
* elf32-ppc.c (ppc_elf_create_linker_section,
ppc_elf_size_dynamic_sections): Likewise.
* elf32-sparc.c (elf32_sparc_check_relocs,
elf32_sparc_size_dynamic_sections): Likewise.
* elflink.c (_bfd_elf_create_got_section): Add SEC_LINKER_CREATED to
section flags.
(_bfd_elf_create_dynamic_sections): Likewise.
(_bfd_elf_make_linker_section_rela): Likewise.
* elflink.h (elf_link_create_dynamic_sections): Likewise.
(bfd_elf,size_dynamic_sections): Call the always_size_sections hook.
(elf_bfd_final_link): Use SEC_LINKER_CREATED instead of SEC_IN_MEMORY
to identify generated bits.
(elf_link_input_bfd): Likewise.

* elf64-alpha.c: Rewrite everything touching relocations.

14 files changed:
bfd/ChangeLog
bfd/bfd-in2.h
bfd/elf-bfd.h
bfd/elf.c
bfd/elf32-i386.c
bfd/elf32-m68k.c
bfd/elf32-mips.c
bfd/elf32-ppc.c
bfd/elf32-sparc.c
bfd/elf64-alpha.c
bfd/elflink.c
bfd/elflink.h
bfd/elfxx-target.h
bfd/section.c

index 68527fb0e12d63ad209acf1fb5f3c0a3dd9292d7..e7957822dbec0fc0e4a651bfa3d45b9c91097481 100644 (file)
@@ -1,3 +1,41 @@
+Fri Jan  3 16:58:31 1997  Richard Henderson  <rth@tamu.edu>
+
+       elf64-alpha multiple .got rewrite:
+
+       * elf-bfd.h (struct elf_backend_data): Add always_size_sections entry.
+       (bfd_elf*_mkobject): Don't define here ...
+       * elfxx-target.h: ... but rather here.  Default always_size_sections
+       hook to NULL.
+       * elf.c (elf_mkobject): Rename to bfd_elf_mkobject, since that was 
+       what the #defines in elf-bfd.h transmuted it to anyway.
+
+       * section.c: Add SEC_LINKER_CREATED flag.
+       * bfd-in2.h: Rebuild.
+       * elf32-i386.c (elf_i386_check_relocs): Add SEC_LINKER_CREATED to
+       relocation section flags.
+       (elf_i386_size_dynamic_sections): Use SEC_LINKER_CREATED instead of
+       SEC_IN_MEMORY to recognize generated bits.
+       * elf32-m68k.c (elf_m68k_check_relocs, elf_m68k_size_dynamic_sections):
+       Likewise.
+       * elf32-mips.c (mips_elf_final_link, mips_elf_create_dynamic_sections,
+       mips_elf_create_compact_rel_section, mips_elf_create_got_section,
+       mips_elf_check_relocs, mips_elf_size_dynamic_sections): Likewise.
+       * elf32-ppc.c (ppc_elf_create_linker_section,
+       ppc_elf_size_dynamic_sections): Likewise.
+       * elf32-sparc.c (elf32_sparc_check_relocs,
+       elf32_sparc_size_dynamic_sections): Likewise.
+       * elflink.c (_bfd_elf_create_got_section): Add SEC_LINKER_CREATED to 
+       section flags.
+       (_bfd_elf_create_dynamic_sections): Likewise.
+       (_bfd_elf_make_linker_section_rela): Likewise.
+       * elflink.h (elf_link_create_dynamic_sections): Likewise.
+       (bfd_elf,size_dynamic_sections): Call the always_size_sections hook.
+       (elf_bfd_final_link): Use SEC_LINKER_CREATED instead of SEC_IN_MEMORY
+       to identify generated bits.
+       (elf_link_input_bfd): Likewise.
+
+       * elf64-alpha.c: Rewrite everything touching relocations.
+
 start-sanitize-v850
 Fri Jan  3 11:42:53 1997  Michael Meissner  <meissner@tiktok.cygnus.com>
 
index d93a1f198ec5674ede41082b2abcd92093c412bd..c37c0a7732d2de7d02eb8132ff04efb70a0a6dba 100644 (file)
@@ -939,6 +939,12 @@ typedef struct sec
           contents.  */
 #define SEC_LINK_DUPLICATES_SAME_CONTENTS 0x600000
 
+        /* This section was created by the linker as part of dynamic
+          relocation or other arcane processing.  It is skipped when
+          going through the first-pass output, trusting that someone
+          else up the line will take care of it later.  */
+#define SEC_LINKER_CREATED 0x800000
+
         /*  End of section flags.  */
 
         /* Some internal packed boolean fields.  */
index ac27d1fe4e4140f6e2cd70868dfc7bb95e83647b..22532598b14f20459939eeb90af711d67bc9f475 100644 (file)
@@ -360,6 +360,13 @@ struct elf_backend_data
   boolean (*elf_backend_adjust_dynamic_symbol)
     PARAMS ((struct bfd_link_info *info, struct elf_link_hash_entry *h));
 
+  /* The ALWAYS_SIZE_SECTIONS function is called by the backend linker
+     after all the linker input files have been seen but before the
+     section sizes have been set.  This is called after
+     ADJUST_DYNAMIC_SYMBOL, but before SIZE_DYNAMIC_SECTIONS.  */
+  boolean (*elf_backend_always_size_sections)
+    PARAMS ((bfd *output_bfd, struct bfd_link_info *info));
+
   /* The SIZE_DYNAMIC_SECTIONS function is called by the ELF backend
      linker after all the linker input files have been seen but before
      the sections sizes have been set.  This is called after
@@ -660,9 +667,6 @@ extern void bfd_elf_print_symbol PARAMS ((bfd *, PTR, asymbol *,
 
 #define bfd_elf32_print_symbol bfd_elf_print_symbol
 #define bfd_elf64_print_symbol bfd_elf_print_symbol
-#define bfd_elf32_mkobject     bfd_elf_mkobject
-#define bfd_elf64_mkobject     bfd_elf_mkobject
-#define elf_mkobject           bfd_elf_mkobject
 
 extern unsigned long bfd_elf_hash PARAMS ((CONST unsigned char *));
 
index 90c74ad2a54aed495f32d9d53f9f7c77069a8d68..3015461cd5e839cb2ef1ea31ed44b1597fa19900 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -103,7 +103,7 @@ elf_read (abfd, offset, size)
 }
 
 boolean
-elf_mkobject (abfd)
+bfd_elf_mkobject (abfd)
      bfd * abfd;
 {
   /* this just does initialization */
index 9ee5966b2c42d2ffc6c9f537b07f6212eab8b23c..f8b1844685782a7a4056105d3157206bbf537fa6 100644 (file)
@@ -60,6 +60,13 @@ enum reloc_type
     R_386_RELATIVE,
     R_386_GOTOFF,
     R_386_GOTPC,
+    FIRST_INVALID_RELOC,
+    LAST_INVALID_RELOC = 19,
+    /* The remaining relocs are a GNU extension.  */
+    R_386_16 = 20,
+    R_386_PC16,
+    R_386_8,
+    R_386_PC8,
     R_386_max
   };
 
@@ -93,6 +100,20 @@ static reloc_howto_type elf_howto_table[]=
   HOWTO(R_386_RELATIVE,  0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_RELATIVE", true,0xffffffff,0xffffffff,false),
   HOWTO(R_386_GOTOFF,    0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_GOTOFF",   true,0xffffffff,0xffffffff,false),
   HOWTO(R_386_GOTPC,     0,2,32,true,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_GOTPC",    true,0xffffffff,0xffffffff,true),
+  { 11 },
+  { 12 },
+  { 13 },
+  { 14 },
+  { 15 },
+  { 16 },
+  { 17 },
+  { 18 },
+  { 19 },
+  /* The remaining relocs are a GNU extension.  */
+  HOWTO(R_386_16,       0,1,16,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_16",       true,0xffff,0xffff,false),
+  HOWTO(R_386_PC16,     0,1,16,true, 0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_PC16",     true,0xffff,0xffff,true),
+  HOWTO(R_386_8,        0,0,8,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_8",         true,0xff,0xff,false),
+  HOWTO(R_386_PC8,      0,0,8,true, 0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_PC8",       true,0xff,0xff,true),
 };
 
 #ifdef DEBUG_GEN_RELOC
@@ -152,6 +173,23 @@ elf_i386_reloc_type_lookup (abfd, code)
       TRACE ("BFD_RELOC_386_GOTPC");
       return &elf_howto_table[ (int)R_386_GOTPC ];
 
+      /* The remaining relocs are a GNU extension.  */
+    case BFD_RELOC_16:
+      TRACE ("BFD_RELOC_16");
+      return &elf_howto_table[(int) R_386_16];
+
+    case BFD_RELOC_16_PCREL:
+      TRACE ("BFD_RELOC_16_PCREL");
+      return &elf_howto_table[(int) R_386_PC16];
+
+    case BFD_RELOC_8:
+      TRACE ("BFD_RELOC_8");
+      return &elf_howto_table[(int) R_386_8];
+
+    case BFD_RELOC_8_PCREL:
+      TRACE ("BFD_RELOC_8_PCREL");
+      return &elf_howto_table[(int) R_386_PC8];
+
     default:
       break;
     }
@@ -166,20 +204,22 @@ elf_i386_info_to_howto (abfd, cache_ptr, dst)
      arelent           *cache_ptr;
      Elf32_Internal_Rela *dst;
 {
-  BFD_ASSERT (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_386_max);
-
-  cache_ptr->howto = &elf_howto_table[ELF32_R_TYPE(dst->r_info)];
+  abort ();
 }
 
 static void
 elf_i386_info_to_howto_rel (abfd, cache_ptr, dst)
-     bfd               *abfd;
-     arelent           *cache_ptr;
+     bfd *abfd;
+     arelent *cache_ptr;
      Elf32_Internal_Rel *dst;
 {
-  BFD_ASSERT (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_386_max);
+  enum reloc_type type;
+
+  type = (enum reloc_type) ELF32_R_TYPE (dst->r_info);
+  BFD_ASSERT (type < R_386_max);
+  BFD_ASSERT (type < FIRST_INVALID_RELOC || type > LAST_INVALID_RELOC);
 
-  cache_ptr->howto = &elf_howto_table[ELF32_R_TYPE(dst->r_info)];
+  cache_ptr->howto = &elf_howto_table[(int) type];
 }
 \f
 /* Functions for the i386 ELF linker.  */
@@ -222,8 +262,8 @@ static const bfd_byte elf_i386_plt_entry[PLT_ENTRY_SIZE] =
 
 static const bfd_byte elf_i386_pic_plt0_entry[PLT_ENTRY_SIZE] =
 {
-  0xff, 0xb3, 4, 0, 0, 0,      /* pushl 4(%ebx) */     
-  0xff, 0xa3, 8, 0, 0, 0,      /* jmp *8(%ebx) */      
+  0xff, 0xb3, 4, 0, 0, 0,      /* pushl 4(%ebx) */
+  0xff, 0xa3, 8, 0, 0, 0,      /* jmp *8(%ebx) */
   0, 0, 0, 0                   /* pad out to 16 bytes.  */
 };
 
@@ -307,7 +347,7 @@ elf_i386_check_relocs (abfd, info, sec, relocs)
        {
        case R_386_GOT32:
          /* This symbol requires a global offset table entry.  */
-     
+
          if (sgot == NULL)
            {
              sgot = bfd_get_section_by_name (dynobj, ".got");
@@ -327,6 +367,7 @@ elf_i386_check_relocs (abfd, info, sec, relocs)
                                                   | SEC_LOAD
                                                   | SEC_HAS_CONTENTS
                                                   | SEC_IN_MEMORY
+                                                  | SEC_LINKER_CREATED
                                                   | SEC_READONLY))
                      || ! bfd_set_section_alignment (dynobj, srelgot, 2))
                    return false;
@@ -391,22 +432,16 @@ elf_i386_check_relocs (abfd, info, sec, relocs)
        case R_386_PLT32:
          /* 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.  */
-         
+             because this might be a case of linking PIC code which is
+             never referenced by a dynamic object, in which case we
+             don't need to generate a procedure linkage table entry
+             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;
@@ -414,7 +449,6 @@ elf_i386_check_relocs (abfd, info, sec, relocs)
        case R_386_32:
        case R_386_PC32:
          if (info->shared
-             && (sec->flags & SEC_ALLOC) != 0
              && (ELF32_R_TYPE (rel->r_info) != R_386_PC32 || h != NULL))
            {
              /* When creating a shared object, we must copy these
@@ -438,14 +472,15 @@ elf_i386_check_relocs (abfd, info, sec, relocs)
                  sreloc = bfd_get_section_by_name (dynobj, name);
                  if (sreloc == NULL)
                    {
+                     flagword flags;
+
                      sreloc = bfd_make_section (dynobj, name);
+                     flags = (SEC_HAS_CONTENTS | SEC_READONLY
+                              | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+                     if ((sec->flags & SEC_ALLOC) != 0)
+                       flags |= SEC_ALLOC | SEC_LOAD;
                      if (sreloc == NULL
-                         || ! bfd_set_section_flags (dynobj, sreloc,
-                                                     (SEC_ALLOC
-                                                      | SEC_LOAD
-                                                      | SEC_HAS_CONTENTS
-                                                      | SEC_IN_MEMORY
-                                                      | SEC_READONLY))
+                         || ! bfd_set_section_flags (dynobj, sreloc, flags)
                          || ! bfd_set_section_alignment (dynobj, sreloc, 2))
                        return false;
                    }
@@ -453,7 +488,7 @@ elf_i386_check_relocs (abfd, info, sec, relocs)
 
              sreloc->_raw_size += sizeof (Elf32_External_Rel);
            }
-            
+
          break;
 
        default:
@@ -498,17 +533,26 @@ elf_i386_adjust_dynamic_symbol (info, h)
   if (h->type == STT_FUNC
       || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
     {
-      if (! elf_hash_table (info)->dynamic_sections_created)
+      if (! info->shared
+         && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
+         && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0)
        {
          /* 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.  */
+             file, but the symbol was never referred to by a dynamic
+             object.  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;
        }
 
+      /* 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;
+       }
+
       s = bfd_get_section_by_name (dynobj, ".plt");
       BFD_ASSERT (s != NULL);
 
@@ -677,7 +721,7 @@ elf_i386_size_dynamic_sections (output_bfd, info)
       const char *name;
       boolean strip;
 
-      if ((s->flags & SEC_IN_MEMORY) == 0)
+      if ((s->flags & SEC_LINKER_CREATED) == 0)
        continue;
 
       /* It's OK to base decisions on the section name, because none
@@ -766,7 +810,7 @@ elf_i386_size_dynamic_sections (output_bfd, info)
       if (s->contents == NULL && s->_raw_size != 0)
        return false;
     }
-         
+
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       /* Add some entries to the .dynamic section.  We fill in the
@@ -855,7 +899,10 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
       bfd_reloc_status_type r;
 
       r_type = ELF32_R_TYPE (rel->r_info);
-      if (r_type < 0 || r_type >= (int) R_386_max)
+      if (r_type < 0
+         || r_type >= (int) R_386_max
+         || (r_type >= (int) FIRST_INVALID_RELOC
+             && r_type <= (int) LAST_INVALID_RELOC))
        {
          bfd_set_error (bfd_error_bad_value);
          return false;
@@ -923,14 +970,21 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
                          || (h->elf_link_hash_flags
                              & ELF_LINK_HASH_DEF_REGULAR) == 0)
                      && (r_type == R_386_32
-                         || r_type == R_386_PC32)
-                     && (input_section->flags & SEC_ALLOC) != 0))
+                         || r_type == R_386_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 if (sec->output_section == NULL)
+               {
+                 (*_bfd_error_handler)
+                   ("%s: warning: unresolvable relocation against symbol `%s' from %s section",
+                    bfd_get_filename (input_bfd), h->root.root.string,
+                    bfd_get_section_name (input_bfd, input_section));
+                 relocation = 0;
+               }
              else
                relocation = (h->root.u.def.value
                              + sec->output_section->vma
@@ -1105,7 +1159,6 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
        case R_386_32:
        case R_386_PC32:
          if (info->shared
-             && (input_section->flags & SEC_ALLOC) != 0
              && (r_type != R_386_PC32
                  || (h != NULL
                      && (! info->symbolic
@@ -1327,7 +1380,7 @@ elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym)
 
       /* 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");
index 2303f62be3a4bef88e54c6c873f572acf953da38..b64f735515ef58f35e22ed12398a26375f7d6361 100644 (file)
@@ -187,9 +187,9 @@ reloc_type_lookup (abfd, code)
 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.  */
+  0, 0, 0, 0,            /* replaced with offset to .got + 4.  */
   0x4e, 0xfb, 0x01, 0x71, /* jmp ([%pc,addr]) */
-  0, 0, 0, 0,            /* replaced with address of .got + 8.  */
+  0, 0, 0, 0,            /* replaced with offset to .got + 8.  */
   0, 0, 0, 0             /* pad out to 20 bytes.  */
 };
 
@@ -197,8 +197,8 @@ static const bfd_byte elf_m68k_plt0_entry[PLT_ENTRY_SIZE] =
 
 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.  */
+  0x4e, 0xfb, 0x01, 0x71, /* jmp ([%pc,symbol@GOTPC]) */
+  0, 0, 0, 0,            /* replaced with offset to symbol's .got entry.  */
   0x2f, 0x3c,            /* move.l #offset,-(%sp) */
   0, 0, 0, 0,            /* replaced with offset into relocation table.  */
   0x60, 0xff,            /* bra.l .plt */
@@ -256,15 +256,15 @@ elf_m68k_check_relocs (abfd, info, sec, relocs)
        case R_68K_GOT8:
        case R_68K_GOT16:
        case R_68K_GOT32:
+         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:
          /* 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.  */
@@ -292,6 +292,7 @@ elf_m68k_check_relocs (abfd, info, sec, relocs)
                                                  | SEC_LOAD
                                                  | SEC_HAS_CONTENTS
                                                  | SEC_IN_MEMORY
+                                                 | SEC_LINKER_CREATED
                                                  | SEC_READONLY))
                      || !bfd_set_section_alignment (dynobj, srelgot, 2))
                    return false;
@@ -355,20 +356,35 @@ elf_m68k_check_relocs (abfd, info, sec, relocs)
        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.  */
-         
+             because this might be a case of linking PIC code which is
+             never referenced by a dynamic object, in which case we
+             don't need to generate a procedure linkage table entry
+             after all.  */
+
          /* If this is a local symbol, we resolve it directly without
             creating a procedure linkage table entry.  */
          if (h == NULL)
            continue;
 
+         h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+         break;
+
+       case R_68K_PLT8O:
+       case R_68K_PLT16O:
+       case R_68K_PLT32O:
+         /* This symbol requires a procedure linkage table entry.  */
+
+         if (h == NULL)
+           {
+             /* It does not make sense to have this relocation for a
+                local symbol.  FIXME: does it?  How to handle it if
+                it does make sense?  */
+             bfd_set_error (bfd_error_bad_value);
+             return false;
+           }
+
          /* Make sure this symbol is output as a dynamic symbol.  */
          if (h->dynindx == -1)
            {
@@ -389,7 +405,13 @@ elf_m68k_check_relocs (abfd, info, sec, relocs)
        case R_68K_16:
        case R_68K_32:
          if (info->shared
-             && (sec->flags & SEC_ALLOC) != 0)
+             && (sec->flags & SEC_ALLOC) != 0
+             && ((ELF32_R_TYPE (rel->r_info) != R_68K_PC8
+                  && ELF32_R_TYPE (rel->r_info) != R_68K_PC16
+                  && ELF32_R_TYPE (rel->r_info) != R_68K_PC32)
+                 || (!info->symbolic
+                     || (h->elf_link_hash_flags
+                         & ELF_LINK_HASH_DEF_REGULAR) == 0)))
            {
              /* When creating a shared object, we must copy these
                 reloc types into the output file.  We create a reloc
@@ -419,6 +441,7 @@ elf_m68k_check_relocs (abfd, info, sec, relocs)
                                                      | SEC_LOAD
                                                      | SEC_HAS_CONTENTS
                                                      | SEC_IN_MEMORY
+                                                     | SEC_LINKER_CREATED
                                                      | SEC_READONLY))
                          || !bfd_set_section_alignment (dynobj, sreloc, 2))
                        return false;
@@ -472,17 +495,30 @@ elf_m68k_adjust_dynamic_symbol (info, h)
   if (h->type == STT_FUNC
       || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
     {
-      if (!elf_hash_table (info)->dynamic_sections_created)
+      if (! info->shared
+         && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
+         && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0
+         /* We must always create the plt entry if it was referenced
+            by a PLTxxO relocation.  In this case we already recorded
+            it as a dynamic symbol.  */
+         && h->dynindx == -1)
        {
-         /* 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.  */
+         /* This case can occur if we saw a PLTxx reloc in an input
+            file, but the symbol was never referred to by a dynamic
+            object.  In such a case, we don't actually need to build
+            a procedure linkage table, and we can just do a PCxx
+            reloc instead.  */
          BFD_ASSERT ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0);
          return true;
        }
 
+      /* 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;
+       }
+
       s = bfd_get_section_by_name (dynobj, ".plt");
       BFD_ASSERT (s != NULL);
 
@@ -651,7 +687,7 @@ elf_m68k_size_dynamic_sections (output_bfd, info)
       const char *name;
       boolean strip;
 
-      if ((s->flags & SEC_IN_MEMORY) == 0)
+      if ((s->flags & SEC_LINKER_CREATED) == 0)
        continue;
 
       /* It's OK to base decisions on the section name, because none
@@ -800,7 +836,6 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section,
   struct elf_link_hash_entry **sym_hashes;
   bfd_vma *local_got_offsets;
   asection *sgot;
-  asection *sgotplt;
   asection *splt;
   asection *sreloc;
   Elf_Internal_Rela *rel;
@@ -812,7 +847,6 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section,
   local_got_offsets = elf_local_got_offsets (input_bfd);
 
   sgot = NULL;
-  sgotplt = NULL;
   splt = NULL;
   sreloc = NULL;
 
@@ -941,8 +975,8 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section,
        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.  */
+         /* Relocation is to the address of the entry for this symbol
+            in the global offset table.  */
          if (h != NULL
              && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
            break;
@@ -953,105 +987,97 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section,
          /* 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;
+         {
+           bfd_vma off;
 
-             off = h->got_offset;
-             BFD_ASSERT (off != (bfd_vma) -1);
-
-             if (!elf_hash_table (info)->dynamic_sections_created
-                 || (info->shared
-                     && info->symbolic
-                     && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)))
-               {
-                 /* This is actually a static link, or it is a
-                     -Bsymbolic link and the symbol is defined
-                     locally.  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 (sgot == NULL)
+             {
+               sgot = bfd_get_section_by_name (dynobj, ".got");
+               BFD_ASSERT (sgot != NULL);
+             }
 
-                 if (info->shared)
-                   {
-                     asection *srelgot;
-                     Elf_Internal_Rela outrel;
+           if (h != NULL)
+             {
+               off = h->got_offset;
+               BFD_ASSERT (off != (bfd_vma) -1);
 
-                     srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
-                     BFD_ASSERT (srelgot != NULL);
+               if (!elf_hash_table (info)->dynamic_sections_created
+                   || (info->shared
+                       && info->symbolic
+                       && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)))
+                 {
+                   /* This is actually a static link, or it is a
+                      -Bsymbolic link and the symbol is defined
+                      locally.  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;
+                     }
+                 }
+             }
+           else
+             {
+               BFD_ASSERT (local_got_offsets != NULL
+                           && local_got_offsets[r_symndx] != (bfd_vma) -1);
 
-                     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;
-                   }
+               off = local_got_offsets[r_symndx];
 
-                 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;
-           }
+               /* 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 = relocation;
+                       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)
+             {
+               /* This relocation does not use the addend.  */
+               rel->r_addend = 0;
+             }
+           else
+             relocation += sgot->output_section->vma;
+         }
          break;
 
        case R_68K_PLT8:
@@ -1060,7 +1086,7 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section,
          /* Relocation is to the entry for this symbol in the
             procedure linkage table.  */
 
-         /* Resolve a PLT32 reloc against a local symbol directly,
+         /* Resolve a PLTxx reloc against a local symbol directly,
             without using the procedure linkage table.  */
          if (h == NULL)
            break;
@@ -1089,14 +1115,7 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section,
        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;
-           }
+         BFD_ASSERT (h != NULL && h->plt_offset == (bfd_vma) -1);
 
          if (splt == NULL)
            {
@@ -1105,6 +1124,10 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section,
            }
 
          relocation = h->plt_offset;
+
+         /* This relocation does not use the addend.  */
+         rel->r_addend = 0;
+
          break;
 
        case R_68K_PC8:
@@ -1117,9 +1140,16 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section,
        case R_68K_16:
        case R_68K_32:
          if (info->shared
-             && (input_section->flags & SEC_ALLOC) != 0)
+             && (input_section->flags & SEC_ALLOC) != 0
+             && ((r_type != R_68K_PC8
+                  && r_type != R_68K_PC16
+                  && r_type != R_68K_PC32)
+                 || (!info->symbolic
+                     || (h->elf_link_hash_flags
+                         & ELF_LINK_HASH_DEF_REGULAR) == 0)))
            {
              Elf_Internal_Rela outrel;
+             int relocate;
 
              /* When generating a shared object, these relocations
                 are copied into the output file to be resolved at run
@@ -1154,13 +1184,15 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section,
                          & ELF_LINK_HASH_DEF_REGULAR) == 0))
                {
                  BFD_ASSERT (h->dynindx != -1);
+                 relocate = false;
                  outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
-                 outrel.r_addend = rel->r_addend;
+                 outrel.r_addend = relocation + rel->r_addend;
                }
              else
                {
                  if (r_type == R_68K_32)
                    {
+                     relocate = true;
                      outrel.r_info = ELF32_R_INFO (0, R_68K_RELATIVE);
                      outrel.r_addend = relocation + rel->r_addend;
                    }
@@ -1194,6 +1226,7 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section,
                            abort ();
                        }
 
+                     relocate = false;
                      outrel.r_info = ELF32_R_INFO (indx, r_type);
                      outrel.r_addend = relocation + rel->r_addend;
                    }
@@ -1206,8 +1239,11 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section,
              ++sreloc->reloc_count;
 
              /* This reloc will be computed at runtime, so there's no
-                 need to do anything now.  */
-             continue;
+                 need to do anything now, except for R_68K_32
+                 relocations that have been turned into
+                 R_68K_RELATIVE.  */
+             if (!relocate)
+               continue;
            }
 
          break;
@@ -1351,7 +1387,7 @@ elf_m68k_finish_dynamic_symbol (output_bfd, info, h, sym)
 
       /* 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");
@@ -1369,14 +1405,19 @@ elf_m68k_finish_dynamic_symbol (output_bfd, info, h, sym)
       if (info->shared
          && info->symbolic
          && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))
-       rela.r_info = ELF32_R_INFO (0, R_68K_RELATIVE);
+       {
+         rela.r_info = ELF32_R_INFO (0, R_68K_RELATIVE);
+         rela.r_addend = bfd_get_32 (output_bfd,
+                                     sgot->contents + (h->got_offset & ~1));
+       }
       else
        {
-         bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got_offset);
+         bfd_put_32 (output_bfd, (bfd_vma) 0,
+                     sgot->contents + (h->got_offset & ~1));
          rela.r_info = ELF32_R_INFO (h->dynindx, R_68K_GLOB_DAT);
+         rela.r_addend = 0;
        }
 
-      rela.r_addend = 0;
       bfd_elf32_swap_reloca_out (output_bfd, &rela,
                                 ((Elf32_External_Rela *) srela->contents
                                  + srela->reloc_count));
@@ -1480,17 +1521,13 @@ elf_m68k_finish_dynamic_sections (output_bfd, info)
              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
+             /* The procedure linkage table relocs (DT_JMPREL) should
+                not be included in the overall relocs (DT_RELA).
+                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)
                {
index 8c45908147334a7be7af373f4534609e83f35f7f..7fb859206311dc946999d1e4c40fb89a97e0ff3f 100644 (file)
@@ -2415,7 +2415,7 @@ static asymbol mips_elf_scom_symbol;
 static asymbol *mips_elf_scom_symbol_ptr;
 
 /* MIPS ELF also uses an acommon section, which represents an
-   allocated common symbol which may be overridden by a        
+   allocated common symbol which may be overridden by a
    definition in a shared library.  */
 static asection mips_elf_acom_section;
 static asymbol mips_elf_acom_symbol;
@@ -2581,7 +2581,7 @@ mips_elf_modify_segment_map (abfd)
          *pm = m;
        }
     }
-         
+
   /* If there are .dynamic and .mdebug sections, we make a room for
      the RTPROC header.  FIXME: Rewrite without section names.  */
   if (bfd_get_section_by_name (abfd, ".interp") == NULL
@@ -3307,7 +3307,7 @@ mips_elf_output_extsym (h, data)
          else
            {
              name = bfd_section_name (output_section->owner, output_section);
-       
+
              if (strcmp (name, ".text") == 0)
                h->esym.asym.sc = scText;
              else if (strcmp (name, ".data") == 0)
@@ -3373,7 +3373,7 @@ mips_elf_output_extsym (h, data)
 #if 0 /* FIXME?  */
       h->esym.ifd = 0;
 #endif
-    }      
+    }
 
   if (! bfd_ecoff_debug_one_external (einfo->abfd, einfo->debug, einfo->swap,
                                      h->root.root.root.string,
@@ -3768,7 +3768,7 @@ mips_elf_final_link (abfd, info)
                    }
                  else
                    esym.asym.value = last;
-               
+
                  if (! bfd_ecoff_debug_one_external (abfd, &debug, swap,
                                                      name[i], &esym))
                    return false;
@@ -3886,7 +3886,7 @@ mips_elf_final_link (abfd, info)
              if (rtproc_sec == NULL)
                {
                  flagword flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY
-                                   | SEC_READONLY);
+                                   | SEC_LINKER_CREATED | SEC_READONLY);
 
                  rtproc_sec = bfd_make_section (abfd, ".rtproc");
                  if (rtproc_sec == NULL
@@ -5043,7 +5043,7 @@ mips_elf_create_dynamic_sections (abfd, info)
   const char * const *namep;
 
   flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
-          | SEC_READONLY);
+          | SEC_LINKER_CREATED | SEC_READONLY);
 
   /* Mips ABI requests the .dynamic section to be read only.  */
   s = bfd_get_section_by_name (abfd, ".dynamic");
@@ -5175,7 +5175,8 @@ mips_elf_create_compact_rel_section (abfd, info)
 
   if (bfd_get_section_by_name (abfd, ".compact_rel") == NULL)
     {
-      flags = SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_READONLY;
+      flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED
+              | SEC_READONLY);
 
       s = bfd_make_section (abfd, ".compact_rel");
       if (s == NULL
@@ -5188,7 +5189,7 @@ mips_elf_create_compact_rel_section (abfd, info)
 
   return true;
 }
-  
+
 /* Create the .got section to hold the global offset table. */
 
 static boolean
@@ -5205,7 +5206,8 @@ mips_elf_create_got_section (abfd, info)
   if (bfd_get_section_by_name (abfd, ".got") != NULL)
     return true;
 
-  flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+          | SEC_LINKER_CREATED);
 
   s = bfd_make_section (abfd, ".got");
   if (s == NULL
@@ -5436,6 +5438,7 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
                                                       | SEC_LOAD
                                                       | SEC_HAS_CONTENTS
                                                       | SEC_IN_MEMORY
+                                                      | SEC_LINKER_CREATED
                                                       | SEC_READONLY))
                          || ! bfd_set_section_alignment (dynobj, sreloc,
                                                          4))
@@ -5661,7 +5664,7 @@ mips_elf_size_dynamic_sections (output_bfd, info)
         of the dynobj section names depend upon the input files.  */
       name = bfd_get_section_name (dynobj, s);
 
-      if ((s->flags & SEC_IN_MEMORY) == 0)
+      if ((s->flags & SEC_LINKER_CREATED) == 0)
        continue;
 
       strip = false;
@@ -6226,7 +6229,7 @@ mips_elf_finish_dynamic_sections (output_bfd, info)
              time ((time_t *) &dyn.d_un.d_val);
              bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
              break;
-             
+
            case DT_MIPS_ICHECKSUM:
              /* XXX FIXME: */
              break;
@@ -6398,7 +6401,7 @@ mips_elf_finish_dynamic_sections (output_bfd, info)
                          + sizeof (Elf32_External_compact_rel));
            cpt.reserved0 = 0;
            cpt.reserved1 = 0;
-           bfd_elf32_swap_compact_rel_out (output_bfd, &cpt, 
+           bfd_elf32_swap_compact_rel_out (output_bfd, &cpt,
                                            ((Elf32_External_compact_rel *)
                                             s->contents));
 
index bb4b8d4600f433a7e9b3c50a75a9fb67081ca95f..e47c46c06df4906ce977f21006a405b4e8e5c860 100644 (file)
@@ -1290,7 +1290,8 @@ ppc_elf_create_linker_section (abfd, info, which)
       defaults.which = which;
       defaults.hole_written_p = false;
       defaults.alignment = 2;
-      defaults.flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
+      defaults.flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
+                       | SEC_IN_MEMORY | SEC_LINKER_CREATED);
 
       switch (which)
        {
@@ -1648,7 +1649,7 @@ ppc_elf_size_dynamic_sections (output_bfd, info)
       const char *name;
       boolean strip;
 
-      if ((s->flags & SEC_IN_MEMORY) == 0)
+      if ((s->flags & SEC_LINKER_CREATED) == 0)
        continue;
 
       /* It's OK to base decisions on the section name, because none
@@ -2067,6 +2068,7 @@ ppc_elf_check_relocs (abfd, info, sec, relocs)
                                                       | SEC_LOAD
                                                       | SEC_HAS_CONTENTS
                                                       | SEC_IN_MEMORY
+                                                      | SEC_LINKER_CREATED
                                                       | SEC_READONLY))
                          || ! bfd_set_section_alignment (dynobj, sreloc, 2))
                        {
index 3e2343cc221afa229c11d5265320bb37d65b6f32..7cc0048aded0634cbd2db34b6077171603323f39 100644 (file)
@@ -26,7 +26,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 static reloc_howto_type *elf32_sparc_reloc_type_lookup
   PARAMS ((bfd *, bfd_reloc_code_real_type));
-static void elf_info_to_howto
+static void elf32_sparc_info_to_howto
   PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
 static boolean elf32_sparc_check_relocs
   PARAMS ((bfd *, struct bfd_link_info *, asection *,
@@ -64,7 +64,7 @@ static bfd_reloc_status_type sparc_elf_notsupported_reloc
 static bfd_reloc_status_type sparc_elf_wdisp16_reloc
   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
 
-reloc_howto_type _bfd_sparc_elf_howto_table[] = 
+reloc_howto_type _bfd_sparc_elf_howto_table[] =
 {
   HOWTO(R_SPARC_NONE,      0,0, 0,false,0,complain_overflow_dont,    bfd_elf_generic_reloc,  "R_SPARC_NONE",    false,0,0x00000000,true),
   HOWTO(R_SPARC_8,         0,0, 8,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc,  "R_SPARC_8",       false,0,0x000000ff,true),
@@ -126,7 +126,7 @@ reloc_howto_type _bfd_sparc_elf_howto_table[] =
 #endif
   HOWTO(R_SPARC_WDISP16,   2,2,16,true, 0,complain_overflow_signed,  sparc_elf_wdisp16_reloc,"R_SPARC_WDISP16", false,0,0x00000000,true),
   HOWTO(R_SPARC_WDISP19,   2,2,22,true, 0,complain_overflow_signed,  bfd_elf_generic_reloc,  "R_SPARC_WDISP19", false,0,0x0007ffff,true),
-  HOWTO(R_SPARC_GLOB_JMP,  0,0,00,false,0,complain_overflow_dont,    bfd_elf_generic_reloc,  "R_SPARC_GLOB_DAT",false,0,0x00000000,true),
+  HOWTO(R_SPARC_GLOB_JMP,  0,0,00,false,0,complain_overflow_dont,    bfd_elf_generic_reloc,  "R_SPARC_GLOB_JMP",false,0,0x00000000,true),
   HOWTO(R_SPARC_7,         0,2, 7,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc,  "R_SPARC_7",       false,0,0x0000007f,true),
   HOWTO(R_SPARC_5,         0,2, 5,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc,  "R_SPARC_5",       false,0,0x0000001f,true),
   HOWTO(R_SPARC_6,         0,2, 6,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc,  "R_SPARC_6",       false,0,0x0000003f,true),
@@ -202,7 +202,7 @@ elf32_sparc_reloc_type_lookup (abfd, code)
    and elf64-sparc.c has its own copy.  */
 
 static void
-elf_info_to_howto (abfd, cache_ptr, dst)
+elf32_sparc_info_to_howto (abfd, cache_ptr, dst)
      bfd *abfd;
      arelent *cache_ptr;
      Elf_Internal_Rela *dst;
@@ -394,6 +394,7 @@ elf32_sparc_check_relocs (abfd, info, sec, relocs)
                                                   | SEC_LOAD
                                                   | SEC_HAS_CONTENTS
                                                   | SEC_IN_MEMORY
+                                                  | SEC_LINKER_CREATED
                                                   | SEC_READONLY))
                      || ! bfd_set_section_alignment (dynobj, srelgot, 2))
                    return false;
@@ -512,8 +513,7 @@ elf32_sparc_check_relocs (abfd, info, sec, relocs)
        case R_SPARC_13:
        case R_SPARC_LO10:
        case R_SPARC_UA32:
-         if (info->shared
-             && (sec->flags & SEC_ALLOC) != 0)
+         if (info->shared)
            {
              /* When creating a shared object, we must copy these
                  relocs into the output file.  We create a reloc
@@ -536,14 +536,15 @@ elf32_sparc_check_relocs (abfd, info, sec, relocs)
                  sreloc = bfd_get_section_by_name (dynobj, name);
                  if (sreloc == NULL)
                    {
+                     flagword flags;
+
                      sreloc = bfd_make_section (dynobj, name);
+                     flags = (SEC_HAS_CONTENTS | SEC_READONLY
+                              | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+                     if ((sec->flags & SEC_ALLOC) != 0)
+                       flags |= SEC_ALLOC | SEC_LOAD;
                      if (sreloc == NULL
-                         || ! bfd_set_section_flags (dynobj, sreloc,
-                                                     (SEC_ALLOC
-                                                      | SEC_LOAD
-                                                      | SEC_HAS_CONTENTS
-                                                      | SEC_IN_MEMORY
-                                                      | SEC_READONLY))
+                         || ! bfd_set_section_flags (dynobj, sreloc, flags)
                          || ! bfd_set_section_alignment (dynobj, sreloc, 2))
                        return false;
                    }
@@ -778,7 +779,7 @@ elf32_sparc_size_dynamic_sections (output_bfd, info)
       const char *name;
       boolean strip;
 
-      if ((s->flags & SEC_IN_MEMORY) == 0)
+      if ((s->flags & SEC_LINKER_CREATED) == 0)
        continue;
 
       /* It's OK to base decisions on the section name, because none
@@ -1043,7 +1044,6 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section,
                      && (! info->symbolic
                          || (h->elf_link_hash_flags
                              & ELF_LINK_HASH_DEF_REGULAR) == 0)
-                     && (input_section->flags & SEC_ALLOC) != 0
                      && (r_type == R_SPARC_8
                          || r_type == R_SPARC_16
                          || r_type == R_SPARC_32
@@ -1232,8 +1232,7 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section,
        case R_SPARC_13:
        case R_SPARC_LO10:
        case R_SPARC_UA32:
-         if (info->shared
-             && (input_section->flags & SEC_ALLOC) != 0)
+         if (info->shared)
            {
              Elf_Internal_Rela outrel;
 
@@ -1328,7 +1327,7 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section,
 
        default:
          break;
-       }               
+       }
 
       if (r_type != R_SPARC_WDISP16)
        r = _bfd_final_link_relocate (howto, input_bfd, input_section,
@@ -1673,10 +1672,8 @@ elf32_sparc_merge_private_bfd_data (ibfd, obfd)
 {
   boolean error;
 
-  /* This function is selected based on the input vector.  We only
-     want to copy information over if the output BFD also uses Elf
-     format.  */
-  if (bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
     return true;
 
   error = false;
@@ -1784,6 +1781,7 @@ elf32_sparc_final_write_processing (abfd, linker)
 #define ELF_MAXPAGESIZE 0x10000
 
 #define bfd_elf32_bfd_reloc_type_lookup        elf32_sparc_reloc_type_lookup
+#define elf_info_to_howto              elf32_sparc_info_to_howto
 #define elf_backend_create_dynamic_sections \
                                        _bfd_elf_create_dynamic_sections
 #define elf_backend_check_relocs       elf32_sparc_check_relocs
index 98882731845edc98c4527a7200b239c5ed582776..ffc612f0785244187a17c15e64d90df9d15c0bc7 100644 (file)
@@ -1,4 +1,4 @@
-/* ALPHA-specific support for 64-bit ELF
+/* Alpha specific support for 64-bit ELF
    Copyright 1996 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@tamu.edu>.
 
@@ -53,18 +53,12 @@ static struct bfd_link_hash_table * elf64_alpha_bfd_link_hash_table_create
 
 static bfd_reloc_status_type elf64_alpha_reloc_nil
   PARAMS((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static bfd_reloc_status_type elf64_alpha_reloc_bad
+  PARAMS((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
 static bfd_reloc_status_type elf64_alpha_do_reloc_gpdisp
   PARAMS((bfd *, bfd_vma, bfd_byte *, bfd_byte *));
 static bfd_reloc_status_type elf64_alpha_reloc_gpdisp
   PARAMS((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
-static bfd_reloc_status_type elf64_alpha_reloc_op_push
-  PARAMS((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
-static bfd_reloc_status_type elf64_alpha_reloc_op_store
-  PARAMS((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
-static bfd_reloc_status_type elf64_alpha_reloc_op_psub
-  PARAMS((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
-static bfd_reloc_status_type elf64_alpha_reloc_op_prshift
-  PARAMS((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
 
 static reloc_howto_type * elf64_alpha_bfd_reloc_type_lookup
   PARAMS((bfd *, bfd_reloc_code_real_type));
@@ -99,6 +93,11 @@ struct alpha_elf_link_hash_entry;
 static boolean elf64_alpha_output_extsym
   PARAMS((struct alpha_elf_link_hash_entry *, PTR));
 
+static boolean elf64_alpha_can_merge_gots
+  PARAMS((bfd *, bfd *));
+static void elf64_alpha_merge_gots
+  PARAMS((bfd *, bfd *));
+
 static boolean elf64_alpha_check_relocs
   PARAMS((bfd *, struct bfd_link_info *, asection *sec,
          const Elf_Internal_Rela *));
@@ -120,9 +119,6 @@ static boolean elf64_alpha_final_link
   PARAMS((bfd *, struct bfd_link_info *));
 
 \f
-#define alpha_elf_tdata(bfd) \
-       ((struct alpha_elf_obj_tdata *)elf_tdata(bfd)->tdata)
-
 struct alpha_elf_link_hash_entry
 {
   struct elf_link_hash_entry root;
@@ -130,11 +126,50 @@ struct alpha_elf_link_hash_entry
   /* External symbol information.  */
   EXTR esym;
 
-  unsigned char flags;
+  /* Cumulative flags for all the .got entries.  */
+  int flags;
+
   /* Contexts (LITUSE) in which a literal was referenced.  */
-#define ALPHA_ELF_LINK_HASH_LU_ADDR 01
-#define ALPHA_ELF_LINK_HASH_LU_MEM 02
-#define ALPHA_ELF_LINK_HASH_LU_FUNC 04
+#define ALPHA_ELF_LINK_HASH_LU_ADDR 0x01
+#define ALPHA_ELF_LINK_HASH_LU_MEM  0x02
+#define ALPHA_ELF_LINK_HASH_LU_BYTE 0x04
+#define ALPHA_ELF_LINK_HASH_LU_FUNC 0x08
+
+  /* Used to implement multiple .got subsections.  */
+  struct alpha_elf_got_entry
+  {
+    struct alpha_elf_got_entry *next;
+
+    /* which .got subsection?  */
+    bfd *gotobj;
+
+    /* the addend in effect for this entry.  */
+    bfd_vma addend;
+
+    /* the .got offset for this entry.  */
+    int got_offset;
+
+    int flags;
+
+    /* An additional flag.  */
+#define ALPHA_ELF_GOT_ENTRY_RELOCS_DONE 0x10
+  } *got_entries;
+
+  /* used to count non-got, non-plt relocations for delayed sizing
+     of relocation sections.  */
+  struct alpha_elf_reloc_entry
+  {
+    struct alpha_elf_reloc_entry *next;
+
+    /* which .reloc section? */
+    asection *srel;
+
+    /* what kind of relocation? */
+    unsigned long rtype;
+
+    /* how many did we find?  */
+    unsigned long count;
+  } *reloc_entries;
 };
 
 /* Alpha ELF linker hash table.  */
@@ -142,6 +177,10 @@ struct alpha_elf_link_hash_entry
 struct alpha_elf_link_hash_table
 {
   struct elf_link_hash_table root;
+
+  /* The head of a list of .got subsections linked through
+     alpha_elf_tdata(abfd)->got_link_next.  */
+  bfd *got_list;
 };
 
 /* Look up an entry in a Alpha ELF linker hash table.  */
@@ -164,6 +203,19 @@ struct alpha_elf_link_hash_table
 #define alpha_elf_hash_table(p) \
   ((struct alpha_elf_link_hash_table *) ((p)->hash))
 
+/* Get the object's symbols as our own entry type.  */
+
+#define alpha_elf_sym_hashes(abfd) \
+  ((struct alpha_elf_link_hash_entry **)elf_sym_hashes(abfd))
+
+/* Should we do dynamic things to this symbol?  */
+
+#define alpha_elf_dynamic_symbol_p(h, info)                            \
+  (((info)->shared && !(info)->symbolic)                               \
+   || (((h)->elf_link_hash_flags                                       \
+       & (ELF_LINK_HASH_DEF_DYNAMIC | ELF_LINK_HASH_REF_REGULAR))      \
+       == (ELF_LINK_HASH_DEF_DYNAMIC | ELF_LINK_HASH_REF_REGULAR)))
+
 /* Create an entry in a Alpha ELF linker hash table.  */
 
 static struct bfd_hash_entry *
@@ -196,6 +248,8 @@ elf64_alpha_link_hash_newfunc (entry, table, string)
         not been set.  -1 means there is no associated ifd.  */
       ret->esym.ifd = -2;
       ret->flags = 0;
+      ret->got_entries = NULL;
+      ret->reloc_entries = NULL;
     }
 
   return (struct bfd_hash_entry *) ret;
@@ -224,7 +278,50 @@ elf64_alpha_bfd_link_hash_table_create (abfd)
   return &ret->root.root;
 }
 \f
+/* We have some private fields hanging off of the elf_tdata structure.  */
+
+struct alpha_elf_obj_tdata
+{
+  struct elf_obj_tdata root;
+
+  /* For every input file, these are the got entries for that object's
+     local symbols.  */
+  struct alpha_elf_got_entry ** local_got_entries;
 
+  /* For every input file, this is the object that owns the got that
+     this input file uses.  */
+  bfd *gotobj;
+
+  /* For every got, this is a linked list through the objects using this got */
+  bfd *in_got_link_next;
+
+  /* For every got, this is a link to the next got subsegment.  */
+  bfd *got_link_next;
+
+  /* For every got, this is the section.  */
+  asection *got;
+
+  /* For every got, this is it's total number of *entries*.  */
+  int total_got_entries;
+
+  /* For every got, this is the sum of the number of *entries* required
+     to hold all of the member object's local got.  */
+  int n_local_got_entries;
+};
+
+#define alpha_elf_tdata(abfd) \
+  ((struct alpha_elf_obj_tdata *) (abfd)->tdata.any)
+
+static boolean
+elf64_alpha_mkobject (abfd)
+     bfd *abfd;
+{
+  abfd->tdata.any = bfd_zalloc (abfd, sizeof (struct alpha_elf_obj_tdata));
+  if (abfd->tdata.any == NULL)
+    return false;
+  return true;
+}
+\f
 /* In case we're on a 32-bit machine, construct a 64-bit "-1" value
    from smaller values.  Start with zero, widen, *then* decrement.  */
 #define MINUS_ONE      (((bfd_vma)0) - 1)
@@ -301,13 +398,13 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         0,                     /* special_function */
-        "LITERAL",             /* name */
+        "ELF_LITERAL",         /* name */
         false,                 /* partial_inplace */
         0xffff,                /* src_mask */
         0xffff,                /* dst_mask */
         false),                /* pcrel_offset */
 
-  /* This reloc only appears immediately following a LITERAL reloc.
+  /* This reloc only appears immediately following an ELF_LITERAL reloc.
      It identifies a use of the literal.  The symbol index is special:
      1 means the literal address is in the base register of a memory
      format instruction; 2 means the literal address is in the byte
@@ -336,7 +433,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
      current location; the load will always be done against a register
      holding the current address.
 
-     NOTE: Unlike ECOFF, partial inplace relocation is not done.  If
+     NOTE: Unlike ECOFF, partial in-place relocation is not done.  If
      any offset is present in the instructions, it is an offset from
      the register to the ldah instruction.  This lets us avoid any
      stupid hackery like inventing a gp value to do partial relocation
@@ -441,7 +538,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        elf64_alpha_reloc_op_push, /* special_function */
+        elf64_alpha_reloc_bad, /* special_function */
         "OP_PUSH",             /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -457,7 +554,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        elf64_alpha_reloc_op_store, /* special_function */
+        elf64_alpha_reloc_bad, /* special_function */
         "OP_STORE",            /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -473,7 +570,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        elf64_alpha_reloc_op_psub, /* special_function */
+        elf64_alpha_reloc_bad, /* special_function */
         "OP_PSUB",             /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -489,7 +586,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        elf64_alpha_reloc_op_prshift, /* special_function */
+        elf64_alpha_reloc_bad, /* special_function */
         "OP_PRSHIFT",          /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -508,7 +605,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         "COPY",
         false,
         0,
-        0, 
+        0,
         true),
 
   HOWTO (R_ALPHA_GLOB_DAT,
@@ -522,7 +619,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         "GLOB_DAT",
         false,
         0,
-        0, 
+        0,
         true),
 
   HOWTO (R_ALPHA_JMP_SLOT,
@@ -547,13 +644,15 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         0,
         complain_overflow_dont,
         bfd_elf_generic_reloc,
-        "RELATIVE", 
+        "RELATIVE",
         false,
         0,
         0,
         true)
 };
 
+/* A relocation function which doesn't do anything.  */
+
 static bfd_reloc_status_type
 elf64_alpha_reloc_nil (abfd, reloc, sym, data, sec, output_bfd, error_message)
      bfd *abfd;
@@ -569,18 +668,38 @@ elf64_alpha_reloc_nil (abfd, reloc, sym, data, sec, output_bfd, error_message)
   return bfd_reloc_ok;
 }
 
+/* A relocation function used for an unsupported reloc.  */
+
+static bfd_reloc_status_type
+elf64_alpha_reloc_bad (abfd, reloc, sym, data, sec, output_bfd, error_message)
+     bfd *abfd;
+     arelent *reloc;
+     asymbol *sym;
+     PTR data;
+     asection *sec;
+     bfd *output_bfd;
+     char **error_message;
+{
+  if (output_bfd)
+    reloc->address += sec->output_offset;
+  return bfd_reloc_notsupported;
+}
+
+/* Do the work of the GPDISP relocation.  */
+
 static bfd_reloc_status_type
 elf64_alpha_do_reloc_gpdisp (abfd, gpdisp, p_ldah, p_lda)
      bfd *abfd;
      bfd_vma gpdisp;
-     bfd_byte *p_ldah, *p_lda;
+     bfd_byte *p_ldah;
+     bfd_byte *p_lda;
 {
   bfd_reloc_status_type ret = bfd_reloc_ok;
   bfd_vma addend;
   unsigned long i_ldah, i_lda;
 
-  i_ldah = bfd_get_32(abfd, p_ldah);
-  i_lda = bfd_get_32(abfd, p_lda);
+  i_ldah = bfd_get_32 (abfd, p_ldah);
+  i_lda = bfd_get_32 (abfd, p_lda);
 
   /* Complain if the instructions are not correct.  */
   if (((i_ldah >> 26) & 0x3f) != 0x09
@@ -594,7 +713,7 @@ elf64_alpha_do_reloc_gpdisp (abfd, gpdisp, p_ldah, p_lda)
 
   gpdisp += addend;
 
-  if ((bfd_signed_vma)gpdisp < -(bfd_signed_vma)0x80000000
+  if ((bfd_signed_vma) gpdisp < -(bfd_signed_vma)0x80000000
       || gpdisp >= 0x7fff8000)
     ret = bfd_reloc_overflow;
 
@@ -609,6 +728,8 @@ elf64_alpha_do_reloc_gpdisp (abfd, gpdisp, p_ldah, p_lda)
   return ret;
 }
 
+/* The special function for the GPDISP reloc.  */
+
 static bfd_reloc_status_type
 elf64_alpha_reloc_gpdisp (abfd, reloc_entry, sym, data, input_section,
                          output_bfd, err_msg)
@@ -635,7 +756,7 @@ elf64_alpha_reloc_gpdisp (abfd, reloc_entry, sym, data, input_section,
       reloc_entry->address + reloc_entry->addend > input_section->_cooked_size)
     return bfd_reloc_outofrange;
 
-  /* The gp used in the portion of the output object to which this 
+  /* The gp used in the portion of the output object to which this
      input object belongs is cached on the input bfd.  */
   gp = _bfd_get_gp_value (abfd);
 
@@ -643,184 +764,18 @@ elf64_alpha_reloc_gpdisp (abfd, reloc_entry, sym, data, input_section,
                + input_section->output_offset
                + reloc_entry->address);
 
-  p_ldah = (bfd_byte *)data + reloc_entry->address;
+  p_ldah = (bfd_byte *) data + reloc_entry->address;
   p_lda = p_ldah + reloc_entry->addend;
 
   ret = elf64_alpha_do_reloc_gpdisp (abfd, gp - relocation, p_ldah, p_lda);
 
   /* Complain if the instructions are not correct.  */
   if (ret == bfd_reloc_dangerous)
-    {
-      *err_msg = "GPDISP relocation did not find ldah and lda instructions";
-    }
+    *err_msg = "GPDISP relocation did not find ldah and lda instructions";
 
   return ret;
 }
 
-/* Due to the nature of the stack operations, I don't think more
-   that one entry is useful.  Test this theory by setting the
-   stack size to a minimum.  */
-/* FIXME: BFD should not use static variables.  */
-#define OP_STACK_SIZE 1
-static bfd_vma elf64_alpha_op_stack[OP_STACK_SIZE];
-static int elf64_alpha_op_tos;
-
-static bfd_reloc_status_type
-elf64_alpha_reloc_op_push (abfd, reloc_entry, sym, data, input_section,
-                          output_bfd, err_msg)
-     bfd *abfd;
-     arelent *reloc_entry;
-     asymbol *sym;
-     PTR data;
-     asection *input_section;
-     bfd *output_bfd;
-     char **err_msg;
-{
-  bfd_reloc_status_type r = bfd_reloc_ok;
-  bfd_vma value;
-
-  /* Don't do anything if we're not doing a final link.  */
-  if (output_bfd)
-    {
-      reloc_entry->address += input_section->output_offset;
-      return bfd_reloc_ok;
-    }
-
-  if (elf64_alpha_op_tos >= OP_STACK_SIZE)
-    {
-      *err_msg = "operation stack overflow";
-      return bfd_reloc_dangerous;
-    }
-
-  /* Get the symbol value.  */
-  /* FIXME: We should fail if this is a dynamic symbol.  Check on that.  */
-  if (bfd_is_und_section (sym->section))
-    r = bfd_reloc_undefined;
-  if (bfd_is_com_section (sym->section))
-    value = 0;
-  else
-    value = sym->value;
-  value += sym->section->output_section->vma;
-  value += sym->section->output_offset;
-  value += reloc_entry->addend;
-
-  elf64_alpha_op_stack[elf64_alpha_op_tos++] = value;
-
-  return r;
-}
-
-static bfd_reloc_status_type
-elf64_alpha_reloc_op_store (abfd, reloc_entry, sym, data, input_section,
-                           output_bfd, err_msg)
-     bfd *abfd;
-     arelent *reloc_entry;
-     asymbol *sym;
-     PTR data;
-     asection *input_section;
-     bfd *output_bfd;
-     char **err_msg;
-{
-  int size, offset;
-  bfd_vma value;
-
-  /* Don't do anything before the final link.  */
-  if (output_bfd)
-    {
-      reloc_entry->address += input_section->output_offset;
-      return bfd_reloc_ok;
-    }
-
-  if (elf64_alpha_op_tos <= 0)
-    {
-      *err_msg = "operation stack underflow";
-      return bfd_reloc_dangerous;
-    }
-
-  /* The offset and size for this reloc are encoded into the addend
-     field by alpha_adjust_reloc_in.  */
-  offset = (reloc_entry->addend >> 8) & 0xff;
-  size = reloc_entry->addend & 0xff;
-
-  value = bfd_get_64 (abfd, data + reloc_entry->address);
-  value &= ~((((bfd_vma)1 << size) - 1) << offset);
-  value |= (elf64_alpha_op_stack[--elf64_alpha_op_tos] 
-           & (((bfd_vma)1 << size) - 1)) << offset;
-  bfd_put_64 (abfd, value, data + reloc_entry->address);
-
-  return bfd_reloc_ok;
-}
-
-static bfd_reloc_status_type
-elf64_alpha_reloc_op_psub (abfd, reloc_entry, sym, data, input_section,
-                          output_bfd, err_msg)
-     bfd *abfd;
-     arelent *reloc_entry;
-     asymbol *sym;
-     PTR data;
-     asection *input_section;
-     bfd *output_bfd;
-     char **err_msg;
-{
-  bfd_reloc_status_type r;
-  bfd_vma value;
-
-  /* Don't do anything before the final link.  */
-  if (output_bfd)
-    {
-      reloc_entry->address += input_section->output_offset;
-      return bfd_reloc_ok;
-    }
-
-  if (elf64_alpha_op_tos <= 0)
-    {
-      *err_msg = "operation stack underflow";
-      return bfd_reloc_dangerous;
-    }
-
-  if (bfd_is_und_section (sym->section))
-    r = bfd_reloc_undefined;
-  if (bfd_is_com_section (sym->section))
-    value = 0;
-  else
-    value = sym->value;
-  value += sym->section->output_section->vma;
-  value += sym->section->output_offset;
-  value += reloc_entry->addend;
-
-  elf64_alpha_op_stack[elf64_alpha_op_tos-1] -= value;
-
-  return r;
-}
-
-static bfd_reloc_status_type
-elf64_alpha_reloc_op_prshift (abfd, reloc_entry, sym, data, input_section,
-                             output_bfd, err_msg)
-     bfd *abfd;
-     arelent *reloc_entry;
-     asymbol *sym;
-     PTR data;
-     asection *input_section;
-     bfd *output_bfd;
-     char **err_msg;
-{
-  /* Don't do anything before the final link.  */
-  if (output_bfd)
-    {
-      reloc_entry->address += input_section->output_offset;
-      return bfd_reloc_ok;
-    }
-
-  if (elf64_alpha_op_tos <= 0)
-    {
-      *err_msg = "operation stack underflow";
-      return bfd_reloc_dangerous;
-    }
-
-  elf64_alpha_op_stack[elf64_alpha_op_tos-1] >>= reloc_entry->addend;
-
-  return bfd_reloc_ok;
-}
-
 /* A mapping from BFD reloc types to Alpha ELF reloc types.  */
 
 struct elf_reloc_map
@@ -836,20 +791,14 @@ static const struct elf_reloc_map elf64_alpha_reloc_map[] =
   {BFD_RELOC_64,               R_ALPHA_REFQUAD},
   {BFD_RELOC_CTOR,             R_ALPHA_REFQUAD},
   {BFD_RELOC_GPREL32,          R_ALPHA_GPREL32},
-  {BFD_RELOC_ALPHA_LITERAL,    R_ALPHA_LITERAL},
+  {BFD_RELOC_ALPHA_ELF_LITERAL,        R_ALPHA_LITERAL},
   {BFD_RELOC_ALPHA_LITUSE,     R_ALPHA_LITUSE},
   {BFD_RELOC_ALPHA_GPDISP,     R_ALPHA_GPDISP},
-  {BFD_RELOC_23_PCREL_S2,      R_ALPHA_BRADDR},  
-  {BFD_RELOC_ALPHA_HINT,       R_ALPHA_HINT},  
-  {BFD_RELOC_16_PCREL,         R_ALPHA_SREL16},  
-  {BFD_RELOC_32_PCREL,         R_ALPHA_SREL32},  
-  {BFD_RELOC_64_PCREL,         R_ALPHA_SREL64},  
-#if 0
-  {BFD_RELOC_ALPHA_OP_PUSH,    R_ALPHA_OP_PUSH},
-  {BFD_RELOC_ALPHA_OP_STORE,   R_ALPHA_OP_STORE},
-  {BFD_RELOC_ALPHA_OP_PSUB,    R_ALPHA_OP_PSUB},
-  {BFD_RELOC_ALPHA_OP_PRSHIFT, R_ALPHA_OP_PRSHIFT}
-#endif
+  {BFD_RELOC_23_PCREL_S2,      R_ALPHA_BRADDR},
+  {BFD_RELOC_ALPHA_HINT,       R_ALPHA_HINT},
+  {BFD_RELOC_16_PCREL,         R_ALPHA_SREL16},
+  {BFD_RELOC_32_PCREL,         R_ALPHA_SREL32},
+  {BFD_RELOC_64_PCREL,         R_ALPHA_SREL64},
 };
 
 /* Given a BFD reloc type, return a HOWTO structure.  */
@@ -897,7 +846,7 @@ elf64_alpha_info_to_howto (abfd, cache_ptr, dst)
 #define PLT_ENTRY_WORD2                0x239c0000      /* lda  $28, 0($28) */
 #define PLT_ENTRY_WORD3                0xc3e00000      /* br   $31, plt0   */
 
-#define RESERVED_GOT_ENTRIES 1
+#define MAX_GOT_ENTRIES                (64*1024 / 8)
 
 #define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so"
 \f
@@ -910,7 +859,7 @@ elf64_alpha_object_p (abfd)
   return bfd_default_set_arch_mach (abfd, bfd_arch_alpha, 0);
 }
 \f
-/* Handle a alpha specific section when reading an object file.  This
+/* Handle an Alpha specific section when reading an object file.  This
    is called when elfcode.h finds a section with an unknown type.
    FIXME: We need to handle the SHF_MIPS_GPREL flag, but I'm not sure
    how to.  */
@@ -1023,16 +972,18 @@ elf64_alpha_fake_sections (abfd, hdr, sec)
       hdr->sh_entsize = 0;
       hdr->sh_info = SIZEOF_ALPHA_DYNSYM_SECNAMES;
     }
+#endif
   else if (strcmp (name, ".sdata") == 0
           || strcmp (name, ".sbss") == 0
           || strcmp (name, ".lit4") == 0
           || strcmp (name, ".lit8") == 0)
     hdr->sh_flags |= SHF_ALPHA_GPREL;
-#endif
 
   return true;
 }
 
+/* Return the number of additional phdrs we will need.  */
+
 static int
 elf64_alpha_additional_program_headers (abfd)
      bfd *abfd;
@@ -1059,62 +1010,40 @@ elf64_alpha_additional_program_headers (abfd)
   return ret;
 }
 
+/* Create the .got section.  */
+
 static boolean
 elf64_alpha_create_got_section(abfd, info)
      bfd *abfd;
      struct bfd_link_info *info;
 {
   asection *s;
-  struct elf_link_hash_entry *h;
 
   if (bfd_get_section_by_name (abfd, ".got"))
     return true;
 
-  s = bfd_make_section(abfd, ".rela.got");
-  if (s == NULL
-      || !bfd_set_section_flags (abfd, s, (SEC_ALLOC | SEC_LOAD
-                                          | SEC_HAS_CONTENTS | SEC_IN_MEMORY
-                                          | SEC_READONLY))
-      || !bfd_set_section_alignment (abfd, s, 3))
-    return false;
-
-  s = bfd_make_section(abfd, ".got");
+  s = bfd_make_section (abfd, ".got");
   if (s == NULL
       || !bfd_set_section_flags (abfd, s, (SEC_ALLOC | SEC_LOAD
-                                          | SEC_HAS_CONTENTS | SEC_IN_MEMORY))
+                                          | SEC_HAS_CONTENTS
+                                          | SEC_IN_MEMORY
+                                          | SEC_LINKER_CREATED))
       || !bfd_set_section_alignment (abfd, s, 3))
     return false;
 
-  s->_raw_size = RESERVED_GOT_ENTRIES * 8;
-
-  /* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got
-     (or .got.plt) 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_elf_link_record_dynamic_symbol (info, h))
-    return false;
-
-  elf_hash_table (info)->hgot = h;
+  alpha_elf_tdata (abfd)->got = s;
 
   return true;
 }
 
+/* Create all the dynamic sections.  */
+
 static boolean
 elf64_alpha_create_dynamic_sections (abfd, info)
      bfd *abfd;
      struct bfd_link_info *info;
 {
-  register asection *s;
+  asection *s;
   struct elf_link_hash_entry *h;
 
   /* We need to create .plt, .rela.plt, .got, and .rela.got sections.  */
@@ -1122,7 +1051,9 @@ elf64_alpha_create_dynamic_sections (abfd, info)
   s = bfd_make_section (abfd, ".plt");
   if (s == NULL
       || ! bfd_set_section_flags (abfd, s, (SEC_ALLOC | SEC_LOAD
-                                           | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+                                           | SEC_HAS_CONTENTS
+                                           | SEC_IN_MEMORY
+                                           | SEC_LINKER_CREATED
                                            | SEC_CODE))
       || ! bfd_set_section_alignment (abfd, s, 3))
     return false;
@@ -1146,21 +1077,51 @@ elf64_alpha_create_dynamic_sections (abfd, info)
   s = bfd_make_section (abfd, ".rela.plt");
   if (s == NULL
       || !bfd_set_section_flags (abfd, s, (SEC_ALLOC | SEC_LOAD
-                                         | SEC_HAS_CONTENTS | SEC_IN_MEMORY
-                                         | SEC_READONLY))
+                                          | SEC_HAS_CONTENTS
+                                          | SEC_IN_MEMORY
+                                          | SEC_LINKER_CREATED
+                                          | SEC_READONLY))
       || ! bfd_set_section_alignment (abfd, s, 3))
     return false;
 
+  /* We may or may not have created a .got section for this object, but
+     we definitely havn't done the rest of the work.  */
+
   if (!elf64_alpha_create_got_section (abfd, info))
     return false;
 
-  return true;
-}
+  s = bfd_make_section(abfd, ".rela.got");
+  if (s == NULL
+      || !bfd_set_section_flags (abfd, s, (SEC_ALLOC | SEC_LOAD
+                                          | SEC_HAS_CONTENTS
+                                          | SEC_IN_MEMORY
+                                          | SEC_LINKER_CREATED
+                                          | SEC_READONLY))
+      || !bfd_set_section_alignment (abfd, s, 3))
+    return false;
 
-/* The structure of the runtile procedure descriptor created by the
-   loader for use by the static exception system.  */
+  /* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the
+     dynobj's .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,
+        alpha_elf_tdata(abfd)->got, (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;
 
-/* FIXME */
+  if (info->shared
+      && ! _bfd_elf_link_record_dynamic_symbol (info, h))
+    return false;
+
+  elf_hash_table (info)->hgot = h;
+
+  return true;
+}
 \f
 /* Read ECOFF debugging information from a .mdebug section into a
    ecoff_debug_info structure.  */
@@ -1435,7 +1396,7 @@ elf64_alpha_output_extsym (h, data)
          else
            {
              name = bfd_section_name (output_section->owner, output_section);
-       
+
              if (strcmp (name, ".text") == 0)
                h->esym.asym.sc = scText;
              else if (strcmp (name, ".data") == 0)
@@ -1485,23 +1446,23 @@ elf64_alpha_output_extsym (h, data)
     {
       /* Set type and value for a symbol with a function stub.  */
       h->esym.asym.st = stProc;
-      sec = h->root.root.u.def.section;
+      sec = bfd_get_section_by_name (einfo->abfd, ".plt");
       if (sec == NULL)
-       h->esym.asym.value = 0;
+       h->esym.asym.value = 0;
       else
-       {
-         output_section = sec->output_section;
-         if (output_section != NULL)
-           h->esym.asym.value = (h->root.plt_offset
-                                 + sec->output_offset
-                                 + output_section->vma);
-         else
-           h->esym.asym.value = 0;
-       }
+       {
+         output_section = sec->output_section;
+         if (output_section != NULL)
+           h->esym.asym.value = (h->root.plt_offset
+                                 + sec->output_offset
+                                 + output_section->vma);
+         else
+           h->esym.asym.value = 0;
+       }
 #if 0 /* FIXME?  */
       h->esym.ifd = 0;
 #endif
-    }      
+    }
 
   if (! bfd_ecoff_debug_one_external (einfo->abfd, einfo->debug, einfo->swap,
                                      h->root.root.root.string,
@@ -1523,9 +1484,10 @@ mips_elf_create_procedure_table (handle, abfd, info, s, debug)
      struct bfd_link_info *info;
      asection *s;
      struct ecoff_debug_info *debug;
- */
-
+*/
 \f
+/* Handle dynamic relocations when doing an Alpha ELF link.  */
+
 static boolean
 elf64_alpha_check_relocs (abfd, info, sec, relocs)
      bfd *abfd;
@@ -1534,287 +1496,698 @@ elf64_alpha_check_relocs (abfd, info, sec, relocs)
      const Elf_Internal_Rela *relocs;
 {
   bfd *dynobj;
-  asection *sgot;
-  asection *srelgot;
   asection *sreloc;
+  const char *rel_sec_name;
   Elf_Internal_Shdr *symtab_hdr;
-  struct elf_link_hash_entry **sym_hashes;
+  struct alpha_elf_link_hash_entry **sym_hashes;
+  struct alpha_elf_got_entry **local_got_entries;
   const Elf_Internal_Rela *rel, *relend;
+  int got_created;
 
   if (info->relocateable)
     return true;
 
-  sgot = srelgot = sreloc = NULL;
-  symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
-  sym_hashes = elf_sym_hashes(abfd);
   dynobj = elf_hash_table(info)->dynobj;
-  if (dynobj)
-    {
-      sgot = bfd_get_section_by_name(dynobj, ".got");
-      srelgot = bfd_get_section_by_name(dynobj, ".rela.got");
-    }
+  if (dynobj == NULL)
+    elf_hash_table(info)->dynobj = dynobj = abfd;
+
+  sreloc = NULL;
+  rel_sec_name = NULL;
+  symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
+  sym_hashes = alpha_elf_sym_hashes(abfd);
+  local_got_entries = alpha_elf_tdata(abfd)->local_got_entries;
+  got_created = 0;
 
   relend = relocs + sec->reloc_count;
   for (rel = relocs; rel < relend; ++rel)
     {
-      unsigned long r_symndx;
+      unsigned long r_symndx, r_type;
       struct alpha_elf_link_hash_entry *h;
 
       r_symndx = ELF64_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
        h = NULL;
       else
-       h = ((struct alpha_elf_link_hash_entry *)
-            sym_hashes[r_symndx - symtab_hdr->sh_info]);
+       {
+         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+         h->root.elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR;
+       }
+      r_type = ELF64_R_TYPE (rel->r_info);
 
-      switch (ELF64_R_TYPE (rel->r_info))
+      switch (r_type)
        {
        case R_ALPHA_LITERAL:
-         /* If this is a load of a function symbol and we are building a
-            shared library or calling a shared library, then we need a
-            .plt entry as well. 
+         {
+           struct alpha_elf_got_entry *gotent;
+           int flags = 0;
 
-            We can tell if it is a function either by noticing the
-            type of the symbol, or, if the type is undefined, by
-            noticing that we have a LITUSE(3) reloc next.
+           if (h)
+             {
+               /* Search for and possibly create a got entry.  */
+               for (gotent = h->got_entries; gotent ; gotent = gotent->next)
+                 if (gotent->gotobj == abfd &&
+                     gotent->addend == rel->r_addend)
+                   break;
+
+               if (!gotent)
+                 {
+                   gotent = ((struct alpha_elf_got_entry *)
+                             bfd_alloc (abfd,
+                                        sizeof (struct alpha_elf_got_entry)));
+                   if (!gotent)
+                     return false;
 
-            Note that it is not fatal to be wrong guessing that a symbol
-            is an object, but it is fatal to be wrong guessing that a 
-            symbol is a function.
+                   gotent->gotobj = abfd;
+                   gotent->addend = rel->r_addend;
+                   gotent->got_offset = -1;
+                   gotent->flags = 0;
 
-            Furthermore, the .plt trampoline does not give constant 
-            function addresses, so if we ever see a function's address
-            taken, we cannot do lazy binding on that function. */
+                   gotent->next = h->got_entries;
+                   h->got_entries = gotent;
 
-         if (h)
+                   alpha_elf_tdata (abfd)->total_got_entries++;
+                 }
+             }
+           else
+             {
+               /* This is a local .got entry -- record for merge.  */
+               if (!local_got_entries)
+                 {
+                   size_t size;
+                   size = (symtab_hdr->sh_info
+                           * sizeof (struct alpha_elf_got_entry *));
+
+                   local_got_entries = ((struct alpha_elf_got_entry **)
+                                        bfd_alloc (abfd, size));
+                   if (!local_got_entries)
+                     return false;
+
+                   memset (local_got_entries, 0, size);
+                   alpha_elf_tdata (abfd)->local_got_entries =
+                     local_got_entries;
+                 }
+
+               for (gotent = local_got_entries[ELF64_R_SYM(rel->r_info)];
+                    gotent != NULL && gotent->addend != rel->r_addend;
+                    gotent = gotent->next)
+                 continue;
+               if (!gotent)
+                 {
+                   gotent = ((struct alpha_elf_got_entry *)
+                             bfd_alloc (abfd,
+                                        sizeof (struct alpha_elf_got_entry)));
+                   if (!gotent)
+                     return false;
+
+                   gotent->gotobj = abfd;
+                   gotent->addend = rel->r_addend;
+                   gotent->got_offset = -1;
+                   gotent->flags = 0;
+
+                   gotent->next = local_got_entries[ELF64_R_SYM(rel->r_info)];
+                   local_got_entries[ELF64_R_SYM(rel->r_info)] = gotent;
+
+                   alpha_elf_tdata(abfd)->total_got_entries++;
+                   alpha_elf_tdata(abfd)->n_local_got_entries++;
+                 }
+             }
+
+           /* Remember how this literal is used from its LITUSEs.
+              This will be important when it comes to decide if we can
+              create a .plt entry for a function symbol.  */
+           if (rel+1 < relend
+               && ELF64_R_TYPE (rel[1].r_info) == R_ALPHA_LITUSE)
+             {
+               do
+                 {
+                   ++rel;
+                   if (rel->r_addend >= 1 && rel->r_addend <= 3)
+                     flags |= 1 << rel->r_addend;
+                 }
+               while (rel+1 < relend &&
+                      ELF64_R_TYPE (rel[1].r_info) == R_ALPHA_LITUSE);
+             }
+           else
+             {
+               /* No LITUSEs -- presumably the address is not being
+                  loaded for nothing.  */
+               flags = ALPHA_ELF_LINK_HASH_LU_ADDR;
+             }
+
+           gotent->flags |= flags;
+           if (h)
+             {
+               /* Make a guess as to whether a .plt entry will be needed.  */
+               if ((h->flags |= flags) == ALPHA_ELF_LINK_HASH_LU_FUNC)
+                 h->root.elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+               else
+                 h->root.elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+             }
+         }
+         /* FALLTHRU */
+
+       case R_ALPHA_GPDISP:
+       case R_ALPHA_GPREL32:
+         /* We don't actually use the .got here, but the sections must
+            be created before the linker maps input sections to output
+            sections.  */
+         if (!got_created)
            {
-             if (rel+1 < relend
-                 && ELF64_R_TYPE (rel[1].r_info) == R_ALPHA_LITUSE)
-               {
-                 switch (rel[1].r_addend)
-                   {
-                   case 1: /* Memory reference */
-                     h->flags |= ALPHA_ELF_LINK_HASH_LU_MEM;
-                     break;
-                   case 3: /* Call reference */
-                     h->flags |= ALPHA_ELF_LINK_HASH_LU_FUNC;
-                     break;
-                   }
-               }
-             else
-               h->flags |= ALPHA_ELF_LINK_HASH_LU_ADDR;
-
-             if (h->root.root.type != bfd_link_hash_undefweak
-                 && (info->shared 
-                     || !(h->root.elf_link_hash_flags
-                          & ELF_LINK_HASH_DEF_REGULAR))
-                 && (h->root.type == STT_FUNC
-                     || (h->root.type == STT_NOTYPE
-                         && (h->flags & ALPHA_ELF_LINK_HASH_LU_FUNC))))
+             if (!elf64_alpha_create_got_section (abfd, info))
+               return false;
+
+             /* Make sure the object's gotobj is set to itself so
+                that we default to every object with its own .got.
+                We'll merge .gots later once we've collected each
+                object's info.  */
+             alpha_elf_tdata(abfd)->gotobj = abfd;
+
+             got_created = 1;
+           }
+         break;
+
+       case R_ALPHA_SREL16:
+       case R_ALPHA_SREL32:
+       case R_ALPHA_SREL64:
+         if (h == NULL)
+           break;
+         /* FALLTHRU */
+
+       case R_ALPHA_REFLONG:
+       case R_ALPHA_REFQUAD:
+         if (rel_sec_name == NULL)
+           {
+             rel_sec_name = (bfd_elf_string_from_elf_section
+                             (abfd, elf_elfheader(abfd)->e_shstrndx,
+                              elf_section_data(sec)->rel_hdr.sh_name));
+             if (rel_sec_name == NULL)
+               return false;
+
+             BFD_ASSERT (strncmp (rel_sec_name, ".rela", 5) == 0
+                         && strcmp (bfd_get_section_name (abfd, sec),
+                                    rel_sec_name+5) == 0);
+           }
+
+         /* We need to create the section here now whether we eventually
+            use it or not so that it gets mapped to an output section by
+            the linker.  If not used, we'll kill it in
+            size_dynamic_sections.  */
+         if (sreloc == NULL)
+           {
+             sreloc = bfd_get_section_by_name (dynobj, rel_sec_name);
+             if (sreloc == NULL)
                {
-                 h->root.elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+                 sreloc = bfd_make_section (dynobj, rel_sec_name);
+                 if (sreloc == NULL
+                     || !bfd_set_section_flags (dynobj, sreloc,
+                                                (SEC_ALLOC|SEC_LOAD
+                                                 | SEC_HAS_CONTENTS
+                                                 | SEC_IN_MEMORY
+                                                 | SEC_LINKER_CREATED
+                                                 | SEC_READONLY))
+                     || !bfd_set_section_alignment (dynobj, sreloc, 3))
+                   return false;
                }
            }
 
-         if (dynobj == NULL)
+         if (h)
            {
-             elf_hash_table(info)->dynobj = dynobj = abfd;
+             /* Since we havn't seen all of the input symbols yet, we
+                don't know whether we'll actually need a dynamic relocation
+                entry for this reloc.  So make a record of it.  Once we
+                find out if this thing needs dynamic relocation we'll
+                expand the relocation sections by the appropriate amount. */
 
-             /* Create the .got section.  */
-             if (!elf64_alpha_create_got_section(dynobj, info))
-               return false;
+             struct alpha_elf_reloc_entry *rent;
+
+             for (rent = h->reloc_entries; rent; rent = rent->next)
+               if (rent->rtype == r_type && rent->srel == sreloc)
+                 break;
+
+             if (!rent)
+               {
+                 rent = ((struct alpha_elf_reloc_entry *)
+                         bfd_alloc (abfd,
+                                    sizeof (struct alpha_elf_reloc_entry)));
+                 if (!rent)
+                   return false;
+
+                 rent->srel = sreloc;
+                 rent->rtype = r_type;
+                 rent->count = 1;
 
-             sgot = bfd_get_section_by_name(dynobj, ".got");
-             srelgot = bfd_get_section_by_name(dynobj, ".rela.got");
+                 rent->next = h->reloc_entries;
+                 h->reloc_entries = rent;
+               }
+             else
+               rent->count++;
            }
+         else if (info->shared)
+           {
+             /* If this is a shared library, we need a RELATIVE reloc.  */
+             sreloc->_raw_size += sizeof (Elf64_External_Rela);
+           }
+         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
+elf64_alpha_adjust_dynamic_symbol (info, h)
+     struct bfd_link_info *info;
+     struct elf_link_hash_entry *h;
+{
+  bfd *dynobj;
+  asection *s;
+  struct alpha_elf_link_hash_entry *ah;
+
+  dynobj = elf_hash_table(info)->dynobj;
+  ah = (struct alpha_elf_link_hash_entry *)h;
+
+  /* Now that we've seen all of the input symbols, finalize our decision
+     about whether this symbol should get a .plt entry.  */
+
+  if (h->root.type != bfd_link_hash_undefweak
+      && alpha_elf_dynamic_symbol_p (h, info)
+      && (h->type == STT_FUNC
+         || (h->type == STT_NOTYPE
+             && ah->flags == ALPHA_ELF_LINK_HASH_LU_FUNC))
+      /* Don't prevent otherwise valid programs from linking by attempting
+        to create a new .got entry somewhere.  A Correct Solution would be
+        to add a new .got section to a new object file and let it be merged
+        somewhere later.  But for now don't bother.  */
+      && ah->got_entries)
+    {
+      h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+
+      s = bfd_get_section_by_name(dynobj, ".plt");
+      if (!s && !elf64_alpha_create_dynamic_sections (dynobj, info))
+       return false;
+
+      /* The first bit of the .plt is reserved.  */
+      if (s->_raw_size == 0)
+       s->_raw_size = PLT_HEADER_SIZE;
+
+      h->plt_offset = s->_raw_size;
+      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 the location
+        in the .plt.  This is required to make function pointers compare
+        equal between the normal executable and the shared library.  */
+      if (!info->shared)
+       {
+         h->root.u.def.section = s;
+         h->root.u.def.value = h->plt_offset;
+       }
+
+      /* We also need a JMP_SLOT entry in the .rela.plt section.  */
+      s = bfd_get_section_by_name (dynobj, ".rela.plt");
+      BFD_ASSERT (s != NULL);
+      s->_raw_size += sizeof (Elf64_External_Rela);
+
+      return true;
+    }
+  else
+    h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+
+  /* 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.  The Alpha, since it uses .got entries for all
+     symbols even in regular objects, does not need the hackery of a
+     .dynbss section and COPY dynamic relocations.  */
+
+  return true;
+}
+
+/* Is it possible to merge two object file's .got tables?  */
+
+static boolean
+elf64_alpha_can_merge_gots (a, b)
+     bfd *a, *b;
+{
+  int total = alpha_elf_tdata (a)->total_got_entries;
+
+  /* Trivial quick fallout test.  */
+  if (total + alpha_elf_tdata (b)->total_got_entries <= MAX_GOT_ENTRIES)
+    return true;
+
+  /* By their nature, local .got entries cannot be merged.  */
+  if ((total += alpha_elf_tdata (b)->n_local_got_entries) > MAX_GOT_ENTRIES)
+    return false;
+
+  /* Failing the common trivial comparison, we must effectively
+     perform the merge.  Not actually performing the merge means that
+     we don't have to store undo information in case we fail.  */
+  {
+    struct alpha_elf_link_hash_entry **hashes = alpha_elf_sym_hashes(b);
+    Elf_Internal_Shdr *symtab_hdr = &elf_tdata(b)->symtab_hdr;
+    int i, n;
+
+    n = symtab_hdr->sh_size / symtab_hdr->sh_entsize - symtab_hdr->sh_info;
+    for (i = 0; i < n; ++i)
+      {
+       struct alpha_elf_got_entry *ae, *be;
+       for (be = hashes[i]->got_entries; be ; be = be->next)
+         {
+           if (be->gotobj != b)
+             continue;
+
+           for (ae = hashes[i]->got_entries; ae ; ae = ae->next)
+             if (ae->gotobj == a && ae->addend == be->addend)
+               goto global_found;
+
+           if (++total > MAX_GOT_ENTRIES)
+             return false;
+         global_found:;
+         }
+      }
+  }
+
+  return true;
+}
+
+/* Actually merge two .got tables.  */
+
+static void
+elf64_alpha_merge_gots (a, b)
+     bfd *a, *b;
+{
+  int total = alpha_elf_tdata(a)->total_got_entries;
+
+  /* Remember local expansion.  */
+  {
+    int e = alpha_elf_tdata(b)->n_local_got_entries;
+    total += e;
+    alpha_elf_tdata(a)->n_local_got_entries += e;
+  }
+
+  /* Let the local .got entries know they are part of a new subsegment.  */
+  {
+    struct alpha_elf_got_entry **local_got_entries;
+    local_got_entries = alpha_elf_tdata(b)->local_got_entries;
+    if (local_got_entries)
+      {
+       int i, n;
+
+       n = elf_tdata(b)->symtab_hdr.sh_info;
+       for (i = 0; i < n; ++i)
+         {
+           struct alpha_elf_got_entry *gotent;
+           for (gotent = local_got_entries[i]; gotent; gotent = gotent->next)
+             gotent->gotobj = a;
+         }
+      }
+  }
+
+  /* Merge the global .got entries.  */
+  {
+    struct alpha_elf_link_hash_entry **hashes = alpha_elf_sym_hashes(b);
+    Elf_Internal_Shdr *symtab_hdr = &elf_tdata(b)->symtab_hdr;
+    int i, n;
+
+    n = symtab_hdr->sh_size / symtab_hdr->sh_entsize - symtab_hdr->sh_info;
+    for (i = 0; i < n; ++i)
+      {
+       struct alpha_elf_got_entry *ae, *be, **pbe, **start;
+       start = &hashes[i]->got_entries;
+       for (pbe = start, be = *start; be ; pbe = &be->next, be = be->next)
+         {
+           if (be->gotobj != b)
+             continue;
 
-         if (h != NULL)
-           {
-             if (h->root.got_offset != MINUS_ONE)
+           for (ae = *start; ae ; ae = ae->next)
+             if (ae->gotobj == a && ae->addend == be->addend)
                {
-                 /* We have already allocated space in this .got.  */
-                 break;
+                 *pbe = be->next;
+                 goto global_found;
                }
+           be->gotobj = a;
+           total += 1;
 
-             /* Make sure this becomes a dynamic symbol.  */
-             if (h->root.dynindx == -1
-                 && ! _bfd_elf_link_record_dynamic_symbol (info, &h->root))
-               return false;
+         global_found:;
+         }
+      }
+  }
 
-             /* Reserve space for a reloc even if we won't use it.  */
-             srelgot->_raw_size += sizeof(Elf64_External_Rela);
+  alpha_elf_tdata(a)->total_got_entries = total;
+  alpha_elf_tdata(b)->gotobj = a;
+}
 
-             /* Create the relocation in adjust_dynamic_symbol */
+/* Calculate the offsets for the got entries.  */
 
-             h->root.got_offset = sgot->_raw_size;
-             sgot->_raw_size += 8;
-           }
-         else
-           {
-             bfd_vma *lgotoff = elf_local_got_offsets(abfd);
-             if (lgotoff == NULL)
-               {
-                 size_t size;
+static boolean
+elf64_alpha_calc_got_offsets_for_symbol (h, arg)
+     struct alpha_elf_link_hash_entry *h;
+     PTR arg;
+{
+  struct alpha_elf_got_entry *gotent;
 
-                 size = elf_tdata(abfd)->symtab_hdr.sh_info * sizeof(bfd_vma);
-                 lgotoff = (bfd_vma *)bfd_alloc(abfd, size);
-                 if (lgotoff == NULL)
-                   return false;
+  for (gotent = h->got_entries; gotent; gotent = gotent->next)
+    {
+      bfd_size_type *plge = &alpha_elf_tdata (gotent->gotobj)->got->_raw_size;
+      gotent->got_offset = *plge;
+      *plge += 8;
+    }
 
-                 elf_local_got_offsets(abfd) = lgotoff;
-                 memset(lgotoff, -1, size);
-               }
+  return true;
+}
 
-             if (lgotoff[ELF64_R_SYM(rel->r_info)] != MINUS_ONE)
-               {
-                 /* We have already allocated space in the .got.  */
-                 break;
-               }
-             lgotoff[ELF64_R_SYM(rel->r_info)] = sgot->_raw_size;
-             sgot->_raw_size += 8;
+static void
+elf64_alpha_calc_got_offsets (info)
+     struct bfd_link_info *info;
+{
+  bfd *i, *got_list = alpha_elf_hash_table(info)->got_list;
 
-             if (info->shared)
-               {
-                 /* If we are generating a shared object, we need to
-                    output a R_ALPHA_RELATIVE reloc so that the dynamic
-                    linker can adjust this GOT entry.  */
-                 srelgot->_raw_size += sizeof(Elf64_External_Rela);
-               }
-           }
-         break;
+  /* First, zero out the .got sizes, as we may be recalculating the
+     .got after optimizing it.  */
+  for (i = got_list; i ; i = alpha_elf_tdata(i)->got_link_next)
+    alpha_elf_tdata(i)->got->_raw_size = 0;
 
-       case R_ALPHA_SREL16:
-       case R_ALPHA_SREL32:
-       case R_ALPHA_SREL64:
-         if (h == NULL)
-           break;
-         /* FALLTHRU */
+  /* Next, fill in the offsets for all the global entries.  */
+  alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
+                               elf64_alpha_calc_got_offsets_for_symbol,
+                               NULL);
 
-       case R_ALPHA_REFLONG:
-       case R_ALPHA_REFQUAD:
-         if (info->shared
-             || (h != NULL
-                 && !(h->root.elf_link_hash_flags
-                      & ELF_LINK_HASH_DEF_REGULAR)))
-           {
-             /* When creating a shared object or referring to a symbol in
-                a shared object, we must copy these relocs into the
-                object file.  We create a reloc section in dynobj and
-                make room for the reloc.  */
-             if (sreloc == NULL)
-               {
-                 const char *name;
-                 name = (bfd_elf_string_from_elf_section
-                         (abfd, elf_elfheader(abfd)->e_shstrndx,
-                          elf_section_data(sec)->rel_hdr.sh_name));
-                 if (name == NULL)
-                   return false;
+  /* Finally, fill in the offsets for the local entries.  */
+  for (i = got_list; i ; i = alpha_elf_tdata(i)->got_link_next)
+    {
+      bfd_size_type got_offset = alpha_elf_tdata(i)->got->_raw_size;
+      bfd *j;
 
-                 BFD_ASSERT (strncmp (name, ".rela", 5) == 0
-                             && strcmp (bfd_get_section_name (abfd, sec),
-                                        name+5) == 0);
+      for (j = i; j ; j = alpha_elf_tdata(j)->in_got_link_next)
+       {
+         struct alpha_elf_got_entry **local_got_entries, *gotent;
+         int k, n;
 
-                 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, 3))
-                       return false;
-                   }
-               }
-             sreloc->_raw_size += sizeof (Elf64_External_Rela);
-           }
-         break;
+         local_got_entries = alpha_elf_tdata(j)->local_got_entries;
+         if (!local_got_entries)
+           continue;
+
+         for (k = 0, n = elf_tdata(j)->symtab_hdr.sh_info; k < n; ++k)
+           for (gotent = local_got_entries[k]; gotent; gotent = gotent->next)
+             {
+               gotent->got_offset = got_offset;
+               got_offset += 8;
+             }
        }
+
+      alpha_elf_tdata(i)->got->_raw_size = got_offset;
     }
+}
 
-  return true;
+/* Remove a section from the output BFD.  */
+
+static void
+elf64_alpha_strip_section_from_output (s)
+     asection *s;
+{
+  asection **spp;
+
+  for (spp = &s->output_section->owner->sections;
+       *spp != s->output_section;
+       spp = &(*spp)->next)
+    continue;
+  *spp = s->output_section->next;
+  --s->output_section->owner->section_count;
 }
 
-/* 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.  */
+/* Constructs the gots.  */
 
 static boolean
-elf64_alpha_adjust_dynamic_symbol (info, h)
+elf64_alpha_always_size_sections (output_bfd, info)
+     bfd *output_bfd;
      struct bfd_link_info *info;
-     struct elf_link_hash_entry *h;
 {
-  bfd *dynobj;
-  asection *s;
-  
-  dynobj = elf_hash_table(info)->dynobj;
+  bfd *i, *got_list, *cur_got_obj, **cur_got_tail;
+  int ngots;
 
-  /* If this is a function, put it in the procedure linkage table.  We
-     will fill in the contents of the procedure linkage table later, 
-     though we could actually do it here.  */
+  if (info->relocateable)
+    return true;
 
-  if (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT)
+  ngots = 0;
+  got_list = NULL;
+  cur_got_obj = NULL;
+  cur_got_tail = NULL;
+  for (i = info->input_bfds; i ; i = i->link_next)
     {
-      /* We hadn't seen all of the input symbols or all of the relocations
-        when we guessed that we needed a .plt entry.  Revise our decision.  */
-      if ((!info->shared
-          && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))
-         || (((struct alpha_elf_link_hash_entry *) h)->flags
-             & ALPHA_ELF_LINK_HASH_LU_ADDR))
+      bfd *this_got = alpha_elf_tdata (i)->gotobj;
+
+      /* Don't play if there is no .got for this input file.  */
+      if (this_got == NULL)
+       continue;
+
+      if (alpha_elf_tdata (this_got)->total_got_entries > MAX_GOT_ENTRIES)
        {
-         h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
-         return true;
+         /* Yikes! A single object file has too many entries.  */
+         (*_bfd_error_handler)
+           ("%s: .got subsegment exceeds 64K (size %d)",
+            bfd_get_filename(i),
+            alpha_elf_tdata(this_got)->total_got_entries * 8);
+         return false;
        }
 
-      s = bfd_get_section_by_name(dynobj, ".plt");
-      BFD_ASSERT(s != NULL);
+      if (cur_got_obj)
+       {
+         if (elf64_alpha_can_merge_gots (cur_got_obj, i))
+           {
+             elf64_alpha_merge_gots (cur_got_obj, i);
+             *cur_got_tail = i;
+           }
+         else
+           {
+             if (++ngots == 2)
+               {
+                 (*info->callbacks->warning)
+                   (info, "using multiple gp values", (char *) NULL,
+                    output_bfd, (asection *) NULL, (bfd_vma) 0);
+               }
+             *cur_got_tail = NULL;
+             alpha_elf_tdata(cur_got_obj)->got_link_next = got_list;
+             got_list = cur_got_obj;
+             cur_got_obj = i;
+           }
+       }
+      else
+       {
+         ++ngots;
+         cur_got_obj = i;
+       }
+      cur_got_tail = &alpha_elf_tdata(i)->in_got_link_next;
+    }
 
-      /* The first bit of the .plt is reserved.  */
-      if (s->_raw_size == 0)
-       s->_raw_size = PLT_HEADER_SIZE;
+  if (cur_got_obj)
+    alpha_elf_tdata (cur_got_obj)->got_link_next = got_list;
+  alpha_elf_hash_table (info)->got_list = got_list = cur_got_obj;
 
-      h->plt_offset = s->_raw_size;
+  /* Once the gots have been merged, fill in the got offsets for everything
+     therein.  */
+  elf64_alpha_calc_got_offsets (info);
 
-      /* If this symbol is not defined in a regular file, and we are not
-        generating a shared library, then set the symbol to the location
-        in the .plt.  This is required to make function pointers compare
-        equal between the normal executable and the shared library.  */
-      if (!info->shared)
+  /* Allocate space for all of the .got subsections.  */
+  for (i = got_list; i ; i = alpha_elf_tdata(i)->got_link_next)
+    {
+      asection *s = alpha_elf_tdata(i)->got;
+      if (s->_raw_size > 0)
        {
-         h->root.u.def.section = s;
-         h->root.u.def.value = s->_raw_size;
+         s->contents = (bfd_byte *) bfd_zalloc (i, s->_raw_size);
+         if (s->contents == NULL)
+           return false;
        }
+    }
 
-      s->_raw_size += PLT_ENTRY_SIZE;
+  return true;
+}
 
-      /* We also need an entry in the .rela.plt section.  */
-      s = bfd_get_section_by_name(dynobj, ".rela.plt");
-      BFD_ASSERT(s != NULL);
-      s->_raw_size += sizeof(Elf64_External_Rela);
+/* Work out the sizes of the dynamic relocation entries.  */
 
-      return true;
+static boolean
+elf64_alpha_calc_dynrel_sizes (h, info)
+     struct alpha_elf_link_hash_entry *h;
+     struct bfd_link_info *info;
+{
+  /* If the symbol was defined as a common symbol in a regular object
+     file, and there was no definition in any dynamic object, then the
+     linker will have allocated space for the symbol in a common
+     section but the ELF_LINK_HASH_DEF_REGULAR flag will not have been
+     set.  This is done for dynamic symbols in
+     elf_adjust_dynamic_symbol but this is not done for non-dynamic
+     symbols, somehow.  */
+  if (((h->root.elf_link_hash_flags
+       & (ELF_LINK_HASH_DEF_REGULAR
+         | ELF_LINK_HASH_REF_REGULAR
+         | ELF_LINK_HASH_DEF_DYNAMIC))
+       == ELF_LINK_HASH_REF_REGULAR)
+      && (h->root.root.type == bfd_link_hash_defined
+         || h->root.root.type == bfd_link_hash_defweak)
+      && !(h->root.root.u.def.section->owner->flags & DYNAMIC))
+    {
+      h->root.elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
     }
 
-  /* 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)
+  /* If the symbol is dynamic, we'll need all the relocations in their
+     natural form.  */
+  if (alpha_elf_dynamic_symbol_p (&h->root, info))
     {
-      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;
+      struct alpha_elf_reloc_entry *relent;
+
+      for (relent = h->reloc_entries; relent; relent = relent->next)
+       {
+         relent->srel->_raw_size +=
+           sizeof (Elf64_External_Rela) * relent->count;
+       }
+
+      /* Only add a .rela.got entry if we're not using a .plt entry.  */
+      if (h->root.plt_offset == MINUS_ONE)
+       {
+         bfd *dynobj = elf_hash_table(info)->dynobj;
+         struct alpha_elf_got_entry *gotent;
+         bfd_size_type count = 0;
+         asection *srel;
+
+         for (gotent = h->got_entries; gotent ; gotent = gotent->next)
+           count++;
+         if (count > 0)
+           {
+             srel = bfd_get_section_by_name (dynobj, ".rela.got");
+             BFD_ASSERT (srel != NULL);
+             srel->_raw_size += sizeof (Elf64_External_Rela) * count;
+           }
+       }
     }
+  /* Otherwise, shared objects require RELATIVE relocs for all REFQUAD
+     and REFLONG relocations.  */
+  else if (info->shared)
+    {
+      struct alpha_elf_reloc_entry *relent;
 
-  /* This is a reference to a symbol defined by a dynamic object which
-     is not a function.  The Alpha, since it uses .got entries for
-     symbols even in regular objects, does not need the hackery of a
-     .dynbss section and COPY dynamic relocations.  */
+      for (relent = h->reloc_entries; relent; relent = relent->next)
+       if (relent->rtype == R_ALPHA_REFLONG
+           || relent->rtype == R_ALPHA_REFQUAD)
+         {
+           relent->srel->_raw_size +=
+             sizeof(Elf64_External_Rela) * relent->count;
+         }
+    }
 
   return true;
 }
@@ -1834,28 +2207,45 @@ elf64_alpha_size_dynamic_sections (output_bfd, info)
   dynobj = elf_hash_table(info)->dynobj;
   BFD_ASSERT(dynobj != NULL);
 
-  if (elf_hash_table(info)->dynamic_sections_created)
+  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 = 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;
+         s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
+       }
+
+      /* Now that we've seen all of the input files, we can decide which
+        symbols need dynamic relocation entries and which don't.  We've
+        collected information in check_relocs that we can now apply to
+        size the dynamic relocation sections.  */
+      alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
+                                   elf64_alpha_calc_dynrel_sizes,
+                                   info);
+
+      /* When building shared libraries, each local .got entry needs a
+        RELATIVE reloc.  */
+      if (info->shared)
+       {
+         bfd *i;
+         asection *srel;
+         bfd_size_type count;
+
+         srel = bfd_get_section_by_name (dynobj, ".rela.got");
+         BFD_ASSERT (srel != NULL);
+
+         for (i = alpha_elf_hash_table(info)->got_list, count = 0;
+              i != NULL;
+              i = alpha_elf_tdata(i)->got_link_next)
+           count += alpha_elf_tdata(i)->n_local_got_entries;
+
+         srel->_raw_size += count * sizeof(Elf64_External_Rela);
        }
     }
-  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 .rel.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;
-    }
+  /* else we're not dynamic and by definition we don't need such things.  */
 
   /* The check_relocs and adjust_dynamic_symbol entry points have
      determined the sizes of the various dynamic sections.  Allocate
@@ -1867,12 +2257,12 @@ elf64_alpha_size_dynamic_sections (output_bfd, info)
       const char *name;
       boolean strip;
 
-      if (!(s->flags & SEC_IN_MEMORY))
+      if (!(s->flags & SEC_LINKER_CREATED))
        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);
+      name = bfd_get_section_name (dynobj, s);
 
       /* If we don't need this section, strip it from the output file.
         This is to handle .rela.bss and .rela.plt.  We must create it
@@ -1884,7 +2274,7 @@ elf64_alpha_size_dynamic_sections (output_bfd, info)
 
       strip = false;
 
-      if (strncmp(name, ".rela", 5) == 0)
+      if (strncmp (name, ".rela", 5) == 0)
        {
          strip = (s->_raw_size == 0);
 
@@ -1907,60 +2297,49 @@ elf64_alpha_size_dynamic_sections (output_bfd, info)
              s->reloc_count = 0;
            }
        }
-      else if (strcmp(name, ".got") == 0)
-       {
-         /* 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)
-           {
-             long c[2], i;
-             asection *p;
-
-             c[0] = 0;
-             c[1] = bfd_count_sections(output_bfd);
-
-             elf_link_hash_traverse (elf_hash_table(info),
-                                     elf64_alpha_adjust_dynindx,
-                                     (PTR)c);
-             elf_hash_table (info)->dynsymcount += c[1];
-
-             for (i = 1, p = output_bfd->sections;
-                  p != NULL;
-                  p = p->next, i++)
-               {
-                 elf_section_data (p)->dynindx = i;
-                 /* These symbols will have no names, so we don't need to
-                    fiddle with dynstr_index.  */
-               }
-           }
-       }
       else if (strcmp (name, ".plt") != 0)
        {
-         /* It's not one of our sections, so don't allocate space.  */
+         /* It's not one of our dynamic sections, so don't allocate space.  */
          continue;
        }
 
       if (strip)
+       elf64_alpha_strip_section_from_output (s);
+      else
        {
-         asection **spp;
+         /* Allocate memory for the section contents.  */
+         s->contents = (bfd_byte *) bfd_zalloc(dynobj, s->_raw_size);
+         if (s->contents == NULL && s->_raw_size != 0)
+           return false;
+       }
+    }
 
-         for (spp = &s->output_section->owner->sections;
-              *spp != s->output_section;
-              spp = &(*spp)->next)
-           continue;
-         *spp = s->output_section->next;
-         --s->output_section->owner->section_count;
+  /* 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)
+    {
+      long c[2], i;
+      asection *p;
 
-         continue;
-       }
+      c[0] = 0;
+      c[1] = bfd_count_sections (output_bfd);
 
-      /* Allocate memory for the section contents.  */
-      s->contents = (bfd_byte *) bfd_zalloc(dynobj, s->_raw_size);
-      if (s->contents == NULL && s->_raw_size != 0)
-       return false;
+      elf_hash_table (info)->dynsymcount += c[1];
+      elf_link_hash_traverse (elf_hash_table(info),
+                             elf64_alpha_adjust_dynindx,
+                             (PTR) c);
+
+      for (i = 1, p = output_bfd->sections;
+          p != NULL;
+          p = p->next, i++)
+       {
+         elf_section_data (p)->dynindx = i;
+         /* These symbols will have no names, so we don't need to
+            fiddle with dynstr_index.  */
+       }
     }
 
   if (elf_hash_table (info)->dynamic_sections_created)
@@ -2036,28 +2415,32 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
   Elf_Internal_Shdr *symtab_hdr;
   Elf_Internal_Rela *rel;
   Elf_Internal_Rela *relend;
-  asection *sec, *sgot, *splt;
-  bfd *dynobj;
+  asection *sec, *sgot, *srel, *srelgot;
+  bfd *dynobj, *gotobj;
   bfd_vma gp;
 
-  symtab_hdr = &elf_tdata(input_bfd)->symtab_hdr;
+  srelgot = srel = NULL;
+  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+  dynobj = elf_hash_table (info)->dynobj;
+  if (dynobj)
+    {
+      srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+    }
 
   /* Find the gp value for this input bfd.  */
   sgot = NULL;
   gp = 0;
-  dynobj = elf_hash_table(info)->dynobj;
-  if (dynobj)
+  gotobj = alpha_elf_tdata (input_bfd)->gotobj;
+  if (gotobj)
     {
-      sgot = bfd_get_section_by_name (dynobj, ".got");
-      splt = bfd_get_section_by_name (dynobj, ".plt");
-
-      gp = _bfd_get_gp_value(dynobj);
+      sgot = alpha_elf_tdata (gotobj)->got;
+      gp = _bfd_get_gp_value (gotobj);
       if (gp == 0)
        {
          gp = (sgot->output_section->vma
                + sgot->output_offset
                + 0x8000);
-         _bfd_set_gp_value(dynobj, gp);
+         _bfd_set_gp_value (gotobj, gp);
        }
     }
 
@@ -2068,7 +2451,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
       int r_type;
       reloc_howto_type *howto;
       unsigned long r_symndx;
-      struct elf_link_hash_entry *h;
+      struct alpha_elf_link_hash_entry *h;
       Elf_Internal_Sym *sym;
       bfd_vma relocation;
       bfd_vma addend;
@@ -2119,43 +2502,27 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
        }
       else
        {
-         h = elf_sym_hashes(input_bfd)[r_symndx - symtab_hdr->sh_info];
+         h = alpha_elf_sym_hashes (input_bfd)[r_symndx - symtab_hdr->sh_info];
 
-         while (h->root.type == bfd_link_hash_indirect
-                || h->root.type == bfd_link_hash_warning)
-           h = (struct elf_link_hash_entry *)h->root.u.i.link;
+         while (h->root.root.type == bfd_link_hash_indirect
+                || h->root.root.type == bfd_link_hash_warning)
+           h = (struct alpha_elf_link_hash_entry *)h->root.root.u.i.link;
 
-         if (h->root.type == bfd_link_hash_defined
-             || h->root.type == bfd_link_hash_defweak)
+         if (h->root.root.type == bfd_link_hash_defined
+             || h->root.root.type == bfd_link_hash_defweak)
            {
-             sec = h->root.u.def.section;
-
-             /* If the symbol was defined as a common symbol in a
-                regular object file, and there was no definition in
-                any dynamic object, then the linker will have
-                allocated space for the symbol in a common section
-                but the ELF_LINK_HASH_DEF_REGULAR flag will not have
-                been set.  This is done for dynamic symbols in
-                elf_adjust_dynamic_symbol but this is not done for
-                non-dynamic symbols, somehow.  */
-             if ((h->elf_link_hash_flags
-                  & (ELF_LINK_HASH_DEF_REGULAR
-                     | ELF_LINK_HASH_REF_REGULAR
-                     | ELF_LINK_HASH_DEF_DYNAMIC))
-                 == ELF_LINK_HASH_REF_REGULAR
-                 && !(sec->owner->flags & DYNAMIC))
-               h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+             sec = h->root.root.u.def.section;
 
 #if rth_notdef
              if ((r_type == R_ALPHA_LITERAL
                   && elf_hash_table(info)->dynamic_sections_created
                   && (!info->shared
                       || !info->symbolic
-                      || !(h->elf_link_hash_flags
+                      || !(h->root.elf_link_hash_flags
                            & ELF_LINK_HASH_DEF_REGULAR)))
                  || (info->shared
                      && (!info->symbolic
-                         || !(h->elf_link_hash_flags
+                         || !(h->root.elf_link_hash_flags
                               & ELF_LINK_HASH_DEF_REGULAR))
                      && (input_section->flags & SEC_ALLOC)
                      && (r_type == R_ALPHA_REFLONG
@@ -2175,19 +2542,19 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
 #endif /* rth_notdef */
              else
                {
-                 relocation = (h->root.u.def.value
+                 relocation = (h->root.root.u.def.value
                                + sec->output_section->vma
                                + sec->output_offset);
                }
            }
-         else if (h->root.type == bfd_link_hash_undefweak)
+         else if (h->root.root.type == bfd_link_hash_undefweak)
            relocation = 0;
          else if (info->shared && !info->symbolic)
            relocation = 0;
          else
            {
              if (!((*info->callbacks->undefined_symbol)
-                   (info, h->root.root.string, input_bfd,
+                   (info, h->root.root.root.string, input_bfd,
                     input_section, rel->r_offset)))
                return false;
              relocation = 0;
@@ -2201,6 +2568,8 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
          {
            bfd_byte *p_ldah, *p_lda;
 
+           BFD_ASSERT(gp != 0);
+
            relocation = (input_section->output_section->vma
                          + input_section->output_offset
                          + rel->r_offset);
@@ -2217,63 +2586,80 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
        case R_ALPHA_OP_STORE:
        case R_ALPHA_OP_PSUB:
        case R_ALPHA_OP_PRSHIFT:
-         /* FIXME */
+         /* We hate these silly beasts.  */
          abort();
 
        case R_ALPHA_LITERAL:
          {
-           bfd_vma gotoff;
+           struct alpha_elf_got_entry *gotent;
 
-           BFD_ASSERT(gp != 0);
            BFD_ASSERT(sgot != NULL);
+           BFD_ASSERT(gp != 0);
+
            if (h != NULL)
              {
-               gotoff = h->got_offset;
-             }
-           else
-             {
-               gotoff = elf_local_got_offsets (input_bfd)[r_symndx];
-
-               /* Use the lsb as a flag indicating that we've already
-                  output the relocation entry.  */
-               if (info->shared)
-                 if (gotoff & 1)
-                   gotoff &= ~(bfd_vma)1;
-                 else
-                   {
-                     asection *srel;
-                     Elf_Internal_Rela outrel;
+               gotent = h->got_entries;
+               while (gotent->gotobj != gotobj || gotent->addend != addend)
+                 gotent = gotent->next;
 
-                     srel = bfd_get_section_by_name (dynobj, ".rela.got");
-                     BFD_ASSERT(srel != NULL);
+               /* Initialize the .got entry's value.  */
+               if (!(gotent->flags & ALPHA_ELF_GOT_ENTRY_RELOCS_DONE))
+                 {
+                   bfd_put_64 (output_bfd, relocation+addend,
+                               sgot->contents + gotent->got_offset);
 
-                     outrel.r_offset = (sgot->output_section->vma
-                                        + sgot->output_offset + gotoff);
-                     outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE);
-                     outrel.r_addend = 0;
+                   /* The dynamic relocations for the .got entries are
+                      done in finish_dynamic_symbol.  */
 
-                     bfd_elf64_swap_reloca_out (output_bfd, &outrel,
-                                                ((Elf64_External_Rela *)
-                                                 srel->contents)
-                                                + srel->reloc_count++);
-
-                     elf_local_got_offsets (input_bfd)[r_symndx] |= 1;
-                   }
+                   gotent->flags |= ALPHA_ELF_GOT_ENTRY_RELOCS_DONE;
+                 }
+             }
+           else
+             {
+               gotent = (alpha_elf_tdata(input_bfd)->
+                         local_got_entries[r_symndx]);
+               while (gotent->addend != addend)
+                 gotent = gotent->next;
+
+               if (!(gotent->flags & ALPHA_ELF_GOT_ENTRY_RELOCS_DONE))
+                 {
+                   bfd_put_64 (output_bfd, relocation+addend,
+                               sgot->contents + gotent->got_offset);
+
+                   /* Local got entries need RELATIVE relocs in shared
+                      libraries.  */
+                   if (info->shared)
+                     {
+                       Elf_Internal_Rela outrel;
+
+                       BFD_ASSERT(srelgot != NULL);
+
+                       outrel.r_offset = (sgot->output_section->vma
+                                          + sgot->output_offset
+                                          + gotent->got_offset);
+                       outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE);
+                       outrel.r_addend = 0;
+
+                       bfd_elf64_swap_reloca_out (output_bfd, &outrel,
+                                                  ((Elf64_External_Rela *)
+                                                   srelgot->contents)
+                                                  + srelgot->reloc_count++);
+                     }
+
+                   gotent->flags |= ALPHA_ELF_GOT_ENTRY_RELOCS_DONE;
+                 }
              }
-
-           /* Initialize the .got entry.  */
-           bfd_put_64 (output_bfd, relocation, sgot->contents + gotoff);
 
            /* Figure the gprel relocation.  */
            addend = 0;
            relocation = (sgot->output_section->vma
                          + sgot->output_offset
-                         + gotoff);
+                         + gotent->got_offset);
            relocation -= gp;
          }
          /* overflow handled by _bfd_final_link_relocate */
          goto default_reloc;
-         
+
        case R_ALPHA_GPREL32:
          BFD_ASSERT(gp != 0);
          relocation -= gp;
@@ -2285,44 +2671,52 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
             the instruction rather than the end.  */
          addend -= 4;
          goto default_reloc;
-         
+
        case R_ALPHA_REFLONG:
        case R_ALPHA_REFQUAD:
-         if (info->shared
-             || (h && !(h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)))
-           {
-             asection *srel;
-             const char *name;
-             Elf_Internal_Rela outrel;
-
-             name = (bfd_elf_string_from_elf_section
-                     (input_bfd, elf_elfheader(input_bfd)->e_shstrndx,
-                      elf_section_data(input_section)->rel_hdr.sh_name));
-             BFD_ASSERT(name != NULL);
-
-             srel = bfd_get_section_by_name(dynobj, name);
-             BFD_ASSERT(srel != NULL);
-
-             outrel.r_offset = (input_section->output_section->vma
-                                + input_section->output_offset
-                                + rel->r_offset);
-             outrel.r_addend = 0;
-             if (h)
-               {
-                 BFD_ASSERT(h->dynindx != -1);
-                 outrel.r_info = ELF64_R_INFO(h->dynindx, r_type);
-                 relocation = 0;
-               }
-             else
-               {
-                 outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE);
-               }
+         {
+           Elf_Internal_Rela outrel;
 
-             bfd_elf64_swap_reloca_out (output_bfd, &outrel,
-                                        ((Elf64_External_Rela *)
-                                         srel->contents)
-                                        + srel->reloc_count++);
-           }
+           /* Careful here to remember RELATIVE relocations for global
+              variables for symbolic shared objects.  */
+
+           if (h && alpha_elf_dynamic_symbol_p (&h->root, info))
+             {
+               BFD_ASSERT(h->root.dynindx != -1);
+               outrel.r_info = ELF64_R_INFO(h->root.dynindx, r_type);
+               outrel.r_addend = addend;
+               addend = 0, relocation = 0;
+             }
+           else if (info->shared)
+             {
+               outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE);
+               outrel.r_addend = 0;
+             }
+           else
+             goto default_reloc;
+
+           if (!srel)
+             {
+               const char *name;
+
+               name = (bfd_elf_string_from_elf_section
+                       (input_bfd, elf_elfheader(input_bfd)->e_shstrndx,
+                        elf_section_data(input_section)->rel_hdr.sh_name));
+               BFD_ASSERT(name != NULL);
+
+               srel = bfd_get_section_by_name (dynobj, name);
+               BFD_ASSERT(srel != NULL);
+             }
+
+           outrel.r_offset = (input_section->output_section->vma
+                              + input_section->output_offset
+                              + rel->r_offset);
+
+           bfd_elf64_swap_reloca_out (output_bfd, &outrel,
+                                      ((Elf64_External_Rela *)
+                                       srel->contents)
+                                      + srel->reloc_count++);
+         }
          goto default_reloc;
 
        default:
@@ -2343,7 +2737,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
            const char *name;
 
            if (h != NULL)
-             name = h->root.root.string;
+             name = h->root.root.root.string;
            else
              {
                name = (bfd_elf_string_from_elf_section
@@ -2383,26 +2777,30 @@ elf64_alpha_finish_dynamic_symbol (output_bfd, info, h, sym)
 
   if (h->plt_offset != MINUS_ONE)
     {
+      /* Fill in the .plt entry for this symbol.  */
       asection *splt, *sgot, *srel;
       Elf_Internal_Rela outrel;
       bfd_vma got_addr, plt_addr;
       bfd_vma plt_index;
+      struct alpha_elf_got_entry *gotent;
 
-      /* This symbol has an entry in the procedure linkage table.  */
+      BFD_ASSERT (h->dynindx != -1);
 
-      BFD_ASSERT(h->dynindx != -1);
-      BFD_ASSERT(h->got_offset != MINUS_ONE);
+      /* The first .got entry will be updated by the .plt with the
+        address of the target function.  */
+      gotent = ((struct alpha_elf_link_hash_entry *) h)->got_entries;
+      BFD_ASSERT (gotent && gotent->addend == 0);
 
-      splt = bfd_get_section_by_name(dynobj, ".plt");
-      BFD_ASSERT(splt != NULL);
-      srel = bfd_get_section_by_name(dynobj, ".rela.plt");
-      BFD_ASSERT(srel != NULL);
-      sgot = bfd_get_section_by_name(dynobj, ".got");
-      BFD_ASSERT(sgot != NULL);
+      splt = bfd_get_section_by_name (dynobj, ".plt");
+      BFD_ASSERT (splt != NULL);
+      srel = bfd_get_section_by_name (dynobj, ".rela.plt");
+      BFD_ASSERT (srel != NULL);
+      sgot = alpha_elf_tdata (gotent->gotobj)->got;
+      BFD_ASSERT (sgot != NULL);
 
       got_addr = (sgot->output_section->vma
-                 + sgot->output_offset 
-                 + h->got_offset);
+                 + sgot->output_offset
+                 + gotent->got_offset);
       plt_addr = (splt->output_section->vma
                  + splt->output_offset
                  + h->plt_offset);
@@ -2422,7 +2820,7 @@ elf64_alpha_finish_dynamic_symbol (output_bfd, info, h, sym)
        insn1 = PLT_ENTRY_WORD1 | (hi & 0xffff);
        insn2 = PLT_ENTRY_WORD2 | (lo & 0xffff);
        insn3 = PLT_ENTRY_WORD3 | ((-(h->plt_offset + 12) >> 2) & 0x1fffff);
-       
+
        bfd_put_32 (output_bfd, insn1, splt->contents + h->plt_offset);
        bfd_put_32 (output_bfd, insn2, splt->contents + h->plt_offset + 4);
        bfd_put_32 (output_bfd, insn3, splt->contents + h->plt_offset + 8);
@@ -2444,38 +2842,45 @@ elf64_alpha_finish_dynamic_symbol (output_bfd, info, h, sym)
          sym->st_shndx = SHN_UNDEF;
        }
 
-      /* Fill in the entry in the global offset table.  */
-      bfd_put_64 (output_bfd, plt_addr, sgot->contents + h->got_offset);
+      /* Fill in the entries in the .got.  */
+      bfd_put_64 (output_bfd, plt_addr, sgot->contents + gotent->got_offset);
+
+      /* Subsequent .got entries will continue to bounce through the .plt.  */
+      while ((gotent = gotent->next) != NULL)
+       {
+         sgot = alpha_elf_tdata(gotent->gotobj)->got;
+         BFD_ASSERT(sgot != NULL);
+         BFD_ASSERT(gotent->addend == 0);
+
+         bfd_put_64 (output_bfd, plt_addr,
+                     sgot->contents + gotent->got_offset);
+       }
     }
-  else if (h->got_offset != MINUS_ONE)
+  else if (alpha_elf_dynamic_symbol_p (h, info))
     {
-      asection *sgot, *srel;
+      /* Fill in the dynamic relocations for this symbol's .got entries.  */
+      asection *srel;
       Elf_Internal_Rela outrel;
+      struct alpha_elf_got_entry *gotent;
 
-      BFD_ASSERT(h->dynindx != -1);
-
-      sgot = bfd_get_section_by_name (dynobj, ".got");
-      BFD_ASSERT (sgot != NULL);
       srel = bfd_get_section_by_name (dynobj, ".rela.got");
       BFD_ASSERT (srel != NULL);
 
-      outrel.r_offset = (sgot->output_section->vma
-                      + sgot->output_offset
-                      + h->got_offset);
-      outrel.r_addend = 0;
-      if (info->shared
-         && info->symbolic
-         && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))
-       outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE);
-      else
+      outrel.r_info = ELF64_R_INFO (h->dynindx, R_ALPHA_GLOB_DAT);
+      for (gotent = ((struct alpha_elf_link_hash_entry *) h)->got_entries;
+          gotent != NULL;
+          gotent = gotent->next)
        {
-         bfd_put_64(output_bfd, (bfd_vma)0, sgot->contents + h->got_offset);
-         outrel.r_info = ELF64_R_INFO(h->dynindx, R_ALPHA_GLOB_DAT);
+         asection *sgot = alpha_elf_tdata (gotent->gotobj)->got;
+         outrel.r_offset = (sgot->output_section->vma
+                            + sgot->output_offset
+                            + gotent->got_offset);
+         outrel.r_addend = gotent->addend;
+
+         bfd_elf64_swap_reloca_out (output_bfd, &outrel,
+                                    ((Elf64_External_Rela *)srel->contents
+                                     + srel->reloc_count++));
        }
-
-      bfd_elf64_swap_reloca_out (output_bfd, &outrel,
-                                ((Elf64_External_Rela *)srel->contents
-                                 + srel->reloc_count++));
     }
 
   /* Mark some specially defined symbols as absolute.  */
@@ -2496,7 +2901,6 @@ elf64_alpha_finish_dynamic_sections (output_bfd, info)
 {
   bfd *dynobj;
   asection *sdyn;
-  asection *sgot;
 
   dynobj = elf_hash_table (info)->dynobj;
   sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
@@ -2534,8 +2938,8 @@ elf64_alpha_finish_dynamic_sections (output_bfd, info)
            case DT_RELASZ:
              /* My interpretation of the TIS v1.1 ELF document indicates
                 that RELASZ should not include JMPREL.  This is not what
-                the rest of the BFD does.  It is, however, what the 
-                glibc ld.so wants.  Do this fixup here until we found 
+                the rest of the BFD does.  It is, however, what the
+                glibc ld.so wants.  Do this fixup here until we found
                 out who is right.  */
              s = bfd_get_section_by_name (output_bfd, ".rela.plt");
              if (s)
@@ -2567,32 +2971,16 @@ elf64_alpha_finish_dynamic_sections (output_bfd, info)
          bfd_put_32 (output_bfd, PLT_HEADER_WORD2, splt->contents + 4);
          bfd_put_32 (output_bfd, PLT_HEADER_WORD3, splt->contents + 8);
          bfd_put_32 (output_bfd, PLT_HEADER_WORD4, splt->contents + 12);
-         
+
          /* The next two words will be filled in by ld.so */
          bfd_put_64 (output_bfd, 0, splt->contents + 16);
          bfd_put_64 (output_bfd, 0, splt->contents + 24);
 
-         elf_section_data (splt->output_section)->this_hdr.sh_entsize = 
+         elf_section_data (splt->output_section)->this_hdr.sh_entsize =
            PLT_HEADER_SIZE;
        }
     }
 
-  /* Set the first entry in the global offset table to the address of
-     the dynamic section.  */
-  sgot = bfd_get_section_by_name (dynobj, ".got");
-  if (sgot && sgot->_raw_size > 0)
-    {
-      if (sdyn == NULL)
-        bfd_put_64 (output_bfd, (bfd_vma)0, sgot->contents);
-      else
-        bfd_put_64 (output_bfd,
-                   sdyn->output_section->vma + sdyn->output_offset,
-                   sgot->contents);
-
-      elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 
-       8 * RESERVED_GOT_ENTRIES;
-    }
-
   if (info->shared)
     {
       asection *sdynsym;
@@ -2801,7 +3189,7 @@ elf64_alpha_final_link (abfd, info)
                    }
                  else
                    esym.asym.value = last;
-               
+
                  if (! bfd_ecoff_debug_one_external (abfd, &debug, swap,
                                                      name[i], &esym))
                    return false;
@@ -2919,7 +3307,9 @@ elf64_alpha_final_link (abfd, info)
              rtproc_sec = bfd_get_section_by_name (abfd, ".rtproc");
              if (rtproc_sec == NULL)
                {
-                 flagword flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY
+                 flagword flags = (SEC_HAS_CONTENTS
+                                   | SEC_IN_MEMORY
+                                   | SEC_LINKER_CREATED
                                    | SEC_READONLY);
 
                  rtproc_sec = bfd_make_section (abfd, ".rtproc");
@@ -3188,6 +3578,27 @@ elf64_alpha_final_link (abfd, info)
 
   /* Now write out the computed sections.  */
 
+  /* The .got subsections...  */
+  {
+    bfd *i, *dynobj = elf_hash_table(info)->dynobj;
+    for (i = alpha_elf_hash_table(info)->got_list;
+        i != NULL;
+        i = alpha_elf_tdata(i)->got_link_next)
+      {
+       asection *sgot;
+
+       /* elf_bfd_final_link already did everything in dynobj.  */
+       if (i == dynobj)
+         continue;
+
+       sgot = alpha_elf_tdata(i)->got;
+       if (! bfd_set_section_contents (abfd, sgot->output_section,
+                                       sgot->contents, sgot->output_offset,
+                                       sgot->_raw_size))
+         return false;
+      }
+  }
+
 #ifdef ERIC_neverdef
   if (reginfo_sec != (asection *) NULL)
     {
@@ -3291,8 +3702,11 @@ elf64_alpha_ecoff_debug_swap =
 #define elf_info_to_howto \
   elf64_alpha_info_to_howto
 
+#define bfd_elf64_mkobject \
+  elf64_alpha_mkobject
+
 #define elf_backend_object_p \
-  elf64_alpha_object_p 
+  elf64_alpha_object_p
 #define elf_backend_section_from_shdr \
   elf64_alpha_section_from_shdr
 #define elf_backend_fake_sections \
@@ -3311,6 +3725,8 @@ elf64_alpha_ecoff_debug_swap =
   elf64_alpha_create_dynamic_sections
 #define elf_backend_adjust_dynamic_symbol \
   elf64_alpha_adjust_dynamic_symbol
+#define elf_backend_always_size_sections \
+  elf64_alpha_always_size_sections
 #define elf_backend_size_dynamic_sections \
   elf64_alpha_size_dynamic_sections
 #define elf_backend_relocate_section \
index 00e840cd3a014f9c6d54cf7882f8a133bd437326..4f7facf93dbe150ceb5cfbe0fc5bc82eaf9d450e 100644 (file)
@@ -38,7 +38,8 @@ _bfd_elf_create_got_section (abfd, info)
   if (bfd_get_section_by_name (abfd, ".got") != NULL)
     return true;
 
-  flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+          | SEC_LINKER_CREATED);
 
   s = bfd_make_section (abfd, ".got");
   if (s == NULL
@@ -72,6 +73,8 @@ _bfd_elf_create_got_section (abfd, info)
       && ! _bfd_elf_link_record_dynamic_symbol (info, h))
     return false;
 
+  elf_hash_table (info)->hgot = h;
+
   /* The first three global offset table entries are reserved.  */
   s->_raw_size += 3 * 4;
 
@@ -93,7 +96,8 @@ _bfd_elf_create_dynamic_sections (abfd, info)
   /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and
      .rel[a].bss sections.  */
 
-  flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+          | SEC_LINKER_CREATED);
 
   s = bfd_make_section (abfd, ".plt");
   if (s == NULL
@@ -226,7 +230,6 @@ _bfd_elf_create_linker_section (abfd, info, which, defaults)
   if (!lsect)
     {
       asection *s;
-      static elf_linker_section_t zero_section;
 
       lsect = (elf_linker_section_t *)
        bfd_alloc (dynobj, sizeof (elf_linker_section_t));
@@ -238,9 +241,9 @@ _bfd_elf_create_linker_section (abfd, info, which, defaults)
 
       /* See if the sections already exist */
       lsect->section = s = bfd_get_section_by_name (dynobj, lsect->name);
-      if (!s)
+      if (!s || (s->flags & defaults->flags) != defaults->flags)
        {
-         lsect->section = s = bfd_make_section (dynobj, lsect->name);
+         lsect->section = s = bfd_make_section_anyway (dynobj, lsect->name);
 
          if (s == NULL)
            return (elf_linker_section_t *)0;
@@ -284,21 +287,28 @@ _bfd_elf_create_linker_section (abfd, info, which, defaults)
                   lsect->sym_name,
                   lsect->name);
 #endif
-         if (!(_bfd_generic_link_add_one_symbol (info,
-                                                 abfd,
-                                                 lsect->sym_name,
-                                                 BSF_GLOBAL,
-                                                 s,
-                                                 ((lsect->hole_size)
-                                                  ? s->_raw_size - lsect->hole_size + lsect->sym_offset
-                                                  : lsect->sym_offset),
-                                                 (const char *) NULL,
-                                                 false,
-                                                 get_elf_backend_data (abfd)->collect,
-                                                 (struct bfd_link_hash_entry **) &h)))
+         h = (struct elf_link_hash_entry *)
+           bfd_link_hash_lookup (info->hash, lsect->sym_name, false, false, false);
+
+         if ((h == NULL || h->root.type == bfd_link_hash_undefined)
+             && !(_bfd_generic_link_add_one_symbol (info,
+                                                    abfd,
+                                                    lsect->sym_name,
+                                                    BSF_GLOBAL,
+                                                    s,
+                                                    ((lsect->hole_size)
+                                                     ? s->_raw_size - lsect->hole_size + lsect->sym_offset
+                                                     : lsect->sym_offset),
+                                                    (const char *) NULL,
+                                                    false,
+                                                    get_elf_backend_data (abfd)->collect,
+                                                    (struct bfd_link_hash_entry **) &h)))
            return (elf_linker_section_t *)0;
 
-         h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_DYNAMIC;
+         if ((defaults->which != LINKER_SECTION_SDATA)
+             && (defaults->which != LINKER_SECTION_SDATA2))
+           h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_DYNAMIC;
+
          h->type = STT_OBJECT;
          lsect->sym_hash = h;
 
@@ -359,6 +369,7 @@ _bfd_elf_make_linker_section_rela (dynobj, lsect, alignment)
                                       | SEC_LOAD
                                       | SEC_HAS_CONTENTS
                                       | SEC_IN_MEMORY
+                                      | SEC_LINKER_CREATED
                                       | SEC_READONLY))
          || ! bfd_set_section_alignment (dynobj, lsect->rel_section, alignment))
        return false;
@@ -366,4 +377,3 @@ _bfd_elf_make_linker_section_rela (dynobj, lsect, alignment)
 
   return true;
 }
-
index 81dcc9b6af35b73472165c036b7cd681cfea0e6e..c98555a8e3df8cb9f77392cdd41f201c29ac5e52 100644 (file)
@@ -35,7 +35,7 @@ struct elf_info_failed
 {
   boolean failed;
   struct bfd_link_info *info;
-};  
+};
 
 /* Given an ELF BFD, add symbols to the global hash table as
    appropriate.  */
@@ -281,7 +281,7 @@ elf_link_add_object_symbols (abfd, info)
                goto error_return;
 
              if (! (_bfd_generic_link_add_one_symbol
-                    (info, abfd, 
+                    (info, abfd,
                      name + sizeof ".gnu.warning." - 1,
                      BSF_WARNING, s, (bfd_vma) 0, msg, false, collect,
                      (struct bfd_link_hash_entry **) NULL)))
@@ -1051,7 +1051,8 @@ elf_link_create_dynamic_sections (abfd, info)
 
   /* Note that we set the SEC_IN_MEMORY flag for all of these
      sections.  */
-  flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
+          | SEC_IN_MEMORY | SEC_LINKER_CREATED);
 
   /* A dynamically linked executable has a .interp section, but a
      shared library does not.  */
@@ -1257,7 +1258,7 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs,
   /* Cache the results for next time, if we can.  */
   if (keep_memory)
     elf_section_data (o)->relocs = internal_relocs;
-                
+
   if (alloc1 != NULL)
     free (alloc1);
 
@@ -1371,6 +1372,13 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
   if (info->hash->creator->flavour != bfd_target_elf_flavour)
     return true;
 
+  /* The backend may have to create some sections regardless of whether
+     we're dynamic or not.  */
+  bed = get_elf_backend_data (output_bfd);
+  if (bed->elf_backend_always_size_sections
+      && ! (*bed->elf_backend_always_size_sections) (output_bfd, info))
+    return false;
+
   dynobj = elf_hash_table (info)->dynobj;
 
   /* If there were no dynamic objects in the link, there is nothing to
@@ -1410,7 +1418,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
          if (indx == (bfd_size_type) -1
              || ! elf_add_dynamic_entry (info, DT_SONAME, indx))
            return false;
-       }      
+       }
 
       if (info->symbolic)
        {
@@ -1494,7 +1502,6 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
 
   /* The backend must work out the sizes of all the other dynamic
      sections.  */
-  bed = get_elf_backend_data (output_bfd);
   if (! (*bed->elf_backend_size_dynamic_sections) (output_bfd, info))
     return false;
 
@@ -1805,7 +1812,7 @@ struct elf_finfo_failed
 {
   boolean failed;
   struct elf_final_link_info *finfo;
-};  
+};
 
 /* Do the final step of an ELF link.  */
 
@@ -2221,7 +2228,7 @@ elf_bfd_final_link (abfd, info)
        {
          if (*rel_hash == NULL)
            continue;
-             
+
          BFD_ASSERT ((*rel_hash)->indx >= 0);
 
          if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
@@ -2375,11 +2382,10 @@ elf_bfd_final_link (abfd, info)
          if ((o->flags & SEC_HAS_CONTENTS) == 0
              || o->_raw_size == 0)
            continue;
-         if ((o->flags & SEC_IN_MEMORY) == 0)
+         if ((o->flags & SEC_LINKER_CREATED) == 0)
            {
              /* At this point, we are only interested in sections
-                 created by elf_link_create_dynamic_sections.  FIXME:
-                 This test is fragile.  */
+                 created by elf_link_create_dynamic_sections.  */
              continue;
            }
          if ((elf_section_data (o->output_section)->this_hdr.sh_type
@@ -2927,11 +2933,10 @@ elf_link_input_bfd (finfo, input_bfd)
          || (o->_raw_size == 0 && (o->flags & SEC_RELOC) == 0))
        continue;
 
-      if ((o->flags & SEC_IN_MEMORY) != 0
-         && input_bfd == elf_hash_table (finfo->info)->dynobj)
+      if ((o->flags & SEC_LINKER_CREATED) != 0)
        {
-         /* Section was created by elf_link_create_dynamic_sections.
-             FIXME: This test is fragile.  */
+         /* Section was created by elf_link_create_dynamic_sections
+            or somesuch.  */
          continue;
        }
 
index 291e3c9459300c73839bff573ff859bf6c39ca68..bed4ed3460441046e26e730b5f9a08e3df1486c1 100644 (file)
@@ -154,6 +154,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #define bfd_elfNN_write_archive_contents _bfd_write_archive_contents
 #endif
 
+#ifndef bfd_elfNN_mkobject
+#define bfd_elfNN_mkobject bfd_elf_mkobject
+#endif
+
 #ifndef bfd_elfNN_mkarchive
 #define bfd_elfNN_mkarchive _bfd_generic_mkarchive
 #endif
@@ -220,6 +224,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #ifndef elf_backend_adjust_dynamic_symbol
 #define elf_backend_adjust_dynamic_symbol 0
 #endif
+#ifndef elf_backend_always_size_sections
+#define elf_backend_always_size_sections 0
+#endif
 #ifndef elf_backend_size_dynamic_sections
 #define elf_backend_size_dynamic_sections 0
 #endif
@@ -289,6 +296,7 @@ static CONST struct elf_backend_data elfNN_bed =
   elf_backend_create_dynamic_sections,
   elf_backend_check_relocs,
   elf_backend_adjust_dynamic_symbol,
+  elf_backend_always_size_sections,
   elf_backend_size_dynamic_sections,
   elf_backend_relocate_section,
   elf_backend_finish_dynamic_symbol,
@@ -324,7 +332,7 @@ const bfd_target TARGET_BIG_SYM =
   /* object_flags: mask of all file flags */
   (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS |
    DYNAMIC | WP_TEXT | D_PAGED),
-  
+
   /* section_flags: mask of all section flags */
   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY |
    SEC_CODE | SEC_DATA | SEC_DEBUGGING | SEC_EXCLUDE | SEC_SORT_ENTRIES),
@@ -363,7 +371,7 @@ const bfd_target TARGET_BIG_SYM =
 
   /* bfd_set_format: set the format of a file being written */
   { bfd_false,
-    bfd_elf_mkobject,
+    bfd_elfNN_mkobject,
     bfd_elfNN_mkarchive,
     bfd_false
   },
@@ -412,7 +420,7 @@ const bfd_target TARGET_LITTLE_SYM =
   /* object_flags: mask of all file flags */
   (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS |
    DYNAMIC | WP_TEXT | D_PAGED),
-  
+
   /* section_flags: mask of all section flags */
   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY |
    SEC_CODE | SEC_DATA | SEC_DEBUGGING | SEC_EXCLUDE | SEC_SORT_ENTRIES),
@@ -451,7 +459,7 @@ const bfd_target TARGET_LITTLE_SYM =
 
   /* bfd_set_format: set the format of a file being written */
   { bfd_false,
-    bfd_elf_mkobject,
+    bfd_elfNN_mkobject,
     bfd_elfNN_mkarchive,
     bfd_false
   },
index 469b0262e50ef2120b92dcd22c20ed2eb223ca79..564a51e5bdbbb732e6c8dbe262f8077ec9488fbf 100644 (file)
@@ -240,7 +240,7 @@ CODE_FRAGMENT
 .           sections. *}
 .#define SEC_COFF_SHARED_LIBRARY 0x800
 .
-.        {* The section is a common section (symbols may be defined
+.        {* The section contains common symbols (symbols may be defined
 .           multiple times, the value of a symbol is the amount of
 .           space it requires, and the largest symbol value is the one
 .           used).  Most targets have exactly one of these (which we
@@ -269,6 +269,40 @@ CODE_FRAGMENT
 .         table.  *}
 .#define SEC_SORT_ENTRIES 0x80000
 .
+.      {* When linking, duplicate sections of the same name should be
+.         discarded, rather than being combined into a single section as
+.         is usually done.  This is similar to how common symbols are
+.         handled.  See SEC_LINK_DUPLICATES below.  *}
+.#define SEC_LINK_ONCE 0x100000
+.
+.      {* If SEC_LINK_ONCE is set, this bitfield describes how the linker
+.         should handle duplicate sections.  *}
+.#define SEC_LINK_DUPLICATES 0x600000
+.
+.      {* This value for SEC_LINK_DUPLICATES means that duplicate
+.         sections with the same name should simply be discarded. *}
+.#define SEC_LINK_DUPLICATES_DISCARD 0x0
+.
+.      {* This value for SEC_LINK_DUPLICATES means that the linker
+.         should warn if there are any duplicate sections, although
+.         it should still only link one copy.  *}
+.#define SEC_LINK_DUPLICATES_ONE_ONLY 0x200000
+.
+.      {* This value for SEC_LINK_DUPLICATES means that the linker
+.         should warn if any duplicate sections are a different size.  *}
+.#define SEC_LINK_DUPLICATES_SAME_SIZE 0x400000
+.
+.      {* This value for SEC_LINK_DUPLICATES means that the linker
+.         should warn if any duplicate sections contain different
+.         contents.  *}
+.#define SEC_LINK_DUPLICATES_SAME_CONTENTS 0x600000
+.
+.      {* This section was created by the linker as part of dynamic
+.         relocation or other arcane processing.  It is skipped when
+.         going through the first-pass output, trusting that someone
+.         else up the line will take care of it later.  *}
+.#define SEC_LINKER_CREATED 0x800000
+.
 .      {*  End of section flags.  *}
 .
 .      {* Some internal packed boolean fields.  *}
@@ -982,6 +1016,6 @@ DESCRIPTION
        Not enough memory exists to create private data for @var{osec}.
 
 .#define bfd_copy_private_section_data(ibfd, isection, obfd, osection) \
-.     BFD_SEND (ibfd, _bfd_copy_private_section_data, \
+.     BFD_SEND (obfd, _bfd_copy_private_section_data, \
 .              (ibfd, isection, obfd, osection))
 */