X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Fobj-elf.c;h=8af563fbd24e6d1c6c1b99175d77248eace9745a;hb=814f1489e9d1d92a30d94d69a0066addcc564bd2;hp=2f93990e721df9b014b714e5de0975273cfff186;hpb=ae4a729bff61b571c63a35ffa265d321cf8f9c89;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c index 2f93990e72..8af563fbd2 100644 --- a/gas/config/obj-elf.c +++ b/gas/config/obj-elf.c @@ -1,13 +1,11 @@ /* ELF object file format - Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005, 2006, 2007 - Free Software Foundation, Inc. + Copyright (C) 1992-2016 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. GAS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2, + published by the Free Software Foundation; either version 3, or (at your option) any later version. GAS is distributed in the hope that it will be useful, but @@ -62,6 +60,10 @@ #include "elf/mep.h" #endif +#ifdef TC_NIOS2 +#include "elf/nios2.h" +#endif + static void obj_elf_line (int); static void obj_elf_size (int); static void obj_elf_type (int); @@ -72,6 +74,7 @@ static void obj_elf_visibility (int); static void obj_elf_symver (int); static void obj_elf_subsection (int); static void obj_elf_popsection (int); +static void obj_elf_gnu_attribute (int); static void obj_elf_tls_common (int); static void obj_elf_lcomm (int); static void obj_elf_struct (int); @@ -113,6 +116,9 @@ static const pseudo_typeS elf_pseudo_table[] = {"vtable_inherit", (void (*) (int)) &obj_elf_vtable_inherit, 0}, {"vtable_entry", (void (*) (int)) &obj_elf_vtable_entry, 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}, @@ -260,19 +266,33 @@ elf_file_symbol (const char *s, int appfile) || (symbol_rootP->bsym->flags & BSF_FILE) == 0) { symbolS *sym; + size_t name_length; sym = symbol_new (s, absolute_section, 0, NULL); symbol_set_frag (sym, &zero_address_frag); + + name_length = strlen (s); + if (name_length > strlen (S_GET_NAME (sym))) + { + obstack_grow (¬es, s, name_length + 1); + S_SET_NAME (sym, (const char *) obstack_finish (¬es)); + } + else + strcpy ((char *) S_GET_NAME (sym), s); + symbol_get_bfdsym (sym)->flags |= BSF_FILE; - if (symbol_rootP != sym) + if (symbol_rootP != sym + && (symbol_rootP->bsym == NULL + || !(symbol_rootP->bsym->flags & BSF_FILE))) { symbol_remove (sym, &symbol_rootP, &symbol_lastP); symbol_insert (sym, symbol_rootP, &symbol_rootP, &symbol_lastP); + } + #ifdef DEBUG - verify_symbol_chain (symbol_rootP, symbol_lastP); + verify_symbol_chain (symbol_rootP, symbol_lastP); #endif - } } #ifdef NEED_ECOFF_DEBUG @@ -382,20 +402,34 @@ obj_elf_lcomm (int ignore ATTRIBUTE_UNUSED) symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT; } +static symbolS * +get_sym_from_input_line_and_check (void) +{ + char *name; + char c; + symbolS *sym; + + c = get_symbol_name (& name); + sym = symbol_find_or_make (name); + *input_line_pointer = c; + SKIP_WHITESPACE_AFTER_NAME (); + + /* There is no symbol name if input_line_pointer has not moved. */ + if (name == input_line_pointer) + as_bad (_("Missing symbol name in directive")); + return sym; +} + static void obj_elf_local (int ignore ATTRIBUTE_UNUSED) { - char *name; int c; symbolS *symbolP; do { - name = input_line_pointer; - c = get_symbol_end (); - symbolP = symbol_find_or_make (name); - *input_line_pointer = c; - SKIP_WHITESPACE (); + symbolP = get_sym_from_input_line_and_check (); + c = *input_line_pointer; S_CLEAR_EXTERNAL (symbolP); symbol_get_obj (symbolP)->local = 1; if (c == ',') @@ -413,19 +447,14 @@ obj_elf_local (int ignore ATTRIBUTE_UNUSED) static void obj_elf_weak (int ignore ATTRIBUTE_UNUSED) { - char *name; int c; symbolS *symbolP; do { - name = input_line_pointer; - c = get_symbol_end (); - symbolP = symbol_find_or_make (name); - *input_line_pointer = c; - SKIP_WHITESPACE (); + symbolP = get_sym_from_input_line_and_check (); + c = *input_line_pointer; S_SET_WEAK (symbolP); - symbol_get_obj (symbolP)->local = 1; if (c == ',') { input_line_pointer++; @@ -441,7 +470,6 @@ obj_elf_weak (int ignore ATTRIBUTE_UNUSED) static void obj_elf_visibility (int visibility) { - char *name; int c; symbolS *symbolP; asymbol *bfdsym; @@ -449,21 +477,17 @@ obj_elf_visibility (int visibility) do { - name = input_line_pointer; - c = get_symbol_end (); - symbolP = symbol_find_or_make (name); - *input_line_pointer = c; - - SKIP_WHITESPACE (); + symbolP = get_sym_from_input_line_and_check (); bfdsym = symbol_get_bfdsym (symbolP); elfsym = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym); - assert (elfsym); + gas_assert (elfsym); elfsym->internal_elf_sym.st_other &= ~3; elfsym->internal_elf_sym.st_other |= visibility; + c = *input_line_pointer; if (c == ',') { input_line_pointer ++; @@ -494,9 +518,9 @@ static struct section_stack *section_stack; static bfd_boolean get_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf) { - const char *gname = inf; + const char *gname = (const char *) inf; const char *group_name = elf_group_name (sec); - + return (group_name == gname || (group_name != NULL && gname != NULL @@ -523,8 +547,8 @@ get_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf) void obj_elf_change_section (const char *name, - int type, - int attr, + unsigned int type, + bfd_vma attr, int entsize, const char *group_name, int linkonce, @@ -544,7 +568,7 @@ obj_elf_change_section (const char *name, if (push) { struct section_stack *elt; - elt = xmalloc (sizeof (struct section_stack)); + elt = XNEW (struct section_stack); elt->next = section_stack; elt->seg = now_seg; elt->prev_seg = previous_section; @@ -577,13 +601,13 @@ obj_elf_change_section (const char *name, else if (type != ssect->type) { if (old_sec == NULL - /* FIXME: gcc, as of 2002-10-22, will emit + /* Some older versions of gcc will emit .section .init_array,"aw",@progbits for __attribute__ ((section (".init_array"))). "@progbits" is incorrect. Also for x86-64 large bss - sections, gcc, as of 2005-07-06, will emit + sections, some older versions of gcc will emit .section .lbss,"aw",@progbits @@ -597,7 +621,9 @@ obj_elf_change_section (const char *name, && ssect->type != SHT_PREINIT_ARRAY) { /* We allow to specify any type for a .note section. */ - if (ssect->type != SHT_NOTE) + if (ssect->type != SHT_NOTE + /* Processor and application defined types are allowed too. */ + && type < SHT_LOPROC) as_warn (_("setting incorrect section type for %s"), name); } @@ -609,7 +635,8 @@ obj_elf_change_section (const char *name, } } - if (old_sec == NULL && (attr & ~ssect->attr) != 0) + if (old_sec == NULL && ((attr & ~(SHF_MASKOS | SHF_MASKPROC)) + & ~ssect->attr) != 0) { /* As a GNU extension, we permit a .note section to be allocatable. If the linker sees an allocatable .note @@ -641,6 +668,14 @@ obj_elf_change_section (const char *name, /* A section on Alpha may have SHF_ALPHA_GPREL. */ else if ((attr & ~ssect->attr) == SHF_ALPHA_GPREL) override = TRUE; +#endif +#ifdef TC_RX + else if (attr == (SHF_EXECINSTR | SHF_WRITE | SHF_ALLOC) + && (ssect->type == SHT_INIT_ARRAY + || ssect->type == SHT_FINI_ARRAY + || ssect->type == SHT_PREINIT_ARRAY)) + /* RX init/fini arrays can and should have the "awx" attributes set. */ + ; #endif else { @@ -650,6 +685,7 @@ obj_elf_change_section (const char *name, override = TRUE; } } + if (!override && old_sec == NULL) attr |= ssect->attr; } @@ -662,6 +698,7 @@ obj_elf_change_section (const char *name, | ((attr & SHF_EXECINSTR) ? SEC_CODE : 0) | ((attr & SHF_MERGE) ? SEC_MERGE : 0) | ((attr & SHF_STRINGS) ? SEC_STRINGS : 0) + | ((attr & SHF_EXCLUDE) ? SEC_EXCLUDE: 0) | ((attr & SHF_TLS) ? SEC_THREAD_LOCAL : 0)); #ifdef md_elf_section_flags flags = md_elf_section_flags (flags, attr, type); @@ -674,6 +711,8 @@ obj_elf_change_section (const char *name, { symbolS *secsym; + if (type == SHT_NULL) + type = bfd_elf_get_default_section_type (flags); elf_section_type (sec) = type; elf_section_flags (sec) = attr; @@ -710,6 +749,11 @@ obj_elf_change_section (const char *name, | SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD | SEC_THREAD_LOCAL))) as_warn (_("ignoring changed section attributes for %s"), name); + else + /* FIXME: Maybe we should consider removing a previously set + processor or application specific attribute as suspicious ? */ + elf_section_flags (sec) = attr; + if ((flags & SEC_MERGE) && old_sec->entsize != (unsigned) entsize) as_warn (_("ignoring changed section entity size for %s"), name); } @@ -720,10 +764,11 @@ obj_elf_change_section (const char *name, #endif } -static int -obj_elf_parse_section_letters (char *str, size_t len) +static bfd_vma +obj_elf_parse_section_letters (char *str, size_t len, bfd_boolean *is_clone) { - int attr = 0; + bfd_vma attr = 0; + *is_clone = FALSE; while (len > 0) { @@ -732,6 +777,9 @@ obj_elf_parse_section_letters (char *str, size_t len) case 'a': attr |= SHF_ALLOC; break; + case 'e': + attr |= SHF_EXCLUDE; + break; case 'w': attr |= SHF_WRITE; break; @@ -750,6 +798,9 @@ obj_elf_parse_section_letters (char *str, size_t len) case 'T': attr |= SHF_TLS; break; + case '?': + *is_clone = TRUE; + break; /* Compatibility. */ case 'm': if (*(str - 1) == 'a') @@ -764,14 +815,27 @@ obj_elf_parse_section_letters (char *str, size_t len) } default: { - char *bad_msg = _("unrecognized .section attribute: want a,w,x,M,S,G,T"); + const char *bad_msg = _("unrecognized .section attribute:" + " want a,e,w,x,M,S,G,T or number"); #ifdef md_elf_section_letter - int md_attr = md_elf_section_letter (*str, &bad_msg); - if (md_attr >= 0) + bfd_vma md_attr = md_elf_section_letter (*str, &bad_msg); + if (md_attr != (bfd_vma) -1) attr |= md_attr; else #endif - as_fatal ("%s", bad_msg); + if (ISDIGIT (*str)) + { + char * end; + + attr |= strtoul (str, & end, 0); + /* Update str and len, allowing for the fact that + we will execute str++ and len-- below. */ + end --; + len -= (end - str); + str = end; + } + else + as_fatal ("%s", bad_msg); } break; } @@ -782,31 +846,7 @@ obj_elf_parse_section_letters (char *str, size_t len) } static int -obj_elf_section_word (char *str, size_t len) -{ - if (len == 5 && strncmp (str, "write", 5) == 0) - return SHF_WRITE; - if (len == 5 && strncmp (str, "alloc", 5) == 0) - return SHF_ALLOC; - if (len == 9 && strncmp (str, "execinstr", 9) == 0) - return SHF_EXECINSTR; - if (len == 3 && strncmp (str, "tls", 3) == 0) - return SHF_TLS; - -#ifdef md_elf_section_word - { - int md_attr = md_elf_section_word (str, len); - if (md_attr >= 0) - return md_attr; - } -#endif - - as_warn (_("unrecognized section attribute")); - return 0; -} - -static int -obj_elf_section_type (char *str, size_t len) +obj_elf_section_type (char *str, size_t len, bfd_boolean warn) { if (len == 8 && strncmp (str, "progbits", 8) == 0) return SHT_PROGBITS; @@ -829,12 +869,57 @@ obj_elf_section_type (char *str, size_t len) } #endif - as_warn (_("unrecognized section type")); + if (ISDIGIT (*str)) + { + char * end; + int type = strtoul (str, & end, 0); + + if (warn && (size_t) (end - str) != len) + as_warn (_("extraneous characters at end of numeric section type")); + + return type; + } + + if (warn) + as_warn (_("unrecognized section type")); + return 0; +} + +static bfd_vma +obj_elf_section_word (char *str, size_t len, int *type) +{ + int ret; + + if (len == 5 && strncmp (str, "write", 5) == 0) + return SHF_WRITE; + if (len == 5 && strncmp (str, "alloc", 5) == 0) + return SHF_ALLOC; + if (len == 9 && strncmp (str, "execinstr", 9) == 0) + return SHF_EXECINSTR; + if (len == 7 && strncmp (str, "exclude", 7) == 0) + return SHF_EXCLUDE; + if (len == 3 && strncmp (str, "tls", 3) == 0) + return SHF_TLS; + +#ifdef md_elf_section_word + { + bfd_vma md_attr = md_elf_section_word (str, len); + if (md_attr > 0) + return md_attr; + } +#endif + + ret = obj_elf_section_type (str, len, FALSE); + if (ret != 0) + *type = ret; + else + as_warn (_("unrecognized section attribute")); + return 0; } /* Get name of section. */ -static char * +const char * obj_elf_section_name (void) { char *name; @@ -864,9 +949,28 @@ obj_elf_section_name (void) return NULL; } - name = xmalloc (end - input_line_pointer + 1); - memcpy (name, input_line_pointer, end - input_line_pointer); - name[end - input_line_pointer] = '\0'; + name = xmemdup0 (input_line_pointer, end - input_line_pointer); + + while (flag_sectname_subst) + { + char *subst = strchr (name, '%'); + if (subst && subst[1] == 'S') + { + int oldlen = strlen (name); + int substlen = strlen (now_seg->name); + int newlen = oldlen - 2 + substlen; + char *newname = XNEWVEC (char, newlen + 1); + int headlen = subst - name; + memcpy (newname, name, headlen); + strcpy (newname + headlen, now_seg->name); + strcat (newname + headlen, subst + 2); + xfree (name); + name = newname; + } + else + break; + } + #ifdef tc_canonicalize_section_name name = tc_canonicalize_section_name (name); #endif @@ -879,10 +983,13 @@ obj_elf_section_name (void) void obj_elf_section (int push) { - char *name, *group_name, *beg; - int type, attr, dummy; + const char *name, *group_name; + char *beg; + int type, dummy; + bfd_vma attr; int entsize; int linkonce; + subsegT new_subsection = -1; #ifndef TC_I370 if (flag_mri) @@ -921,15 +1028,33 @@ obj_elf_section (int push) ++input_line_pointer; SKIP_WHITESPACE (); + if (push && ISDIGIT (*input_line_pointer)) + { + /* .pushsection has an optional subsection. */ + new_subsection = (subsegT) get_absolute_expression (); + + SKIP_WHITESPACE (); + + /* Stop if we don't see a comma. */ + if (*input_line_pointer != ',') + goto done; + + /* Skip the comma. */ + ++input_line_pointer; + SKIP_WHITESPACE (); + } + if (*input_line_pointer == '"') { + bfd_boolean is_clone; + beg = demand_copy_C_string (&dummy); if (beg == NULL) { ignore_rest_of_line (); return; } - attr |= obj_elf_parse_section_letters (beg, strlen (beg)); + attr |= obj_elf_parse_section_letters (beg, strlen (beg), &is_clone); SKIP_WHITESPACE (); if (*input_line_pointer == ',') @@ -948,14 +1073,22 @@ obj_elf_section (int push) ignore_rest_of_line (); return; } - type = obj_elf_section_type (beg, strlen (beg)); + type = obj_elf_section_type (beg, strlen (beg), TRUE); } else if (c == '@' || c == '%') { - beg = ++input_line_pointer; - c = get_symbol_end (); - *input_line_pointer = c; - type = obj_elf_section_type (beg, input_line_pointer - beg); + ++input_line_pointer; + + if (ISDIGIT (* input_line_pointer)) + { + type = strtoul (input_line_pointer, & input_line_pointer, 0); + } + else + { + c = get_symbol_name (& beg); + (void) restore_line_pointer (c); + type = obj_elf_section_type (beg, input_line_pointer - beg, TRUE); + } } else input_line_pointer = save; @@ -981,16 +1114,26 @@ obj_elf_section (int push) attr &= ~SHF_MERGE; } + if ((attr & SHF_GROUP) != 0 && is_clone) + { + as_warn (_("? section flag ignored with G present")); + is_clone = FALSE; + } if ((attr & SHF_GROUP) != 0 && *input_line_pointer == ',') { ++input_line_pointer; group_name = obj_elf_section_name (); if (group_name == NULL) attr &= ~SHF_GROUP; - else if (strncmp (input_line_pointer, ",comdat", 7) == 0) + else if (*input_line_pointer == ',') { - input_line_pointer += 7; - linkonce = 1; + ++input_line_pointer; + SKIP_WHITESPACE (); + if (strncmp (input_line_pointer, "comdat", 6) == 0) + { + input_line_pointer += 6; + linkonce = 1; + } } else if (strncmp (name, ".gnu.linkonce", 13) == 0) linkonce = 1; @@ -1000,6 +1143,16 @@ obj_elf_section (int push) as_warn (_("group name for SHF_GROUP not specified")); attr &= ~SHF_GROUP; } + + if (is_clone) + { + const char *now_group = elf_group_name (now_seg); + if (now_group != NULL) + { + group_name = xstrdup (now_group); + linkonce = (now_seg->flags & SEC_LINK_ONCE) != 0; + } + } } else { @@ -1014,11 +1167,11 @@ obj_elf_section (int push) ignore_rest_of_line (); return; } - beg = ++input_line_pointer; - c = get_symbol_end (); - *input_line_pointer = c; + ++input_line_pointer; + c = get_symbol_name (& beg); + (void) restore_line_pointer (c); - attr |= obj_elf_section_word (beg, input_line_pointer - beg); + attr |= obj_elf_section_word (beg, input_line_pointer - beg, & type); SKIP_WHITESPACE (); } @@ -1027,9 +1180,13 @@ obj_elf_section (int push) } } +done: demand_empty_rest_of_line (); obj_elf_change_section (name, type, attr, entsize, group_name, linkonce, push); + + if (push && new_subsection != -1) + subseg_set (now_seg, new_subsection); } /* Change to the .data section. */ @@ -1089,7 +1246,7 @@ obj_elf_struct (int i) static void obj_elf_subsection (int ignore ATTRIBUTE_UNUSED) { - register int temp; + int temp; #ifdef md_flush_pending_output md_flush_pending_output (); @@ -1193,14 +1350,8 @@ obj_elf_symver (int ignore ATTRIBUTE_UNUSED) char old_lexat; symbolS *sym; - name = input_line_pointer; - c = get_symbol_end (); + sym = get_sym_from_input_line_and_check (); - sym = symbol_find_or_make (name); - - *input_line_pointer = c; - - SKIP_WHITESPACE (); if (*input_line_pointer != ',') { as_bad (_("expected comma after name in .symver")); @@ -1210,19 +1361,18 @@ obj_elf_symver (int ignore ATTRIBUTE_UNUSED) ++input_line_pointer; SKIP_WHITESPACE (); - name = input_line_pointer; /* Temporarily include '@' in symbol names. */ old_lexat = lex_type[(unsigned char) '@']; lex_type[(unsigned char) '@'] |= LEX_NAME; - c = get_symbol_end (); + c = get_symbol_name (& name); lex_type[(unsigned char) '@'] = old_lexat; if (symbol_get_obj (sym)->versioned_name == NULL) { symbol_get_obj (sym)->versioned_name = xstrdup (name); - *input_line_pointer = c; + (void) restore_line_pointer (c); if (strchr (symbol_get_obj (sym)->versioned_name, ELF_VER_CHR) == NULL) @@ -1245,7 +1395,7 @@ obj_elf_symver (int ignore ATTRIBUTE_UNUSED) return; } - *input_line_pointer = c; + (void) restore_line_pointer (c); } demand_empty_rest_of_line (); @@ -1265,8 +1415,7 @@ obj_elf_vtable_inherit (int ignore ATTRIBUTE_UNUSED) if (*input_line_pointer == '#') ++input_line_pointer; - cname = input_line_pointer; - c = get_symbol_end (); + c = get_symbol_name (& cname); csym = symbol_find (cname); /* GCFIXME: should check that we don't have two .vtable_inherits for @@ -1275,17 +1424,17 @@ obj_elf_vtable_inherit (int ignore ATTRIBUTE_UNUSED) if (csym == NULL || symbol_get_frag (csym) == NULL) { - as_bad ("expected `%s' to have already been set for .vtable_inherit", + as_bad (_("expected `%s' to have already been set for .vtable_inherit"), cname); bad = 1; } *input_line_pointer = c; - SKIP_WHITESPACE (); + SKIP_WHITESPACE_AFTER_NAME (); if (*input_line_pointer != ',') { - as_bad ("expected comma after name in .vtable_inherit"); + as_bad (_("expected comma after name in .vtable_inherit")); ignore_rest_of_line (); return NULL; } @@ -1305,10 +1454,9 @@ obj_elf_vtable_inherit (int ignore ATTRIBUTE_UNUSED) } else { - pname = input_line_pointer; - c = get_symbol_end (); + c = get_symbol_name (& pname); psym = symbol_find_or_make (pname); - *input_line_pointer = c; + restore_line_pointer (c); } demand_empty_rest_of_line (); @@ -1316,7 +1464,7 @@ obj_elf_vtable_inherit (int ignore ATTRIBUTE_UNUSED) if (bad) return NULL; - assert (symbol_get_value_expression (csym)->X_op == O_constant); + gas_assert (symbol_get_value_expression (csym)->X_op == O_constant); return fix_new (symbol_get_frag (csym), symbol_get_value_expression (csym)->X_add_number, 0, psym, 0, 0, BFD_RELOC_VTABLE_INHERIT); @@ -1329,23 +1477,16 @@ obj_elf_vtable_inherit (int ignore ATTRIBUTE_UNUSED) struct fix * obj_elf_vtable_entry (int ignore ATTRIBUTE_UNUSED) { - char *name; symbolS *sym; offsetT offset; - char c; if (*input_line_pointer == '#') ++input_line_pointer; - name = input_line_pointer; - c = get_symbol_end (); - sym = symbol_find_or_make (name); - *input_line_pointer = c; - - SKIP_WHITESPACE (); + sym = get_sym_from_input_line_and_check (); if (*input_line_pointer != ',') { - as_bad ("expected comma after name in .vtable_entry"); + as_bad (_("expected comma after name in .vtable_entry")); ignore_rest_of_line (); return NULL; } @@ -1362,6 +1503,195 @@ obj_elf_vtable_entry (int ignore ATTRIBUTE_UNUSED) BFD_RELOC_VTABLE_ENTRY); } +#define skip_whitespace(str) do { if (*(str) == ' ') ++(str); } while (0) + +static inline int +skip_past_char (char ** str, char c) +{ + if (**str == c) + { + (*str)++; + return 0; + } + else + return -1; +} +#define skip_past_comma(str) skip_past_char (str, ',') + +/* A list of attributes that have been explicitly set by the assembly code. + VENDOR is the vendor id, BASE is the tag shifted right by the number + of bits in MASK, and bit N of MASK is set if tag BASE+N has been set. */ +struct recorded_attribute_info { + struct recorded_attribute_info *next; + int vendor; + unsigned int base; + unsigned long mask; +}; +static struct recorded_attribute_info *recorded_attributes; + +/* Record that we have seen an explicit specification of attribute TAG + for vendor VENDOR. */ + +static void +record_attribute (int vendor, unsigned int tag) +{ + unsigned int base; + unsigned long mask; + struct recorded_attribute_info *rai; + + base = tag / (8 * sizeof (rai->mask)); + mask = 1UL << (tag % (8 * sizeof (rai->mask))); + for (rai = recorded_attributes; rai; rai = rai->next) + if (rai->vendor == vendor && rai->base == base) + { + rai->mask |= mask; + return; + } + + rai = XNEW (struct recorded_attribute_info); + rai->next = recorded_attributes; + rai->vendor = vendor; + rai->base = base; + rai->mask = mask; + recorded_attributes = rai; +} + +/* Return true if we have seen an explicit specification of attribute TAG + for vendor VENDOR. */ + +bfd_boolean +obj_elf_seen_attribute (int vendor, unsigned int tag) +{ + unsigned int base; + unsigned long mask; + struct recorded_attribute_info *rai; + + base = tag / (8 * sizeof (rai->mask)); + mask = 1UL << (tag % (8 * sizeof (rai->mask))); + for (rai = recorded_attributes; rai; rai = rai->next) + if (rai->vendor == vendor && rai->base == base) + return (rai->mask & mask) != 0; + return FALSE; +} + +/* Parse an attribute directive for VENDOR. + Returns the attribute number read, or zero on error. */ + +int +obj_elf_vendor_attribute (int vendor) +{ + expressionS exp; + int type; + int tag; + unsigned int i = 0; + char *s = NULL; + + /* Read the first number or name. */ + skip_whitespace (input_line_pointer); + s = input_line_pointer; + if (ISDIGIT (*input_line_pointer)) + { + expression (& exp); + if (exp.X_op != O_constant) + goto bad; + tag = exp.X_add_number; + } + else + { + char *name; + + /* A name may contain '_', but no other punctuation. */ + for (; ISALNUM (*input_line_pointer) || *input_line_pointer == '_'; + ++input_line_pointer) + i++; + if (i == 0) + goto bad; + + name = xstrndup (s, i); + +#ifndef CONVERT_SYMBOLIC_ATTRIBUTE +#define CONVERT_SYMBOLIC_ATTRIBUTE(a) -1 +#endif + + tag = CONVERT_SYMBOLIC_ATTRIBUTE (name); + if (tag == -1) + { + as_bad (_("Attribute name not recognised: %s"), name); + ignore_rest_of_line (); + free (name); + return 0; + } + free (name); + } + + type = _bfd_elf_obj_attrs_arg_type (stdoutput, vendor, tag); + + if (skip_past_comma (&input_line_pointer) == -1) + goto bad; + if (type & 1) + { + expression (& exp); + if (exp.X_op != O_constant) + { + as_bad (_("expected numeric constant")); + ignore_rest_of_line (); + return 0; + } + i = exp.X_add_number; + } + if ((type & 3) == 3 + && skip_past_comma (&input_line_pointer) == -1) + { + as_bad (_("expected comma")); + ignore_rest_of_line (); + return 0; + } + if (type & 2) + { + int len; + + skip_whitespace (input_line_pointer); + if (*input_line_pointer != '"') + goto bad_string; + s = demand_copy_C_string (&len); + } + + record_attribute (vendor, tag); + switch (type & 3) + { + case 3: + bfd_elf_add_obj_attr_int_string (stdoutput, vendor, tag, i, s); + break; + case 2: + bfd_elf_add_obj_attr_string (stdoutput, vendor, tag, s); + break; + case 1: + bfd_elf_add_obj_attr_int (stdoutput, vendor, tag, i); + break; + default: + abort (); + } + + demand_empty_rest_of_line (); + return tag; +bad_string: + as_bad (_("bad string constant")); + ignore_rest_of_line (); + return 0; +bad: + as_bad (_("expected , ")); + ignore_rest_of_line (); + return 0; +} + +/* Parse a .gnu_attribute directive. */ + +static void +obj_elf_gnu_attribute (int ignored ATTRIBUTE_UNUSED) +{ + obj_elf_vendor_attribute (OBJ_ATTR_GNU); +} + void elf_obj_read_begin_hook (void) { @@ -1398,7 +1728,7 @@ elf_copy_symbol_attributes (symbolS *dest, symbolS *src) if (srcelf->size) { if (destelf->size == NULL) - destelf->size = xmalloc (sizeof (expressionS)); + destelf->size = XNEW (expressionS); *destelf->size = *srcelf->size; } else @@ -1476,15 +1806,15 @@ obj_elf_version (int ignore ATTRIBUTE_UNUSED) static void obj_elf_size (int ignore ATTRIBUTE_UNUSED) { - char *name = input_line_pointer; - char c = get_symbol_end (); + char *name; + char c = get_symbol_name (&name); char *p; expressionS exp; symbolS *sym; p = input_line_pointer; *p = c; - SKIP_WHITESPACE (); + SKIP_WHITESPACE_AFTER_NAME (); if (*input_line_pointer != ',') { *p = 0; @@ -1515,14 +1845,14 @@ obj_elf_size (int ignore ATTRIBUTE_UNUSED) } else { - symbol_get_obj (sym)->size = xmalloc (sizeof (expressionS)); + symbol_get_obj (sym)->size = XNEW (expressionS); *symbol_get_obj (sym)->size = exp; } demand_empty_rest_of_line (); } /* Handle the ELF .type pseudo-op. This sets the type of a symbol. - There are five syntaxes: + There are six syntaxes: The first (used on Solaris) is .type SYM,#function @@ -1534,25 +1864,45 @@ obj_elf_size (int ignore ATTRIBUTE_UNUSED) .type SYM,%function The fifth (used on SVR4/860) is .type SYM,"function" + The sixth (emitted by recent SunPRO under Solaris) is + .type SYM,[0-9] + where the integer is the STT_* value. */ +static char * +obj_elf_type_name (char *cp) +{ + char *p; + + p = input_line_pointer; + if (*input_line_pointer >= '0' + && *input_line_pointer <= '9') + { + while (*input_line_pointer >= '0' + && *input_line_pointer <= '9') + ++input_line_pointer; + *cp = *input_line_pointer; + *input_line_pointer = '\0'; + } + else + *cp = get_symbol_name (&p); + + return p; +} + static void obj_elf_type (int ignore ATTRIBUTE_UNUSED) { - char *name; char c; int type; - const char *typename; + const char *type_name; symbolS *sym; elf_symbol_type *elfsym; - name = input_line_pointer; - c = get_symbol_end (); - sym = symbol_find_or_make (name); + sym = get_sym_from_input_line_and_check (); + c = *input_line_pointer; elfsym = (elf_symbol_type *) symbol_get_bfdsym (sym); - *input_line_pointer = c; - SKIP_WHITESPACE (); if (*input_line_pointer == ',') ++input_line_pointer; @@ -1563,28 +1913,88 @@ obj_elf_type (int ignore ATTRIBUTE_UNUSED) || *input_line_pointer == '%') ++input_line_pointer; - typename = input_line_pointer; - c = get_symbol_end (); + type_name = obj_elf_type_name (& c); type = 0; - if (strcmp (typename, "function") == 0 - || strcmp (typename, "STT_FUNC") == 0) + if (strcmp (type_name, "function") == 0 + || strcmp (type_name, "2") == 0 + || strcmp (type_name, "STT_FUNC") == 0) type = BSF_FUNCTION; - else if (strcmp (typename, "object") == 0 - || strcmp (typename, "STT_OBJECT") == 0) + else if (strcmp (type_name, "object") == 0 + || strcmp (type_name, "1") == 0 + || strcmp (type_name, "STT_OBJECT") == 0) type = BSF_OBJECT; - else if (strcmp (typename, "tls_object") == 0 - || strcmp (typename, "STT_TLS") == 0) + else if (strcmp (type_name, "tls_object") == 0 + || strcmp (type_name, "6") == 0 + || strcmp (type_name, "STT_TLS") == 0) type = BSF_OBJECT | BSF_THREAD_LOCAL; - else if (strcmp (typename, "notype") == 0 - || strcmp (typename, "STT_NOTYPE") == 0) + else if (strcmp (type_name, "notype") == 0 + || strcmp (type_name, "0") == 0 + || strcmp (type_name, "STT_NOTYPE") == 0) ; + else if (strcmp (type_name, "common") == 0 + || strcmp (type_name, "5") == 0 + || strcmp (type_name, "STT_COMMON") == 0) + { + type = BSF_OBJECT; + + if (! S_IS_COMMON (sym)) + { + if (S_IS_VOLATILE (sym)) + { + sym = symbol_clone (sym, 1); + S_SET_SEGMENT (sym, bfd_com_section_ptr); + S_SET_VALUE (sym, 0); + S_SET_EXTERNAL (sym); + symbol_set_frag (sym, &zero_address_frag); + S_CLEAR_VOLATILE (sym); + } + else if (S_IS_DEFINED (sym) || symbol_equated_p (sym)) + as_bad (_("symbol '%s' is already defined"), S_GET_NAME (sym)); + else + { + /* FIXME: Is it safe to just change the section ? */ + S_SET_SEGMENT (sym, bfd_com_section_ptr); + S_SET_VALUE (sym, 0); + S_SET_EXTERNAL (sym); + } + } + } + else if (strcmp (type_name, "gnu_indirect_function") == 0 + || strcmp (type_name, "10") == 0 + || strcmp (type_name, "STT_GNU_IFUNC") == 0) + { + const struct elf_backend_data *bed; + + bed = get_elf_backend_data (stdoutput); + if (!(bed->elf_osabi == ELFOSABI_GNU + || bed->elf_osabi == ELFOSABI_FREEBSD + /* GNU is still using the default value 0. */ + || bed->elf_osabi == ELFOSABI_NONE)) + as_bad (_("symbol type \"%s\" is supported only by GNU and FreeBSD targets"), + type_name); + type = BSF_FUNCTION | BSF_GNU_INDIRECT_FUNCTION; + } + else if (strcmp (type_name, "gnu_unique_object") == 0) + { + struct elf_backend_data *bed; + + bed = (struct elf_backend_data *) get_elf_backend_data (stdoutput); + if (!(bed->elf_osabi == ELFOSABI_GNU + /* GNU is still using the default value 0. */ + || bed->elf_osabi == ELFOSABI_NONE)) + as_bad (_("symbol type \"%s\" is supported only by GNU targets"), + type_name); + type = BSF_OBJECT | BSF_GNU_UNIQUE; + /* PR 10549: Always set OSABI field to GNU for objects containing unique symbols. */ + bed->elf_osabi = ELFOSABI_GNU; + } #ifdef md_elf_symbol_type - else if ((type = md_elf_symbol_type (typename, sym, elfsym)) != -1) + else if ((type = md_elf_symbol_type (type_name, sym, elfsym)) != -1) ; #endif else - as_bad (_("unrecognized symbol type \"%s\""), typename); + as_bad (_("unrecognized symbol type \"%s\""), type_name); *input_line_pointer = c; @@ -1612,13 +2022,18 @@ obj_elf_ident (int ignore ATTRIBUTE_UNUSED) char *p; comment_section = subseg_new (".comment", 0); bfd_set_section_flags (stdoutput, comment_section, - SEC_READONLY | SEC_HAS_CONTENTS); + SEC_READONLY | SEC_HAS_CONTENTS + | SEC_MERGE | SEC_STRINGS); + comment_section->entsize = 1; +#ifdef md_elf_section_change_hook + md_elf_section_change_hook (); +#endif p = frag_more (1); *p = 0; } else subseg_set (comment_section, 0); - stringer (1); + stringer (8 + 1); subseg_set (old_section, old_subsection); } @@ -1629,7 +2044,7 @@ obj_elf_ident (int ignore ATTRIBUTE_UNUSED) void obj_elf_init_stab_section (segT seg) { - char *file; + const char *file; char *p; char *stabstr_name; unsigned int stroff; @@ -1642,12 +2057,10 @@ obj_elf_init_stab_section (segT seg) p = frag_more (12); /* Zero it out. */ memset (p, 0, 12); - as_where (&file, NULL); - stabstr_name = xmalloc (strlen (segment_name (seg)) + 4); - strcpy (stabstr_name, segment_name (seg)); - strcat (stabstr_name, "str"); + file = as_where (NULL); + stabstr_name = concat (segment_name (seg), "str", (char *) NULL); stroff = get_stab_string_offset (file, stabstr_name); - know (stroff == 1); + know (stroff == 1 || (stroff == 0 && file[0] == '\0')); md_number_to_chars (p, stroff, 4); seg_info (seg)->stabu.p = p; } @@ -1669,9 +2082,7 @@ adjust_stab_sections (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED) if (!strcmp ("str", sec->name + strlen (sec->name) - 3)) return; - name = alloca (strlen (sec->name) + 4); - strcpy (name, sec->name); - strcat (name, "str"); + name = concat (sec->name, "str", NULL); strsec = bfd_get_section_by_name (abfd, name); if (strsec) strsz = bfd_section_size (abfd, strsec); @@ -1680,10 +2091,11 @@ adjust_stab_sections (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED) nsyms = bfd_section_size (abfd, sec) / 12 - 1; p = seg_info (sec)->stabu.p; - assert (p != 0); + gas_assert (p != 0); bfd_h_put_16 (abfd, nsyms, p + 6); bfd_h_put_32 (abfd, strsz, p + 8); + free (name); } #ifdef NEED_ECOFF_DEBUG @@ -1731,6 +2143,7 @@ void elf_frob_symbol (symbolS *symp, int *puntp) { struct elf_obj_sy *sy_obj; + expressionS *size; #ifdef NEED_ECOFF_DEBUG if (ECOFF_DEBUGGING) @@ -1739,24 +2152,20 @@ elf_frob_symbol (symbolS *symp, int *puntp) sy_obj = symbol_get_obj (symp); - if (sy_obj->size != NULL) + size = sy_obj->size; + if (size != NULL) { - switch (sy_obj->size->X_op) + if (resolve_expression (size) + && size->X_op == O_constant) + S_SET_SIZE (symp, size->X_add_number); + else { - case O_subtract: - S_SET_SIZE (symp, - (S_GET_VALUE (sy_obj->size->X_add_symbol) - + sy_obj->size->X_add_number - - S_GET_VALUE (sy_obj->size->X_op_symbol))); - break; - case O_constant: - S_SET_SIZE (symp, - (S_GET_VALUE (sy_obj->size->X_add_symbol) - + sy_obj->size->X_add_number)); - break; - default: - as_bad (_(".size expression too complicated to fix up")); - break; + if (!flag_allow_nonconst_size) + as_bad (_(".size expression for %s " + "does not evaluate to a constant"), S_GET_NAME (symp)); + else + as_warn (_(".size expression for %s " + "does not evaluate to a constant"), S_GET_NAME (symp)); } free (sy_obj->size); sy_obj->size = NULL; @@ -1767,7 +2176,9 @@ elf_frob_symbol (symbolS *symp, int *puntp) char *p; p = strchr (sy_obj->versioned_name, ELF_VER_CHR); - know (p != NULL); + 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. @@ -1780,14 +2191,15 @@ elf_frob_symbol (symbolS *symp, int *puntp) symbol. However, it's not clear whether it is the best approach. */ - if (! S_IS_DEFINED (symp)) + else if (! S_IS_DEFINED (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'"), + as_bad (_("invalid attempt to declare external version name" + " as default in symbol `%s'"), sy_obj->versioned_name); *puntp = TRUE; } @@ -1875,6 +2287,7 @@ struct group_list asection **head; /* Section lists. */ unsigned int *elt_count; /* Number of sections in each list. */ unsigned int num_group; /* Number of lists. */ + struct hash_control *indexes; /* Maps group name to index in head array. */ }; /* Called via bfd_map_over_sections. If SEC is a member of a group, @@ -1885,24 +2298,24 @@ struct group_list static void build_group_lists (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf) { - struct group_list *list = inf; + struct group_list *list = (struct group_list *) inf; const char *group_name = elf_group_name (sec); unsigned int i; + unsigned int *elem_idx; + unsigned int *idx_ptr; if (group_name == NULL) return; /* If this group already has a list, add the section to the head of the list. */ - for (i = 0; i < list->num_group; i++) + elem_idx = (unsigned int *) hash_find (list->indexes, group_name); + if (elem_idx != NULL) { - if (strcmp (group_name, elf_group_name (list->head[i])) == 0) - { - elf_next_in_group (sec) = list->head[i]; - list->head[i] = sec; - list->elt_count[i] += 1; - return; - } + elf_next_in_group (sec) = list->head[*elem_idx]; + list->head[*elem_idx] = sec; + list->elt_count[*elem_idx] += 1; + return; } /* New group. Make the arrays bigger in chunks to minimize calls to @@ -1911,41 +2324,48 @@ build_group_lists (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf) if ((i & 127) == 0) { unsigned int newsize = i + 128; - list->head = xrealloc (list->head, newsize * sizeof (*list->head)); - list->elt_count = xrealloc (list->elt_count, - newsize * sizeof (*list->elt_count)); + list->head = XRESIZEVEC (asection *, list->head, newsize); + list->elt_count = XRESIZEVEC (unsigned int, list->elt_count, newsize); } list->head[i] = sec; list->elt_count[i] = 1; list->num_group += 1; + + /* Add index to hash. */ + idx_ptr = XNEW (unsigned int); + *idx_ptr = i; + hash_insert (list->indexes, group_name, idx_ptr); +} + +static void free_section_idx (const char *key ATTRIBUTE_UNUSED, void *val) +{ + free ((unsigned int *) val); } void -elf_frob_file (void) +elf_adjust_symtab (void) { struct group_list list; unsigned int i; - bfd_map_over_sections (stdoutput, adjust_stab_sections, NULL); - /* Go find section groups. */ list.num_group = 0; list.head = NULL; list.elt_count = NULL; + list.indexes = hash_new (); bfd_map_over_sections (stdoutput, build_group_lists, &list); /* Make the SHT_GROUP sections that describe each section group. We can't set up the section contents here yet, because elf section indices have yet to be calculated. elf.c:set_group_contents does the rest of the work. */ - for (i = 0; i < list.num_group; i++) + for (i = 0; i < list.num_group; i++) { const char *group_name = elf_group_name (list.head[i]); const char *sec_name; asection *s; flagword flags; struct symbol *sy; - int has_sym; bfd_size_type size; flags = SEC_READONLY | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_GROUP; @@ -1961,17 +2381,7 @@ elf_frob_file (void) } } - sec_name = group_name; - sy = symbol_find_exact (group_name); - has_sym = 0; - if (sy != NULL - && (sy == symbol_lastP - || (sy->sy_next != NULL - && sy->sy_next->sy_previous == sy))) - { - has_sym = 1; - sec_name = ".group"; - } + sec_name = ".group"; s = subseg_force_new (sec_name, 0); if (s == NULL || !bfd_set_section_flags (stdoutput, s, flags) @@ -1984,8 +2394,27 @@ elf_frob_file (void) /* Pass a pointer to the first section in this group. */ elf_next_in_group (s) = list.head[i]; - if (has_sym) - elf_group_id (s) = sy->bsym; + /* Make sure that the signature symbol for the group has the + name of the group. */ + sy = symbol_find_exact (group_name); + if (!sy + || (sy != symbol_lastP + && (sy->sy_next == NULL + || sy->sy_next->sy_previous != sy))) + { + /* Create the symbol now. */ + sy = symbol_new (group_name, now_seg, (valueT) 0, frag_now); +#ifdef TE_SOLARIS + /* Before Solaris 11 build 154, Sun ld rejects local group + signature symbols, so make them weak hidden instead. */ + symbol_get_bfdsym (sy)->flags |= BSF_WEAK; + S_SET_OTHER (sy, STV_HIDDEN); +#else + symbol_get_obj (sy)->local = 1; +#endif + symbol_table_insert (sy); + } + elf_group_id (s) = symbol_get_bfdsym (sy); size = 4 * (list.elt_count[i] + 1); bfd_set_section_size (stdoutput, s, size); @@ -1994,6 +2423,16 @@ elf_frob_file (void) frag_wane (frag_now); } + /* Cleanup hash. */ + hash_traverse (list.indexes, free_section_idx); + hash_die (list.indexes); +} + +void +elf_frob_file (void) +{ + bfd_map_over_sections (stdoutput, adjust_stab_sections, NULL); + #ifdef elf_tc_final_processing elf_tc_final_processing (); #endif @@ -2021,8 +2460,7 @@ elf_frob_file_before_adjust (void) p = strchr (symbol_get_obj (symp)->versioned_name, ELF_VER_CHR); - know (p != NULL); - if (p[1] == ELF_VER_CHR && p[2] == 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); @@ -2091,7 +2529,7 @@ elf_frob_file_after_relocs (void) bfd_errmsg (bfd_get_error ())); sec = bfd_get_section_by_name (stdoutput, ".mdebug"); - assert (sec != NULL); + gas_assert (sec != NULL); know (!stdoutput->output_has_begun); @@ -2218,6 +2656,29 @@ sco_id (void) #endif /* SCO_ELF */ +static void +elf_generate_asm_lineno (void) +{ +#ifdef NEED_ECOFF_DEBUG + if (ECOFF_DEBUGGING) + ecoff_generate_asm_lineno (); +#endif +} + +static void +elf_process_stab (segT sec ATTRIBUTE_UNUSED, + int what ATTRIBUTE_UNUSED, + const char *string ATTRIBUTE_UNUSED, + int type ATTRIBUTE_UNUSED, + int other ATTRIBUTE_UNUSED, + int desc ATTRIBUTE_UNUSED) +{ +#ifdef NEED_ECOFF_DEBUG + if (ECOFF_DEBUGGING) + ecoff_stab (sec, what, string, type, other, desc); +#endif +} + static int elf_separate_stab_sections (void) { @@ -2258,13 +2719,8 @@ const struct format_ops elf_format_ops = 0, /* s_get_type */ 0, /* s_set_type */ elf_copy_symbol_attributes, -#ifdef NEED_ECOFF_DEBUG - ecoff_generate_asm_lineno, - ecoff_stab, -#else - 0, /* generate_asm_lineno */ - 0, /* process_stab */ -#endif + elf_generate_asm_lineno, + elf_process_stab, elf_separate_stab_sections, elf_init_stab_section, elf_sec_sym_ok_for_reloc, @@ -2275,5 +2731,7 @@ const struct format_ops elf_format_ops = 0, /* ecoff_set_ext */ #endif elf_obj_read_begin_hook, - elf_obj_symbol_new_hook + elf_obj_symbol_new_hook, + 0, + elf_adjust_symtab };