Add support for creating shared libraries under i386 ELF and SPARC
authorIan Lance Taylor <ian@airs.com>
Tue, 26 Jul 1994 17:18:37 +0000 (17:18 +0000)
committerIan Lance Taylor <ian@airs.com>
Tue, 26 Jul 1994 17:18:37 +0000 (17:18 +0000)
ELF.  Based on patches by Eric Youngdale <ericy@cais.cais.com>.
* libelf.h (struct elf_link_hash_entry): Remove copy_offset field.
Add got_offset and plt_offset fields.
(ELF_LINK_HASH_REF_DYNAMIC_MULTIPLE): Don't define.
(ELF_LINK_HASH_DEF_DYNAMIC_MULTIPLE): Don't define.
(ELF_LINK_HASH_NEEDS_COPY): Define.
(struct elf_backend_data): Add check_relocs field.
(struct bfd_elf_section_data): Change relocs from PTR to
Elf_Internal_Rela *.
(struct elf_obj_tdata): Add local_got_offsets field.
(elf_local_got_offsets): Define accessor macro.
(bfd_elf32_link_create_dynamic_sections): Declare.
(bfd_elf32_link_record_dynamic_symbol): Declare.
(bfd_elf64_link_create_dynamic_sections): Declare.
(bfd_elf64_link_record_dynamic_symbol): Declare.
* elfcode.h (elf_slurp_reloc_table): Don't use the section data
relocs field.
(elf_link_record_dynamic_symbol): Make globally visible.  Use
macro to rename to NAME(bfd_elf,link_record_dynamic_symbol).
(elf_link_add_object_symbols): If creating a shared library, put
make all local symbols dynamic.  Don't bother with the
DYNAMIC_MULTIPLE flags.  Call the check_relocs backend function if
it is defined.
(elf_link_create_dynamic_sections): Make globally visible.  Use
macro to rename to NAME(bfd_elf,link_create_dynamic_sections).  If
creating a shared library, make sure that _DYNAMIC is added as a
dynamic symbol.
(elf_link_read_relocs): New function.
(NAME(bfd_elf,record_link_assignment)): If creating a shared
library, always create symbols, and always make them dynamic.
(elf_bfd_final_link): Permit creation of shared libraries.
(elf_link_input_bfd): Use elf_link_read_relocs to get the relocs.
* elf.c (_bfd_elf_link_hash_newfunc): Don't initialize
copy_offset.  Initialize got_offset and plt_offset.
* elf32-target.h (elf_backend_check_relocs): Define as 0 if not
defined.
(elf32_bed): Initialize check_relocs field.
* elf64-target.h (elf_backend_check_relocs): Define as 0 if not
defined.
(elf64_bed): Initialize check_relocs field.
* elf32-i386.c (elf_howto_table): Change R_386_PLT32 and
R_386_GOTPC to be pc_relative and pcrel_offset.
(elf_i386_pic_plt0_entry): Define.
(elf_i386_pic_plt_entry): Define.
(elf_i386_create_dynamic_sections): Create a .got.plt section, and
define _GLOBAL_OFFSET_TABLE_ at the start of it.  If creating a
shared library, make sure that _GLOBAL_OFFSET_TABLE_ is added as a
dynamic symbol.  Don't create .rel.bss if creating a shared
library.
(elf_i386_check_relocs): New function.
(elf_i386_adjust_dynamic_symbol): Don't make a PLT entry if the
symbol already has one.  When making a PLT entry, set plt_offset.
Don't create a copy reloc when creating a shared library.  Don't
set copy_offset, just set ELF_LINK_HASH_NEEDS_COPY.
(elf_i386_allocate_dynamic_section): Remove.
(elf_i386_size_dynamic_sections): Look through all the sections
rather than assuming we know their names.  Remove any empty reloc
or plt sections.  Only add a DT_DEBUG entry if not creating a
shared library.  Only add a DT_PLTGOT entry if there is a PLT.
Add a DT_TEXTREL entry if required.
(elf_i386_relocate_section): Permit undefined symbols when
creating a shared library.  Handle the special relocation types
specially.
(elf_i386_finish_dynamic_symbol): Create a PLT entry if plt_offset
is set.  If creating a shared library, produce a PIC PLT entry.
Only mark a PLT symbol as undefined if it was not defined by a
regular object file.  Create a GOT entry if got_offset is set.
Create a copy reloc if ELF_LINK_HASH_NEEDS_COPY is set.
(elf_i386_finish_dynamic_sections): Change the handling of
DT_RELSZ to simply subtract out the size of .rel.plt.  If creating
a shared library, produce PIC PLT code.
(elf_backend_check_relocs): Define.
* elf32-sparc.c (elf_sparc_howto_table): Change R_SPARC_GOT10,
R_SPARC_GOT22, and R_SPARC_PC10 to not warn about reloc overflow.
(elf32_sparc_create_dynamic_sections): If creating a shared
library, make sure that _GLOBAL_OFFSET_TABLE_ is added as a
        dynamic symbol, and set the type to STT_OBJECT.  Likewise for
        _PROCEDURE_LINKAGE_TABLE_.  Don't create .rel.bss if creating a
        shared library.
