* ldgram.y (memory_spec): Provide empty action.
[deliverable/binutils-gdb.git] / bfd / elflink.c
index c30915be5db36a97f83d024e6c8906fb244eafbf..f8cc645ad76f528e806ffb3ae4c46b635d0fd297 100644 (file)
@@ -1,5 +1,6 @@
 /* ELF linking support for BFD.
-   Copyright 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
+   Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+   Free Software Foundation, Inc.
 
 This file is part of BFD, the Binary File Descriptor library.
 
@@ -41,9 +42,17 @@ _bfd_elf_create_got_section (abfd, info)
 
   switch (bed->s->arch_size)
     {
-    case 32: ptralign = 2; break;
-    case 64: ptralign = 3; break;
-    default: abort();
+    case 32:
+      ptralign = 2;
+      break;
+
+    case 64:
+      ptralign = 3;
+      break;
+
+    default:
+      bfd_set_error (bfd_error_bad_value);
+      return false;
     }
 
   flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
@@ -64,24 +73,27 @@ _bfd_elf_create_got_section (abfd, info)
        return false;
     }
 
-  /* 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,
-        bed->got_symbol_offset, (const char *) NULL, false,
-        bed->collect, (struct bfd_link_hash_entry **) &h)))
-    return false;
-  h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
-  h->type = STT_OBJECT;
+  if (bed->want_got_sym)
+    {
+      /* 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,
+            bed->got_symbol_offset, (const char *) NULL, false,
+            bed->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;
+      if (info->shared
+         && ! _bfd_elf_link_record_dynamic_symbol (info, h))
+       return false;
 
-  elf_hash_table (info)->hgot = h;
+      elf_hash_table (info)->hgot = h;
+    }
 
   /* The first bit of the global offset table is the header.  */
   s->_raw_size += bed->got_header_size + bed->got_symbol_offset;
@@ -89,7 +101,6 @@ _bfd_elf_create_got_section (abfd, info)
   return true;
 }
 \f
-
 /* Create dynamic sections when linking against a dynamic object.  */
 
 boolean
@@ -100,13 +111,21 @@ _bfd_elf_create_dynamic_sections (abfd, info)
   flagword flags, pltflags;
   register asection *s;
   struct elf_backend_data *bed = get_elf_backend_data (abfd);
-  int ptralign = 0;
+  int ptralign;
 
   switch (bed->s->arch_size)
     {
-    case 32: ptralign = 2; break;
-    case 64: ptralign = 3; break;
-    default: abort();
+    case 32:
+      ptralign = 2;
+      break;
+
+    case 64:
+      ptralign = 3;
+      break;
+
+    default:
+      bfd_set_error (bfd_error_bad_value);
+      return false;
     }
 
   /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and
@@ -118,7 +137,7 @@ _bfd_elf_create_dynamic_sections (abfd, info)
   pltflags = flags;
   pltflags |= SEC_CODE;
   if (bed->plt_not_loaded)
-    pltflags &= ~ (SEC_LOAD | SEC_HAS_CONTENTS);
+    pltflags &= ~ (SEC_CODE | SEC_LOAD | SEC_HAS_CONTENTS);
   if (bed->plt_readonly)
     pltflags |= SEC_READONLY;
 
@@ -147,7 +166,7 @@ _bfd_elf_create_dynamic_sections (abfd, info)
        return false;
     }
 
