/* ELF object file format
- Copyright (C) 1992-2020 Free Software Foundation, Inc.
+ Copyright (C) 1992-2021 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
static void obj_elf_tls_common (int);
static void obj_elf_lcomm (int);
static void obj_elf_struct (int);
+static void obj_elf_attach_to_group (int);
static const pseudo_typeS elf_pseudo_table[] =
{
+ {"attach_to_group", obj_elf_attach_to_group, 0},
{"comm", obj_elf_common, 0},
{"common", obj_elf_common, 1},
{"ident", obj_elf_ident, 0},
/* A GNU extension for object attributes. */
{"gnu_attribute", obj_elf_gnu_attribute, 0},
- /* These are used for dwarf. */
- {"2byte", cons, 2},
- {"4byte", cons, 4},
- {"8byte", cons, 8},
/* These are used for dwarf2. */
{ "file", dwarf2_directive_file, 0 },
{ "loc", dwarf2_directive_loc, 0 },
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)))
if (*input_line_pointer == '.')
input_line_pointer++;
/* Some say data, some say bss. */
- if (strncmp (input_line_pointer, "bss\"", 4) == 0)
+ if (startswith (input_line_pointer, "bss\""))
input_line_pointer += 4;
- else if (strncmp (input_line_pointer, "data\"", 5) == 0)
+ else if (startswith (input_line_pointer, "data\""))
input_line_pointer += 5;
else
{
symbolP = get_sym_from_input_line_and_check ();
bfdsym = symbol_get_bfdsym (symbolP);
- elfsym = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym);
+ elfsym = elf_symbol_from (bfdsym);
gas_assert (elfsym);
static struct section_stack *section_stack;
-static bfd_boolean
-get_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
+/* ELF section flags for unique sections. */
+#define SEC_ASSEMBLER_SHF_MASK SHF_GNU_RETAIN
+
+/* Return TRUE iff SEC matches the section info INF. */
+
+static bool
+get_section_by_match (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
{
struct elf_section_match *match = (struct elf_section_match *) inf;
const char *gname = match->group_name;
const char *group_name = elf_group_name (sec);
const char *linked_to_symbol_name
= sec->map_head.linked_to_symbol_name;
- unsigned int info = elf_section_data (sec)->this_hdr.sh_info;
+ unsigned int sh_info = elf_section_data (sec)->this_hdr.sh_info;
+ bfd_vma sh_flags = (elf_section_data (sec)->this_hdr.sh_flags
+ & SEC_ASSEMBLER_SHF_MASK);
- return (info == match->info
+ return (sh_info == match->sh_info
+ && sh_flags == match->sh_flags
&& ((bfd_section_flags (sec) & SEC_ASSEMBLER_SECTION_ID)
== (match->flags & SEC_ASSEMBLER_SECTION_ID))
&& sec->section_id == match->section_id
previous_section = now_seg;
previous_subsection = now_subseg;
- old_sec = bfd_get_section_by_name_if (stdoutput, name, get_section,
+ old_sec = bfd_get_section_by_name_if (stdoutput, name, get_section_by_match,
(void *) match_p);
if (old_sec)
{
if (ssect != NULL)
{
- bfd_boolean override = FALSE;
+ bool override = false;
if (type == SHT_NULL)
type = ssect->type;
}
}
- if (old_sec == NULL && ((attr & ~(SHF_MASKOS | SHF_MASKPROC))
+ if (old_sec == NULL && ((attr & ~(SHF_LINK_ORDER
+ | SHF_MASKOS
+ | SHF_MASKPROC))
& ~ssect->attr) != 0)
{
+ /* Strip SHF_GNU_RETAIN. */
+ bfd_vma generic_attr = attr;
+ if (elf_tdata (stdoutput)->has_gnu_osabi)
+ generic_attr &= ~SHF_GNU_RETAIN;
+
/* As a GNU extension, we permit a .note section to be
allocatable. If the linker sees an allocatable .note
section, it will create a PT_NOTE segment in the output
file. We also allow "x" for .note.GNU-stack. */
if (ssect->type == SHT_NOTE
- && (attr == SHF_ALLOC || attr == SHF_EXECINSTR))
+ && (generic_attr == SHF_ALLOC
+ || generic_attr == SHF_EXECINSTR))
;
/* Allow different SHF_MERGE and SHF_STRINGS if we have
something like .rodata.str. */
else if (ssect->suffix_length == -2
&& name[ssect->prefix_length] == '.'
- && (attr
+ && (generic_attr
& ~ssect->attr
& ~SHF_MERGE
& ~SHF_STRINGS) == 0)
;
/* .interp, .strtab and .symtab can have SHF_ALLOC. */
- else if (attr == SHF_ALLOC
+ else if (generic_attr == SHF_ALLOC
&& (strcmp (name, ".interp") == 0
|| strcmp (name, ".strtab") == 0
|| strcmp (name, ".symtab") == 0))
- override = TRUE;
+ override = true;
/* .note.GNU-stack can have SHF_EXECINSTR. */
- else if (attr == SHF_EXECINSTR
+ else if (generic_attr == SHF_EXECINSTR
&& strcmp (name, ".note.GNU-stack") == 0)
- override = TRUE;
+ override = true;
#ifdef TC_ALPHA
/* A section on Alpha may have SHF_ALPHA_GPREL. */
- else if ((attr & ~ssect->attr) == SHF_ALPHA_GPREL)
- override = TRUE;
+ else if ((generic_attr & ~ssect->attr) == SHF_ALPHA_GPREL)
+ override = true;
#endif
#ifdef TC_RX
- else if (attr == (SHF_EXECINSTR | SHF_WRITE | SHF_ALLOC)
+ else if (generic_attr == (SHF_EXECINSTR | SHF_WRITE | SHF_ALLOC)
&& (ssect->type == SHT_INIT_ARRAY
|| ssect->type == SHT_FINI_ARRAY
|| ssect->type == SHT_PREINIT_ARRAY))
if (match_p->group_name == NULL)
as_warn (_("setting incorrect section attributes for %s"),
name);
- override = TRUE;
+ override = true;
}
}
type = bfd_elf_get_default_section_type (flags);
elf_section_type (sec) = type;
elf_section_flags (sec) = attr;
- elf_section_data (sec)->this_hdr.sh_info = match_p->info;
+ elf_section_data (sec)->this_hdr.sh_info = match_p->sh_info;
/* Prevent SEC_HAS_CONTENTS from being inadvertently set. */
if (type == SHT_NOBITS)
/* 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 exp = { .X_op = O_constant };
+ symbol_set_value_expression (secsym, &exp);
+ symbol_set_bfdsym (secsym, sec->symbol);
+ }
else
symbol_table_insert (section_symbol (sec));
}
}
else
/* FIXME: Maybe we should consider removing a previously set
- processor or application specific attribute as suspicious ? */
+ processor or application specific attribute as suspicious? */
elf_section_flags (sec) = attr;
if ((flags & SEC_MERGE) && old_sec->entsize != (unsigned) entsize)
static bfd_vma
obj_elf_parse_section_letters (char *str, size_t len,
- bfd_boolean *is_clone, bfd_vma *gnu_attr)
+ bool *is_clone, bfd_vma *gnu_attr)
{
bfd_vma attr = 0;
- *is_clone = FALSE;
+ *is_clone = false;
while (len > 0)
{
case 'd':
*gnu_attr |= SHF_GNU_MBIND;
break;
+ case 'R':
+ *gnu_attr |= SHF_GNU_RETAIN;
+ break;
case '?':
- *is_clone = TRUE;
+ *is_clone = true;
break;
/* Compatibility. */
case 'm':
if (ISDIGIT (*str))
{
char * end;
+ struct elf_backend_data *bed;
+ bfd_vma numeric_flags = strtoul (str, &end, 0);
+
+ attr |= numeric_flags;
+
+ bed = (struct elf_backend_data *)
+ get_elf_backend_data (stdoutput);
+
+ if (bed->elf_osabi == ELFOSABI_NONE
+ || bed->elf_osabi == ELFOSABI_STANDALONE
+ || bed->elf_osabi == ELFOSABI_GNU
+ || bed->elf_osabi == ELFOSABI_FREEBSD)
+ {
+ /* Add flags in the SHF_MASKOS range to gnu_attr for
+ OSABIs that support those flags.
+ Also adding the flags for ELFOSABI_{NONE,STANDALONE}
+ allows them to be validated later in obj_elf_section.
+ We can't just always set these bits in gnu_attr for
+ all OSABIs, since Binutils does not recognize all
+ SHF_MASKOS bits for non-GNU OSABIs. It's therefore
+ possible that numeric flags are being used to set bits
+ in the SHF_MASKOS range for those targets, and we
+ don't want assembly to fail in those situations. */
+ *gnu_attr |= (numeric_flags & SHF_MASKOS);
+ }
- attr |= strtoul (str, & end, 0);
/* Update str and len, allowing for the fact that
we will execute str++ and len-- below. */
end --;
}
static int
-obj_elf_section_type (char *str, size_t len, bfd_boolean warn)
+obj_elf_section_type (char *str, size_t len, bool warn)
{
- if (len == 8 && strncmp (str, "progbits", 8) == 0)
+ if (len == 8 && startswith (str, "progbits"))
return SHT_PROGBITS;
- if (len == 6 && strncmp (str, "nobits", 6) == 0)
+ if (len == 6 && startswith (str, "nobits"))
return SHT_NOBITS;
- if (len == 4 && strncmp (str, "note", 4) == 0)
+ if (len == 4 && startswith (str, "note"))
return SHT_NOTE;
- if (len == 10 && strncmp (str, "init_array", 10) == 0)
+ if (len == 10 && startswith (str, "init_array"))
return SHT_INIT_ARRAY;
- if (len == 10 && strncmp (str, "fini_array", 10) == 0)
+ if (len == 10 && startswith (str, "fini_array"))
return SHT_FINI_ARRAY;
- if (len == 13 && strncmp (str, "preinit_array", 13) == 0)
+ if (len == 13 && startswith (str, "preinit_array"))
return SHT_PREINIT_ARRAY;
#ifdef md_elf_section_type
{
int ret;
- if (len == 5 && strncmp (str, "write", 5) == 0)
+ if (len == 5 && startswith (str, "write"))
return SHF_WRITE;
- if (len == 5 && strncmp (str, "alloc", 5) == 0)
+ if (len == 5 && startswith (str, "alloc"))
return SHF_ALLOC;
- if (len == 9 && strncmp (str, "execinstr", 9) == 0)
+ if (len == 9 && startswith (str, "execinstr"))
return SHF_EXECINSTR;
- if (len == 7 && strncmp (str, "exclude", 7) == 0)
+ if (len == 7 && startswith (str, "exclude"))
return SHF_EXCLUDE;
- if (len == 3 && strncmp (str, "tls", 3) == 0)
+ if (len == 3 && startswith (str, "tls"))
return SHF_TLS;
#ifdef md_elf_section_word
}
#endif
- ret = obj_elf_section_type (str, len, FALSE);
+ ret = obj_elf_section_type (str, len, false);
if (ret != 0)
*type = ret;
else
return name;
}
+static void
+obj_elf_attach_to_group (int dummy ATTRIBUTE_UNUSED)
+{
+ const char * gname = obj_elf_section_name ();
+
+ if (gname == NULL)
+ {
+ as_warn (_("group name not parseable"));
+ return;
+ }
+
+ if (elf_group_name (now_seg))
+ {
+ as_warn (_("section %s already has a group (%s)"),
+ bfd_section_name (now_seg), elf_group_name (now_seg));
+ return;
+ }
+
+ elf_group_name (now_seg) = xstrdup (gname);
+ elf_section_flags (now_seg) |= SHF_GROUP;
+}
+
void
obj_elf_section (int push)
{
int linkonce;
subsegT new_subsection = -1;
struct elf_section_match match;
+ unsigned long linked_to_section_index = -1UL;
if (flag_mri)
{
if (*input_line_pointer == '"')
{
- bfd_boolean is_clone;
+ bool is_clone;
beg = demand_copy_C_string (&dummy);
if (beg == NULL)
ignore_rest_of_line ();
return;
}
- type = obj_elf_section_type (beg, strlen (beg), TRUE);
+ type = obj_elf_section_type (beg, strlen (beg), true);
}
else if (c == '@' || c == '%')
{
(void) restore_line_pointer (c);
type = obj_elf_section_type (beg,
input_line_pointer - beg,
- TRUE);
+ true);
}
}
else
if ((attr & SHF_LINK_ORDER) != 0 && *input_line_pointer == ',')
{
- char c;
- unsigned int length;
++input_line_pointer;
SKIP_WHITESPACE ();
- c = get_symbol_name (& beg);
- (void) restore_line_pointer (c);
- length = input_line_pointer - beg;
- if (length)
- match.linked_to_symbol_name = xmemdup0 (beg, length);
+ /* Check for a numeric section index, rather than a symbol name. */
+ if (ISDIGIT (* input_line_pointer))
+ {
+ linked_to_section_index = strtoul (input_line_pointer, & input_line_pointer, 0);
+ }
+ else
+ {
+ char c;
+ unsigned int length;
+
+ c = get_symbol_name (& beg);
+ (void) restore_line_pointer (c);
+ length = input_line_pointer - beg;
+ if (length)
+ match.linked_to_symbol_name = xmemdup0 (beg, length);
+ }
}
if ((attr & SHF_GROUP) != 0 && is_clone)
{
as_warn (_("? section flag ignored with G present"));
- is_clone = FALSE;
+ is_clone = false;
}
+
if ((attr & SHF_GROUP) != 0 && *input_line_pointer == ',')
{
++input_line_pointer;
{
++input_line_pointer;
SKIP_WHITESPACE ();
- if (strncmp (input_line_pointer, "comdat", 6) == 0)
+ if (startswith (input_line_pointer, "comdat"))
{
input_line_pointer += 6;
linkonce = 1;
}
}
- else if (strncmp (name, ".gnu.linkonce", 13) == 0)
+ else if (startswith (name, ".gnu.linkonce"))
linkonce = 1;
}
else if ((attr & SHF_GROUP) != 0)
if (ISDIGIT (* input_line_pointer))
{
char *t = input_line_pointer;
- match.info = strtoul (input_line_pointer,
+ match.sh_info = strtoul (input_line_pointer,
&input_line_pointer, 0);
- if (match.info == (unsigned int) -1)
+ if (match.sh_info == (unsigned int) -1)
{
as_warn (_("unsupported mbind section info: %s"), t);
- match.info = 0;
+ match.sh_info = 0;
}
}
else
input_line_pointer = save;
}
+ if ((gnu_attr & SHF_GNU_RETAIN) != 0)
+ match.sh_flags |= SHF_GNU_RETAIN;
+
if (*input_line_pointer == ',')
{
char *save = input_line_pointer;
+
++input_line_pointer;
SKIP_WHITESPACE ();
- if (strncmp (input_line_pointer, "unique", 6) == 0)
+ if (startswith (input_line_pointer, "unique"))
{
input_line_pointer += 6;
SKIP_WHITESPACE ();
if (ISDIGIT (* input_line_pointer))
{
bfd_vma id;
- bfd_boolean overflow;
+ bool overflow;
char *t = input_line_pointer;
if (sizeof (bfd_vma) <= sizeof (unsigned long))
{
done:
demand_empty_rest_of_line ();
- obj_elf_change_section (name, type, attr, entsize, &match, linkonce,
- push);
-
- if ((gnu_attr & SHF_GNU_MBIND) != 0)
+ if ((gnu_attr & (SHF_GNU_MBIND | SHF_GNU_RETAIN)) != 0)
{
- struct elf_backend_data *bed;
+ const struct elf_backend_data *bed;
+ bool mbind_p = (gnu_attr & SHF_GNU_MBIND) != 0;
- if ((attr & SHF_ALLOC) == 0)
+ if (mbind_p && (attr & SHF_ALLOC) == 0)
as_bad (_("SHF_ALLOC isn't set for GNU_MBIND section: %s"), name);
- bed = (struct elf_backend_data *) get_elf_backend_data (stdoutput);
- if (bed->elf_osabi == ELFOSABI_NONE)
- bed->elf_osabi = ELFOSABI_GNU;
- else if (bed->elf_osabi != ELFOSABI_GNU
- && bed->elf_osabi != ELFOSABI_FREEBSD)
- as_bad (_("GNU_MBIND section is supported only by GNU "
- "and FreeBSD targets"));
- elf_tdata (stdoutput)->has_gnu_osabi |= elf_gnu_osabi_mbind;
+ bed = get_elf_backend_data (stdoutput);
+
+ if (bed->elf_osabi != ELFOSABI_GNU
+ && bed->elf_osabi != ELFOSABI_FREEBSD
+ && bed->elf_osabi != ELFOSABI_NONE)
+ as_bad (_("%s section is supported only by GNU and FreeBSD targets"),
+ mbind_p ? "GNU_MBIND" : "GNU_RETAIN");
+ else
+ {
+ if (mbind_p)
+ elf_tdata (stdoutput)->has_gnu_osabi |= elf_gnu_osabi_mbind;
+ if ((gnu_attr & SHF_GNU_RETAIN) != 0)
+ elf_tdata (stdoutput)->has_gnu_osabi |= elf_gnu_osabi_retain;
+
+ attr |= gnu_attr;
+ }
+ }
+
+ obj_elf_change_section (name, type, attr, entsize, &match, linkonce,
+ push);
+
+ if (linked_to_section_index != -1UL)
+ {
+ elf_section_flags (now_seg) |= SHF_LINK_ORDER;
+ elf_section_data (now_seg)->this_hdr.sh_link = linked_to_section_index;
+ /* FIXME: Should we perform some sanity checking on the section index ? */
}
- elf_section_flags (now_seg) |= gnu_attr;
if (push && new_subsection != -1)
subseg_set (now_seg, new_subsection);
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 (*input_line_pointer == ',')
+ {
+ char *save = input_line_pointer;
- if (strchr (symbol_get_obj (sym)->versioned_name,
- ELF_VER_CHR) == NULL)
+ ++input_line_pointer;
+ SKIP_WHITESPACE ();
+ if (startswith (input_line_pointer, "local"))
{
- 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 (startswith (input_line_pointer, "hidden"))
{
- 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 (startswith (input_line_pointer, "remove"))
+ {
+ input_line_pointer += 6;
+ sy_obj->visibility = visibility_remove;
+ }
+ else
+ input_line_pointer = save;
}
demand_empty_rest_of_line ();
/* Return true if we have seen an explicit specification of attribute TAG
for vendor VENDOR. */
-bfd_boolean
+bool
obj_elf_seen_attribute (int vendor, unsigned int tag)
{
unsigned int base;
for (rai = recorded_attributes; rai; rai = rai->next)
if (rai->vendor == vendor && rai->base == base)
return (rai->mask & mask) != 0;
- return FALSE;
+ return false;
}
/* Parse an attribute directive for VENDOR.
#endif
}
+/* Deduplicate size expressions. We might get into trouble with
+ multiple freeing or use after free if we leave them pointing to the
+ same expressionS. */
+
+void
+elf_obj_symbol_clone_hook (symbolS *newsym, symbolS *orgsym ATTRIBUTE_UNUSED)
+{
+ struct elf_obj_sy *newelf = symbol_get_obj (newsym);
+ if (newelf->size)
+ {
+ expressionS *exp = XNEW (expressionS);
+ *exp = *newelf->size;
+ newelf->size = exp;
+ }
+}
+
/* When setting one symbol equal to another, by default we probably
want them to have the same "size", whatever it means in the current
context. */
}
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
{
|| strcmp (type_name, "10") == 0
|| strcmp (type_name, "STT_GNU_IFUNC") == 0)
{
- struct elf_backend_data *bed;
+ const struct elf_backend_data *bed;
- bed = (struct elf_backend_data *) get_elf_backend_data (stdoutput);
- if (bed->elf_osabi == ELFOSABI_NONE)
- bed->elf_osabi = ELFOSABI_GNU;
- else if (bed->elf_osabi != ELFOSABI_GNU
- && bed->elf_osabi != ELFOSABI_FREEBSD)
+ bed = get_elf_backend_data (stdoutput);
+ if (bed->elf_osabi != ELFOSABI_NONE
+ && bed->elf_osabi != ELFOSABI_GNU
+ && 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;
}
else if (strcmp (type_name, "gnu_unique_object") == 0)
{
- struct elf_backend_data *bed;
+ const struct elf_backend_data *bed;
- bed = (struct elf_backend_data *) get_elf_backend_data (stdoutput);
- if (bed->elf_osabi == ELFOSABI_NONE)
- bed->elf_osabi = ELFOSABI_GNU;
- else if (bed->elf_osabi != ELFOSABI_GNU)
+ bed = get_elf_backend_data (stdoutput);
+ if (bed->elf_osabi != ELFOSABI_NONE
+ && bed->elf_osabi != ELFOSABI_GNU)
as_bad (_("symbol type \"%s\" is supported only by GNU targets"),
type_name);
elf_tdata (stdoutput)->has_gnu_osabi |= elf_gnu_osabi_unique;
p = frag_more (12);
/* Zero it out. */
memset (p, 0, 12);
- file = as_where (NULL);
+ file = remap_debug_filename (as_where (NULL));
stabstr_name = concat (segment_name (seg), "str", (char *) NULL);
- stroff = get_stab_string_offset (file, stabstr_name, TRUE);
+ stroff = get_stab_string_offset (file, stabstr_name, true);
know (stroff == 1 || (stroff == 0 && file[0] == '\0'));
md_number_to_chars (p, stroff, 4);
seg_info (seg)->stabu.p = p;
+ xfree ((char *) file);
}
#endif
char *p;
int strsz, nsyms;
- if (strncmp (".stab", sec->name, 5))
+ if (!startswith (sec->name, ".stab"))
return;
if (!strcmp ("str", sec->name + strlen (sec->name) - 3))
return;
supposed to *EXT to the external symbol information, and return
whether the symbol should be used at all. */
-static bfd_boolean
+static bool
elf_get_extr (asymbol *sym, EXTR *ext)
{
if (sym->udata.p == NULL)
- return FALSE;
+ return false;
*ext = *(EXTR *) sym->udata.p;
- return TRUE;
+ return true;
}
/* This function is called by bfd_ecoff_debug_externals. It has
{
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. */
-
- else if (! S_IS_DEFINED (symp))
+ against the correct versioned symbol. */
+
+ /* 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));
because we are in the middle of the final loop. */
S_SET_VALUE (symp2,
(S_GET_VALUE (symp)
- - symbol_get_frag (symp)->fr_address));
+ - (symbol_get_frag (symp)->fr_address
+ / OCTETS_PER_BYTE)));
symbol_set_frag (symp2, symbol_get_frag (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 (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, idx_ptr, 0);
}
-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. */
symbol_table_insert (sy);
}
elf_group_id (s) = symbol_get_bfdsym (sy);
+ /* Mark the group signature symbol as used so that it will be
+ included in the symbol table. */
+ symbol_mark_used_in_reloc (sy);
}
}
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)
/* Set up the external symbols. */
debug.ssext = debug.ssext_end = NULL;
debug.external_ext = debug.external_ext_end = NULL;
- if (! bfd_ecoff_debug_externals (stdoutput, &debug, debug_swap, TRUE,
+ if (! bfd_ecoff_debug_externals (stdoutput, &debug, debug_swap, true,
elf_get_extr, elf_set_index))
as_fatal (_("failed to set up debugging information: %s"),
bfd_errmsg (bfd_get_error ()));
#endif
elf_obj_read_begin_hook,
elf_obj_symbol_new_hook,
- 0,
+ elf_obj_symbol_clone_hook,
elf_adjust_symtab
};