(elf32_sparc_check_relocs): New function.
(elf32_sparc_adjust_dynamic_symbol): Don't make a PLT entry if the
symbol already has one.  When making a PLT entry, set plt_offset.
Don't create a copy reloc when creating a shared library.  Don't
set copy_offset, just set ELF_LINK_HASH_NEEDS_COPY.
(elf32_sparc_allocate_dynamic_section): Remove.
(elf32_sparc_size_dynamic_sections): Look through all the sections
rather than assuming we know their names.  Only add a DT_DEBUG
entry if not creating a shared library.  Add a DT_TEXTREL entry if
required.
(elf32_sparc_relocate_section): Permit undefined symbols when
creating a shared library.  Handle the special relocation types
specially.
(elf32_sparc_finish_dynamic_symbol): Create a PLT entry if plt_offset
is set.  Only mark a PLT symbol as undefined if it was not defined
by a regular object file.  Create a GOT entry if got_offset is
set.  Create a copy reloc if ELF_LINK_HASH_NEEDS_COPY is set.
(elf32_sparc_finish_dynamic_sections): Store dynobj in a local
variable.
(elf_backend_check_relocs): Define.

bfd/ChangeLog
bfd/elf32-target.h
bfd/elf64-target.h
bfd/elfcode.h
bfd/libelf.h

index d0085567d546b6e7c4a94c93e8243fac64e0709e..0d2dd4994f800f97a0e75a78b613cc82fb43be64 100644 (file)
@@ -1,3 +1,106 @@
+Tue Jul 26 11:04:00 1994  Ian Lance Taylor  (ian@sanguine.cygnus.com)
+
+       Add support for creating shared libraries under i386 ELF and SPARC
+       ELF.  Based on patches by Eric Youngdale <ericy@cais.cais.com>.
+       * libelf.h (struct elf_link_hash_entry): Remove copy_offset field.
+       Add got_offset and plt_offset fields.
+       (ELF_LINK_HASH_REF_DYNAMIC_MULTIPLE): Don't define.
+       (ELF_LINK_HASH_DEF_DYNAMIC_MULTIPLE): Don't define.
+       (ELF_LINK_HASH_NEEDS_COPY): Define.
+       (struct elf_backend_data): Add check_relocs field.
+       (struct bfd_elf_section_data): Change relocs from PTR to
+       Elf_Internal_Rela *.
+       (struct elf_obj_tdata): Add local_got_offsets field.
+       (elf_local_got_offsets): Define accessor macro.
+       (bfd_elf32_link_create_dynamic_sections): Declare.
+       (bfd_elf32_link_record_dynamic_symbol): Declare.
+       (bfd_elf64_link_create_dynamic_sections): Declare.
+       (bfd_elf64_link_record_dynamic_symbol): Declare.
+       * elfcode.h (elf_slurp_reloc_table): Don't use the section data
+       relocs field.
+       (elf_link_record_dynamic_symbol): Make globally visible.  Use
+       macro to rename to NAME(bfd_elf,link_record_dynamic_symbol).
+       (elf_link_add_object_symbols): If creating a shared library, put
+       make all local symbols dynamic.  Don't bother with the
+       DYNAMIC_MULTIPLE flags.  Call the check_relocs backend function if
+       it is defined.
+       (elf_link_create_dynamic_sections): Make globally visible.  Use
+       macro to rename to NAME(bfd_elf,link_create_dynamic_sections).  If
+       creating a shared library, make sure that _DYNAMIC is added as a
+       dynamic symbol.
+       (elf_link_read_relocs): New function.
+       (NAME(bfd_elf,record_link_assignment)): If creating a shared
+       library, always create symbols, and always make them dynamic.
+       (elf_bfd_final_link): Permit creation of shared libraries.
+       (elf_link_input_bfd): Use elf_link_read_relocs to get the relocs.
+       * elf.c (_bfd_elf_link_hash_newfunc): Don't initialize
+       copy_offset.  Initialize got_offset and plt_offset.
+       * elf32-target.h (elf_backend_check_relocs): Define as 0 if not
+       defined.
+       (elf32_bed): Initialize check_relocs field.
+       * elf64-target.h (elf_backend_check_relocs): Define as 0 if not
+       defined.
+       (elf64_bed): Initialize check_relocs field.
+       * elf32-i386.c (elf_howto_table): Change R_386_PLT32 and
+       R_386_GOTPC to be pc_relative and pcrel_offset.
+       (elf_i386_pic_plt0_entry): Define.
+       (elf_i386_pic_plt_entry): Define.
+       (elf_i386_create_dynamic_sections): Create a .got.plt section, and
+       define _GLOBAL_OFFSET_TABLE_ at the start of it.  If creating a
+       shared library, make sure that _GLOBAL_OFFSET_TABLE_ is added as a
+       dynamic symbol.  Don't create .rel.bss if creating a shared
+       library.
+       (elf_i386_check_relocs): New function.
+       (elf_i386_adjust_dynamic_symbol): Don't make a PLT entry if the
+       symbol already has one.  When making a PLT entry, set plt_offset.
+       Don't create a copy reloc when creating a shared library.  Don't
+       set copy_offset, just set ELF_LINK_HASH_NEEDS_COPY.
+       (elf_i386_allocate_dynamic_section): Remove.
+       (elf_i386_size_dynamic_sections): Look through all the sections
+       rather than assuming we know their names.  Remove any empty reloc
+       or plt sections.  Only add a DT_DEBUG entry if not creating a
+       shared library.  Only add a DT_PLTGOT entry if there is a PLT.
+       Add a DT_TEXTREL entry if required.
+       (elf_i386_relocate_section): Permit undefined symbols when
+       creating a shared library.  Handle the special relocation types
+       specially.
+       (elf_i386_finish_dynamic_symbol): Create a PLT entry if plt_offset
+       is set.  If creating a shared library, produce a PIC PLT entry.
+       Only mark a PLT symbol as undefined if it was not defined by a
+       regular object file.  Create a GOT entry if got_offset is set.
+       Create a copy reloc if ELF_LINK_HASH_NEEDS_COPY is set.
+       (elf_i386_finish_dynamic_sections): Change the handling of
+       DT_RELSZ to simply subtract out the size of .rel.plt.  If creating
+       a shared library, produce PIC PLT code.
+       (elf_backend_check_relocs): Define.
+       * elf32-sparc.c (elf_sparc_howto_table): Change R_SPARC_GOT10,
+       R_SPARC_GOT22, and R_SPARC_PC10 to not warn about reloc overflow.
+       (elf32_sparc_create_dynamic_sections): If creating a shared
+       library, make sure that _GLOBAL_OFFSET_TABLE_ is added as a
+        dynamic symbol, and set the type to STT_OBJECT.  Likewise for
+        _PROCEDURE_LINKAGE_TABLE_.  Don't create .rel.bss if creating a
+        shared library.
+       (elf32_sparc_check_relocs): New function.
+       (elf32_sparc_adjust_dynamic_symbol): Don't make a PLT entry if the
+       symbol already has one.  When making a PLT entry, set plt_offset.
+       Don't create a copy reloc when creating a shared library.  Don't
+       set copy_offset, just set ELF_LINK_HASH_NEEDS_COPY.
+       (elf32_sparc_allocate_dynamic_section): Remove.
+       (elf32_sparc_size_dynamic_sections): Look through all the sections
+       rather than assuming we know their names.  Only add a DT_DEBUG
+       entry if not creating a shared library.  Add a DT_TEXTREL entry if
+       required.
+       (elf32_sparc_relocate_section): Permit undefined symbols when
+       creating a shared library.  Handle the special relocation types
+       specially.
+       (elf32_sparc_finish_dynamic_symbol): Create a PLT entry if plt_offset
+       is set.  Only mark a PLT symbol as undefined if it was not defined
+       by a regular object file.  Create a GOT entry if got_offset is
+       set.  Create a copy reloc if ELF_LINK_HASH_NEEDS_COPY is set.
+       (elf32_sparc_finish_dynamic_sections): Store dynobj in a local
+       variable.
+       (elf_backend_check_relocs): Define.
+
 Mon Jul 25 12:21:07 1994  Stan Shebs  (shebs@andros.cygnus.com)
 
        * configure.in (pc532mach_vec): Change to pc532machaout_vec.
