2004-01-12 Michael Chastain <mec.gnu@mindspring.com>
[deliverable/binutils-gdb.git] / bfd / elflink.c
index cb6b0b2ba1f9aa170cd095a5125e8f35f278286b..f58a67aade2f1818671afbe913cf383bcaf283f4 100644 (file)
@@ -32,7 +32,7 @@ _bfd_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
   asection *s;
   struct elf_link_hash_entry *h;
   struct bfd_link_hash_entry *bh;
-  struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   int ptralign;
 
   /* This function may be called more than once.  */
@@ -115,9 +115,9 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
   register asection *s;
   struct elf_link_hash_entry *h;
   struct bfd_link_hash_entry *bh;
-  struct elf_backend_data *bed;
+  const struct elf_backend_data *bed;
 
-  if (! is_elf_hash_table (info))
+  if (! is_elf_hash_table (info->hash))
     return FALSE;
 
   if (elf_hash_table (info)->dynamic_sections_created)
@@ -144,8 +144,7 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
        return FALSE;
     }
 
-  if (! info->traditional_format
-      && info->hash->creator->flavour == bfd_target_elf_flavour)
+  if (! info->traditional_format)
     {
       s = bfd_make_section (abfd, ".eh_frame_hdr");
       if (s == NULL
@@ -248,7 +247,7 @@ _bfd_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
 {
   flagword flags, pltflags;
   asection *s;
-  struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
   /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and
      .rel[a].bss sections.  */
@@ -309,7 +308,7 @@ _bfd_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
         section into the .bss section of the final image.  */
       s = bfd_make_section (abfd, ".dynbss");
       if (s == NULL
-         || ! bfd_set_section_flags (abfd, s, SEC_ALLOC))
+         || ! bfd_set_section_flags (abfd, s, SEC_ALLOC | SEC_LINKER_CREATED))
        return FALSE;
 
       /* The .rel[a].bss section holds copy relocs.  This section is not
@@ -353,9 +352,8 @@ _bfd_elf_link_record_dynamic_symbol (struct bfd_link_info *info,
   if (h->dynindx == -1)
     {
       struct elf_strtab_hash *dynstr;
-      char *p, *alc;
+      char *p;
       const char *name;
-      bfd_boolean copy;
       bfd_size_type indx;
 
       /* XXX: The ABI draft says the linker must turn hidden and
@@ -393,28 +391,18 @@ _bfd_elf_link_record_dynamic_symbol (struct bfd_link_info *info,
         table.  */
       name = h->root.root.string;
       p = strchr (name, ELF_VER_CHR);
-      if (p == NULL)
-       {
-         alc = NULL;
-         copy = FALSE;
-       }
-      else
-       {
-         size_t len = p - name + 1;
+      if (p != NULL)
+       /* We know that the p points into writable memory.  In fact,
+          there are only a few symbols that have read-only names, being
+          those like _GLOBAL_OFFSET_TABLE_ that are created specially
+          by the backends.  Most symbols will have names pointing into
+          an ELF string table read from a file, or to objalloc memory.  */
+       *p = 0;
 
-         alc = bfd_malloc (len);
-         if (alc == NULL)
-           return FALSE;
-         memcpy (alc, name, len - 1);
-         alc[len - 1] = '\0';
-         name = alc;
-         copy = TRUE;
-       }
-
-      indx = _bfd_elf_strtab_add (dynstr, name, copy);
+      indx = _bfd_elf_strtab_add (dynstr, name, p != NULL);
 
-      if (alc != NULL)
-       free (alc);
+      if (p != NULL)
+       *p = ELF_VER_CHR;
 
       if (indx == (bfd_size_type) -1)
        return FALSE;
@@ -435,7 +423,7 @@ bfd_elf_record_link_assignment (bfd *output_bfd ATTRIBUTE_UNUSED,
 {
   struct elf_link_hash_entry *h;
 
-  if (info->hash->creator->flavour != bfd_target_elf_flavour)
+  if (!is_elf_hash_table (info->hash))
     return TRUE;
 
   h = elf_link_hash_lookup (elf_hash_table (info), name, TRUE, TRUE, FALSE);
@@ -505,7 +493,7 @@ elf_link_record_local_dynamic_symbol (struct bfd_link_info *info,
   Elf_External_Sym_Shndx eshndx;
   char esym[sizeof (Elf64_External_Sym)];
 
-  if (! is_elf_hash_table (info))
+  if (! is_elf_hash_table (info->hash))
     return 0;
 
   /* See if the entry exists already.  */
@@ -806,7 +794,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
   else
     olddef = TRUE;
 
-  /* We need to rememeber if a symbol has a definition in a dynamic
+  /* We need to remember if a symbol has a definition in a dynamic
      object or is weak in all dynamic objects. Internal and hidden
      visibility will make it unavailable to dynamic objects.  */
   if (newdyn && (h->elf_link_hash_flags & ELF_LINK_DYNAMIC_DEF) == 0)
@@ -869,7 +857,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
       return TRUE;
     }
 
-  /* We need to treat weak definiton right, depending on if there is a
+  /* We need to treat weak definition right, depending on if there is a
      definition from a dynamic object.  */
   if (bind == STB_WEAK)
     {
@@ -962,12 +950,16 @@ _bfd_elf_merge_symbol (bfd *abfd,
   /* It's OK to change the type if either the existing symbol or the
      new symbol is weak unless it comes from a DT_NEEDED entry of
      a shared object, in which case, the DT_NEEDED entry may not be
-     required at the run time.  */
+     required at the run time. The type change is also OK if the
+     old symbol is undefined and the new symbol is defined.  */
 
   if ((! dt_needed && oldweakdef)
       || oldweakundef
       || newweakdef
-      || newweakundef)
+      || newweakundef
+      || (newdef
+         && (h->root.type == bfd_link_hash_undefined
+             || h->root.type == bfd_link_hash_undefweak)))
     *type_change_ok = TRUE;
 
   /* It's OK to change the size if either the existing symbol or the
@@ -1134,7 +1126,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
              h->size, abfd, bfd_link_hash_common, sym->st_size)))
        return FALSE;
 
-      /* If the predumed common symbol in the dynamic object is
+      /* If the presumed common symbol in the dynamic object is
         larger, pretend that the new symbol has its size.  */
 
       if (h->size > *pvalue)
@@ -1164,7 +1156,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
       /* Handle the case where we had a versioned symbol in a dynamic
         library and now find a definition in a normal object.  In this
         case, we make the versioned symbol point to the normal one.  */
-      struct elf_backend_data *bed = get_elf_backend_data (abfd);
+      const struct elf_backend_data *bed = get_elf_backend_data (abfd);
       flip->root.type = h->root.type;
       h->root.type = bfd_link_hash_indirect;
       h->root.u.i.link = (struct bfd_link_hash_entry *) flip;
@@ -1247,7 +1239,7 @@ _bfd_elf_add_default_symbol (bfd *abfd,
   char *shortname;
   struct elf_link_hash_entry *hi;
   struct bfd_link_hash_entry *bh;
-  struct elf_backend_data *bed;
+  const struct elf_backend_data *bed;
   bfd_boolean collect;
   bfd_boolean dynamic;
   char *p;
@@ -1264,7 +1256,7 @@ _bfd_elf_add_default_symbol (bfd *abfd,
 
   if (override)
     {
-      /* We are overridden by an old defition. We need to check if we
+      /* We are overridden by an old definition. We need to check if we
         need to create the indirect symbol from the default name.  */
       hi = elf_link_hash_lookup (elf_hash_table (info), name, TRUE,
                                 FALSE, FALSE);
@@ -1423,7 +1415,7 @@ nondefault:
     {
       /* Here SHORTNAME is a versioned name, so we don't expect to see
         the type of override we do in the case above unless it is
-        overridden by a versioned definiton.  */
+        overridden by a versioned definition.  */
       if (hi->root.type != bfd_link_hash_defined
          && hi->root.type != bfd_link_hash_defweak)
        (*_bfd_error_handler)
@@ -1501,22 +1493,18 @@ _bfd_elf_export_symbol (struct elf_link_hash_entry *h, void *data)
 
       for (t = eif->verdefs; t != NULL; t = t->next)
        {
-         if (t->globals != NULL)
+         if (t->globals.list != NULL)
            {
-             for (d = t->globals; d != NULL; d = d->next)
-               {
-                 if ((*d->match) (d, h->root.root.string))
-                   goto doit;
-               }
+             d = (*t->match) (&t->globals, NULL, h->root.root.string);
+             if (d != NULL)
+               goto doit;
            }
 
-         if (t->locals != NULL)
+         if (t->locals.list != NULL)
            {
-             for (d = t->locals ; d != NULL; d = d->next)
-               {
-                 if ((*d->match) (d, h->root.root.string))
-                   return TRUE;
-               }
+             d = (*t->match) (&t->locals, NULL, h->root.root.string);
+             if (d != NULL)
+               return TRUE;
            }
        }
 
@@ -1621,7 +1609,7 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
 {
   struct elf_assign_sym_version_info *sinfo;
   struct bfd_link_info *info;
-  struct elf_backend_data *bed;
+  const struct elf_backend_data *bed;
   struct elf_info_failed eif;
   char *p;
   bfd_size_type amt;
@@ -1695,31 +1683,19 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
              t->used = TRUE;
              d = NULL;
 
-             if (t->globals != NULL)
-               {
-                 for (d = t->globals; d != NULL; d = d->next)
-                   if ((*d->match) (d, alc))
-                     break;
-               }
+             if (t->globals.list != NULL)
+               d = (*t->match) (&t->globals, NULL, alc);
 
              /* See if there is anything to force this symbol to
                 local scope.  */
-             if (d == NULL && t->locals != NULL)
+             if (d == NULL && t->locals.list != NULL)
                {
-                 for (d = t->locals; d != NULL; d = d->next)
-                   {
-                     if ((*d->match) (d, alc))
-                       {
-                         if (h->dynindx != -1
-                             && info->shared
-                             && ! info->export_dynamic)
-                           {
-                             (*bed->elf_backend_hide_symbol) (info, h, TRUE);
-                           }
-
-                         break;
-                       }
-                   }
+                 d = (*t->match) (&t->locals, NULL, alc);
+                 if (d != NULL
+                     && h->dynindx != -1
+                     && info->shared
+                     && ! info->export_dynamic)
+                   (*bed->elf_backend_hide_symbol) (info, h, TRUE);
                }
 
              free (alc);
@@ -1740,18 +1716,14 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
            return TRUE;
 
          amt = sizeof *t;
-         t = bfd_alloc (sinfo->output_bfd, amt);
+         t = bfd_zalloc (sinfo->output_bfd, amt);
          if (t == NULL)
            {
              sinfo->failed = TRUE;
              return FALSE;
            }
 
-         t->next = NULL;
          t->name = p;
-         t->globals = NULL;
-         t->locals = NULL;
-         t->deps = NULL;
          t->name_indx = (unsigned int) -1;
          t->used = TRUE;
 
@@ -1797,30 +1769,26 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
       local_ver = NULL;
       for (t = sinfo->verdefs; t != NULL; t = t->next)
        {
-         if (t->globals != NULL)
+         if (t->globals.list != NULL)
            {
              bfd_boolean matched;
 
              matched = FALSE;
-             for (d = t->globals; d != NULL; d = d->next)
-               {
-                 if ((*d->match) (d, h->root.root.string))
-                   {
-                     if (d->symver)
-                       matched = TRUE;
-                     else
-                       {
-                         /* There is a version without definition.  Make
-                            the symbol the default definition for this
-                            version.  */
-                         h->verinfo.vertree = t;
-                         local_ver = NULL;
-                         d->script = 1;
-                         break;
-                       }
-                   }
-               }
-
+             d = NULL;
+             while ((d = (*t->match) (&t->globals, d,
+                                      h->root.root.string)) != NULL)
+               if (d->symver)
+                 matched = TRUE;
+               else
+                 {
+                   /* There is a version without definition.  Make
+                      the symbol the default definition for this
+                      version.  */
+                   h->verinfo.vertree = t;
+                   local_ver = NULL;
+                   d->script = 1;
+                   break;
+                 }
              if (d != NULL)
                break;
              else if (matched)
@@ -1829,19 +1797,18 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
                (*bed->elf_backend_hide_symbol) (info, h, TRUE);
            }
 
-         if (t->locals != NULL)
+         if (t->locals.list != NULL)
            {
-             for (d = t->locals; d != NULL; d = d->next)
+             d = NULL;
+             while ((d = (*t->match) (&t->locals, d,
+                                      h->root.root.string)) != NULL)
                {
+                 local_ver = t;
                  /* If the match is "*", keep looking for a more
-                    explicit, perhaps even global, match.  */
-                 if (d->pattern[0] == '*' && d->pattern[1] == '\0')
-                   local_ver = t;
-                 else if ((*d->match) (d, h->root.root.string))
-                   {
-                     local_ver = t;
-                     break;
-                   }
+                    explicit, perhaps even global, match.
+                    XXX: Shouldn't this be !d->wildcard instead?  */
+                 if (d->pattern[0] != '*' || d->pattern[1] != '\0')
+                   break;
                }
 
              if (d != NULL)
@@ -1875,15 +1842,18 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
 
 static bfd_boolean
 elf_link_read_relocs_from_section (bfd *abfd,
+                                  asection *sec,
                                   Elf_Internal_Shdr *shdr,
                                   void *external_relocs,
                                   Elf_Internal_Rela *internal_relocs)
 {
-  struct elf_backend_data *bed;
+  const struct elf_backend_data *bed;
   void (*swap_in) (bfd *, const bfd_byte *, Elf_Internal_Rela *);
   const bfd_byte *erela;
   const bfd_byte *erelaend;
   Elf_Internal_Rela *irela;
+  Elf_Internal_Shdr *symtab_hdr;
+  size_t nsyms;
 
   /* If there aren't any relocations, that's OK.  */
   if (!shdr)
@@ -1897,6 +1867,9 @@ elf_link_read_relocs_from_section (bfd *abfd,
   if (bfd_bread (external_relocs, shdr->sh_size, abfd) != shdr->sh_size)
     return FALSE;
 
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  nsyms = symtab_hdr->sh_size / symtab_hdr->sh_entsize;
+
   bed = get_elf_backend_data (abfd);
 
   /* Convert the external relocations to the internal format.  */
@@ -1915,7 +1888,21 @@ elf_link_read_relocs_from_section (bfd *abfd,
   irela = internal_relocs;
   while (erela < erelaend)
     {
+      bfd_vma r_symndx;
+
       (*swap_in) (abfd, erela, irela);
+      r_symndx = ELF32_R_SYM (irela->r_info);
+      if (bed->s->arch_size == 64)
+       r_symndx >>= 24;
+      if ((size_t) r_symndx >= nsyms)
+       {
+         (*_bfd_error_handler)
+           (_("%s: bad reloc symbol index (0x%lx >= 0x%lx) for offset 0x%lx in section `%s'"),
+            bfd_archive_filename (abfd), (unsigned long) r_symndx,
+            (unsigned long) nsyms, irela->r_offset, sec->name);
+         bfd_set_error (bfd_error_bad_value);
+         return FALSE;
+       }
       irela += bed->s->int_rels_per_ext_rel;
       erela += shdr->sh_entsize;
     }
@@ -1943,7 +1930,7 @@ _bfd_elf_link_read_relocs (bfd *abfd,
   Elf_Internal_Shdr *rel_hdr;
   void *alloc1 = NULL;
   Elf_Internal_Rela *alloc2 = NULL;
-  struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
   if (elf_section_data (o)->relocs != NULL)
     return elf_section_data (o)->relocs;
@@ -1979,12 +1966,12 @@ _bfd_elf_link_read_relocs (bfd *abfd,
       external_relocs = alloc1;
     }
 
-  if (!elf_link_read_relocs_from_section (abfd, rel_hdr,
+  if (!elf_link_read_relocs_from_section (abfd, o, rel_hdr,
                                          external_relocs,
                                          internal_relocs))
     goto error_return;
   if (!elf_link_read_relocs_from_section
-      (abfd,
+      (abfd, o,
        elf_section_data (o)->rel_hdr2,
        ((bfd_byte *) external_relocs) + rel_hdr->sh_size,
        internal_relocs + (NUM_SHDR_ENTRIES (rel_hdr)
@@ -2076,7 +2063,7 @@ _bfd_elf_link_output_relocs (bfd *output_bfd,
   Elf_Internal_Shdr *output_rel_hdr;
   asection *output_section;
   unsigned int *rel_countp = NULL;
-  struct elf_backend_data *bed;
+  const struct elf_backend_data *bed;
   void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *);
 
   output_section = input_section->output_section;
@@ -2218,12 +2205,12 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h,
      will force it local.  */
   if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0
       && eif->info->shared
-      && is_elf_hash_table (eif->info)
+      && is_elf_hash_table (eif->info->hash)
       && (eif->info->symbolic
          || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
       && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
     {
-      struct elf_backend_data *bed;
+      const struct elf_backend_data *bed;
       bfd_boolean force_local;
 
       bed = get_elf_backend_data (elf_hash_table (eif->info)->dynobj);
@@ -2238,7 +2225,7 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h,
   if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
       && h->root.type == bfd_link_hash_undefweak)
     {
-      struct elf_backend_data *bed;
+      const struct elf_backend_data *bed;
       bed = get_elf_backend_data (elf_hash_table (eif->info)->dynobj);
       (*bed->elf_backend_hide_symbol) (eif->info, h, TRUE);
     }
@@ -2267,7 +2254,7 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h,
        h->weakdef = NULL;
       else
        {
-         struct elf_backend_data *bed;
+         const struct elf_backend_data *bed;
 
          bed = get_elf_backend_data (elf_hash_table (eif->info)->dynobj);
          (*bed->elf_backend_copy_indirect_symbol) (bed, weakdef, h);
@@ -2286,9 +2273,9 @@ _bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data)
 {
   struct elf_info_failed *eif = data;
   bfd *dynobj;
-  struct elf_backend_data *bed;
+  const struct elf_backend_data *bed;
 
-  if (! is_elf_hash_table (eif->info))
+  if (! is_elf_hash_table (eif->info->hash))
     return FALSE;
 
   if (h->root.type == bfd_link_hash_warning)
@@ -2531,3 +2518,31 @@ _bfd_elf_symbol_refs_local_p (struct elf_link_hash_entry *h,
      dynamic linker will resolve them locally.  */
   return local_protected;
 }
+
+/* Caches some TLS segment info, and ensures that the TLS segment vma is
+   aligned.  Returns the first TLS output section.  */
+
+struct bfd_section *
+_bfd_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
+{
+  struct bfd_section *sec, *tls;
+  unsigned int align = 0;
+
+  for (sec = obfd->sections; sec != NULL; sec = sec->next)
+    if ((sec->flags & SEC_THREAD_LOCAL) != 0)
+      break;
+  tls = sec;
+
+  for (; sec != NULL && (sec->flags & SEC_THREAD_LOCAL) != 0; sec = sec->next)
+    if (sec->alignment_power > align)
+      align = sec->alignment_power;
+
+  elf_hash_table (info)->tls_sec = tls;
+
+  /* Ensure the alignment of the first section is the largest alignment,
+     so that the tls segment starts aligned.  */
+  if (tls != NULL)
+    tls->alignment_power = align;
+
+  return tls;
+}
This page took 0.030181 seconds and 4 git commands to generate.