symbolS *sym;
size_t name_length;
- sym = symbol_new (s, absolute_section, 0, NULL);
- symbol_set_frag (sym, &zero_address_frag);
+ sym = symbol_new (s, absolute_section, &zero_address_frag, 0);
name_length = strlen (s);
if (name_length > strlen (S_GET_NAME (sym)))
/* Add a symbol for this section to the symbol table. */
secsym = symbol_find (name);
if (secsym != NULL)
- symbol_set_bfdsym (secsym, sec->symbol);
+ {
+ /* We could be repurposing an undefined symbol here: make sure we
+ reset sy_value to look like other section symbols in order to avoid
+ trying to incorrectly resolve this section symbol later on. */
+ static const expressionS expr = { .X_op = O_constant };
+ symbol_set_value_expression (secsym, &expr);
+ symbol_set_bfdsym (secsym, sec->symbol);
+ }
else
symbol_table_insert (section_symbol (sec));
}
demand_empty_rest_of_line ();
}
+static struct elf_versioned_name_list *
+obj_elf_find_and_add_versioned_name (const char *version_name,
+ const char *sym_name,
+ const char *ver,
+ struct elf_obj_sy *sy_obj)
+{
+ struct elf_versioned_name_list *versioned_name;
+ const char *p;
+
+ for (p = ver + 1; *p == ELF_VER_CHR; p++)
+ ;
+
+ /* NB: Since some tests in ld/testsuite/ld-elfvers have no version
+ names, we have to disable this. */
+ if (0 && *p == '\0')
+ {
+ as_bad (_("missing version name in `%s' for symbol `%s'"),
+ version_name, sym_name);
+ return NULL;
+ }
+
+ versioned_name = sy_obj->versioned_name;
+
+ switch (p - ver)
+ {
+ case 1:
+ case 2:
+ break;
+ case 3:
+ if (sy_obj->rename)
+ {
+ if (strcmp (versioned_name->name, version_name) == 0)
+ return versioned_name;
+ else
+ {
+ as_bad (_("only one version name with `@@@' is allowed "
+ "for symbol `%s'"), sym_name);
+ return NULL;
+ }
+ }
+ sy_obj->rename = TRUE;
+ break;
+ default:
+ as_bad (_("invalid version name '%s' for symbol `%s'"),
+ version_name, sym_name);
+ return NULL;
+ }
+
+ for (;
+ versioned_name != NULL;
+ versioned_name = versioned_name->next)
+ if (strcmp (versioned_name->name, version_name) == 0)
+ return versioned_name;
+
+ /* Add this versioned name to the head of the list, */
+ versioned_name = (struct elf_versioned_name_list *)
+ xmalloc (sizeof (*versioned_name));
+ versioned_name->name = xstrdup (version_name);
+ versioned_name->next = sy_obj->versioned_name;
+ sy_obj->versioned_name = versioned_name;
+
+ return versioned_name;
+}
+
/* This handles the .symver pseudo-op, which is used to specify a
symbol version. The syntax is ``.symver NAME,SYMVERNAME''.
SYMVERNAME may contain ELF_VER_CHR ('@') characters. This
obj_elf_symver (int ignore ATTRIBUTE_UNUSED)
{
char *name;
+ const char *sym_name;
char c;
char old_lexat;
symbolS *sym;
+ struct elf_obj_sy *sy_obj;
+ char *p;
sym = get_sym_from_input_line_and_check ();
lex_type[(unsigned char) '@'] |= LEX_NAME;
c = get_symbol_name (& name);
lex_type[(unsigned char) '@'] = old_lexat;
+ sym_name = S_GET_NAME (sym);
if (S_IS_COMMON (sym))
{
as_bad (_("`%s' can't be versioned to common symbol '%s'"),
- name, S_GET_NAME (sym));
+ name, sym_name);
+ ignore_rest_of_line ();
+ return;
+ }
+
+ p = strchr (name, ELF_VER_CHR);
+ if (p == NULL)
+ {
+ as_bad (_("missing version name in `%s' for symbol `%s'"),
+ name, sym_name);
ignore_rest_of_line ();
return;
}
- if (symbol_get_obj (sym)->versioned_name == NULL)
+ sy_obj = symbol_get_obj (sym);
+ if (obj_elf_find_and_add_versioned_name (name, sym_name,
+ p, sy_obj) == NULL)
{
- symbol_get_obj (sym)->versioned_name = xstrdup (name);
+ sy_obj->bad_version = TRUE;
+ ignore_rest_of_line ();
+ return;
+ }
- (void) restore_line_pointer (c);
+ (void) restore_line_pointer (c);
- if (strchr (symbol_get_obj (sym)->versioned_name,
- ELF_VER_CHR) == NULL)
+ if (*input_line_pointer == ',')
+ {
+ char *save = input_line_pointer;
+
+ ++input_line_pointer;
+ SKIP_WHITESPACE ();
+ if (strncmp (input_line_pointer, "local", 5) == 0)
{
- as_bad (_("missing version name in `%s' for symbol `%s'"),
- symbol_get_obj (sym)->versioned_name,
- S_GET_NAME (sym));
- ignore_rest_of_line ();
- return;
+ input_line_pointer += 5;
+ sy_obj->visibility = visibility_local;
}
- }
- else
- {
- if (strcmp (symbol_get_obj (sym)->versioned_name, name))
+ else if (strncmp (input_line_pointer, "hidden", 6) == 0)
{
- as_bad (_("multiple versions [`%s'|`%s'] for symbol `%s'"),
- name, symbol_get_obj (sym)->versioned_name,
- S_GET_NAME (sym));
- ignore_rest_of_line ();
- return;
+ input_line_pointer += 6;
+ sy_obj->visibility = visibility_hidden;
}
-
- (void) restore_line_pointer (c);
+ else if (strncmp (input_line_pointer, "remove", 6) == 0)
+ {
+ input_line_pointer += 6;
+ sy_obj->visibility = visibility_remove;
+ }
+ else
+ input_line_pointer = save;
}
demand_empty_rest_of_line ();
}
else
{
- if (destelf->size != NULL)
- free (destelf->size);
+ free (destelf->size);
destelf->size = NULL;
}
S_SET_SIZE (dest, S_GET_SIZE (src));
if (exp.X_op == O_constant)
{
S_SET_SIZE (sym, exp.X_add_number);
- if (symbol_get_obj (sym)->size)
- {
- xfree (symbol_get_obj (sym)->size);
- symbol_get_obj (sym)->size = NULL;
- }
+ xfree (symbol_get_obj (sym)->size);
+ symbol_get_obj (sym)->size = NULL;
}
else
{
&& bed->elf_osabi != ELFOSABI_FREEBSD)
as_bad (_("symbol type \"%s\" is supported only by GNU "
"and FreeBSD targets"), type_name);
+ /* MIPS targets do not support IFUNCS. */
+ else if (bed->target_id == MIPS_ELF_DATA)
+ as_bad (_("symbol type \"%s\" is not supported by "
+ "MIPS targets"), type_name);
elf_tdata (stdoutput)->has_gnu_osabi |= elf_gnu_osabi_ifunc;
type = BSF_FUNCTION | BSF_GNU_INDIRECT_FUNCTION;
}
{
struct elf_obj_sy *sy_obj;
expressionS *size;
+ struct elf_versioned_name_list *versioned_name;
#ifdef NEED_ECOFF_DEBUG
if (ECOFF_DEBUGGING)
sy_obj->size = NULL;
}
- if (sy_obj->versioned_name != NULL)
+ versioned_name = sy_obj->versioned_name;
+ if (versioned_name)
{
- char *p;
-
- p = strchr (sy_obj->versioned_name, ELF_VER_CHR);
- if (p == NULL)
- /* We will have already reported an error about a missing version. */
- *puntp = TRUE;
-
/* This symbol was given a new name with the .symver directive.
-
If this is an external reference, just rename the symbol to
include the version string. This will make the relocs be
- against the correct versioned symbol.
-
- If this is a definition, add an alias. FIXME: Using an alias
- will permit the debugging information to refer to the right
- symbol. However, it's not clear whether it is the best
- approach. */
+ against the correct versioned symbol. */
- else if (! S_IS_DEFINED (symp))
+ /* We will have already reported an version error. */
+ if (sy_obj->bad_version)
+ *puntp = TRUE;
+ /* elf_frob_file_before_adjust only allows one version symbol for
+ renamed symbol. */
+ else if (sy_obj->rename)
+ S_SET_NAME (symp, versioned_name->name);
+ else if (S_IS_COMMON (symp))
{
- /* Verify that the name isn't using the @@ syntax--this is
- reserved for definitions of the default version to link
- against. */
- if (p[1] == ELF_VER_CHR)
- {
- as_bad (_("invalid attempt to declare external version name"
- " as default in symbol `%s'"),
- sy_obj->versioned_name);
- *puntp = TRUE;
- }
- S_SET_NAME (symp, sy_obj->versioned_name);
+ as_bad (_("`%s' can't be versioned to common symbol '%s'"),
+ versioned_name->name, S_GET_NAME (symp));
+ *puntp = TRUE;
}
else
{
- if (p[1] == ELF_VER_CHR && p[2] == ELF_VER_CHR)
- {
- size_t l;
-
- /* The @@@ syntax is a special case. It renames the
- symbol name to versioned_name with one `@' removed. */
- l = strlen (&p[3]) + 1;
- memmove (&p[2], &p[3], l);
- S_SET_NAME (symp, sy_obj->versioned_name);
- }
- else
+ asymbol *bfdsym;
+ elf_symbol_type *elfsym;
+
+ /* This is a definition. Add an alias for each version.
+ FIXME: Using an alias will permit the debugging information
+ to refer to the right symbol. However, it's not clear
+ whether it is the best approach. */
+
+ /* FIXME: Creating a new symbol here is risky. We're
+ in the final loop over the symbol table. We can
+ get away with it only because the symbol goes to
+ the end of the list, where the loop will still see
+ it. It would probably be better to do this in
+ obj_frob_file_before_adjust. */
+ for (; versioned_name != NULL;
+ versioned_name = versioned_name->next)
{
- symbolS *symp2;
-
- /* FIXME: Creating a new symbol here is risky. We're
- in the final loop over the symbol table. We can
- get away with it only because the symbol goes to
- the end of the list, where the loop will still see
- it. It would probably be better to do this in
- obj_frob_file_before_adjust. */
-
- symp2 = symbol_find_or_make (sy_obj->versioned_name);
-
- /* Now we act as though we saw symp2 = sym. */
- if (S_IS_COMMON (symp))
- {
- as_bad (_("`%s' can't be versioned to common symbol '%s'"),
- sy_obj->versioned_name, S_GET_NAME (symp));
- *puntp = TRUE;
- return;
- }
+ symbolS *symp2 = symbol_find_or_make (versioned_name->name);
S_SET_SEGMENT (symp2, S_GET_SEGMENT (symp));
if (S_IS_EXTERNAL (symp))
S_SET_EXTERNAL (symp2);
}
+
+ switch (symbol_get_obj (symp)->visibility)
+ {
+ case visibility_unchanged:
+ break;
+ case visibility_hidden:
+ bfdsym = symbol_get_bfdsym (symp);
+ elfsym = elf_symbol_from (bfd_asymbol_bfd (bfdsym),
+ bfdsym);
+ elfsym->internal_elf_sym.st_other &= ~3;
+ elfsym->internal_elf_sym.st_other |= STV_HIDDEN;
+ break;
+ case visibility_remove:
+ symbol_remove (symp, &symbol_rootP, &symbol_lastP);
+ break;
+ case visibility_local:
+ S_CLEAR_EXTERNAL (symp);
+ break;
+ }
}
}
{
asection **head; /* Section lists. */
unsigned int num_group; /* Number of lists. */
- struct hash_control *indexes; /* Maps group name to index in head array. */
+ htab_t indexes; /* Maps group name to index in head array. */
};
static struct group_list groups;
/* If this group already has a list, add the section to the head of
the list. */
- elem_idx = (unsigned int *) hash_find (list->indexes, group_name);
+ elem_idx = (unsigned int *) str_hash_find (list->indexes, group_name);
if (elem_idx != NULL)
{
elf_next_in_group (sec) = list->head[*elem_idx];
/* Add index to hash. */
idx_ptr = XNEW (unsigned int);
*idx_ptr = i;
- hash_insert (list->indexes, group_name, idx_ptr);
+ str_hash_insert (list->indexes, group_name, (char *)idx_ptr);
}
-static void free_section_idx (const char *key ATTRIBUTE_UNUSED, void *val)
+static int
+free_section_idx (void **slot, void *arg ATTRIBUTE_UNUSED)
{
- free ((unsigned int *) val);
+ string_tuple_t *tuple = *((string_tuple_t **) slot);
+ free ((char *)tuple->value);
+ return 1;
}
/* Create symbols for group signature. */
/* Go find section groups. */
groups.num_group = 0;
groups.head = NULL;
- groups.indexes = hash_new ();
+ groups.indexes = str_htab_create ();
bfd_map_over_sections (stdoutput, build_additional_section_info,
&groups);
if (!sy || !symbol_on_chain (sy, symbol_rootP, symbol_lastP))
{
/* Create the symbol now. */
- sy = symbol_new (group_name, now_seg, (valueT) 0, frag_now);
+ sy = symbol_new (group_name, now_seg, frag_now, 0);
#ifdef TE_SOLARIS
/* Before Solaris 11 build 154, Sun ld rejects local group
signature symbols, so make them weak hidden instead. */
symbolS *symp;
for (symp = symbol_rootP; symp; symp = symbol_next (symp))
- if (!S_IS_DEFINED (symp))
- {
- if (symbol_get_obj (symp)->versioned_name)
- {
- char *p;
-
- /* The @@@ syntax is a special case. If the symbol is
- not defined, 2 `@'s will be removed from the
- versioned_name. */
-
- p = strchr (symbol_get_obj (symp)->versioned_name,
- ELF_VER_CHR);
- if (p != NULL && p[1] == ELF_VER_CHR && p[2] == ELF_VER_CHR)
- {
- size_t l = strlen (&p[3]) + 1;
- memmove (&p[1], &p[3], l);
- }
- if (symbol_used_p (symp) == 0
- && symbol_used_in_reloc_p (symp) == 0)
- symbol_remove (symp, &symbol_rootP, &symbol_lastP);
- }
+ {
+ struct elf_obj_sy *sy_obj = symbol_get_obj (symp);
+ int is_defined = !!S_IS_DEFINED (symp);
- /* If there was .weak foo, but foo was neither defined nor
- used anywhere, remove it. */
+ if (sy_obj->versioned_name)
+ {
+ char *p = strchr (sy_obj->versioned_name->name,
+ ELF_VER_CHR);
- else if (S_IS_WEAK (symp)
- && symbol_used_p (symp) == 0
- && symbol_used_in_reloc_p (symp) == 0)
- symbol_remove (symp, &symbol_rootP, &symbol_lastP);
- }
+ if (sy_obj->rename)
+ {
+ /* The @@@ syntax is a special case. If the symbol is
+ not defined, 2 `@'s will be removed from the
+ versioned_name. Otherwise, 1 `@' will be removed. */
+ size_t l = strlen (&p[3]) + 1;
+ memmove (&p[1 + is_defined], &p[3], l);
+ }
+
+ if (!is_defined)
+ {
+ /* Verify that the name isn't using the @@ syntax--this
+ is reserved for definitions of the default version
+ to link against. */
+ if (!sy_obj->rename && p[1] == ELF_VER_CHR)
+ {
+ as_bad (_("invalid attempt to declare external "
+ "version name as default in symbol `%s'"),
+ sy_obj->versioned_name->name);
+ return;
+ }
+
+ /* Only one version symbol is allowed for undefined
+ symbol. */
+ if (sy_obj->versioned_name->next)
+ {
+ as_bad (_("multiple versions [`%s'|`%s'] for "
+ "symbol `%s'"),
+ sy_obj->versioned_name->name,
+ sy_obj->versioned_name->next->name,
+ S_GET_NAME (symp));
+ return;
+ }
+
+ sy_obj->rename = TRUE;
+ }
+ }
+
+ /* If there was .symver or .weak, but symbol was neither
+ defined nor used anywhere, remove it. */
+ if (!is_defined
+ && (sy_obj->versioned_name || S_IS_WEAK (symp))
+ && symbol_used_p (symp) == 0
+ && symbol_used_in_reloc_p (symp) == 0)
+ symbol_remove (symp, &symbol_rootP, &symbol_lastP);
+ }
}
}
}
/* Cleanup hash. */
- hash_traverse (groups.indexes, free_section_idx);
- hash_die (groups.indexes);
+ htab_traverse (groups.indexes, free_section_idx, NULL);
+ htab_delete (groups.indexes);
#ifdef NEED_ECOFF_DEBUG
if (ECOFF_DEBUGGING)