index 67dabecc71fe9b73e1bb708355a11829fc0dd942..c1091f2a9bb04d2779c90adc1283c0a577193800 100644 (file)
@@ -121,6 +121,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #ifndef elf_backend_create_dynamic_sections
 #define elf_backend_create_dynamic_sections 0
 #endif
+#ifndef elf_backend_check_relocs
+#define elf_backend_check_relocs       0
+#endif
 #ifndef elf_backend_adjust_dynamic_symbol
 #define elf_backend_adjust_dynamic_symbol 0
 #endif
@@ -171,6 +174,7 @@ static CONST struct elf_backend_data elf32_bed =
   elf_backend_add_symbol_hook,
   elf_backend_link_output_symbol_hook,
   elf_backend_create_dynamic_sections,
+  elf_backend_check_relocs,
   elf_backend_adjust_dynamic_symbol,
   elf_backend_size_dynamic_sections,
   elf_backend_relocate_section,
index a85b5d0d3a70eb3f37dec4c9f91024cd23fd0f4d..006d60cbdb0d3e8bd2352c5588b4b1d2f4d9164f 100644 (file)
@@ -124,6 +124,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #ifndef elf_backend_create_dynamic_sections
 #define elf_backend_create_dynamic_sections 0
 #endif
+#ifndef elf_backend_check_relocs
+#define elf_backend_check_relocs       0
+#endif
 #ifndef elf_backend_adjust_dynamic_symbol
 #define elf_backend_adjust_dynamic_symbol 0
 #endif
@@ -174,6 +177,7 @@ static CONST struct elf_backend_data elf64_bed =
   elf_backend_add_symbol_hook,
   elf_backend_link_output_symbol_hook,
   elf_backend_create_dynamic_sections,
+  elf_backend_check_relocs,
   elf_backend_adjust_dynamic_symbol,
   elf_backend_size_dynamic_sections,
   elf_backend_relocate_section,
index fd02038f0a0be65a4857df538cf9f9cac41adeb3..49f24c4cf575d76cba47467a5822b3aa3ca24873 100644 (file)
@@ -116,6 +116,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #define elf_find_section               NAME(bfd_elf,find_section)
 #define elf_bfd_link_add_symbols       NAME(bfd_elf,bfd_link_add_symbols)
 #define elf_add_dynamic_entry          NAME(bfd_elf,add_dynamic_entry)
+#define elf_link_create_dynamic_sections \
+  NAME(bfd_elf,link_create_dynamic_sections)
+#define elf_link_record_dynamic_symbol  \
+  NAME(bfd_elf,link_record_dynamic_symbol)
 #define elf_bfd_final_link             NAME(bfd_elf,bfd_final_link)
 
 #if ARCH_SIZE == 64
@@ -2931,23 +2935,19 @@ elf_slurp_reloc_table (abfd, asect, symbols)
              && (asect->reloc_count
                  == d->rel_hdr.sh_size / d->rel_hdr.sh_entsize));
 
