+ /* Set up the version definition section. */
+ s = bfd_get_section_by_name (dynobj, ".gnu.version_d");
+ BFD_ASSERT (s != NULL);
+
+ /* We may have created additional version definitions if we are
+ just linking a regular application. */
+ verdefs = asvinfo.verdefs;
+
+ if (verdefs == NULL)
+ {
+ asection **spp;
+
+ /* Don't include this section in the output file. */
+ for (spp = &output_bfd->sections;
+ *spp != s->output_section;
+ spp = &(*spp)->next)
+ ;
+ *spp = s->output_section->next;
+ --output_bfd->section_count;
+ }
+ else
+ {
+ unsigned int cdefs;
+ bfd_size_type size;
+ struct bfd_elf_version_tree *t;
+ bfd_byte *p;
+ Elf_Internal_Verdef def;
+ Elf_Internal_Verdaux defaux;
+
+ if (asvinfo.removed_dynamic)
+ {
+ /* Some dynamic symbols were changed to be local
+ symbols. In this case, we renumber all of the
+ dynamic symbols, so that we don't have a hole. If
+ the backend changed dynsymcount, then assume that the
+ new symbols are at the start. This is the case on
+ the MIPS. FIXME: The names of the removed symbols
+ will still be in the dynamic string table, wasting
+ space. */
+ elf_hash_table (info)->dynsymcount =
+ 1 + (elf_hash_table (info)->dynsymcount - old_dynsymcount);
+ elf_link_hash_traverse (elf_hash_table (info),
+ elf_link_renumber_dynsyms,
+ (PTR) info);
+ }
+
+ cdefs = 0;
+ size = 0;
+
+ /* Make space for the base version. */
+ size += sizeof (Elf_External_Verdef);
+ size += sizeof (Elf_External_Verdaux);
+ ++cdefs;
+
+ for (t = verdefs; t != NULL; t = t->next)
+ {
+ struct bfd_elf_version_deps *n;
+
+ size += sizeof (Elf_External_Verdef);
+ size += sizeof (Elf_External_Verdaux);
+ ++cdefs;
+
+ for (n = t->deps; n != NULL; n = n->next)
+ size += sizeof (Elf_External_Verdaux);
+ }
+
+ s->_raw_size = size;
+ s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size);
+ if (s->contents == NULL && s->_raw_size != 0)
+ return false;
+
+ /* Fill in the version definition section. */
+
+ p = s->contents;
+
+ def.vd_version = VER_DEF_CURRENT;
+ def.vd_flags = VER_FLG_BASE;
+ def.vd_ndx = 1;
+ def.vd_cnt = 1;
+ def.vd_aux = sizeof (Elf_External_Verdef);
+ def.vd_next = (sizeof (Elf_External_Verdef)
+ + sizeof (Elf_External_Verdaux));
+
+ if (soname_indx != -1)
+ {
+ def.vd_hash = bfd_elf_hash ((const unsigned char *) soname);
+ defaux.vda_name = soname_indx;
+ }
+ else
+ {
+ const char *name;
+ bfd_size_type indx;
+
+ name = output_bfd->filename;
+ def.vd_hash = bfd_elf_hash ((const unsigned char *) name);
+ indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
+ name, true, false);
+ if (indx == (bfd_size_type) -1)
+ return false;
+ defaux.vda_name = indx;
+ }
+ defaux.vda_next = 0;
+
+ _bfd_elf_swap_verdef_out (output_bfd, &def,
+ (Elf_External_Verdef *)p);
+ p += sizeof (Elf_External_Verdef);
+ _bfd_elf_swap_verdaux_out (output_bfd, &defaux,
+ (Elf_External_Verdaux *) p);
+ p += sizeof (Elf_External_Verdaux);
+
+ for (t = verdefs; t != NULL; t = t->next)
+ {
+ unsigned int cdeps;
+ struct bfd_elf_version_deps *n;
+ struct elf_link_hash_entry *h;
+
+ cdeps = 0;
+ for (n = t->deps; n != NULL; n = n->next)
+ ++cdeps;
+
+ /* Add a symbol representing this version. */
+ h = NULL;
+ if (! (_bfd_generic_link_add_one_symbol
+ (info, dynobj, t->name, BSF_GLOBAL, bfd_abs_section_ptr,
+ (bfd_vma) 0, (const char *) NULL, false,
+ get_elf_backend_data (dynobj)->collect,
+ (struct bfd_link_hash_entry **) &h)))
+ return false;
+ h->elf_link_hash_flags &= ~ ELF_LINK_NON_ELF;
+ h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+ h->type = STT_OBJECT;
+ h->verinfo.vertree = t;
+
+ if (! _bfd_elf_link_record_dynamic_symbol (info, h))
+ return false;
+
+ def.vd_version = VER_DEF_CURRENT;
+ def.vd_flags = 0;
+ if (t->globals == NULL && t->locals == NULL && ! t->used)
+ def.vd_flags |= VER_FLG_WEAK;
+ def.vd_ndx = t->vernum + 1;
+ def.vd_cnt = cdeps + 1;
+ def.vd_hash = bfd_elf_hash ((const unsigned char *) t->name);
+ def.vd_aux = sizeof (Elf_External_Verdef);
+ if (t->next != NULL)
+ def.vd_next = (sizeof (Elf_External_Verdef)
+ + (cdeps + 1) * sizeof (Elf_External_Verdaux));
+ else
+ def.vd_next = 0;
+
+ _bfd_elf_swap_verdef_out (output_bfd, &def,
+ (Elf_External_Verdef *) p);
+ p += sizeof (Elf_External_Verdef);
+
+ defaux.vda_name = h->dynstr_index;
+ if (t->deps == NULL)
+ defaux.vda_next = 0;
+ else
+ defaux.vda_next = sizeof (Elf_External_Verdaux);
+ t->name_indx = defaux.vda_name;
+
+ _bfd_elf_swap_verdaux_out (output_bfd, &defaux,
+ (Elf_External_Verdaux *) p);
+ p += sizeof (Elf_External_Verdaux);
+
+ for (n = t->deps; n != NULL; n = n->next)
+ {
+ defaux.vda_name = n->version_needed->name_indx;
+ if (n->next == NULL)
+ defaux.vda_next = 0;
+ else
+ defaux.vda_next = sizeof (Elf_External_Verdaux);
+
+ _bfd_elf_swap_verdaux_out (output_bfd, &defaux,
+ (Elf_External_Verdaux *) p);
+ p += sizeof (Elf_External_Verdaux);
+ }
+ }
+
+ if (! elf_add_dynamic_entry (info, DT_VERDEF, 0)
+ || ! elf_add_dynamic_entry (info, DT_VERDEFNUM, cdefs))
+ return false;
+
+ elf_tdata (output_bfd)->cverdefs = cdefs;
+ }
+
+ /* Work out the size of the version reference section. */
+
+ s = bfd_get_section_by_name (dynobj, ".gnu.version_r");
+ BFD_ASSERT (s != NULL);
+ {
+ struct elf_find_verdep_info sinfo;
+
+ sinfo.output_bfd = output_bfd;
+ sinfo.info = info;
+ sinfo.vers = elf_tdata (output_bfd)->cverdefs;
+ if (sinfo.vers == 0)
+ sinfo.vers = 1;
+ sinfo.failed = false;
+
+ elf_link_hash_traverse (elf_hash_table (info),
+ elf_link_find_version_dependencies,
+ (PTR) &sinfo);
+
+ if (elf_tdata (output_bfd)->verref == NULL)
+ {
+ asection **spp;
+
+ /* We don't have any version definitions, so we can just
+ remove the section. */
+
+ for (spp = &output_bfd->sections;
+ *spp != s->output_section;
+ spp = &(*spp)->next)
+ ;
+ *spp = s->output_section->next;
+ --output_bfd->section_count;
+ }
+ else
+ {
+ Elf_Internal_Verneed *t;
+ unsigned int size;
+ unsigned int crefs;
+ bfd_byte *p;
+
+ /* Build the version definition section. */
+ size = 0;
+ crefs = 0;
+ for (t = elf_tdata (output_bfd)->verref;
+ t != NULL;
+ t = t->vn_nextref)
+ {
+ Elf_Internal_Vernaux *a;
+
+ size += sizeof (Elf_External_Verneed);
+ ++crefs;
+ for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
+ size += sizeof (Elf_External_Vernaux);
+ }
+
+ s->_raw_size = size;
+ s->contents = (bfd_byte *) bfd_alloc (output_bfd, size);
+ if (s->contents == NULL)
+ return false;
+
+ p = s->contents;
+ for (t = elf_tdata (output_bfd)->verref;
+ t != NULL;
+ t = t->vn_nextref)
+ {
+ unsigned int caux;
+ Elf_Internal_Vernaux *a;
+ bfd_size_type indx;
+
+ caux = 0;
+ for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
+ ++caux;
+
+ t->vn_version = VER_NEED_CURRENT;
+ t->vn_cnt = caux;
+ if (elf_dt_name (t->vn_bfd) != NULL)
+ indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
+ elf_dt_name (t->vn_bfd),
+ true, false);
+ else
+ indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
+ t->vn_bfd->filename, true, false);
+ if (indx == (bfd_size_type) -1)
+ return false;
+ t->vn_file = indx;
+ t->vn_aux = sizeof (Elf_External_Verneed);
+ if (t->vn_nextref == NULL)
+ t->vn_next = 0;
+ else
+ t->vn_next = (sizeof (Elf_External_Verneed)
+ + caux * sizeof (Elf_External_Vernaux));
+
+ _bfd_elf_swap_verneed_out (output_bfd, t,
+ (Elf_External_Verneed *) p);
+ p += sizeof (Elf_External_Verneed);
+
+ for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
+ {
+ a->vna_hash = bfd_elf_hash ((const unsigned char *)
+ a->vna_nodename);
+ indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
+ a->vna_nodename, true, false);
+ if (indx == (bfd_size_type) -1)
+ return false;
+ a->vna_name = indx;
+ if (a->vna_nextptr == NULL)
+ a->vna_next = 0;
+ else
+ a->vna_next = sizeof (Elf_External_Vernaux);
+
+ _bfd_elf_swap_vernaux_out (output_bfd, a,
+ (Elf_External_Vernaux *) p);
+ p += sizeof (Elf_External_Vernaux);
+ }
+ }
+
+ if (! elf_add_dynamic_entry (info, DT_VERNEED, 0)
+ || ! elf_add_dynamic_entry (info, DT_VERNEEDNUM, crefs))
+ return false;
+
+ elf_tdata (output_bfd)->cverrefs = crefs;
+ }
+ }
+
+ dynsymcount = elf_hash_table (info)->dynsymcount;
+
+ /* Work out the size of the symbol version section. */
+ s = bfd_get_section_by_name (dynobj, ".gnu.version");
+ BFD_ASSERT (s != NULL);
+ if (dynsymcount == 0
+ || (verdefs == NULL && elf_tdata (output_bfd)->verref == NULL))
+ {
+ asection **spp;
+
+ /* We don't need any symbol versions; just discard the
+ section. */
+ for (spp = &output_bfd->sections;
+ *spp != s->output_section;
+ spp = &(*spp)->next)
+ ;
+ *spp = s->output_section->next;
+ --output_bfd->section_count;
+ }
+ else
+ {
+ s->_raw_size = dynsymcount * sizeof (Elf_External_Versym);
+ s->contents = (bfd_byte *) bfd_zalloc (output_bfd, s->_raw_size);
+ if (s->contents == NULL)
+ return false;
+
+ if (! elf_add_dynamic_entry (info, DT_VERSYM, 0))
+ return false;
+ }
+
+ /* Set the size of the .dynsym and .hash sections. We counted
+ the number of dynamic symbols in elf_link_add_object_symbols.
+ We will build the contents of .dynsym and .hash when we build