2009-09-01 Tristan Gingold <gingold@adacore.com>
[deliverable/binutils-gdb.git] / bfd / elflink.c
index 70bca46953e97adf1c95949fa373932d71c8ccac..d6534f768dea26b3781e16763a691262f0026824 100644 (file)
@@ -1248,6 +1248,9 @@ _bfd_elf_merge_symbol (bfd *abfd,
   oldweak = (h->root.type == bfd_link_hash_defweak
             || h->root.type == bfd_link_hash_undefweak);
 
+  if (bind == STB_GNU_UNIQUE)
+    h->unique_global = 1;
+
   /* If a new weak symbol definition comes from a regular file and the
      old symbol comes from a dynamic library, we treat the new one as
      strong.  Similarly, an old weak symbol definition from a regular
@@ -2602,6 +2605,7 @@ _bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data)
      about symbols which are defined by one dynamic object and
      referenced by another one?  */
   if (!h->needs_plt
+      && h->type != STT_GNU_IFUNC
       && (h->def_regular
          || !h->def_dynamic
          || (!h->ref_regular
@@ -3549,7 +3553,11 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
          unsigned long shlink;
 
          if (!bfd_malloc_and_get_section (abfd, s, &dynbuf))
-           goto error_free_dyn;
+           {
+error_free_dyn:
+             free (dynbuf);
+             goto error_return;
+           }
 
          elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
          if (elfsec == SHN_BAD)
@@ -3633,11 +3641,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
                  amt = strlen (fnm) + 1;
                  anm = bfd_alloc (abfd, amt);
                  if (anm == NULL)
-                   {
-                   error_free_dyn:
-                     free (dynbuf);
-                     goto error_return;
-                   }
+                   goto error_free_dyn;
                  memcpy (anm, fnm, amt);
                  n->name = anm;
                  n->by = abfd;
@@ -3871,24 +3875,31 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
       common = bed->common_definition (isym);
 
       bind = ELF_ST_BIND (isym->st_info);
-      if (bind == STB_LOCAL)
+      switch (bind)
        {
+       case STB_LOCAL:
          /* This should be impossible, since ELF requires that all
             global symbols follow all local symbols, and that sh_info
             point to the first global symbol.  Unfortunately, Irix 5
             screws this up.  */
          continue;
-       }
-      else if (bind == STB_GLOBAL)
-       {
+
+       case STB_GLOBAL:
          if (isym->st_shndx != SHN_UNDEF && !common)
            flags = BSF_GLOBAL;
-       }
-      else if (bind == STB_WEAK)
-       flags = BSF_WEAK;
-      else
-       {
+         break;
+
+       case STB_WEAK:
+         flags = BSF_WEAK;
+         break;
+
+       case STB_GNU_UNIQUE:
+         flags = BSF_GNU_UNIQUE;
+         break;
+
+       default:
          /* Leave it up to the processor backend.  */
+         break;
        }
 
       if (isym->st_shndx == SHN_UNDEF)
@@ -4140,7 +4151,9 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *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;
+
       *sym_hash = h;
+      h->unique_global = (flags & BSF_GNU_UNIQUE) != 0;
 
       new_weakdef = FALSE;
       if (dynamic
@@ -4279,20 +4292,25 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
          if (ELF_ST_TYPE (isym->st_info) != STT_NOTYPE
              && (definition || h->type == STT_NOTYPE))
            {
-             if (h->type != STT_NOTYPE
-                 && h->type != ELF_ST_TYPE (isym->st_info)
-                 && ! type_change_ok)
-               (*_bfd_error_handler)
-                 (_("Warning: type of symbol `%s' changed"
-                    " from %d to %d in %B"),
-                  abfd, name, h->type, ELF_ST_TYPE (isym->st_info));
+             unsigned int type = ELF_ST_TYPE (isym->st_info);
 
-             h->type = ELF_ST_TYPE (isym->st_info);
-           }
+             /* Turn an IFUNC symbol from a DSO into a normal FUNC
+                symbol.  */
+             if (type == STT_GNU_IFUNC
+                 && (abfd->flags & DYNAMIC) != 0)
+               type = STT_FUNC;
+
+             if (h->type != type)
+               {
+                 if (h->type != STT_NOTYPE && ! type_change_ok)
+                   (*_bfd_error_handler)
+                     (_("Warning: type of symbol `%s' changed"
+                        " from %d to %d in %B"),
+                      abfd, name, h->type, type);
 
-         /* STT_GNU_IFUNC symbol must go through PLT.  */
-         if (h->type == STT_GNU_IFUNC)
-           h->needs_plt = 1;
+                 h->type = type;
+               }
+           }
 
          /* Merge st_other field.  */
          elf_merge_st_other (abfd, h, isym, definition, dynamic);
@@ -7744,6 +7762,7 @@ bfd_elf_perform_complex_relocation (bfd *input_bfd,
   else
     shift = (8 * wordsz) - (start + len);
 
+  /* FIXME: octets_per_byte.  */
   x = get_value (wordsz, chunksz, input_bfd, contents + rel->r_offset);
 
 #ifdef DEBUG
@@ -7775,6 +7794,7 @@ bfd_elf_perform_complex_relocation (bfd *input_bfd,
          relocation, (mask << shift),
          ((relocation & mask) << shift), x);
 #endif
+  /* FIXME: octets_per_byte.  */
   put_value (wordsz, chunksz, input_bfd, x, contents + rel->r_offset);
   return r;
 }
@@ -8082,6 +8102,8 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
              + (i2e - 1) * sizeof (Elf_Internal_Rela));
 
   count = dynamic_relocs->size / ext_size;
+  if (count == 0)
+    return 0;
   sort = bfd_zmalloc (sort_elt * count);
 
   if (sort == NULL)
@@ -8112,6 +8134,7 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
          }
        erel = o->contents;
        erelend = o->contents + o->size;
+       /* FIXME: octets_per_byte.  */
        p = sort + o->output_offset / ext_size * sort_elt;
 
        while (erel < erelend)
@@ -8156,6 +8179,7 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
 
        erel = o->contents;
        erelend = o->contents + o->size;
+       /* FIXME: octets_per_byte.  */
        p = sort + o->output_offset / ext_size * sort_elt;
        while (erel < erelend)
          {
@@ -8564,6 +8588,8 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
   sym.st_other = h->other;
   if (h->forced_local)
     sym.st_info = ELF_ST_INFO (STB_LOCAL, h->type);
+  else if (h->unique_global)
+    sym.st_info = ELF_ST_INFO (STB_GNU_UNIQUE, h->type);
   else if (h->root.type == bfd_link_hash_undefweak
           || h->root.type == bfd_link_hash_defweak)
     sym.st_info = ELF_ST_INFO (STB_WEAK, h->type);
@@ -8655,7 +8681,7 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
      forced local syms when non-shared is due to a historical quirk.
      STT_GNU_IFUNC symbol must go through PLT.  */
   if ((h->type == STT_GNU_IFUNC
-       && h->ref_regular
+       && h->def_regular
        && !finfo->info->relocatable)
       || ((h->dynindx != -1
           || h->forced_local)
@@ -8685,12 +8711,17 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
          || ELF_ST_BIND (sym.st_info) == STB_WEAK))
     {
       int bindtype;
+      unsigned int type = ELF_ST_TYPE (sym.st_info);
+
+      /* Turn an undefined IFUNC symbol into a normal FUNC symbol. */
+      if (type == STT_GNU_IFUNC)
+       type = STT_FUNC;
 
       if (h->ref_regular_nonweak)
        bindtype = STB_GLOBAL;
       else
        bindtype = STB_WEAK;
-      sym.st_info = ELF_ST_INFO (bindtype, ELF_ST_TYPE (sym.st_info));
+      sym.st_info = ELF_ST_INFO (bindtype, type);
     }
 
   /* If this is a symbol defined in a dynamic library, don't use the
@@ -9670,6 +9701,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
          break;
        default:
          {
+           /* FIXME: octets_per_byte.  */
            if (! (o->flags & SEC_EXCLUDE)
                && ! (o->output_section->flags & SEC_NEVER_LOAD)
                && ! bfd_set_section_contents (output_bfd, o->output_section,
@@ -9993,6 +10025,7 @@ elf_fixup_link_order (bfd *abfd, asection *o)
       offset &= ~(bfd_vma) 0 << s->alignment_power;
       s->output_offset = offset;
       sections[n]->offset = offset;
+      /* FIXME: octets_per_byte.  */
       offset += sections[n]->size;
     }
 
@@ -10972,6 +11005,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
               != SHT_STRTAB)
              || strcmp (bfd_get_section_name (abfd, o), ".dynstr") != 0)
            {
+             /* FIXME: octets_per_byte.  */
              if (! bfd_set_section_contents (abfd, o->output_section,
                                              o->contents,
                                              (file_ptr) o->output_offset,
This page took 0.029519 seconds and 4 git commands to generate.