-  native_relocs = (bfd_byte *) elf_section_data (asect)->relocs;
-  if (native_relocs == NULL)
+  allocated = (PTR) malloc (d->rel_hdr.sh_size);
+  if (allocated == NULL)
     {
-      allocated = (PTR) malloc (d->rel_hdr.sh_size);
-      if (allocated == NULL)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         goto error_return;
-       }
+      bfd_set_error (bfd_error_no_memory);
+      goto error_return;
+    }
 
-      if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0
-         || (bfd_read (allocated, 1, d->rel_hdr.sh_size, abfd)
-             != d->rel_hdr.sh_size))
-       goto error_return;
+  if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0
+      || (bfd_read (allocated, 1, d->rel_hdr.sh_size, abfd)
+         != d->rel_hdr.sh_size))
+    goto error_return;
 
-      native_relocs = (bfd_byte *) allocated;
-    }
+  native_relocs = (bfd_byte *) allocated;
 
   relents = ((arelent *)
             bfd_alloc (abfd, asect->reloc_count * sizeof (arelent)));
@@ -3750,10 +3750,8 @@ static boolean elf_link_add_object_symbols
   PARAMS ((bfd *, struct bfd_link_info *));
 static boolean elf_link_add_archive_symbols
   PARAMS ((bfd *, struct bfd_link_info *));
-static INLINE boolean elf_link_record_dynamic_symbol
-  PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
-static boolean elf_link_create_dynamic_sections
-  PARAMS ((bfd *, struct bfd_link_info *));
+static Elf_Internal_Rela *elf_link_read_relocs
+  PARAMS ((bfd *, asection *, PTR, Elf_Internal_Rela *, boolean));
 static boolean elf_adjust_dynamic_symbol
   PARAMS ((struct elf_link_hash_entry *, PTR));
 
@@ -3947,7 +3945,7 @@ elf_link_add_archive_symbols (abfd, info)
    read the input files, since we need to have a list of all of them
    before we can determine the final sizes of the output sections.  */
 
-static INLINE boolean
+INLINE boolean
 elf_link_record_dynamic_symbol (info, h)
      struct bfd_link_info *info;
      struct elf_link_hash_entry *h;
@@ -3977,6 +3975,8 @@ elf_link_add_object_symbols (abfd, info)
                                      const Elf_Internal_Sym *,
                                      const char **, flagword *,
                                      asection **, bfd_vma *));
+  boolean (*check_relocs) PARAMS ((bfd *, struct bfd_link_info *,
+                                  asection *, const Elf_Internal_Rela *));
   boolean collect;
   Elf_Internal_Shdr *hdr;
   size_t symcount;
@@ -4055,9 +4055,9 @@ elf_link_add_object_symbols (abfd, info)
 
       dynamic = true;
 
-      /* You can't use -r against a dynamic object.  There's no hope
-        of using a dynamic object which does not exactly match the
-        format of the output file.  */
+      /* You can't use -r against a dynamic object.  Also, there's no
+        hope of using a dynamic object which does not exactly match
+        the format of the output file.  */
       if (info->relocateable
          || info->hash->creator != abfd->xvec)
        {
@@ -4143,7 +4143,6 @@ elf_link_add_object_symbols (abfd, info)
       strindex = bfd_add_to_strtab (abfd,
                                    elf_hash_table (info)->dynstr,
                                    name);
-      
       if (strindex == (unsigned long) -1)
        goto error_return;
       if (! elf_add_dynamic_entry (info, DT_NEEDED, strindex))
@@ -4334,6 +4333,7 @@ elf_link_add_object_symbols (abfd, info)
          weaks = *sym_hash;
        }
 
+      /* Get the alignment of a common symbol.  */
       if (sym.st_shndx == SHN_COMMON
          && h->root.type == bfd_link_hash_common)
        h->root.u.c.alignment_power = bfd_log2 (sym.st_value);
@@ -4344,7 +4344,7 @@ elf_link_add_object_symbols (abfd, info)
          boolean dynsym;
          int new_flag;
 