-  s = bfd_make_section (abfd, 
+  s = bfd_make_section (abfd,
                        bed->default_use_rela_p ? ".rela.plt" : ".rel.plt");
   if (s == NULL
       || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
@@ -183,9 +202,9 @@ _bfd_elf_create_dynamic_sections (abfd, info)
      copy relocs.  */
       if (! info->shared)
        {
-         s = bfd_make_section (abfd, 
-                               (bed->default_use_rela_p 
-                                ? ".rela.bss" : ".rel.bss")); 
+         s = bfd_make_section (abfd,
+                               (bed->default_use_rela_p
+                                ? ".rela.bss" : ".rel.bss"));
          if (s == NULL
              || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
              || ! bfd_set_section_alignment (abfd, s, ptralign))
@@ -196,7 +215,6 @@ _bfd_elf_create_dynamic_sections (abfd, info)
   return true;
 }
 \f
-
 /* Record a new dynamic symbol.  We record the dynamic symbols as we
    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.
@@ -212,12 +230,31 @@ _bfd_elf_link_record_dynamic_symbol (info, h)
 {
   if (h->dynindx == -1)
     {
-      struct bfd_strtab_hash *dynstr;
+      struct elf_strtab_hash *dynstr;
       char *p, *alc;
       const char *name;
       boolean copy;
       bfd_size_type indx;
 
+      /* XXX: The ABI draft says the linker must turn hidden and
+        internal symbols into STB_LOCAL symbols when producing the
+        DSO. However, if ld.so honors st_other in the dynamic table,
+        this would not be necessary.  */
+      switch (ELF_ST_VISIBILITY (h->other))
+       {
+       case STV_INTERNAL:
+       case STV_HIDDEN:
+         if (h->root.type != bfd_link_hash_undefined
+             && h->root.type != bfd_link_hash_undefweak)
+           {
+             h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
+             return true;
+           }
+
+       default:
+         break;
+       }
+
       h->dynindx = elf_hash_table (info)->dynsymcount;
       ++elf_hash_table (info)->dynsymcount;
 
@@ -225,7 +262,7 @@ _bfd_elf_link_record_dynamic_symbol (info, h)
       if (dynstr == NULL)
        {
          /* Create a strtab to hold the dynamic symbol names.  */
-         elf_hash_table (info)->dynstr = dynstr = _bfd_elf_stringtab_init ();
+         elf_hash_table (info)->dynstr = dynstr = _bfd_elf_strtab_init ();
          if (dynstr == NULL)
            return false;
        }
@@ -241,16 +278,18 @@ _bfd_elf_link_record_dynamic_symbol (info, h)
        }
       else
        {
-         alc = bfd_malloc (p - name + 1);
+         size_t len = p - name + 1;
+
+         alc = bfd_malloc ((bfd_size_type) len);
          if (alc == NULL)
            return false;
-         strncpy (alc, name, p - name);
-         alc[p - name] = '\0';
+         memcpy (alc, name, len - 1);
+         alc[len - 1] = '\0';
          name = alc;
          copy = true;
        }
 
-      indx = _bfd_stringtab_add (dynstr, name, true, copy);
+      indx = _bfd_elf_strtab_add (dynstr, name, copy);
 
       if (alc != NULL)
        free (alc);
@@ -263,6 +302,98 @@ _bfd_elf_link_record_dynamic_symbol (info, h)
   return true;
 }
 
+/* Record a new local dynamic symbol.  Returns 0 on failure, 1 on
+   success, and 2 on a failure caused by attempting to record a symbol
+   in a discarded section, eg. a discarded link-once section symbol.  */
+
+int
+elf_link_record_local_dynamic_symbol (info, input_bfd, input_indx)
+     struct bfd_link_info *info;
+     bfd *input_bfd;
+     long input_indx;
+{
+  bfd_size_type amt;
+  struct elf_link_local_dynamic_entry *entry;
+  struct elf_link_hash_table *eht;
+  struct elf_strtab_hash *dynstr;
+  unsigned long dynstr_index;
+  char *name;
+  Elf_External_Sym_Shndx eshndx;
+  char esym[sizeof (Elf64_External_Sym)];
+
+  if (! is_elf_hash_table (info))
+    return 0;
+
+  /* See if the entry exists already.  */
+  for (entry = elf_hash_table (info)->dynlocal; entry ; entry = entry->next)
+    if (entry->input_bfd == input_bfd && entry->input_indx == input_indx)
+      return 1;
+
+  amt = sizeof (*entry);
+  entry = (struct elf_link_local_dynamic_entry *) bfd_alloc (input_bfd, amt);
+  if (entry == NULL)
+    return 0;
+
+  /* Go find the symbol, so that we can find it's name.  */
+  if (!bfd_elf_get_elf_syms (input_bfd, &elf_tdata (input_bfd)->symtab_hdr,
+                            (size_t) 1, (size_t) input_indx,
+                            &entry->isym, esym, &eshndx))
+    {
+      bfd_release (input_bfd, entry);
+      return 0;
+    }
+
+  if (entry->isym.st_shndx != SHN_UNDEF
+      && (entry->isym.st_shndx < SHN_LORESERVE
+         || entry->isym.st_shndx > SHN_HIRESERVE))
+    {
+      asection *s;
+
+      s = bfd_section_from_elf_index (input_bfd, entry->isym.st_shndx);
+      if (s == NULL || bfd_is_abs_section (s->output_section))
+       {
+         /* We can still bfd_release here as nothing has done another
+            bfd_alloc.  We can't do this later in this function.  */
+         bfd_release (input_bfd, entry);
+         return 2;
+       }
+    }
+
+  name = (bfd_elf_string_from_elf_section
+         (input_bfd, elf_tdata (input_bfd)->symtab_hdr.sh_link,
+          entry->isym.st_name));
+
+  dynstr = elf_hash_table (info)->dynstr;
+  if (dynstr == NULL)
+    {
+      /* Create a strtab to hold the dynamic symbol names.  */
+      elf_hash_table (info)->dynstr = dynstr = _bfd_elf_strtab_init ();
+      if (dynstr == NULL)
+       return 0;
+    }
+
+  dynstr_index = _bfd_elf_strtab_add (dynstr, name, false);
+  if (dynstr_index == (unsigned long) -1)
+    return 0;
+  entry->isym.st_name = dynstr_index;
+
+  eht = elf_hash_table (info);
+
+  entry->next = eht->dynlocal;
+  eht->dynlocal = entry;
+  entry->input_bfd = input_bfd;
+  entry->input_indx = input_indx;
+  eht->dynsymcount++;
+
+  /* Whatever binding the symbol had before, it's now local.  */
+  entry->isym.st_info
+    = ELF_ST_INFO (STB_LOCAL, ELF_ST_TYPE (entry->isym.st_info));
+
+  /* The dynindx will be set at the end of size_dynamic_sections.  */
+
+  return 1;
+}
+
 /* Return the dynindex of a local dynamic symbol.  */
 
 long
