X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gas%2Fconfig%2Fobj-elf.c;h=e93d59cb081c1ac180dc72d6c226cad4bac44f6c;hb=9a01ec4c0368048fb5ea1ba1b3af9afbd651b529;hp=52c6b641227537cf4bbe2443094e89c04e2e7268;hpb=4b95cf5c0c75d6efc1b2f96af72317aecca079f1;p=binutils-gdb.git diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c index 52c6b641227..e93d59cb081 100644 --- a/gas/config/obj-elf.c +++ b/gas/config/obj-elf.c @@ -1,5 +1,5 @@ /* ELF object file format - Copyright (C) 1992-2014 Free Software Foundation, Inc. + Copyright (C) 1992-2021 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -23,7 +23,6 @@ #include "safe-ctype.h" #include "subsegs.h" #include "obstack.h" -#include "struc-symbol.h" #include "dwarf2dbg.h" #ifndef ECOFF_DEBUGGING @@ -34,6 +33,7 @@ #ifdef NEED_ECOFF_DEBUG #include "ecoff.h" +#include "bfd/ecoff-bfd.h" #endif #ifdef TC_ALPHA @@ -48,10 +48,6 @@ #include "elf/ppc.h" #endif -#ifdef TC_I370 -#include "elf/i370.h" -#endif - #ifdef TC_I386 #include "elf/x86-64.h" #endif @@ -64,6 +60,10 @@ #include "elf/nios2.h" #endif +#ifdef TC_PRU +#include "elf/pru.h" +#endif + static void obj_elf_line (int); static void obj_elf_size (int); static void obj_elf_type (int); @@ -78,9 +78,11 @@ 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); +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}, @@ -113,18 +115,14 @@ static const pseudo_typeS elf_pseudo_table[] = {"subsection", obj_elf_subsection, 0}, /* These are GNU extensions to aid in garbage collecting C++ vtables. */ - {"vtable_inherit", (void (*) (int)) &obj_elf_vtable_inherit, 0}, - {"vtable_entry", (void (*) (int)) &obj_elf_vtable_entry, 0}, + {"vtable_inherit", obj_elf_vtable_inherit, 0}, + {"vtable_entry", 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}, - {"8byte", cons, 8}, /* These are used for dwarf2. */ - { "file", (void (*) (int)) dwarf2_directive_file, 0 }, + { "file", dwarf2_directive_file, 0 }, { "loc", dwarf2_directive_loc, 0 }, { "loc_mark_labels", dwarf2_directive_loc_mark_labels, 0 }, @@ -133,6 +131,7 @@ static const pseudo_typeS elf_pseudo_table[] = {"offset", obj_elf_struct, 0}, {"struct", obj_elf_struct, 0}, {"text", obj_elf_text, 0}, + {"bss", obj_elf_bss, 0}, {"tls_common", obj_elf_tls_common, 0}, @@ -160,6 +159,7 @@ static const pseudo_typeS ecoff_debug_pseudo_table[] = { "etype", ecoff_directive_type, 0 }, /* ECOFF specific debugging information. */ + { "aent", ecoff_directive_ent, 1 }, { "begin", ecoff_directive_begin, 0 }, { "bend", ecoff_directive_bend, 0 }, { "end", ecoff_directive_end, 0 }, @@ -260,16 +260,17 @@ elf_sec_sym_ok_for_reloc (asection *sec) void elf_file_symbol (const char *s, int appfile) { + asymbol *bsym; + if (!appfile || symbol_rootP == NULL - || symbol_rootP->bsym == NULL - || (symbol_rootP->bsym->flags & BSF_FILE) == 0) + || (bsym = symbol_get_bfdsym (symbol_rootP)) == NULL + || (bsym->flags & BSF_FILE) == 0) { symbolS *sym; - unsigned int name_length; + 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))) @@ -282,14 +283,17 @@ elf_file_symbol (const char *s, int appfile) symbol_get_bfdsym (sym)->flags |= BSF_FILE; - if (symbol_rootP != sym) + if (symbol_rootP != sym + && ((bsym = symbol_get_bfdsym (symbol_rootP)) == NULL + || (bsym->flags & BSF_FILE) == 0)) { 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 @@ -321,9 +325,9 @@ elf_common_parse (int ignore ATTRIBUTE_UNUSED, symbolS *symbolP, addressT size) 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 { @@ -406,11 +410,10 @@ get_sym_from_input_line_and_check (void) char c; symbolS *sym; - name = input_line_pointer; - c = get_symbol_end (); + c = get_symbol_name (& name); sym = symbol_find_or_make (name); *input_line_pointer = c; - SKIP_WHITESPACE (); + SKIP_WHITESPACE_AFTER_NAME (); /* There is no symbol name if input_line_pointer has not moved. */ if (name == input_line_pointer) @@ -478,7 +481,7 @@ obj_elf_visibility (int visibility) 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); @@ -513,16 +516,37 @@ struct section_stack 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) { - const char *gname = (const char *) 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); - - return (group_name == gname - || (group_name != NULL - && gname != NULL - && strcmp (group_name, gname) == 0)); + const char *linked_to_symbol_name + = sec->map_head.linked_to_symbol_name; + 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 (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 + && (group_name == gname + || (group_name != NULL + && gname != NULL + && strcmp (group_name, gname) == 0)) + && (linked_to_symbol_name == match->linked_to_symbol_name + || (linked_to_symbol_name != NULL + && match->linked_to_symbol_name != NULL + && strcmp (linked_to_symbol_name, + match->linked_to_symbol_name) == 0))); } /* Handle the .section pseudo-op. This code supports two different @@ -545,10 +569,10 @@ get_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf) void obj_elf_change_section (const char *name, - int type, + unsigned int type, bfd_vma attr, int entsize, - const char *group_name, + struct elf_section_match *match_p, int linkonce, int push) { @@ -558,6 +582,12 @@ obj_elf_change_section (const char *name, const struct elf_backend_data *bed; const struct bfd_elf_special_section *ssect; + if (match_p == NULL) + { + static struct elf_section_match unused_match; + match_p = &unused_match; + } + #ifdef md_flush_pending_output md_flush_pending_output (); #endif @@ -566,7 +596,7 @@ obj_elf_change_section (const char *name, if (push) { struct section_stack *elt; - elt = (struct section_stack *) xmalloc (sizeof (struct section_stack)); + elt = XNEW (struct section_stack); elt->next = section_stack; elt->seg = now_seg; elt->prev_seg = previous_section; @@ -574,11 +604,11 @@ obj_elf_change_section (const char *name, elt->prev_subseg = previous_subsection; section_stack = elt; } - previous_section = now_seg; - previous_subsection = now_subseg; - old_sec = bfd_get_section_by_name_if (stdoutput, name, get_section, - (void *) group_name); + obj_elf_section_change_hook (); + + old_sec = bfd_get_section_by_name_if (stdoutput, name, get_section_by_match, + (void *) match_p); if (old_sec) { sec = old_sec; @@ -592,7 +622,7 @@ obj_elf_change_section (const char *name, if (ssect != NULL) { - bfd_boolean override = FALSE; + bool override = false; if (type == SHT_NULL) type = ssect->type; @@ -619,7 +649,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); } @@ -631,41 +663,50 @@ obj_elf_change_section (const char *name, } } - if (old_sec == NULL && (attr & ~ssect->attr) != 0) + 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)) @@ -674,12 +715,13 @@ obj_elf_change_section (const char *name, #endif else { - if (group_name == NULL) + if (match_p->group_name == NULL) as_warn (_("setting incorrect section attributes for %s"), name); - override = TRUE; + override = true; } } + if (!override && old_sec == NULL) attr |= ssect->attr; } @@ -709,20 +751,36 @@ obj_elf_change_section (const char *name, 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->sh_info; /* Prevent SEC_HAS_CONTENTS from being inadvertently set. */ if (type == SHT_NOBITS) seg_info (sec)->bss = 1; - bfd_set_section_flags (stdoutput, sec, flags); + /* Set the section ID and flags. */ + sec->section_id = match_p->section_id; + flags |= match_p->flags; + + /* Set the linked-to symbol name. */ + sec->map_head.linked_to_symbol_name + = match_p->linked_to_symbol_name; + + bfd_set_section_flags (sec, flags); if (flags & SEC_MERGE) sec->entsize = entsize; - elf_group_name (sec) = group_name; + elf_group_name (sec) = match_p->group_name; /* 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)); } @@ -730,7 +788,17 @@ obj_elf_change_section (const char *name, { if (type != SHT_NULL && (unsigned) type != elf_section_type (old_sec)) - as_warn (_("ignoring changed section type for %s"), name); + { + if (ssect != NULL) + /* This is a special section with known type. User + assembly might get the section type wrong; Even high + profile projects like glibc have done so in the past. + So don't error in this case. */ + as_warn (_("ignoring changed section type for %s"), name); + else + /* Do error when assembly isn't self-consistent. */ + as_bad (_("changed section type for %s"), name); + } if (attr != 0) { @@ -742,9 +810,19 @@ obj_elf_change_section (const char *name, | SEC_EXCLUDE | SEC_SORT_ENTRIES | SEC_MERGE | SEC_STRINGS | SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD | SEC_THREAD_LOCAL))) - as_warn (_("ignoring changed section attributes for %s"), name); + { + if (ssect != NULL) + as_warn (_("ignoring changed section attributes for %s"), name); + else + as_bad (_("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); + as_bad (_("changed section entity size for %s"), name); } } @@ -754,10 +832,11 @@ obj_elf_change_section (const char *name, } static bfd_vma -obj_elf_parse_section_letters (char *str, size_t len, bfd_boolean *is_clone) +obj_elf_parse_section_letters (char *str, size_t len, + bool *is_clone, bfd_vma *gnu_attr) { bfd_vma attr = 0; - *is_clone = FALSE; + *is_clone = false; while (len > 0) { @@ -769,6 +848,9 @@ obj_elf_parse_section_letters (char *str, size_t len, bfd_boolean *is_clone) case 'e': attr |= SHF_EXCLUDE; break; + case 'o': + attr |= SHF_LINK_ORDER; + break; case 'w': attr |= SHF_WRITE; break; @@ -787,8 +869,14 @@ obj_elf_parse_section_letters (char *str, size_t len, bfd_boolean *is_clone) case 'T': attr |= SHF_TLS; break; + 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': @@ -802,16 +890,54 @@ obj_elf_parse_section_letters (char *str, size_t len, bfd_boolean *is_clone) } break; } + /* Fall through. */ default: { - char *bad_msg = _("unrecognized .section attribute: want a,e,w,x,M,S,G,T"); + const char *bad_msg = _("unrecognized .section attribute:" + " want a,e,o,w,x,M,S,G,T or number"); #ifdef md_elf_section_letter 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; + 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); + } + + /* 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; } @@ -822,19 +948,19 @@ obj_elf_parse_section_letters (char *str, size_t len, bfd_boolean *is_clone) } 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 @@ -845,6 +971,17 @@ obj_elf_section_type (char *str, size_t len, bfd_boolean warn) } #endif + 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; @@ -855,15 +992,15 @@ obj_elf_section_word (char *str, size_t len, int *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 @@ -874,7 +1011,7 @@ obj_elf_section_word (char *str, size_t len, int *type) } #endif - ret = obj_elf_section_type (str, len, FALSE); + ret = obj_elf_section_type (str, len, false); if (ret != 0) *type = ret; else @@ -884,7 +1021,7 @@ obj_elf_section_word (char *str, size_t len, int *type) } /* Get name of section. */ -char * +const char * obj_elf_section_name (void) { char *name; @@ -914,9 +1051,28 @@ obj_elf_section_name (void) return NULL; } - name = (char *) 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 @@ -926,17 +1082,42 @@ obj_elf_section_name (void) 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) { - char *name, *group_name, *beg; + const char *name; + char *beg; int type, dummy; bfd_vma attr; + bfd_vma gnu_attr; int entsize; int linkonce; subsegT new_subsection = -1; + struct elf_section_match match; + unsigned long linked_to_section_index = -1UL; -#ifndef TC_I370 if (flag_mri) { char mri_type; @@ -945,8 +1126,7 @@ obj_elf_section (int push) md_flush_pending_output (); #endif - previous_section = now_seg; - previous_subsection = now_subseg; + obj_elf_section_change_hook (); s_mri_sect (&mri_type); @@ -956,14 +1136,27 @@ obj_elf_section (int push) return; } -#endif /* ! defined (TC_I370) */ name = obj_elf_section_name (); if (name == NULL) return; + + memset (&match, 0, sizeof (match)); + + symbolS * sym; + if ((sym = symbol_find (name)) != NULL + && ! symbol_section_p (sym) + && S_IS_DEFINED (sym) + && ! S_IS_VOLATILE (sym) + && ! S_CAN_BE_REDEFINED (sym)) + { + as_bad (_("section name '%s' already defined as another symbol"), name); + ignore_rest_of_line (); + return; + } type = SHT_NULL; attr = 0; - group_name = NULL; + gnu_attr = 0; entsize = 0; linkonce = 0; @@ -991,7 +1184,7 @@ obj_elf_section (int push) if (*input_line_pointer == '"') { - bfd_boolean is_clone; + bool is_clone; beg = demand_copy_C_string (&dummy); if (beg == NULL) @@ -999,7 +1192,8 @@ obj_elf_section (int push) ignore_rest_of_line (); return; } - attr |= obj_elf_parse_section_letters (beg, strlen (beg), &is_clone); + attr |= obj_elf_parse_section_letters (beg, strlen (beg), + &is_clone, &gnu_attr); SKIP_WHITESPACE (); if (*input_line_pointer == ',') @@ -1018,14 +1212,22 @@ obj_elf_section (int push) 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 == '%') { - beg = ++input_line_pointer; - c = get_symbol_end (); - *input_line_pointer = c; - type = obj_elf_section_type (beg, input_line_pointer - beg, TRUE); + ++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; @@ -1051,28 +1253,51 @@ obj_elf_section (int push) attr &= ~SHF_MERGE; } + if ((attr & SHF_LINK_ORDER) != 0 && *input_line_pointer == ',') + { + ++input_line_pointer; + SKIP_WHITESPACE (); + /* 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; - group_name = obj_elf_section_name (); - if (group_name == NULL) + match.group_name = obj_elf_section_name (); + if (match.group_name == NULL) attr &= ~SHF_GROUP; else if (*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) @@ -1086,10 +1311,91 @@ obj_elf_section (int push) const char *now_group = elf_group_name (now_seg); if (now_group != NULL) { - group_name = xstrdup (now_group); + match.group_name = xstrdup (now_group); linkonce = (now_seg->flags & SEC_LINK_ONCE) != 0; } } + + if ((gnu_attr & SHF_GNU_MBIND) != 0 && *input_line_pointer == ',') + { + char *save = input_line_pointer; + ++input_line_pointer; + SKIP_WHITESPACE (); + if (ISDIGIT (* input_line_pointer)) + { + char *t = input_line_pointer; + match.sh_info = strtoul (input_line_pointer, + &input_line_pointer, 0); + if (match.sh_info == (unsigned int) -1) + { + as_warn (_("unsupported mbind section info: %s"), t); + 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 (startswith (input_line_pointer, "unique")) + { + input_line_pointer += 6; + SKIP_WHITESPACE (); + if (*input_line_pointer == ',') + { + ++input_line_pointer; + SKIP_WHITESPACE (); + if (ISDIGIT (* input_line_pointer)) + { + bfd_vma id; + bool overflow; + char *t = input_line_pointer; + if (sizeof (bfd_vma) <= sizeof (unsigned long)) + { + errno = 0; + id = strtoul (input_line_pointer, + &input_line_pointer, 0); + overflow = (id == (unsigned long) -1 + && errno == ERANGE); + } + else + { + id = bfd_scan_vma + (input_line_pointer, + (const char **) &input_line_pointer, 0); + overflow = id == ~(bfd_vma) 0; + } + if (overflow || id > (unsigned int) -1) + { + char *linefeed, saved_char = 0; + if ((linefeed = strchr (t, '\n')) != NULL) + { + saved_char = *linefeed; + *linefeed = '\0'; + } + as_bad (_("unsupported section id: %s"), t); + if (saved_char) + *linefeed = saved_char; + } + else + { + match.section_id = id; + match.flags |= SEC_ASSEMBLER_SECTION_ID; + } + } + } + } + else + input_line_pointer = save; + } } else { @@ -1104,11 +1410,12 @@ 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, & type); + attr |= obj_elf_section_word (beg, input_line_pointer - beg, + &type); SKIP_WHITESPACE (); } @@ -1117,15 +1424,71 @@ obj_elf_section (int push) } } -done: + done: demand_empty_rest_of_line (); - obj_elf_change_section (name, type, attr, entsize, group_name, linkonce, push); + if ((gnu_attr & (SHF_GNU_MBIND | SHF_GNU_RETAIN)) != 0) + { + const struct elf_backend_data *bed; + bool mbind_p = (gnu_attr & SHF_GNU_MBIND) != 0; + + if (mbind_p && (attr & SHF_ALLOC) == 0) + as_bad (_("SHF_ALLOC isn't set for GNU_MBIND section: %s"), name); + + 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 ? */ + } if (push && new_subsection != -1) subseg_set (now_seg, new_subsection); } +/* Change to the .bss section. */ + +void +obj_elf_bss (int i ATTRIBUTE_UNUSED) +{ + int temp; + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + obj_elf_section_change_hook (); + + temp = get_absolute_expression (); + subseg_set (bss_section, (subsegT) temp); + demand_empty_rest_of_line (); + +#ifdef md_elf_section_change_hook + md_elf_section_change_hook (); +#endif +} + /* Change to the .data section. */ void @@ -1135,8 +1498,8 @@ obj_elf_data (int i) md_flush_pending_output (); #endif - previous_section = now_seg; - previous_subsection = now_subseg; + obj_elf_section_change_hook (); + s_data (i); #ifdef md_elf_section_change_hook @@ -1153,8 +1516,8 @@ obj_elf_text (int i) md_flush_pending_output (); #endif - previous_section = now_seg; - previous_subsection = now_subseg; + obj_elf_section_change_hook (); + s_text (i); #ifdef md_elf_section_change_hook @@ -1171,8 +1534,8 @@ obj_elf_struct (int i) md_flush_pending_output (); #endif - previous_section = now_seg; - previous_subsection = now_subseg; + obj_elf_section_change_hook (); + s_struct (i); #ifdef md_elf_section_change_hook @@ -1189,8 +1552,7 @@ obj_elf_subsection (int ignore ATTRIBUTE_UNUSED) md_flush_pending_output (); #endif - previous_section = now_seg; - previous_subsection = now_subseg; + obj_elf_section_change_hook (); temp = get_absolute_expression (); subseg_set (now_seg, (subsegT) temp); @@ -1229,8 +1591,8 @@ obj_elf_previous (int ignore ATTRIBUTE_UNUSED) new_section = previous_section; new_subsection = previous_subsection; - previous_section = now_seg; - previous_subsection = now_subseg; + obj_elf_section_change_hook (); + subseg_set (new_section, new_subsection); #ifdef md_elf_section_change_hook @@ -1273,6 +1635,70 @@ obj_elf_line (int ignore ATTRIBUTE_UNUSED) 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 @@ -1283,9 +1709,12 @@ static void 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 (); @@ -1298,42 +1727,65 @@ 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; + sym_name = S_GET_NAME (sym); - if (symbol_get_obj (sym)->versioned_name == NULL) + if (S_IS_COMMON (sym)) { - symbol_get_obj (sym)->versioned_name = xstrdup (name); + as_bad (_("`%s' can't be versioned to common symbol '%s'"), + name, sym_name); + ignore_rest_of_line (); + return; + } - *input_line_pointer = c; + 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 (strchr (symbol_get_obj (sym)->versioned_name, - ELF_VER_CHR) == NULL) - { - 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; - } + sy_obj = symbol_get_obj (sym); + if (obj_elf_find_and_add_versioned_name (name, sym_name, + p, sy_obj) == NULL) + { + sy_obj->bad_version = true; + ignore_rest_of_line (); + return; } - else + + (void) restore_line_pointer (c); + + if (*input_line_pointer == ',') { - if (strcmp (symbol_get_obj (sym)->versioned_name, name)) + char *save = input_line_pointer; + + ++input_line_pointer; + SKIP_WHITESPACE (); + if (startswith (input_line_pointer, "local")) { - 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 += 5; + sy_obj->visibility = visibility_local; } - - *input_line_pointer = c; + else if (startswith (input_line_pointer, "hidden")) + { + input_line_pointer += 6; + sy_obj->visibility = visibility_hidden; + } + 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 (); @@ -1344,7 +1796,7 @@ obj_elf_symver (int ignore ATTRIBUTE_UNUSED) syntax is ".vtable_inherit CHILDNAME, PARENTNAME". */ struct fix * -obj_elf_vtable_inherit (int ignore ATTRIBUTE_UNUSED) +obj_elf_get_vtable_inherit (void) { char *cname, *pname; symbolS *csym, *psym; @@ -1353,8 +1805,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 @@ -1370,7 +1821,7 @@ obj_elf_vtable_inherit (int ignore ATTRIBUTE_UNUSED) *input_line_pointer = c; - SKIP_WHITESPACE (); + SKIP_WHITESPACE_AFTER_NAME (); if (*input_line_pointer != ',') { as_bad (_("expected comma after name in .vtable_inherit")); @@ -1393,10 +1844,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 (); @@ -1410,12 +1860,21 @@ obj_elf_vtable_inherit (int ignore ATTRIBUTE_UNUSED) 0, psym, 0, 0, BFD_RELOC_VTABLE_INHERIT); } +/* This is a version of obj_elf_get_vtable_inherit() that is + suitable for use in struct _pseudo_type tables. */ + +void +obj_elf_vtable_inherit (int ignore ATTRIBUTE_UNUSED) +{ + (void) obj_elf_get_vtable_inherit (); +} + /* This handles the .vtable_entry pseudo-op, which is used to indicate to the linker that a vtable slot was used. The syntax is ".vtable_entry tablename, offset". */ struct fix * -obj_elf_vtable_entry (int ignore ATTRIBUTE_UNUSED) +obj_elf_get_vtable_entry (void) { symbolS *sym; offsetT offset; @@ -1443,6 +1902,15 @@ obj_elf_vtable_entry (int ignore ATTRIBUTE_UNUSED) BFD_RELOC_VTABLE_ENTRY); } +/* This is a version of obj_elf_get_vtable_entry() that is + suitable for use in struct _pseudo_type tables. */ + +void +obj_elf_vtable_entry (int ignore ATTRIBUTE_UNUSED) +{ + (void) obj_elf_get_vtable_entry (); +} + #define skip_whitespace(str) do { if (*(str) == ' ') ++(str); } while (0) static inline int @@ -1458,6 +1926,62 @@ skip_past_char (char ** str, char c) } #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. */ + +bool +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. */ @@ -1491,9 +2015,7 @@ obj_elf_vendor_attribute (int vendor) if (i == 0) goto bad; - name = (char *) alloca (i + 1); - memcpy (name, s, i); - name[i] = '\0'; + name = xstrndup (s, i); #ifndef CONVERT_SYMBOLIC_ATTRIBUTE #define CONVERT_SYMBOLIC_ATTRIBUTE(a) -1 @@ -1504,8 +2026,10 @@ obj_elf_vendor_attribute (int vendor) { 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); @@ -1540,6 +2064,7 @@ obj_elf_vendor_attribute (int vendor) s = demand_copy_C_string (&len); } + record_attribute (vendor, tag); switch (type & 3) { case 3: @@ -1557,11 +2082,11 @@ obj_elf_vendor_attribute (int vendor) demand_empty_rest_of_line (); return tag; -bad_string: + bad_string: as_bad (_("bad string constant")); ignore_rest_of_line (); return 0; -bad: + bad: as_bad (_("expected , ")); ignore_rest_of_line (); return 0; @@ -1599,6 +2124,22 @@ elf_obj_symbol_new_hook (symbolS *symbolP) #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. */ @@ -1611,13 +2152,12 @@ elf_copy_symbol_attributes (symbolS *dest, symbolS *src) if (srcelf->size) { if (destelf->size == NULL) - destelf->size = (expressionS *) xmalloc (sizeof (expressionS)); + destelf->size = XNEW (expressionS); *destelf->size = *srcelf->size; } else { - if (destelf->size != NULL) - free (destelf->size); + free (destelf->size); destelf->size = NULL; } S_SET_SIZE (dest, S_GET_SIZE (src)); @@ -1655,9 +2195,8 @@ obj_elf_version (int ignore ATTRIBUTE_UNUSED) /* Create the .note section. */ note_secp = subseg_new (".note", 0); - bfd_set_section_flags (stdoutput, - note_secp, - SEC_HAS_CONTENTS | SEC_READONLY); + bfd_set_section_flags (note_secp, SEC_HAS_CONTENTS | SEC_READONLY); + record_alignment (note_secp, 2); /* Process the version string. */ len = strlen (name) + 1; @@ -1689,15 +2228,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; @@ -1720,16 +2259,12 @@ obj_elf_size (int ignore ATTRIBUTE_UNUSED) 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 { - symbol_get_obj (sym)->size = - (expressionS *) xmalloc (sizeof (expressionS)); + symbol_get_obj (sym)->size = XNEW (expressionS); *symbol_get_obj (sym)->size = exp; } demand_empty_rest_of_line (); @@ -1769,7 +2304,7 @@ obj_elf_type_name (char *cp) *input_line_pointer = '\0'; } else - *cp = get_symbol_end (); + *cp = get_symbol_name (&p); return p; } @@ -1851,27 +2386,29 @@ obj_elf_type (int ignore ATTRIBUTE_UNUSED) 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); + 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_GNU - /* GNU is still using the default value 0. */ - || bed->elf_osabi == ELFOSABI_NONE)) + 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; 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 (type_name, sym, elfsym)) != -1) @@ -1885,7 +2422,38 @@ obj_elf_type (int ignore ATTRIBUTE_UNUSED) if (*input_line_pointer == '"') ++input_line_pointer; - elfsym->symbol.flags |= type; +#ifdef md_elf_symbol_type_change + if (!md_elf_symbol_type_change (sym, elfsym, type)) +#endif + { + flagword mask = BSF_FUNCTION | BSF_OBJECT; + + if (type != BSF_FUNCTION) + mask |= BSF_GNU_INDIRECT_FUNCTION; + if (type != BSF_OBJECT) + { + mask |= BSF_GNU_UNIQUE | BSF_THREAD_LOCAL; + + if (S_IS_COMMON (sym)) + { + as_bad (_("cannot change type of common symbol '%s'"), + S_GET_NAME (sym)); + mask = type = 0; + } + } + + /* Don't warn when changing to STT_NOTYPE. */ + if (type) + { + flagword new = (elfsym->symbol.flags & ~mask) | type; + + if (new != (elfsym->symbol.flags | type)) + as_warn (_("symbol '%s' already has its type set"), S_GET_NAME (sym)); + elfsym->symbol.flags = new; + } + else + elfsym->symbol.flags &= ~mask; + } demand_empty_rest_of_line (); } @@ -1905,9 +2473,8 @@ 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_MERGE | SEC_STRINGS); + bfd_set_section_flags (comment_section, (SEC_READONLY | SEC_HAS_CONTENTS + | SEC_MERGE | SEC_STRINGS)); comment_section->entsize = 1; #ifdef md_elf_section_change_hook md_elf_section_change_hook (); @@ -1928,27 +2495,26 @@ 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; /* Force the section to align to a longword boundary. Without this, UnixWare ar crashes. */ - bfd_set_section_alignment (stdoutput, seg, 2); + bfd_set_section_alignment (seg, 2); /* Make space for this first symbol. */ p = frag_more (12); /* Zero it out. */ memset (p, 0, 12); - as_where (&file, NULL); - stabstr_name = (char *) xmalloc (strlen (segment_name (seg)) + 4); - strcpy (stabstr_name, segment_name (seg)); - strcat (stabstr_name, "str"); - stroff = get_stab_string_offset (file, stabstr_name); + 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); 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 @@ -1963,26 +2529,25 @@ adjust_stab_sections (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED) 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; - name = (char *) 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); + strsz = bfd_section_size (strsec); else strsz = 0; - nsyms = bfd_section_size (abfd, sec) / 12 - 1; + nsyms = bfd_section_size (sec) / 12 - 1; p = seg_info (sec)->stabu.p; 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 @@ -2006,13 +2571,13 @@ elf_ecoff_set_ext (symbolS *sym, struct ecoff_extr *ext) 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 @@ -2031,6 +2596,7 @@ elf_frob_symbol (symbolS *symp, int *puntp) { struct elf_obj_sy *sy_obj; expressionS *size; + struct elf_versioned_name_list *versioned_name; #ifdef NEED_ECOFF_DEBUG if (ECOFF_DEBUGGING) @@ -2047,7 +2613,7 @@ elf_frob_symbol (symbolS *symp, int *puntp) S_SET_SIZE (symp, size->X_add_number); else { - if (flag_size_check == size_check_error) + if (!flag_allow_nonconst_size) as_bad (_(".size expression for %s " "does not evaluate to a constant"), S_GET_NAME (symp)); else @@ -2058,63 +2624,47 @@ elf_frob_symbol (symbolS *symp, int *puntp) 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); - know (p != NULL); - /* 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. */ - - 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. */ + symbolS *symp2 = symbol_find_or_make (versioned_name->name); S_SET_SEGMENT (symp2, S_GET_SEGMENT (symp)); @@ -2122,7 +2672,8 @@ elf_frob_symbol (symbolS *symp, int *puntp) 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)); @@ -2137,6 +2688,24 @@ elf_frob_symbol (symbolS *symp, int *puntp) 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; + } } } @@ -2147,40 +2716,26 @@ elf_frob_symbol (symbolS *symp, int *puntp) as_bad (_("symbol `%s' can not be both weak and common"), S_GET_NAME (symp)); } - -#ifdef TC_MIPS - /* The Irix 5 and 6 assemblers set the type of any common symbol and - any undefined non-function symbol to STT_OBJECT. We try to be - compatible, since newer Irix 5 and 6 linkers care. However, we - only set undefined symbols to be STT_OBJECT if we are on Irix, - because that is the only time gcc will generate the necessary - .global directives to mark functions. */ - - if (S_IS_COMMON (symp)) - symbol_get_bfdsym (symp)->flags |= BSF_OBJECT; - - if (strstr (TARGET_OS, "irix") != NULL - && ! S_IS_DEFINED (symp) - && (symbol_get_bfdsym (symp)->flags & BSF_FUNCTION) == 0) - symbol_get_bfdsym (symp)->flags |= BSF_OBJECT; -#endif } 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. */ + htab_t indexes; /* Maps group name to index in head array. */ }; +static struct group_list groups; + /* Called via bfd_map_over_sections. If SEC is a member of a group, add it to a list of sections belonging to the group. INF is a pointer to a struct group_list, which is where we store the head of - each list. */ + each list. If its link_to_symbol_name isn't NULL, set up its + linked-to section. */ static void -build_group_lists (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf) +build_additional_section_info (bfd *abfd ATTRIBUTE_UNUSED, + asection *sec, void *inf) { struct group_list *list = (struct group_list *) inf; const char *group_name = elf_group_name (sec); @@ -2188,17 +2743,28 @@ build_group_lists (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf) unsigned int *elem_idx; unsigned int *idx_ptr; + if (sec->map_head.linked_to_symbol_name) + { + symbolS *linked_to_sym; + linked_to_sym = symbol_find (sec->map_head.linked_to_symbol_name); + if (!linked_to_sym || !S_IS_DEFINED (linked_to_sym)) + as_bad (_("undefined linked-to symbol `%s' on section `%s'"), + sec->map_head.linked_to_symbol_name, + bfd_section_name (sec)); + else + elf_linked_to_section (sec) = S_GET_SEGMENT (linked_to_sym); + } + if (group_name == NULL) return; /* 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]; list->head[*elem_idx] = sec; - list->elt_count[*elem_idx] += 1; return; } @@ -2208,58 +2774,57 @@ build_group_lists (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf) if ((i & 127) == 0) { unsigned int newsize = i + 128; - list->head = (asection **) xrealloc (list->head, - newsize * sizeof (*list->head)); - list->elt_count = (unsigned int *) - xrealloc (list->elt_count, newsize * sizeof (*list->elt_count)); + list->head = XRESIZEVEC (asection *, list->head, newsize); } list->head[i] = sec; - list->elt_count[i] = 1; list->num_group += 1; /* Add index to hash. */ - idx_ptr = (unsigned int *) xmalloc (sizeof (unsigned int)); + 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. */ + void elf_adjust_symtab (void) { - struct group_list list; unsigned int i; /* 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); - + groups.num_group = 0; + groups.head = NULL; + groups.indexes = str_htab_create (); + bfd_map_over_sections (stdoutput, build_additional_section_info, + &groups); + /* 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 < groups.num_group; i++) { - const char *group_name = elf_group_name (list.head[i]); + const char *group_name = elf_group_name (groups.head[i]); const char *sec_name; asection *s; flagword flags; struct symbol *sy; - bfd_size_type size; flags = SEC_READONLY | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_GROUP; - for (s = list.head[i]; s != NULL; s = elf_next_in_group (s)) + for (s = groups.head[i]; s != NULL; s = elf_next_in_group (s)) if ((s->flags ^ flags) & SEC_LINK_ONCE) { flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; - if (s != list.head[i]) + if (s != groups.head[i]) { as_warn (_("assuming all members of group `%s' are COMDAT"), group_name); @@ -2270,8 +2835,8 @@ elf_adjust_symtab (void) sec_name = ".group"; s = subseg_force_new (sec_name, 0); if (s == NULL - || !bfd_set_section_flags (stdoutput, s, flags) - || !bfd_set_section_alignment (stdoutput, s, 2)) + || !bfd_set_section_flags (s, flags) + || !bfd_set_section_alignment (s, 2)) { as_fatal (_("can't create group: %s"), bfd_errmsg (bfd_get_error ())); @@ -2279,17 +2844,15 @@ elf_adjust_symtab (void) elf_section_type (s) = SHT_GROUP; /* Pass a pointer to the first section in this group. */ - elf_next_in_group (s) = list.head[i]; + elf_next_in_group (s) = groups.head[i]; + elf_sec_group (groups.head[i]) = s; /* 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))) + 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. */ @@ -2301,17 +2864,10 @@ elf_adjust_symtab (void) 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); - s->contents = (unsigned char *) frag_more (size); - frag_now->fr_fix = frag_now_fix_octets (); - frag_wane (frag_now); + /* Mark the group signature symbol as used so that it will be + included in the symbol table. */ + symbol_mark_used_in_reloc (sy); } - - /* Cleanup hash. */ - hash_traverse (list.indexes, free_section_idx); - hash_die (list.indexes); } void @@ -2334,37 +2890,61 @@ elf_frob_file_before_adjust (void) 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); - know (p != NULL); - if (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); + } } } @@ -2376,6 +2956,31 @@ elf_frob_file_before_adjust (void) void elf_frob_file_after_relocs (void) { + unsigned int i; + + /* Set SHT_GROUP section size. */ + for (i = 0; i < groups.num_group; i++) + { + asection *s, *head, *group; + bfd_size_type size; + + head = groups.head[i]; + size = 4; + for (s = head; s != NULL; s = elf_next_in_group (s)) + size += (s->flags & SEC_RELOC) != 0 ? 8 : 4; + + group = elf_sec_group (head); + subseg_set (group, 0); + bfd_set_section_size (group, size); + group->contents = (unsigned char *) frag_more (size); + frag_now->fr_fix = frag_now_fix_octets (); + frag_wane (frag_now); + } + + /* Cleanup hash. */ + htab_traverse (groups.indexes, free_section_idx, NULL); + htab_delete (groups.indexes); + #ifdef NEED_ECOFF_DEBUG if (ECOFF_DEBUGGING) /* Generate the ECOFF debugging information. */ @@ -2410,7 +3015,7 @@ elf_frob_file_after_relocs (void) /* 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 ())); @@ -2424,8 +3029,8 @@ elf_frob_file_after_relocs (void) to force the ELF backend to allocate a file position, and then write out the data. FIXME: Is this really the best way to do this? */ - bfd_set_section_size - (stdoutput, sec, bfd_ecoff_debug_size (stdoutput, &debug, debug_swap)); + bfd_set_section_size (sec, bfd_ecoff_debug_size (stdoutput, &debug, + debug_swap)); /* Pass BUF to bfd_set_section_contents because this will eventually become a call to fwrite, and ISO C prohibits @@ -2446,103 +3051,6 @@ elf_frob_file_after_relocs (void) #endif /* NEED_ECOFF_DEBUG */ } -#ifdef SCO_ELF - -/* Heavily plagiarized from obj_elf_version. The idea is to emit the - SCO specific identifier in the .notes section to satisfy the SCO - linker. - - This looks more complicated than it really is. As opposed to the - "obvious" solution, this should handle the cross dev cases - correctly. (i.e, hosting on a 64 bit big endian processor, but - generating SCO Elf code) Efficiency isn't a concern, as there - should be exactly one of these sections per object module. - - SCO OpenServer 5 identifies it's ELF modules with a standard ELF - .note section. - - int_32 namesz = 4 ; Name size - int_32 descsz = 12 ; Descriptive information - int_32 type = 1 ; - char name[4] = "SCO" ; Originator name ALWAYS SCO + NULL - int_32 version = (major ver # << 16) | version of tools ; - int_32 source = (tool_id << 16 ) | 1 ; - int_32 info = 0 ; These are set by the SCO tools, but we - don't know enough about the source - environment to set them. SCO ld currently - ignores them, and recommends we set them - to zero. */ - -#define SCO_MAJOR_VERSION 0x1 -#define SCO_MINOR_VERSION 0x1 - -void -sco_id (void) -{ - - char *name; - unsigned int c; - char ch; - char *p; - asection *seg = now_seg; - subsegT subseg = now_subseg; - Elf_Internal_Note i_note; - Elf_External_Note e_note; - asection *note_secp = NULL; - int i, len; - - /* create the .note section */ - - note_secp = subseg_new (".note", 0); - bfd_set_section_flags (stdoutput, - note_secp, - SEC_HAS_CONTENTS | SEC_READONLY); - - /* process the version string */ - - i_note.namesz = 4; - i_note.descsz = 12; /* 12 descriptive bytes */ - i_note.type = NT_VERSION; /* Contains a version string */ - - p = frag_more (sizeof (i_note.namesz)); - md_number_to_chars (p, i_note.namesz, 4); - - p = frag_more (sizeof (i_note.descsz)); - md_number_to_chars (p, i_note.descsz, 4); - - p = frag_more (sizeof (i_note.type)); - md_number_to_chars (p, i_note.type, 4); - - p = frag_more (4); - strcpy (p, "SCO"); - - /* Note: this is the version number of the ELF we're representing */ - p = frag_more (4); - md_number_to_chars (p, (SCO_MAJOR_VERSION << 16) | (SCO_MINOR_VERSION), 4); - - /* Here, we pick a magic number for ourselves (yes, I "registered" - it with SCO. The bottom bit shows that we are compat with the - SCO ABI. */ - p = frag_more (4); - md_number_to_chars (p, 0x4c520000 | 0x0001, 4); - - /* If we knew (or cared) what the source language options were, we'd - fill them in here. SCO has given us permission to ignore these - and just set them to zero. */ - p = frag_more (4); - md_number_to_chars (p, 0x0000, 4); - - frag_align (2, 0, 0); - - /* We probably can't restore the current segment, for there likely - isn't one yet... */ - if (seg && subseg) - subseg_set (seg, subseg); - -} - -#endif /* SCO_ELF */ - static void elf_generate_asm_lineno (void) { @@ -2619,6 +3127,6 @@ const struct format_ops elf_format_ops = #endif elf_obj_read_begin_hook, elf_obj_symbol_new_hook, - 0, + elf_obj_symbol_clone_hook, elf_adjust_symtab };