-         /* Remember the symbol size, type and alignment.  */
+         /* Remember the symbol size and type.  */
          if (sym.st_size != 0)
            {
              /* FIXME: We should probably somehow give a warning if
@@ -4372,8 +4372,9 @@ elf_link_add_object_symbols (abfd, info)
                new_flag = ELF_LINK_HASH_REF_REGULAR;
              else
                new_flag = ELF_LINK_HASH_DEF_REGULAR;
-             if ((old_flags & (ELF_LINK_HASH_DEF_DYNAMIC
-                               | ELF_LINK_HASH_REF_DYNAMIC)) != 0)
+             if (info->shared
+                 || (old_flags & (ELF_LINK_HASH_DEF_DYNAMIC
+                                  | ELF_LINK_HASH_REF_DYNAMIC)) != 0)
                dynsym = true;
            }
          else
@@ -4382,20 +4383,10 @@ elf_link_add_object_symbols (abfd, info)
                new_flag = ELF_LINK_HASH_REF_DYNAMIC;
              else
                new_flag = ELF_LINK_HASH_DEF_DYNAMIC;
-             if ((old_flags & new_flag) != 0)
-               {
-                 if (! definition)
-                   new_flag = ELF_LINK_HASH_REF_DYNAMIC_MULTIPLE;
-                 else
-                   new_flag = ELF_LINK_HASH_DEF_DYNAMIC_MULTIPLE;
-                 dynsym = true;
-               }
-             else
-               {
-                 if ((old_flags & (ELF_LINK_HASH_DEF_REGULAR
-                                   | ELF_LINK_HASH_REF_REGULAR)) != 0)
-                   dynsym = true;
-               }
+             if ((old_flags & new_flag) != 0
+                 || (old_flags & (ELF_LINK_HASH_DEF_REGULAR
+                                  | ELF_LINK_HASH_REF_REGULAR)) != 0)
+               dynsym = true;
            }
 
          h->elf_link_hash_flags |= new_flag;
@@ -4466,7 +4457,65 @@ elf_link_add_object_symbols (abfd, info)
     }
 
   if (buf != NULL)
-    free (buf);
+    {
+      free (buf);
+      buf = NULL;
+    }
+
+  /* If this object is the same format as the output object, and it is
+     not a shared library, then let the backend look through the
+     relocs.
+
+     This is required to build global offset table entries and to
+     arrange for dynamic relocs.  It is not required for the
+     particular common case of linking non PIC code, even when linking
+     against shared libraries, but unfortunately there is no way of
+     knowing whether an object file has been compiled PIC or not.
+     Looking through the relocs is not particularly time consuming.
+     The problem is that we must either (1) keep the relocs in memory,
+     which causes the linker to require additional runtime memory or
+     (2) read the relocs twice from the input file, which wastes time.
+     This would be a good case for using mmap.
+
+     I have no idea how to handle linking PIC code into a file of a
+     different format.  It probably can't be done.  */
+  check_relocs = get_elf_backend_data (abfd)->check_relocs;
+  if (! dynamic
+      && abfd->xvec == info->hash->creator
+      && check_relocs != NULL)
+    {
+      asection *o;
+
+      for (o = abfd->sections; o != NULL; o = o->next)
+       {
+         Elf_Internal_Rela *internal_relocs;
+         boolean ok;
+
+         if ((o->flags & SEC_RELOC) == 0
+             || o->reloc_count == 0)
+           continue;
+
+         /* I believe we can ignore the relocs for any section which
+             does not form part of the final process image, such as a
+             debugging section.  */
+         if ((o->flags & SEC_ALLOC) == 0)
+           continue;
+
+         internal_relocs = elf_link_read_relocs (abfd, o, (PTR) NULL,
+                                                 (Elf_Internal_Rela *) NULL,
+                                                 info->keep_memory);
+         if (internal_relocs == NULL)
+           goto error_return;
+
+         ok = (*check_relocs) (abfd, info, o, internal_relocs);
+
+         if (! info->keep_memory)
+           free (internal_relocs);
+
+         if (! ok)
+           goto error_return;
+       }
+    }
 
   return true;
 
@@ -4485,7 +4534,7 @@ elf_link_add_object_symbols (abfd, info)
    are assigned to the output sections.  We work out the actual
    contents and size of these sections later.  */
 
-static boolean
+boolean
 elf_link_create_dynamic_sections (abfd, info)
      bfd *abfd;
      struct bfd_link_info *info;
@@ -4509,6 +4558,25 @@ elf_link_create_dynamic_sections (abfd, info)
        return false;
     }
 
+  s = bfd_make_section (abfd, ".dynsym");
+  if (s == NULL
+      || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
+      || ! bfd_set_section_alignment (abfd, s, LOG_FILE_ALIGN))
+    return false;
+
+  /* The first .dynsym symbol is a dummy.  */
+  elf_hash_table (info)->dynsymcount = 1;
+
+  s = bfd_make_section (abfd, ".dynstr");
+  if (s == NULL
+      || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY))
+    return false;
+
+  /* Create a strtab to hold the dynamic symbol names.  */
+  elf_hash_table (info)->dynstr = bfd_new_strtab (abfd);
+  if (elf_hash_table (info)->dynstr == NULL)
+    return false;
+
   s = bfd_make_section (abfd, ".dynamic");
   if (s == NULL
       || ! bfd_set_section_flags (abfd, s, flags)
@@ -4530,24 +4598,9 @@ elf_link_create_dynamic_sections (abfd, info)
          (struct bfd_link_hash_entry **) &h)))
     return false;
   h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
-
-  s = bfd_make_section (abfd, ".dynsym");
-  if (s == NULL
-      || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
-      || ! bfd_set_section_alignment (abfd, s, LOG_FILE_ALIGN))
-    return false;
-
-  /* The first .dynsym symbol is a dummy.  */
-  elf_hash_table (info)->dynsymcount = 1;
-
-  s = bfd_make_section (abfd, ".dynstr");
-  if (s == NULL
-      || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY))
-    return false;
-
-  /* Create a strtab to hold the dynamic symbol names.  */
-  elf_hash_table (info)->dynstr = bfd_new_strtab (abfd);
-  if (elf_hash_table (info)->dynstr == NULL)
+                
+  if (info->shared
+      && ! elf_link_record_dynamic_symbol (info, h))
     return false;
 
   s = bfd_make_section (abfd, ".hash");
@@ -4604,6 +4657,122 @@ elf_add_dynamic_entry (info, tag, val)
   return true;
 }
 