@@ -293,13 +424,16 @@ elf_link_renumber_hash_table_dynsyms (h, data)
 {
   size_t *count = (size_t *) data;
 
+  if (h->root.type == bfd_link_hash_warning)
+    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
   if (h->dynindx != -1)
     h->dynindx = ++(*count);
 
   return true;
 }
 
-/* Assign dynsym indicies.  In a shared library we generate a section
+/* Assign dynsym indices.  In a shared library we generate a section
    symbol for each output section, which come first.  Next come all of
    the back-end allocated local dynamic syms, followed by the rest of
    the global symbols.  */
@@ -315,7 +449,8 @@ _bfd_elf_link_renumber_dynsyms (output_bfd, info)
     {
       asection *p;
       for (p = output_bfd->sections; p ; p = p->next)
-       elf_section_data (p)->dynindx = ++dynsymcount;
+       if ((p->flags & SEC_EXCLUDE) == 0)
+         elf_section_data (p)->dynindx = ++dynsymcount;
     }
 
   if (elf_hash_table (info)->dynlocal)
@@ -360,9 +495,9 @@ _bfd_elf_create_linker_section (abfd, info, which, defaults)
   if (!lsect)
     {
       asection *s;
+      bfd_size_type amt = sizeof (elf_linker_section_t);
 
-      lsect = (elf_linker_section_t *)
-       bfd_alloc (dynobj, sizeof (elf_linker_section_t));
+      lsect = (elf_linker_section_t *) bfd_alloc (dynobj, amt);
 
       *lsect = *defaults;
       elf_linker_section (dynobj, which) = lsect;
@@ -394,10 +529,10 @@ _bfd_elf_create_linker_section (abfd, info, which, defaults)
          s->_raw_size += lsect->hole_size;
          if (lsect->hole_offset > lsect->max_hole_offset)
            {
-             (*_bfd_error_handler) (_("%s: Section %s is already to large to put hole of %ld bytes in"),
+             (*_bfd_error_handler) (_("%s: Section %s is too large to add hole of %ld bytes"),
                                     bfd_get_filename (abfd),
                                     lsect->name,
-                                    (long)lsect->hole_size);
+                                    (long) lsect->hole_size);
 
              bfd_set_error (bfd_error_bad_value);
              return (elf_linker_section_t *)0;
@@ -463,14 +598,13 @@ _bfd_elf_create_linker_section (abfd, info, which, defaults)
 
   return lsect;
 }
-
 \f
 /* Find a linker generated pointer with a given addend and type.  */
 
 elf_linker_section_pointers_t *
 _bfd_elf_find_pointer_linker_section (linker_pointers, addend, which)
      elf_linker_section_pointers_t *linker_pointers;
-     bfd_signed_vma addend;
+     bfd_vma addend;
      elf_linker_section_enum_t which;
 {
   for ( ; linker_pointers != NULL; linker_pointers = linker_pointers->next)
@@ -481,7 +615,6 @@ _bfd_elf_find_pointer_linker_section (linker_pointers, addend, which)
 
   return (elf_linker_section_pointers_t *)0;
 }
-
 \f
 /* Make the .rela section corresponding to the generated linker section.  */
 
This page took 0.027165 seconds and 4 git commands to generate.