+/* Read and swap the relocs for a section.  They may have been cached.
+   If the EXTERNAL_RELOCS and INTERNAL_RELOCS arguments are not NULL,
+   they are used as buffers to read into.  They are known to be large
+   enough.  If the INTERNAL_RELOCS relocs argument is NULL, the return
+   value is allocated using either malloc or bfd_alloc, according to
+   the KEEP_MEMORY argument.  */
+
+static Elf_Internal_Rela *
+elf_link_read_relocs (abfd, o, external_relocs, internal_relocs, keep_memory)
+     bfd *abfd;
+     asection *o;
+     PTR external_relocs;
+     Elf_Internal_Rela *internal_relocs;
+     boolean keep_memory;
+{
+  Elf_Internal_Shdr *rel_hdr;
+  PTR alloc1 = NULL;
+  Elf_Internal_Rela *alloc2 = NULL;
+
+  if (elf_section_data (o)->relocs != NULL)
+    return elf_section_data (o)->relocs;
+
+  if (o->reloc_count == 0)
+    return NULL;
+
+  rel_hdr = &elf_section_data (o)->rel_hdr;
+
+  if (internal_relocs == NULL)
+    {
+      size_t size;
+
+      size = o->reloc_count * sizeof (Elf_Internal_Rela);
+      if (keep_memory)
+       internal_relocs = (Elf_Internal_Rela *) bfd_alloc (abfd, size);
+      else
+       internal_relocs = alloc2 = (Elf_Internal_Rela *) malloc (size);
+      if (internal_relocs == NULL)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         goto error_return;
+       }
+    }
+
+  if (external_relocs == NULL)
+    {
+      alloc1 = (PTR) malloc (rel_hdr->sh_size);
+      if (alloc1 == NULL)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         goto error_return;
+       }
+      external_relocs = alloc1;
+    }
+
+  if ((bfd_seek (abfd, rel_hdr->sh_offset, SEEK_SET) != 0)
+      || (bfd_read (external_relocs, 1, rel_hdr->sh_size, abfd)
+         != rel_hdr->sh_size))
+    goto error_return;
+
+  /* Swap in the relocs.  For convenience, we always produce an
+     Elf_Internal_Rela array; if the relocs are Rel, we set the addend
+     to 0.  */
+  if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
+    {
+      Elf_External_Rel *erel;
+      Elf_External_Rel *erelend;
+      Elf_Internal_Rela *irela;
+
+      erel = (Elf_External_Rel *) external_relocs;
+      erelend = erel + o->reloc_count;
+      irela = internal_relocs;
+      for (; erel < erelend; erel++, irela++)
+       {
+         Elf_Internal_Rel irel;
+
+         elf_swap_reloc_in (abfd, erel, &irel);
+         irela->r_offset = irel.r_offset;
+         irela->r_info = irel.r_info;
+         irela->r_addend = 0;
+       }
+    }
+  else
+    {
+      Elf_External_Rela *erela;
+      Elf_External_Rela *erelaend;
+      Elf_Internal_Rela *irela;
+
+      BFD_ASSERT (rel_hdr->sh_entsize == sizeof (Elf_External_Rela));
+
+      erela = (Elf_External_Rela *) external_relocs;
+      erelaend = erela + o->reloc_count;
+      irela = internal_relocs;
+      for (; erela < erelaend; erela++, irela++)
+       elf_swap_reloca_in (abfd, erela, irela);
+    }
+
+  /* Cache the results for next time, if we can.  */
+  if (keep_memory)
+    elf_section_data (o)->relocs = internal_relocs;
+                
+  if (alloc1 != NULL)
+    free (alloc1);
+
+  /* Don't free alloc2, since if it was allocated we are passing it
+     back (under the name of internal_relocs).  */
+
+  return internal_relocs;
+
+ error_return:
+  if (alloc1 != NULL)
+    free (alloc1);
+  if (alloc2 != NULL)
+    free (alloc2);
+  return NULL;
+}
+
 /* Record an assignment to a symbol made by a linker script.  We need
    this in case some dynamic object refers to this symbol.  */
 
@@ -4617,17 +4786,20 @@ NAME(bfd_elf,record_link_assignment) (output_bfd, info, name)
   struct elf_link_hash_entry *h;
 
   /* This is called after we have examined all the input objects.  If
-     the symbol does not exist, it merely means that no object refers
-     to it, and we can just ignore it at this point.  */
+     we are generating a shared library, we always output these
+     symbols.  Otherwise, if the symbol does not exist, it merely
+     means that no object refers to it, and we can just ignore it at
+     this point.  */
   h = elf_link_hash_lookup (elf_hash_table (info), name,
-                           false, false, false);
+                           info->shared, info->shared, false);
   if (h == NULL)
-    return true;
+    return ! info->shared;
 
   h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
 
-  if ((h->elf_link_hash_flags & (ELF_LINK_HASH_DEF_DYNAMIC
-                                | ELF_LINK_HASH_REF_DYNAMIC)) != 0
+  if (((h->elf_link_hash_flags & (ELF_LINK_HASH_DEF_DYNAMIC
+                                 | ELF_LINK_HASH_REF_DYNAMIC)) != 0
+       || info->shared)
       && h->dynindx == -1)
     {
       if (! elf_link_record_dynamic_symbol (info, h))
@@ -4969,12 +5141,7 @@ elf_bfd_final_link (abfd, info)
   struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
   if (info->shared)
-    {
-      fprintf (stderr,
-              "Generating ELF shared libraries is not yet supported\n");
-      bfd_set_error (bfd_error_invalid_operation);
-      return false;
-    }
+    abfd->flags |= DYNAMIC;
 
   dynobj = elf_hash_table (info)->dynobj;
 
@@ -5936,8 +6103,6 @@ elf_link_input_bfd (finfo, input_bfd)
   /* Relocate the contents of each section.  */
   for (o = input_bfd->sections; o != NULL; o = o->next)
     {
-      Elf_Internal_Shdr *input_rel_hdr;
-
       if ((o->flags & SEC_HAS_CONTENTS) == 0)
        continue;
 
@@ -5956,59 +6121,16 @@ elf_link_input_bfd (finfo, input_bfd)
 
       if ((o->flags & SEC_RELOC) != 0)
        {
-         PTR external_relocs;
-
-         /* Get the external relocs.  They may have been cached.  */
-         external_relocs = elf_section_data (o)->relocs;
-         if (external_relocs == NULL)
-           {
-             input_rel_hdr = &elf_section_data (o)->rel_hdr;
-             if ((bfd_seek (input_bfd, input_rel_hdr->sh_offset, SEEK_SET)
-                  != 0)
-                 || (bfd_read (finfo->external_relocs, 1,
-                              input_rel_hdr->sh_size, input_bfd)
-                     != input_rel_hdr->sh_size))
-               return false;
-             external_relocs = finfo->external_relocs;
-           }
-
-         /* Swap in the relocs.  For convenience, we always produce
-            an Elf_Internal_Rela array; if the relocs are Rel, we set
-            the addend to 0.  */
-         if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
-           {
-             Elf_External_Rel *erel;
-             Elf_External_Rel *erelend;
-             Elf_Internal_Rela *irela;
-
-             erel = (Elf_External_Rel *) external_relocs;
-             erelend = erel + o->reloc_count;
-             irela = finfo->internal_relocs;
-             for (; erel < erelend; erel++, irela++)
-               {
-                 Elf_Internal_Rel irel;
-
-                 elf_swap_reloc_in (input_bfd, erel, &irel);
-                 irela->r_offset = irel.r_offset;
-                 irela->r_info = irel.r_info;
-                 irela->r_addend = 0;
-               }
-           }
-         else
-           {
-             Elf_External_Rela *erela;
-             Elf_External_Rela *erelaend;
-             Elf_Internal_Rela *irela;
-
-             BFD_ASSERT (input_rel_hdr->sh_entsize
-                         == sizeof (Elf_External_Rela));
-
-             erela = (Elf_External_Rela *) external_relocs;
-             erelaend = erela + o->reloc_count;
-             irela = finfo->internal_relocs;
-             for (; erela < erelaend; erela++, irela++)
-               elf_swap_reloca_in (input_bfd, erela, irela);
-           }
+         Elf_Internal_Rela *internal_relocs;
+
+         /* Get the swapped relocs.  */
+         internal_relocs = elf_link_read_relocs (input_bfd, o,
+                                                 finfo->external_relocs,
+                                                 finfo->internal_relocs,
+                                                 false);
+         if (internal_relocs == NULL
+             && o->reloc_count > 0)
+           return false;
 
          /* Relocate the section by invoking a back end routine.
 
@@ -6033,7 +6155,7 @@ elf_link_input_bfd (finfo, input_bfd)
          if (! (*relocate_section) (output_bfd, finfo->info,
                                     input_bfd, o,
                                     finfo->contents,
-                                    finfo->internal_relocs,
+                                    internal_relocs,
                                     finfo->internal_syms,
                                     finfo->sections,
                                     finfo->symstrtab->tab))
@@ -6044,11 +6166,12 @@ elf_link_input_bfd (finfo, input_bfd)
              Elf_Internal_Rela *irela;
              Elf_Internal_Rela *irelaend;
              struct elf_link_hash_entry **rel_hash;
+             Elf_Internal_Shdr *input_rel_hdr;
              Elf_Internal_Shdr *output_rel_hdr;
 
              /* Adjust the reloc addresses and symbol indices.  */
 
-             irela = finfo->internal_relocs;
+             irela = internal_relocs;
              irelaend = irela + o->reloc_count;
              rel_hash = (elf_section_data (o->output_section)->rel_hashes
                          + o->output_section->reloc_count);
@@ -6164,10 +6287,11 @@ elf_link_input_bfd (finfo, input_bfd)
                }
 
              /* Swap out the relocs.  */
+             input_rel_hdr = &elf_section_data (o)->rel_hdr;
              output_rel_hdr = &elf_section_data (o->output_section)->rel_hdr;
              BFD_ASSERT (output_rel_hdr->sh_entsize
                          == input_rel_hdr->sh_entsize);
-             irela = finfo->internal_relocs;
+             irela = internal_relocs;
              irelaend = irela + o->reloc_count;
              if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
                {
index f14ac95ccee5aa86fbc2acf792ae38a6cc6df595..d43f135a5700ccbb9a2af059ab9348c626c08001 100644 (file)
@@ -89,9 +89,18 @@ struct elf_link_hash_entry
      one.  Otherwise it is NULL.  */
   struct elf_link_hash_entry *weakdef;
 
-  /* If we need to generate a COPY reloc, the processor specific
-     backend uses this to hold the offset into the reloc section.  */
-  bfd_vma copy_offset;
+  /* If this symbol requires an entry in the global offset table, the
+     processor specific backend uses this field to hold the offset
+     into the .got section.  If this field is -1, then the symbol does
+     not require a global offset table entry.  */
+  bfd_vma got_offset;
+
+  /* If this symbol requires an entry in the procedure linkage table,
+     the processor specific backend uses these two fields to hold the
+     offset into the procedure linkage section and the offset into the
+     .got section.  If plt_offset is -1, then the symbol does not
+     require an entry in the procedure linkage table.  */
+  bfd_vma plt_offset;
 
   /* Symbol type (STT_NOTYPE, STT_OBJECT, etc.).  */
   char type;
@@ -106,14 +115,12 @@ struct elf_link_hash_entry
 #define ELF_LINK_HASH_REF_DYNAMIC 04
   /* Symbol is defined by a shared object.  */
 #define ELF_LINK_HASH_DEF_DYNAMIC 010
-  /* Symbol is referenced by two or more shared objects.  */
-#define ELF_LINK_HASH_REF_DYNAMIC_MULTIPLE 020
-  /* Symbol is defined by two or more shared objects.  */
-#define ELF_LINK_HASH_DEF_DYNAMIC_MULTIPLE 040
   /* Dynamic symbol has been adjustd.  */
-#define ELF_LINK_HASH_DYNAMIC_ADJUSTED 0100
+#define ELF_LINK_HASH_DYNAMIC_ADJUSTED 020
   /* Symbol is defined as weak.  */
-#define ELF_LINK_HASH_DEFINED_WEAK 0200
+#define ELF_LINK_HASH_DEFINED_WEAK 040
+  /* Symbol needs a copy reloc.  */
+#define ELF_LINK_HASH_NEEDS_COPY 0100
 };
 
 /* ELF linker hash table.  */
@@ -277,6 +284,20 @@ struct elf_backend_data
   boolean (*elf_backend_create_dynamic_sections)
     PARAMS ((bfd *abfd, struct bfd_link_info *info));
 
+  /* The CHECK_RELOCS function is called by the add_symbols phase of
+     the ELF backend linker.  It is called once for each section with
+     relocs of an object file, just after the symbols for the object
+     file have been added to the global linker hash table.  The
+     function must look through the relocs and do any special handling
+     required.  This generally means allocating space in the global
+     offset table, and perhaps allocating space for a reloc.  The
+     relocs are always passed as Rela structures; if the section
+     actually uses Rel structures, the r_addend field will always be
+     zero.  */
+  boolean (*check_relocs)
+    PARAMS ((bfd *abfd, struct bfd_link_info *info, asection *o,
+            const Elf_Internal_Rela *relocs));
+
   /* The ADJUST_DYNAMIC_SYMBOL function is called by the ELF backend
      linker for every symbol which is defined by a dynamic object and
      referenced by a regular object.  This is called after all the
@@ -396,8 +417,10 @@ struct bfd_elf_section_data {
   /* Used by the backend linker to store the symbol hash table entries
      associated with relocs against global symbols.  */
   struct elf_link_hash_entry **rel_hashes;
-  /* A pointer to the unswapped external relocs; this may be NULL.  */
-  PTR relocs;
+  /* A pointer to the swapped relocs.  If the section uses REL relocs,
+     rather than RELA, all the r_addend fields will be zero.  This
+     pointer may be NULL.  It is used by the backend linker.  */
+  Elf_Internal_Rela *relocs;
 };
 
 #define elf_section_data(sec)  ((struct bfd_elf_section_data*)sec->used_by_bfd)
@@ -443,6 +466,10 @@ struct elf_obj_tdata
      minus the sh_info field of the symbol table header.  */
   struct elf_link_hash_entry **sym_hashes;
 
+  /* A mapping from local symbols to offsets into the global offset
+     table, used when linking.  This is indexed by the symbol index.  */
+  bfd_vma *local_got_offsets;
+
   /* The linker ELF emulation code needs to let the backend ELF linker
      know what filename should be used for a dynamic object if the
      dynamic object is found using a search.  This field is used to
@@ -473,6 +500,7 @@ struct elf_obj_tdata
 #define elf_gp(bfd)            (elf_tdata(bfd) -> gp)
 #define elf_gp_size(bfd)       (elf_tdata(bfd) -> gp_size)
 #define elf_sym_hashes(bfd)    (elf_tdata(bfd) -> sym_hashes)
+#define elf_local_got_offsets(bfd) (elf_tdata(bfd) -> local_got_offsets)
 #define elf_dt_needed_name(bfd)        (elf_tdata(bfd) -> dt_needed_name)
 #define elf_bad_symtab(bfd)    (elf_tdata(bfd) -> bad_symtab)
 \f
@@ -565,6 +593,10 @@ extern void bfd_elf32_swap_dyn_out
   PARAMS ((bfd *, const Elf_Internal_Dyn *, Elf32_External_Dyn *));
 extern boolean bfd_elf32_add_dynamic_entry
   PARAMS ((struct bfd_link_info *, bfd_vma, bfd_vma));
+extern boolean bfd_elf32_link_create_dynamic_sections
+  PARAMS ((bfd *, struct bfd_link_info *));
+extern boolean bfd_elf32_link_record_dynamic_symbol
+  PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
 
 /* If the target doesn't have reloc handling written yet:  */
 extern void bfd_elf32_no_info_to_howto PARAMS ((bfd *, arelent *,
@@ -626,6 +658,10 @@ extern void bfd_elf64_swap_dyn_out
   PARAMS ((bfd *, const Elf_Internal_Dyn *, Elf64_External_Dyn *));
 extern boolean bfd_elf64_add_dynamic_entry
   PARAMS ((struct bfd_link_info *, bfd_vma, bfd_vma));
+extern boolean bfd_elf64_link_create_dynamic_sections
+  PARAMS ((bfd *, struct bfd_link_info *));
+extern boolean bfd_elf64_link_record_dynamic_symbol
+  PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
 
 /* If the target doesn't have reloc handling written yet:  */
 extern void bfd_elf64_no_info_to_howto PARAMS ((bfd *, arelent *,