obj-elf.c revision 94536
133965Sjdp/* ELF object file format 289857Sobrien Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 360484Sobrien Free Software Foundation, Inc. 433965Sjdp 533965Sjdp This file is part of GAS, the GNU Assembler. 633965Sjdp 733965Sjdp GAS is free software; you can redistribute it and/or modify 833965Sjdp it under the terms of the GNU General Public License as 933965Sjdp published by the Free Software Foundation; either version 2, 1033965Sjdp or (at your option) any later version. 1133965Sjdp 1233965Sjdp GAS is distributed in the hope that it will be useful, but 1333965Sjdp WITHOUT ANY WARRANTY; without even the implied warranty of 1433965Sjdp MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 1533965Sjdp the GNU General Public License for more details. 1633965Sjdp 1733965Sjdp You should have received a copy of the GNU General Public License 1833965Sjdp along with GAS; see the file COPYING. If not, write to the Free 1933965Sjdp Software Foundation, 59 Temple Place - Suite 330, Boston, MA 2077298Sobrien 02111-1307, USA. */ 2133965Sjdp 2233965Sjdp#define OBJ_HEADER "obj-elf.h" 2333965Sjdp#include "as.h" 2489857Sobrien#include "safe-ctype.h" 2533965Sjdp#include "subsegs.h" 2633965Sjdp#include "obstack.h" 2733965Sjdp 2833965Sjdp#ifndef ECOFF_DEBUGGING 2933965Sjdp#define ECOFF_DEBUGGING 0 3033965Sjdp#else 3133965Sjdp#define NEED_ECOFF_DEBUG 3233965Sjdp#endif 3333965Sjdp 3433965Sjdp#ifdef NEED_ECOFF_DEBUG 3533965Sjdp#include "ecoff.h" 3633965Sjdp#endif 3733965Sjdp 3838889Sjdp#ifdef TC_ALPHA 3938889Sjdp#include "elf/alpha.h" 4038889Sjdp#endif 4138889Sjdp 4233965Sjdp#ifdef TC_MIPS 4333965Sjdp#include "elf/mips.h" 4433965Sjdp#endif 4533965Sjdp 4633965Sjdp#ifdef TC_PPC 4733965Sjdp#include "elf/ppc.h" 4833965Sjdp#endif 4933965Sjdp 5060484Sobrien#ifdef TC_I370 5160484Sobrien#include "elf/i370.h" 5260484Sobrien#endif 5360484Sobrien 5433965Sjdpstatic bfd_vma elf_s_get_size PARAMS ((symbolS *)); 5533965Sjdpstatic void elf_s_set_size PARAMS ((symbolS *, bfd_vma)); 5633965Sjdpstatic bfd_vma elf_s_get_align PARAMS ((symbolS *)); 5733965Sjdpstatic void elf_s_set_align PARAMS ((symbolS *, bfd_vma)); 5877298Sobrienstatic void elf_s_set_other PARAMS ((symbolS *, int)); 5933965Sjdpstatic int elf_sec_sym_ok_for_reloc PARAMS ((asection *)); 6033965Sjdpstatic void adjust_stab_sections PARAMS ((bfd *, asection *, PTR)); 6189857Sobrienstatic void build_group_lists PARAMS ((bfd *, asection *, PTR)); 6277298Sobrienstatic int elf_separate_stab_sections PARAMS ((void)); 6377298Sobrienstatic void elf_init_stab_section PARAMS ((segT)); 6433965Sjdp 6533965Sjdp#ifdef NEED_ECOFF_DEBUG 6633965Sjdpstatic boolean elf_get_extr PARAMS ((asymbol *, EXTR *)); 6733965Sjdpstatic void elf_set_index PARAMS ((asymbol *, bfd_size_type)); 6833965Sjdp#endif 6933965Sjdp 7033965Sjdpstatic void obj_elf_line PARAMS ((int)); 7133965Sjdpvoid obj_elf_version PARAMS ((int)); 7233965Sjdpstatic void obj_elf_size PARAMS ((int)); 7333965Sjdpstatic void obj_elf_type PARAMS ((int)); 7433965Sjdpstatic void obj_elf_ident PARAMS ((int)); 7533965Sjdpstatic void obj_elf_weak PARAMS ((int)); 7633965Sjdpstatic void obj_elf_local PARAMS ((int)); 7760484Sobrienstatic void obj_elf_visibility PARAMS ((int)); 7889857Sobrienstatic void obj_elf_change_section 7989857Sobrien PARAMS ((const char *, int, int, int, const char *, int)); 8089857Sobrienstatic int obj_elf_parse_section_letters PARAMS ((char *, size_t)); 8189857Sobrienstatic int obj_elf_section_word PARAMS ((char *, size_t)); 8289857Sobrienstatic char *obj_elf_section_name PARAMS ((void)); 8389857Sobrienstatic int obj_elf_section_type PARAMS ((char *, size_t)); 8433965Sjdpstatic void obj_elf_symver PARAMS ((int)); 8538889Sjdpstatic void obj_elf_subsection PARAMS ((int)); 8660484Sobrienstatic void obj_elf_popsection PARAMS ((int)); 8733965Sjdp 8833965Sjdpstatic const pseudo_typeS elf_pseudo_table[] = 8933965Sjdp{ 9033965Sjdp {"comm", obj_elf_common, 0}, 9160484Sobrien {"common", obj_elf_common, 1}, 9233965Sjdp {"ident", obj_elf_ident, 0}, 9333965Sjdp {"local", obj_elf_local, 0}, 9433965Sjdp {"previous", obj_elf_previous, 0}, 9533965Sjdp {"section", obj_elf_section, 0}, 9633965Sjdp {"section.s", obj_elf_section, 0}, 9733965Sjdp {"sect", obj_elf_section, 0}, 9833965Sjdp {"sect.s", obj_elf_section, 0}, 9960484Sobrien {"pushsection", obj_elf_section, 1}, 10060484Sobrien {"popsection", obj_elf_popsection, 0}, 10133965Sjdp {"size", obj_elf_size, 0}, 10233965Sjdp {"type", obj_elf_type, 0}, 10333965Sjdp {"version", obj_elf_version, 0}, 10433965Sjdp {"weak", obj_elf_weak, 0}, 10533965Sjdp 10677298Sobrien /* These define symbol visibility. */ 10760484Sobrien {"internal", obj_elf_visibility, STV_INTERNAL}, 10860484Sobrien {"hidden", obj_elf_visibility, STV_HIDDEN}, 10960484Sobrien {"protected", obj_elf_visibility, STV_PROTECTED}, 11060484Sobrien 11133965Sjdp /* These are used for stabs-in-elf configurations. */ 11233965Sjdp {"line", obj_elf_line, 0}, 11333965Sjdp 11433965Sjdp /* This is a GNU extension to handle symbol versions. */ 11533965Sjdp {"symver", obj_elf_symver, 0}, 11633965Sjdp 11738889Sjdp /* A GNU extension to change subsection only. */ 11838889Sjdp {"subsection", obj_elf_subsection, 0}, 11938889Sjdp 12060484Sobrien /* These are GNU extensions to aid in garbage collecting C++ vtables. */ 12177298Sobrien {"vtable_inherit", (void (*) PARAMS ((int))) &obj_elf_vtable_inherit, 0}, 12277298Sobrien {"vtable_entry", (void (*) PARAMS ((int))) &obj_elf_vtable_entry, 0}, 12360484Sobrien 12477298Sobrien /* These are used for dwarf. */ 12533965Sjdp {"2byte", cons, 2}, 12633965Sjdp {"4byte", cons, 4}, 12733965Sjdp {"8byte", cons, 8}, 12833965Sjdp 12933965Sjdp /* We need to trap the section changing calls to handle .previous. */ 13033965Sjdp {"data", obj_elf_data, 0}, 13133965Sjdp {"text", obj_elf_text, 0}, 13233965Sjdp 13333965Sjdp /* End sentinel. */ 13460484Sobrien {NULL, NULL, 0}, 13533965Sjdp}; 13633965Sjdp 13733965Sjdpstatic const pseudo_typeS ecoff_debug_pseudo_table[] = 13833965Sjdp{ 13933965Sjdp#ifdef NEED_ECOFF_DEBUG 14033965Sjdp /* COFF style debugging information for ECOFF. .ln is not used; .loc 14133965Sjdp is used instead. */ 14233965Sjdp { "def", ecoff_directive_def, 0 }, 14333965Sjdp { "dim", ecoff_directive_dim, 0 }, 14433965Sjdp { "endef", ecoff_directive_endef, 0 }, 14533965Sjdp { "file", ecoff_directive_file, 0 }, 14633965Sjdp { "scl", ecoff_directive_scl, 0 }, 14733965Sjdp { "tag", ecoff_directive_tag, 0 }, 14833965Sjdp { "val", ecoff_directive_val, 0 }, 14933965Sjdp 15033965Sjdp /* COFF debugging requires pseudo-ops .size and .type, but ELF 15133965Sjdp already has meanings for those. We use .esize and .etype 15233965Sjdp instead. These are only generated by gcc anyhow. */ 15333965Sjdp { "esize", ecoff_directive_size, 0 }, 15433965Sjdp { "etype", ecoff_directive_type, 0 }, 15533965Sjdp 15633965Sjdp /* ECOFF specific debugging information. */ 15733965Sjdp { "begin", ecoff_directive_begin, 0 }, 15833965Sjdp { "bend", ecoff_directive_bend, 0 }, 15933965Sjdp { "end", ecoff_directive_end, 0 }, 16033965Sjdp { "ent", ecoff_directive_ent, 0 }, 16133965Sjdp { "fmask", ecoff_directive_fmask, 0 }, 16233965Sjdp { "frame", ecoff_directive_frame, 0 }, 16333965Sjdp { "loc", ecoff_directive_loc, 0 }, 16433965Sjdp { "mask", ecoff_directive_mask, 0 }, 16533965Sjdp 16633965Sjdp /* Other ECOFF directives. */ 16733965Sjdp { "extern", ecoff_directive_extern, 0 }, 16833965Sjdp 16933965Sjdp /* These are used on Irix. I don't know how to implement them. */ 17033965Sjdp { "alias", s_ignore, 0 }, 17133965Sjdp { "bgnb", s_ignore, 0 }, 17233965Sjdp { "endb", s_ignore, 0 }, 17333965Sjdp { "lab", s_ignore, 0 }, 17433965Sjdp { "noalias", s_ignore, 0 }, 17533965Sjdp { "verstamp", s_ignore, 0 }, 17633965Sjdp { "vreg", s_ignore, 0 }, 17733965Sjdp#endif 17833965Sjdp 17960484Sobrien {NULL, NULL, 0} /* end sentinel */ 18033965Sjdp}; 18133965Sjdp 18233965Sjdp#undef NO_RELOC 18333965Sjdp#include "aout/aout64.h" 18433965Sjdp 18533965Sjdp/* This is called when the assembler starts. */ 18633965Sjdp 18733965Sjdpvoid 18833965Sjdpelf_begin () 18933965Sjdp{ 19033965Sjdp /* Add symbols for the known sections to the symbol table. */ 19133965Sjdp symbol_table_insert (section_symbol (bfd_get_section_by_name (stdoutput, 19238889Sjdp TEXT_SECTION_NAME))); 19333965Sjdp symbol_table_insert (section_symbol (bfd_get_section_by_name (stdoutput, 19438889Sjdp DATA_SECTION_NAME))); 19533965Sjdp symbol_table_insert (section_symbol (bfd_get_section_by_name (stdoutput, 19638889Sjdp BSS_SECTION_NAME))); 19733965Sjdp} 19833965Sjdp 19933965Sjdpvoid 20033965Sjdpelf_pop_insert () 20133965Sjdp{ 20233965Sjdp pop_insert (elf_pseudo_table); 20333965Sjdp if (ECOFF_DEBUGGING) 20433965Sjdp pop_insert (ecoff_debug_pseudo_table); 20533965Sjdp} 20633965Sjdp 20733965Sjdpstatic bfd_vma 20833965Sjdpelf_s_get_size (sym) 20933965Sjdp symbolS *sym; 21033965Sjdp{ 21133965Sjdp return S_GET_SIZE (sym); 21233965Sjdp} 21333965Sjdp 21433965Sjdpstatic void 21533965Sjdpelf_s_set_size (sym, sz) 21633965Sjdp symbolS *sym; 21733965Sjdp bfd_vma sz; 21833965Sjdp{ 21933965Sjdp S_SET_SIZE (sym, sz); 22033965Sjdp} 22133965Sjdp 22233965Sjdpstatic bfd_vma 22333965Sjdpelf_s_get_align (sym) 22433965Sjdp symbolS *sym; 22533965Sjdp{ 22633965Sjdp return S_GET_ALIGN (sym); 22733965Sjdp} 22833965Sjdp 22933965Sjdpstatic void 23033965Sjdpelf_s_set_align (sym, align) 23133965Sjdp symbolS *sym; 23233965Sjdp bfd_vma align; 23333965Sjdp{ 23433965Sjdp S_SET_ALIGN (sym, align); 23533965Sjdp} 23633965Sjdp 23760484Sobrienint 23860484Sobrienelf_s_get_other (sym) 23960484Sobrien symbolS *sym; 24060484Sobrien{ 24160484Sobrien return elf_symbol (symbol_get_bfdsym (sym))->internal_elf_sym.st_other; 24260484Sobrien} 24360484Sobrien 24433965Sjdpstatic void 24577298Sobrienelf_s_set_other (sym, other) 24677298Sobrien symbolS *sym; 24777298Sobrien int other; 24877298Sobrien{ 24977298Sobrien S_SET_OTHER (sym, other); 25077298Sobrien} 25177298Sobrien 25233965Sjdpstatic int 25333965Sjdpelf_sec_sym_ok_for_reloc (sec) 25433965Sjdp asection *sec; 25533965Sjdp{ 25633965Sjdp return obj_sec_sym_ok_for_reloc (sec); 25733965Sjdp} 25833965Sjdp 25933965Sjdpvoid 26033965Sjdpelf_file_symbol (s) 26177298Sobrien const char *s; 26233965Sjdp{ 26333965Sjdp symbolS *sym; 26433965Sjdp 26533965Sjdp sym = symbol_new (s, absolute_section, (valueT) 0, (struct frag *) 0); 26660484Sobrien symbol_set_frag (sym, &zero_address_frag); 26760484Sobrien symbol_get_bfdsym (sym)->flags |= BSF_FILE; 26833965Sjdp 26933965Sjdp if (symbol_rootP != sym) 27033965Sjdp { 27133965Sjdp symbol_remove (sym, &symbol_rootP, &symbol_lastP); 27233965Sjdp symbol_insert (sym, symbol_rootP, &symbol_rootP, &symbol_lastP); 27333965Sjdp#ifdef DEBUG 27433965Sjdp verify_symbol_chain (symbol_rootP, symbol_lastP); 27533965Sjdp#endif 27633965Sjdp } 27733965Sjdp 27833965Sjdp#ifdef NEED_ECOFF_DEBUG 27933965Sjdp ecoff_new_file (s); 28033965Sjdp#endif 28133965Sjdp} 28233965Sjdp 28360484Sobrienvoid 28460484Sobrienobj_elf_common (is_common) 28560484Sobrien int is_common; 28633965Sjdp{ 28733965Sjdp char *name; 28833965Sjdp char c; 28933965Sjdp char *p; 29033965Sjdp int temp, size; 29133965Sjdp symbolS *symbolP; 29233965Sjdp int have_align; 29333965Sjdp 29460484Sobrien if (flag_mri && is_common) 29560484Sobrien { 29660484Sobrien s_mri_common (0); 29760484Sobrien return; 29860484Sobrien } 29960484Sobrien 30033965Sjdp name = input_line_pointer; 30133965Sjdp c = get_symbol_end (); 30233965Sjdp /* just after name is now '\0' */ 30333965Sjdp p = input_line_pointer; 30433965Sjdp *p = c; 30533965Sjdp SKIP_WHITESPACE (); 30633965Sjdp if (*input_line_pointer != ',') 30733965Sjdp { 30889857Sobrien as_bad (_("expected comma after symbol-name")); 30933965Sjdp ignore_rest_of_line (); 31033965Sjdp return; 31133965Sjdp } 31233965Sjdp input_line_pointer++; /* skip ',' */ 31333965Sjdp if ((temp = get_absolute_expression ()) < 0) 31433965Sjdp { 31560484Sobrien as_bad (_(".COMMon length (%d.) <0! Ignored."), temp); 31633965Sjdp ignore_rest_of_line (); 31733965Sjdp return; 31833965Sjdp } 31933965Sjdp size = temp; 32033965Sjdp *p = 0; 32133965Sjdp symbolP = symbol_find_or_make (name); 32233965Sjdp *p = c; 32333965Sjdp if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) 32433965Sjdp { 32589857Sobrien as_bad (_("symbol `%s' is already defined"), S_GET_NAME (symbolP)); 32633965Sjdp ignore_rest_of_line (); 32733965Sjdp return; 32833965Sjdp } 32933965Sjdp if (S_GET_VALUE (symbolP) != 0) 33033965Sjdp { 33160484Sobrien if (S_GET_VALUE (symbolP) != (valueT) size) 33233965Sjdp { 33389857Sobrien as_warn (_("length of .comm \"%s\" is already %ld; not changed to %d"), 33433965Sjdp S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), size); 33533965Sjdp } 33633965Sjdp } 33733965Sjdp know (symbolP->sy_frag == &zero_address_frag); 33833965Sjdp if (*input_line_pointer != ',') 33933965Sjdp have_align = 0; 34033965Sjdp else 34133965Sjdp { 34233965Sjdp have_align = 1; 34333965Sjdp input_line_pointer++; 34433965Sjdp SKIP_WHITESPACE (); 34533965Sjdp } 34633965Sjdp if (! have_align || *input_line_pointer != '"') 34733965Sjdp { 34833965Sjdp if (! have_align) 34933965Sjdp temp = 0; 35033965Sjdp else 35133965Sjdp { 35233965Sjdp temp = get_absolute_expression (); 35333965Sjdp if (temp < 0) 35433965Sjdp { 35533965Sjdp temp = 0; 35689857Sobrien as_warn (_("common alignment negative; 0 assumed")); 35733965Sjdp } 35833965Sjdp } 35960484Sobrien if (symbol_get_obj (symbolP)->local) 36033965Sjdp { 36133965Sjdp segT old_sec; 36233965Sjdp int old_subsec; 36333965Sjdp char *pfrag; 36433965Sjdp int align; 36533965Sjdp 36633965Sjdp /* allocate_bss: */ 36733965Sjdp old_sec = now_seg; 36833965Sjdp old_subsec = now_subseg; 36933965Sjdp if (temp) 37033965Sjdp { 37133965Sjdp /* convert to a power of 2 alignment */ 37233965Sjdp for (align = 0; (temp & 1) == 0; temp >>= 1, ++align); 37333965Sjdp if (temp != 1) 37433965Sjdp { 37589857Sobrien as_bad (_("common alignment not a power of 2")); 37633965Sjdp ignore_rest_of_line (); 37733965Sjdp return; 37833965Sjdp } 37933965Sjdp } 38033965Sjdp else 38133965Sjdp align = 0; 38233965Sjdp record_alignment (bss_section, align); 38333965Sjdp subseg_set (bss_section, 0); 38433965Sjdp if (align) 38533965Sjdp frag_align (align, 0, 0); 38633965Sjdp if (S_GET_SEGMENT (symbolP) == bss_section) 38760484Sobrien symbol_get_frag (symbolP)->fr_symbol = 0; 38860484Sobrien symbol_set_frag (symbolP, frag_now); 38933965Sjdp pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, 39033965Sjdp (offsetT) size, (char *) 0); 39133965Sjdp *pfrag = 0; 39233965Sjdp S_SET_SIZE (symbolP, size); 39333965Sjdp S_SET_SEGMENT (symbolP, bss_section); 39433965Sjdp S_CLEAR_EXTERNAL (symbolP); 39533965Sjdp subseg_set (old_sec, old_subsec); 39633965Sjdp } 39733965Sjdp else 39833965Sjdp { 39933965Sjdp allocate_common: 40033965Sjdp S_SET_VALUE (symbolP, (valueT) size); 40133965Sjdp S_SET_ALIGN (symbolP, temp); 40233965Sjdp S_SET_EXTERNAL (symbolP); 40333965Sjdp S_SET_SEGMENT (symbolP, bfd_com_section_ptr); 40433965Sjdp } 40533965Sjdp } 40633965Sjdp else 40733965Sjdp { 40833965Sjdp input_line_pointer++; 40933965Sjdp /* @@ Some use the dot, some don't. Can we get some consistency?? */ 41033965Sjdp if (*input_line_pointer == '.') 41133965Sjdp input_line_pointer++; 41233965Sjdp /* @@ Some say data, some say bss. */ 41333965Sjdp if (strncmp (input_line_pointer, "bss\"", 4) 41433965Sjdp && strncmp (input_line_pointer, "data\"", 5)) 41533965Sjdp { 41633965Sjdp while (*--input_line_pointer != '"') 41733965Sjdp ; 41833965Sjdp input_line_pointer--; 41933965Sjdp goto bad_common_segment; 42033965Sjdp } 42133965Sjdp while (*input_line_pointer++ != '"') 42233965Sjdp ; 42333965Sjdp goto allocate_common; 42433965Sjdp } 42533965Sjdp 42660484Sobrien symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT; 42733965Sjdp 42833965Sjdp demand_empty_rest_of_line (); 42933965Sjdp return; 43033965Sjdp 43133965Sjdp { 43233965Sjdp bad_common_segment: 43333965Sjdp p = input_line_pointer; 43433965Sjdp while (*p && *p != '\n') 43533965Sjdp p++; 43633965Sjdp c = *p; 43733965Sjdp *p = '\0'; 43860484Sobrien as_bad (_("bad .common segment %s"), input_line_pointer + 1); 43933965Sjdp *p = c; 44033965Sjdp input_line_pointer = p; 44133965Sjdp ignore_rest_of_line (); 44233965Sjdp return; 44333965Sjdp } 44433965Sjdp} 44533965Sjdp 44633965Sjdpstatic void 44733965Sjdpobj_elf_local (ignore) 44860484Sobrien int ignore ATTRIBUTE_UNUSED; 44933965Sjdp{ 45033965Sjdp char *name; 45133965Sjdp int c; 45233965Sjdp symbolS *symbolP; 45333965Sjdp 45433965Sjdp do 45533965Sjdp { 45633965Sjdp name = input_line_pointer; 45733965Sjdp c = get_symbol_end (); 45833965Sjdp symbolP = symbol_find_or_make (name); 45933965Sjdp *input_line_pointer = c; 46033965Sjdp SKIP_WHITESPACE (); 46133965Sjdp S_CLEAR_EXTERNAL (symbolP); 46260484Sobrien symbol_get_obj (symbolP)->local = 1; 46333965Sjdp if (c == ',') 46433965Sjdp { 46533965Sjdp input_line_pointer++; 46633965Sjdp SKIP_WHITESPACE (); 46733965Sjdp if (*input_line_pointer == '\n') 46833965Sjdp c = '\n'; 46933965Sjdp } 47033965Sjdp } 47133965Sjdp while (c == ','); 47233965Sjdp demand_empty_rest_of_line (); 47333965Sjdp} 47433965Sjdp 47533965Sjdpstatic void 47633965Sjdpobj_elf_weak (ignore) 47760484Sobrien int ignore ATTRIBUTE_UNUSED; 47833965Sjdp{ 47933965Sjdp char *name; 48033965Sjdp int c; 48133965Sjdp symbolS *symbolP; 48233965Sjdp 48333965Sjdp do 48433965Sjdp { 48533965Sjdp name = input_line_pointer; 48633965Sjdp c = get_symbol_end (); 48733965Sjdp symbolP = symbol_find_or_make (name); 48833965Sjdp *input_line_pointer = c; 48933965Sjdp SKIP_WHITESPACE (); 49033965Sjdp S_SET_WEAK (symbolP); 49160484Sobrien symbol_get_obj (symbolP)->local = 1; 49233965Sjdp if (c == ',') 49333965Sjdp { 49433965Sjdp input_line_pointer++; 49533965Sjdp SKIP_WHITESPACE (); 49633965Sjdp if (*input_line_pointer == '\n') 49733965Sjdp c = '\n'; 49833965Sjdp } 49933965Sjdp } 50033965Sjdp while (c == ','); 50133965Sjdp demand_empty_rest_of_line (); 50233965Sjdp} 50333965Sjdp 50460484Sobrienstatic void 50560484Sobrienobj_elf_visibility (visibility) 50660484Sobrien int visibility; 50760484Sobrien{ 50860484Sobrien char *name; 50960484Sobrien int c; 51060484Sobrien symbolS *symbolP; 51160484Sobrien asymbol *bfdsym; 51260484Sobrien elf_symbol_type *elfsym; 51360484Sobrien 51460484Sobrien do 51560484Sobrien { 51660484Sobrien name = input_line_pointer; 51760484Sobrien c = get_symbol_end (); 51860484Sobrien symbolP = symbol_find_or_make (name); 51960484Sobrien *input_line_pointer = c; 52060484Sobrien 52160484Sobrien SKIP_WHITESPACE (); 52260484Sobrien 52360484Sobrien bfdsym = symbol_get_bfdsym (symbolP); 52460484Sobrien elfsym = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym); 52560484Sobrien 52660484Sobrien assert (elfsym); 52760484Sobrien 52860484Sobrien elfsym->internal_elf_sym.st_other = visibility; 52960484Sobrien 53060484Sobrien if (c == ',') 53160484Sobrien { 53260484Sobrien input_line_pointer ++; 53360484Sobrien 53460484Sobrien SKIP_WHITESPACE (); 53560484Sobrien 53660484Sobrien if (*input_line_pointer == '\n') 53760484Sobrien c = '\n'; 53860484Sobrien } 53960484Sobrien } 54060484Sobrien while (c == ','); 54160484Sobrien 54260484Sobrien demand_empty_rest_of_line (); 54360484Sobrien} 54460484Sobrien 54533965Sjdpstatic segT previous_section; 54633965Sjdpstatic int previous_subsection; 54733965Sjdp 54860484Sobrienstruct section_stack 54960484Sobrien{ 55060484Sobrien struct section_stack *next; 55160484Sobrien segT seg, prev_seg; 55260484Sobrien int subseg, prev_subseg; 55360484Sobrien}; 55460484Sobrien 55560484Sobrienstatic struct section_stack *section_stack; 55660484Sobrien 55733965Sjdp/* Handle the .section pseudo-op. This code supports two different 55833965Sjdp syntaxes. 55933965Sjdp 56033965Sjdp The first is found on Solaris, and looks like 56133965Sjdp .section ".sec1",#alloc,#execinstr,#write 56233965Sjdp Here the names after '#' are the SHF_* flags to turn on for the 56333965Sjdp section. I'm not sure how it determines the SHT_* type (BFD 56433965Sjdp doesn't really give us control over the type, anyhow). 56533965Sjdp 56633965Sjdp The second format is found on UnixWare, and probably most SVR4 56733965Sjdp machines, and looks like 56833965Sjdp .section .sec1,"a",@progbits 56933965Sjdp The quoted string may contain any combination of a, w, x, and 57033965Sjdp represents the SHF_* flags to turn on for the section. The string 57133965Sjdp beginning with '@' can be progbits or nobits. There should be 57233965Sjdp other possibilities, but I don't know what they are. In any case, 57333965Sjdp BFD doesn't really let us set the section type. */ 57433965Sjdp 57533965Sjdp/* Certain named sections have particular defined types, listed on p. 57633965Sjdp 4-19 of the ABI. */ 57733965Sjdpstruct special_section 57833965Sjdp{ 57933965Sjdp const char *name; 58033965Sjdp int type; 58133965Sjdp int attributes; 58233965Sjdp}; 58333965Sjdp 58460484Sobrienstatic struct special_section const special_sections[] = 58533965Sjdp{ 58633965Sjdp { ".bss", SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, 58733965Sjdp { ".comment", SHT_PROGBITS, 0 }, 58833965Sjdp { ".data", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, 58933965Sjdp { ".data1", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, 59033965Sjdp { ".debug", SHT_PROGBITS, 0 }, 59133965Sjdp { ".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, 59233965Sjdp { ".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, 59333965Sjdp { ".line", SHT_PROGBITS, 0 }, 59433965Sjdp { ".note", SHT_NOTE, 0 }, 59533965Sjdp { ".rodata", SHT_PROGBITS, SHF_ALLOC }, 59633965Sjdp { ".rodata1", SHT_PROGBITS, SHF_ALLOC }, 59733965Sjdp { ".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, 59894536Sobrien#if 0 59994536Sobrien /* FIXME: The current gcc, as of 2002-03-03, will emit 60033965Sjdp 60194536Sobrien .section .init_array,"aw",@progbits 60294536Sobrien 60394536Sobrien for __attribute__ ((section (".init_array"))). "@progbits" marks 60494536Sobrien the incorrect section type. For now, we make them with 60594536Sobrien SHT_PROGBITS. BFD will fix the section type. Gcc should be changed 60694536Sobrien to emit 60794536Sobrien 60894536Sobrien .section .init_array 60994536Sobrien 61094536Sobrien */ 61194536Sobrien { ".init_array",SHT_INIT_ARRAY, SHF_ALLOC + SHF_WRITE }, 61294536Sobrien { ".fini_array",SHT_FINI_ARRAY, SHF_ALLOC + SHF_WRITE }, 61394536Sobrien { ".preinit_array",SHT_PREINIT_ARRAY, SHF_ALLOC + SHF_WRITE }, 61494536Sobrien#else 61594536Sobrien { ".init_array",SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, 61694536Sobrien { ".fini_array",SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, 61794536Sobrien { ".preinit_array",SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, 61894536Sobrien#endif 61994536Sobrien 62033965Sjdp#ifdef ELF_TC_SPECIAL_SECTIONS 62133965Sjdp ELF_TC_SPECIAL_SECTIONS 62233965Sjdp#endif 62333965Sjdp 62433965Sjdp#if 0 62533965Sjdp /* The following section names are special, but they can not 62633965Sjdp reasonably appear in assembler code. Some of the attributes are 62733965Sjdp processor dependent. */ 62833965Sjdp { ".dynamic", SHT_DYNAMIC, SHF_ALLOC /* + SHF_WRITE */ }, 62933965Sjdp { ".dynstr", SHT_STRTAB, SHF_ALLOC }, 63033965Sjdp { ".dynsym", SHT_DYNSYM, SHF_ALLOC }, 63133965Sjdp { ".got", SHT_PROGBITS, 0 }, 63233965Sjdp { ".hash", SHT_HASH, SHF_ALLOC }, 63333965Sjdp { ".interp", SHT_PROGBITS, /* SHF_ALLOC */ }, 63433965Sjdp { ".plt", SHT_PROGBITS, 0 }, 63533965Sjdp { ".shstrtab",SHT_STRTAB, 0 }, 63633965Sjdp { ".strtab", SHT_STRTAB, /* SHF_ALLOC */ }, 63733965Sjdp { ".symtab", SHT_SYMTAB, /* SHF_ALLOC */ }, 63833965Sjdp#endif 63933965Sjdp 64033965Sjdp { NULL, 0, 0 } 64133965Sjdp}; 64233965Sjdp 64389857Sobrienstatic void 64489857Sobrienobj_elf_change_section (name, type, attr, entsize, group_name, push) 64589857Sobrien const char *name; 64689857Sobrien int type; 64789857Sobrien int attr; 64889857Sobrien int entsize; 64989857Sobrien const char *group_name; 65089857Sobrien int push; 65133965Sjdp{ 65277298Sobrien asection *old_sec; 65333965Sjdp segT sec; 65477298Sobrien flagword flags; 65577298Sobrien int i; 65633965Sjdp 65733965Sjdp#ifdef md_flush_pending_output 65833965Sjdp md_flush_pending_output (); 65933965Sjdp#endif 66033965Sjdp 66160484Sobrien /* Switch to the section, creating it if necessary. */ 66260484Sobrien if (push) 66360484Sobrien { 66460484Sobrien struct section_stack *elt; 66560484Sobrien elt = xmalloc (sizeof (struct section_stack)); 66660484Sobrien elt->next = section_stack; 66760484Sobrien elt->seg = now_seg; 66860484Sobrien elt->prev_seg = previous_section; 66960484Sobrien elt->subseg = now_subseg; 67060484Sobrien elt->prev_subseg = previous_subsection; 67160484Sobrien section_stack = elt; 67260484Sobrien } 67360484Sobrien previous_section = now_seg; 67460484Sobrien previous_subsection = now_subseg; 67560484Sobrien 67677298Sobrien old_sec = bfd_get_section_by_name (stdoutput, name); 67760484Sobrien sec = subseg_new (name, 0); 67860484Sobrien 67977298Sobrien /* See if this is one of the special sections. */ 68077298Sobrien for (i = 0; special_sections[i].name != NULL; i++) 68177298Sobrien if (strcmp (name, special_sections[i].name) == 0) 68277298Sobrien { 68377298Sobrien if (type == SHT_NULL) 68477298Sobrien type = special_sections[i].type; 68577298Sobrien else if (type != special_sections[i].type) 68677298Sobrien { 68777298Sobrien if (old_sec == NULL) 68860484Sobrien { 68989857Sobrien as_warn (_("setting incorrect section type for %s"), name); 69060484Sobrien } 69177298Sobrien else 69277298Sobrien { 69389857Sobrien as_warn (_("ignoring incorrect section type for %s"), name); 69477298Sobrien type = special_sections[i].type; 69577298Sobrien } 69660484Sobrien } 69777298Sobrien if ((attr &~ special_sections[i].attributes) != 0 69877298Sobrien && old_sec == NULL) 69977298Sobrien { 70077298Sobrien /* As a GNU extension, we permit a .note section to be 70177298Sobrien allocatable. If the linker sees an allocateable .note 70277298Sobrien section, it will create a PT_NOTE segment in the output 70377298Sobrien file. */ 70477298Sobrien if (strcmp (name, ".note") != 0 70577298Sobrien || attr != SHF_ALLOC) 70689857Sobrien as_warn (_("setting incorrect section attributes for %s"), 70777298Sobrien name); 70877298Sobrien } 70977298Sobrien attr |= special_sections[i].attributes; 71077298Sobrien break; 71177298Sobrien } 71260484Sobrien 71377298Sobrien /* Convert ELF type and flags to BFD flags. */ 71477298Sobrien flags = (SEC_RELOC 71577298Sobrien | ((attr & SHF_WRITE) ? 0 : SEC_READONLY) 71677298Sobrien | ((attr & SHF_ALLOC) ? SEC_ALLOC : 0) 71777298Sobrien | (((attr & SHF_ALLOC) && type != SHT_NOBITS) ? SEC_LOAD : 0) 71889857Sobrien | ((attr & SHF_EXECINSTR) ? SEC_CODE : 0) 71989857Sobrien | ((attr & SHF_MERGE) ? SEC_MERGE : 0) 72089857Sobrien | ((attr & SHF_STRINGS) ? SEC_STRINGS : 0)); 72160484Sobrien#ifdef md_elf_section_flags 72277298Sobrien flags = md_elf_section_flags (flags, attr, type); 72360484Sobrien#endif 72460484Sobrien 72577298Sobrien if (old_sec == NULL) 72677298Sobrien { 72777298Sobrien symbolS *secsym; 72877298Sobrien 72960484Sobrien /* Prevent SEC_HAS_CONTENTS from being inadvertently set. */ 73060484Sobrien if (type == SHT_NOBITS) 73160484Sobrien seg_info (sec)->bss = 1; 73260484Sobrien 73360484Sobrien bfd_set_section_flags (stdoutput, sec, flags); 73489857Sobrien if (flags & SEC_MERGE) 73589857Sobrien sec->entsize = entsize; 73689857Sobrien elf_group_name (sec) = group_name; 73760484Sobrien 73860484Sobrien /* Add a symbol for this section to the symbol table. */ 73960484Sobrien secsym = symbol_find (name); 74060484Sobrien if (secsym != NULL) 74160484Sobrien symbol_set_bfdsym (secsym, sec->symbol); 74260484Sobrien else 74360484Sobrien symbol_table_insert (section_symbol (sec)); 74460484Sobrien } 74577298Sobrien else if (attr != 0) 74677298Sobrien { 74777298Sobrien /* If section attributes are specified the second time we see a 74877298Sobrien particular section, then check that they are the same as we 74977298Sobrien saw the first time. */ 75077298Sobrien if ((old_sec->flags ^ flags) 75177298Sobrien & (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE 75289857Sobrien | SEC_EXCLUDE | SEC_SORT_ENTRIES | SEC_MERGE | SEC_STRINGS)) 75389857Sobrien as_warn (_("ignoring changed section attributes for %s"), name); 75489857Sobrien else if ((flags & SEC_MERGE) && old_sec->entsize != (unsigned) entsize) 75589857Sobrien as_warn (_("ignoring changed section entity size for %s"), name); 75689857Sobrien else if ((attr & SHF_GROUP) != 0 75789857Sobrien && strcmp (elf_group_name (old_sec), group_name) != 0) 75889857Sobrien as_warn (_("ignoring new section group for %s"), name); 75977298Sobrien } 76060484Sobrien 76160484Sobrien#ifdef md_elf_section_change_hook 76277298Sobrien md_elf_section_change_hook (); 76360484Sobrien#endif 76460484Sobrien} 76560484Sobrien 76689857Sobrienstatic int 76760484Sobrienobj_elf_parse_section_letters (str, len) 76860484Sobrien char *str; 76960484Sobrien size_t len; 77060484Sobrien{ 77160484Sobrien int attr = 0; 77260484Sobrien 77360484Sobrien while (len > 0) 77460484Sobrien { 77560484Sobrien switch (*str) 77660484Sobrien { 77760484Sobrien case 'a': 77860484Sobrien attr |= SHF_ALLOC; 77960484Sobrien break; 78060484Sobrien case 'w': 78160484Sobrien attr |= SHF_WRITE; 78260484Sobrien break; 78360484Sobrien case 'x': 78460484Sobrien attr |= SHF_EXECINSTR; 78560484Sobrien break; 78689857Sobrien case 'M': 78789857Sobrien attr |= SHF_MERGE; 78889857Sobrien break; 78989857Sobrien case 'S': 79089857Sobrien attr |= SHF_STRINGS; 79189857Sobrien break; 79289857Sobrien case 'G': 79389857Sobrien attr |= SHF_GROUP; 79489857Sobrien break; 79589857Sobrien /* Compatibility. */ 79689857Sobrien case 'm': 79789857Sobrien if (*(str - 1) == 'a') 79889857Sobrien { 79989857Sobrien attr |= SHF_MERGE; 80089857Sobrien if (len > 1 && str[1] == 's') 80189857Sobrien { 80289857Sobrien attr |= SHF_STRINGS; 80389857Sobrien str++, len--; 80489857Sobrien } 80589857Sobrien break; 80689857Sobrien } 80760484Sobrien default: 80860484Sobrien { 80989857Sobrien char *bad_msg = _("unrecognized .section attribute: want a,w,x,M,S,G"); 81060484Sobrien#ifdef md_elf_section_letter 81160484Sobrien int md_attr = md_elf_section_letter (*str, &bad_msg); 81260484Sobrien if (md_attr >= 0) 81360484Sobrien attr |= md_attr; 81460484Sobrien else 81560484Sobrien#endif 81660484Sobrien { 81760484Sobrien as_warn ("%s", bad_msg); 81860484Sobrien attr = -1; 81960484Sobrien } 82060484Sobrien } 82160484Sobrien break; 82260484Sobrien } 82360484Sobrien str++, len--; 82460484Sobrien } 82560484Sobrien 82660484Sobrien return attr; 82760484Sobrien} 82860484Sobrien 82989857Sobrienstatic int 83060484Sobrienobj_elf_section_word (str, len) 83160484Sobrien char *str; 83260484Sobrien size_t len; 83360484Sobrien{ 83460484Sobrien if (len == 5 && strncmp (str, "write", 5) == 0) 83560484Sobrien return SHF_WRITE; 83660484Sobrien if (len == 5 && strncmp (str, "alloc", 5) == 0) 83760484Sobrien return SHF_ALLOC; 83860484Sobrien if (len == 9 && strncmp (str, "execinstr", 9) == 0) 83960484Sobrien return SHF_EXECINSTR; 84060484Sobrien 84160484Sobrien#ifdef md_elf_section_word 84260484Sobrien { 84360484Sobrien int md_attr = md_elf_section_word (str, len); 84460484Sobrien if (md_attr >= 0) 84560484Sobrien return md_attr; 84660484Sobrien } 84760484Sobrien#endif 84860484Sobrien 84989857Sobrien as_warn (_("unrecognized section attribute")); 85060484Sobrien return 0; 85160484Sobrien} 85260484Sobrien 85389857Sobrienstatic int 85460484Sobrienobj_elf_section_type (str, len) 85560484Sobrien char *str; 85660484Sobrien size_t len; 85760484Sobrien{ 85860484Sobrien if (len == 8 && strncmp (str, "progbits", 8) == 0) 85960484Sobrien return SHT_PROGBITS; 86060484Sobrien if (len == 6 && strncmp (str, "nobits", 6) == 0) 86160484Sobrien return SHT_NOBITS; 86260484Sobrien 86360484Sobrien#ifdef md_elf_section_type 86460484Sobrien { 86560484Sobrien int md_type = md_elf_section_type (str, len); 86660484Sobrien if (md_type >= 0) 86760484Sobrien return md_type; 86860484Sobrien } 86960484Sobrien#endif 87060484Sobrien 87189857Sobrien as_warn (_("unrecognized section type")); 87260484Sobrien return 0; 87360484Sobrien} 87460484Sobrien 87589857Sobrien/* Get name of section. */ 87689857Sobrienstatic char * 87789857Sobrienobj_elf_section_name () 87889857Sobrien{ 87989857Sobrien char *name; 88089857Sobrien 88189857Sobrien SKIP_WHITESPACE (); 88289857Sobrien if (*input_line_pointer == '"') 88389857Sobrien { 88489857Sobrien int dummy; 88589857Sobrien 88689857Sobrien name = demand_copy_C_string (&dummy); 88789857Sobrien if (name == NULL) 88889857Sobrien { 88989857Sobrien ignore_rest_of_line (); 89089857Sobrien return NULL; 89189857Sobrien } 89289857Sobrien } 89389857Sobrien else 89489857Sobrien { 89589857Sobrien char *end = input_line_pointer; 89689857Sobrien 89789857Sobrien while (0 == strchr ("\n\t,; ", *end)) 89889857Sobrien end++; 89989857Sobrien if (end == input_line_pointer) 90089857Sobrien { 90189857Sobrien as_warn (_("missing name")); 90289857Sobrien ignore_rest_of_line (); 90389857Sobrien return NULL; 90489857Sobrien } 90589857Sobrien 90689857Sobrien name = xmalloc (end - input_line_pointer + 1); 90789857Sobrien memcpy (name, input_line_pointer, end - input_line_pointer); 90889857Sobrien name[end - input_line_pointer] = '\0'; 90989857Sobrien input_line_pointer = end; 91089857Sobrien } 91189857Sobrien SKIP_WHITESPACE (); 91289857Sobrien return name; 91389857Sobrien} 91489857Sobrien 91560484Sobrienvoid 91660484Sobrienobj_elf_section (push) 91760484Sobrien int push; 91860484Sobrien{ 91989857Sobrien char *name, *group_name, *beg; 92060484Sobrien int type, attr, dummy; 92189857Sobrien int entsize; 92260484Sobrien 92360484Sobrien#ifndef TC_I370 92433965Sjdp if (flag_mri) 92533965Sjdp { 92633965Sjdp char mri_type; 92733965Sjdp 92860484Sobrien#ifdef md_flush_pending_output 92977298Sobrien md_flush_pending_output (); 93060484Sobrien#endif 93160484Sobrien 93233965Sjdp previous_section = now_seg; 93333965Sjdp previous_subsection = now_subseg; 93433965Sjdp 93533965Sjdp s_mri_sect (&mri_type); 93633965Sjdp 93733965Sjdp#ifdef md_elf_section_change_hook 93833965Sjdp md_elf_section_change_hook (); 93933965Sjdp#endif 94033965Sjdp 94133965Sjdp return; 94233965Sjdp } 94360484Sobrien#endif /* ! defined (TC_I370) */ 94433965Sjdp 94589857Sobrien name = obj_elf_section_name (); 94689857Sobrien if (name == NULL) 94789857Sobrien return; 94833965Sjdp type = SHT_NULL; 94933965Sjdp attr = 0; 95089857Sobrien group_name = NULL; 95189857Sobrien entsize = 0; 95233965Sjdp 95333965Sjdp if (*input_line_pointer == ',') 95433965Sjdp { 95533965Sjdp /* Skip the comma. */ 95633965Sjdp ++input_line_pointer; 95733965Sjdp SKIP_WHITESPACE (); 95838889Sjdp 95933965Sjdp if (*input_line_pointer == '"') 96033965Sjdp { 96160484Sobrien beg = demand_copy_C_string (&dummy); 96260484Sobrien if (beg == NULL) 96333965Sjdp { 96460484Sobrien ignore_rest_of_line (); 96560484Sobrien return; 96633965Sjdp } 96760484Sobrien attr |= obj_elf_parse_section_letters (beg, strlen (beg)); 96833965Sjdp 96933965Sjdp SKIP_WHITESPACE (); 97033965Sjdp if (*input_line_pointer == ',') 97133965Sjdp { 97260484Sobrien char c; 97389857Sobrien char *save = input_line_pointer; 97489857Sobrien 97533965Sjdp ++input_line_pointer; 97633965Sjdp SKIP_WHITESPACE (); 97760484Sobrien c = *input_line_pointer; 97860484Sobrien if (c == '"') 97933965Sjdp { 98060484Sobrien beg = demand_copy_C_string (&dummy); 98160484Sobrien if (beg == NULL) 98233965Sjdp { 98360484Sobrien ignore_rest_of_line (); 98460484Sobrien return; 98533965Sjdp } 98660484Sobrien type = obj_elf_section_type (beg, strlen (beg)); 98733965Sjdp } 98860484Sobrien else if (c == '@' || c == '%') 98960484Sobrien { 99060484Sobrien beg = ++input_line_pointer; 99160484Sobrien c = get_symbol_end (); 99260484Sobrien *input_line_pointer = c; 99360484Sobrien type = obj_elf_section_type (beg, input_line_pointer - beg); 99460484Sobrien } 99589857Sobrien else 99689857Sobrien input_line_pointer = save; 99733965Sjdp } 99889857Sobrien 99989857Sobrien SKIP_WHITESPACE (); 100089857Sobrien if ((attr & SHF_MERGE) != 0 && *input_line_pointer == ',') 100189857Sobrien { 100289857Sobrien ++input_line_pointer; 100389857Sobrien SKIP_WHITESPACE (); 100489857Sobrien entsize = get_absolute_expression (); 100589857Sobrien SKIP_WHITESPACE (); 100689857Sobrien if (entsize < 0) 100789857Sobrien { 100889857Sobrien as_warn (_("invalid merge entity size")); 100989857Sobrien attr &= ~SHF_MERGE; 101089857Sobrien entsize = 0; 101189857Sobrien } 101289857Sobrien } 101389857Sobrien else if ((attr & SHF_MERGE) != 0) 101489857Sobrien { 101589857Sobrien as_warn (_("entity size for SHF_MERGE not specified")); 101689857Sobrien attr &= ~SHF_MERGE; 101789857Sobrien } 101889857Sobrien 101989857Sobrien if ((attr & SHF_GROUP) != 0 && *input_line_pointer == ',') 102089857Sobrien { 102189857Sobrien ++input_line_pointer; 102289857Sobrien group_name = obj_elf_section_name (); 102389857Sobrien if (group_name == NULL) 102489857Sobrien attr &= ~SHF_GROUP; 102589857Sobrien } 102689857Sobrien else if ((attr & SHF_GROUP) != 0) 102789857Sobrien { 102889857Sobrien as_warn (_("group name for SHF_GROUP not specified")); 102989857Sobrien attr &= ~SHF_GROUP; 103089857Sobrien } 103133965Sjdp } 103233965Sjdp else 103333965Sjdp { 103433965Sjdp do 103533965Sjdp { 103660484Sobrien char c; 103760484Sobrien 103833965Sjdp SKIP_WHITESPACE (); 103933965Sjdp if (*input_line_pointer != '#') 104033965Sjdp { 104189857Sobrien as_warn (_("character following name is not '#'")); 104233965Sjdp ignore_rest_of_line (); 104333965Sjdp return; 104433965Sjdp } 104560484Sobrien beg = ++input_line_pointer; 104660484Sobrien c = get_symbol_end (); 104760484Sobrien *input_line_pointer = c; 104860484Sobrien 104960484Sobrien attr |= obj_elf_section_word (beg, input_line_pointer - beg); 105060484Sobrien 105133965Sjdp SKIP_WHITESPACE (); 105233965Sjdp } 105333965Sjdp while (*input_line_pointer++ == ','); 105433965Sjdp --input_line_pointer; 105533965Sjdp } 105633965Sjdp } 105733965Sjdp 105860484Sobrien demand_empty_rest_of_line (); 105933965Sjdp 106089857Sobrien obj_elf_change_section (name, type, attr, entsize, group_name, push); 106133965Sjdp} 106233965Sjdp 106333965Sjdp/* Change to the .data section. */ 106433965Sjdp 106560484Sobrienvoid 106633965Sjdpobj_elf_data (i) 106733965Sjdp int i; 106833965Sjdp{ 106933965Sjdp#ifdef md_flush_pending_output 107033965Sjdp md_flush_pending_output (); 107133965Sjdp#endif 107233965Sjdp 107333965Sjdp previous_section = now_seg; 107433965Sjdp previous_subsection = now_subseg; 107533965Sjdp s_data (i); 107633965Sjdp 107733965Sjdp#ifdef md_elf_section_change_hook 107833965Sjdp md_elf_section_change_hook (); 107933965Sjdp#endif 108033965Sjdp} 108133965Sjdp 108233965Sjdp/* Change to the .text section. */ 108333965Sjdp 108460484Sobrienvoid 108533965Sjdpobj_elf_text (i) 108633965Sjdp int i; 108733965Sjdp{ 108833965Sjdp#ifdef md_flush_pending_output 108933965Sjdp md_flush_pending_output (); 109033965Sjdp#endif 109133965Sjdp 109233965Sjdp previous_section = now_seg; 109333965Sjdp previous_subsection = now_subseg; 109433965Sjdp s_text (i); 109533965Sjdp 109633965Sjdp#ifdef md_elf_section_change_hook 109733965Sjdp md_elf_section_change_hook (); 109833965Sjdp#endif 109933965Sjdp} 110033965Sjdp 110138889Sjdpstatic void 110238889Sjdpobj_elf_subsection (ignore) 110360484Sobrien int ignore ATTRIBUTE_UNUSED; 110438889Sjdp{ 110538889Sjdp register int temp; 110638889Sjdp 110738889Sjdp#ifdef md_flush_pending_output 110838889Sjdp md_flush_pending_output (); 110938889Sjdp#endif 111038889Sjdp 111138889Sjdp previous_section = now_seg; 111238889Sjdp previous_subsection = now_subseg; 111338889Sjdp 111438889Sjdp temp = get_absolute_expression (); 111538889Sjdp subseg_set (now_seg, (subsegT) temp); 111638889Sjdp demand_empty_rest_of_line (); 111738889Sjdp 111838889Sjdp#ifdef md_elf_section_change_hook 111938889Sjdp md_elf_section_change_hook (); 112038889Sjdp#endif 112138889Sjdp} 112238889Sjdp 112333965Sjdp/* This can be called from the processor backends if they change 112433965Sjdp sections. */ 112533965Sjdp 112633965Sjdpvoid 112733965Sjdpobj_elf_section_change_hook () 112833965Sjdp{ 112933965Sjdp previous_section = now_seg; 113033965Sjdp previous_subsection = now_subseg; 113133965Sjdp} 113233965Sjdp 113333965Sjdpvoid 113433965Sjdpobj_elf_previous (ignore) 113560484Sobrien int ignore ATTRIBUTE_UNUSED; 113633965Sjdp{ 113760484Sobrien segT new_section; 113860484Sobrien int new_subsection; 113960484Sobrien 114033965Sjdp if (previous_section == 0) 114133965Sjdp { 114289857Sobrien as_warn (_(".previous without corresponding .section; ignored")); 114333965Sjdp return; 114433965Sjdp } 114533965Sjdp 114633965Sjdp#ifdef md_flush_pending_output 114733965Sjdp md_flush_pending_output (); 114833965Sjdp#endif 114933965Sjdp 115060484Sobrien new_section = previous_section; 115160484Sobrien new_subsection = previous_subsection; 115260484Sobrien previous_section = now_seg; 115360484Sobrien previous_subsection = now_subseg; 115460484Sobrien subseg_set (new_section, new_subsection); 115533965Sjdp 115633965Sjdp#ifdef md_elf_section_change_hook 115733965Sjdp md_elf_section_change_hook (); 115833965Sjdp#endif 115933965Sjdp} 116033965Sjdp 116133965Sjdpstatic void 116260484Sobrienobj_elf_popsection (xxx) 116360484Sobrien int xxx ATTRIBUTE_UNUSED; 116460484Sobrien{ 116560484Sobrien struct section_stack *top = section_stack; 116660484Sobrien 116760484Sobrien if (top == NULL) 116860484Sobrien { 116989857Sobrien as_warn (_(".popsection without corresponding .pushsection; ignored")); 117060484Sobrien return; 117160484Sobrien } 117260484Sobrien 117360484Sobrien#ifdef md_flush_pending_output 117460484Sobrien md_flush_pending_output (); 117560484Sobrien#endif 117660484Sobrien 117760484Sobrien section_stack = top->next; 117860484Sobrien previous_section = top->prev_seg; 117960484Sobrien previous_subsection = top->prev_subseg; 118060484Sobrien subseg_set (top->seg, top->subseg); 118160484Sobrien free (top); 118260484Sobrien 118360484Sobrien#ifdef md_elf_section_change_hook 118460484Sobrien md_elf_section_change_hook (); 118560484Sobrien#endif 118660484Sobrien} 118760484Sobrien 118860484Sobrienstatic void 118933965Sjdpobj_elf_line (ignore) 119060484Sobrien int ignore ATTRIBUTE_UNUSED; 119133965Sjdp{ 119233965Sjdp /* Assume delimiter is part of expression. BSD4.2 as fails with 119377298Sobrien delightful bug, so we are not being incompatible here. */ 119433965Sjdp new_logical_line ((char *) NULL, (int) (get_absolute_expression ())); 119533965Sjdp demand_empty_rest_of_line (); 119633965Sjdp} 119733965Sjdp 119860484Sobrien/* This handles the .symver pseudo-op, which is used to specify a 119933965Sjdp symbol version. The syntax is ``.symver NAME,SYMVERNAME''. 120033965Sjdp SYMVERNAME may contain ELF_VER_CHR ('@') characters. This 120133965Sjdp pseudo-op causes the assembler to emit a symbol named SYMVERNAME 120233965Sjdp with the same value as the symbol NAME. */ 120333965Sjdp 120433965Sjdpstatic void 120533965Sjdpobj_elf_symver (ignore) 120660484Sobrien int ignore ATTRIBUTE_UNUSED; 120733965Sjdp{ 120833965Sjdp char *name; 120933965Sjdp char c; 121089857Sobrien char old_lexat; 121133965Sjdp symbolS *sym; 121233965Sjdp 121333965Sjdp name = input_line_pointer; 121433965Sjdp c = get_symbol_end (); 121533965Sjdp 121633965Sjdp sym = symbol_find_or_make (name); 121733965Sjdp 121833965Sjdp *input_line_pointer = c; 121933965Sjdp 122033965Sjdp SKIP_WHITESPACE (); 122133965Sjdp if (*input_line_pointer != ',') 122233965Sjdp { 122360484Sobrien as_bad (_("expected comma after name in .symver")); 122433965Sjdp ignore_rest_of_line (); 122533965Sjdp return; 122633965Sjdp } 122733965Sjdp 122833965Sjdp ++input_line_pointer; 122933965Sjdp name = input_line_pointer; 123033965Sjdp 123189857Sobrien /* Temporarily include '@' in symbol names. */ 123289857Sobrien old_lexat = lex_type[(unsigned char) '@']; 123389857Sobrien lex_type[(unsigned char) '@'] |= LEX_NAME; 123489857Sobrien c = get_symbol_end (); 123589857Sobrien lex_type[(unsigned char) '@'] = old_lexat; 123689857Sobrien 123777298Sobrien if (symbol_get_obj (sym)->versioned_name == NULL) 123877298Sobrien { 123977298Sobrien symbol_get_obj (sym)->versioned_name = xstrdup (name); 124033965Sjdp 124177298Sobrien *input_line_pointer = c; 124233965Sjdp 124377298Sobrien if (strchr (symbol_get_obj (sym)->versioned_name, 124477298Sobrien ELF_VER_CHR) == NULL) 124577298Sobrien { 124677298Sobrien as_bad (_("missing version name in `%s' for symbol `%s'"), 124777298Sobrien symbol_get_obj (sym)->versioned_name, 124877298Sobrien S_GET_NAME (sym)); 124977298Sobrien ignore_rest_of_line (); 125077298Sobrien return; 125177298Sobrien } 125277298Sobrien } 125377298Sobrien else 125433965Sjdp { 125577298Sobrien if (strcmp (symbol_get_obj (sym)->versioned_name, name)) 125677298Sobrien { 125777298Sobrien as_bad (_("multiple versions [`%s'|`%s'] for symbol `%s'"), 125877298Sobrien name, symbol_get_obj (sym)->versioned_name, 125977298Sobrien S_GET_NAME (sym)); 126077298Sobrien ignore_rest_of_line (); 126177298Sobrien return; 126277298Sobrien } 126377298Sobrien 126477298Sobrien *input_line_pointer = c; 126533965Sjdp } 126633965Sjdp 126733965Sjdp demand_empty_rest_of_line (); 126833965Sjdp} 126933965Sjdp 127060484Sobrien/* This handles the .vtable_inherit pseudo-op, which is used to indicate 127160484Sobrien to the linker the hierarchy in which a particular table resides. The 127260484Sobrien syntax is ".vtable_inherit CHILDNAME, PARENTNAME". */ 127360484Sobrien 127477298Sobrienstruct fix * 127560484Sobrienobj_elf_vtable_inherit (ignore) 127660484Sobrien int ignore ATTRIBUTE_UNUSED; 127760484Sobrien{ 127860484Sobrien char *cname, *pname; 127960484Sobrien symbolS *csym, *psym; 128060484Sobrien char c, bad = 0; 128160484Sobrien 128260484Sobrien if (*input_line_pointer == '#') 128360484Sobrien ++input_line_pointer; 128460484Sobrien 128560484Sobrien cname = input_line_pointer; 128660484Sobrien c = get_symbol_end (); 128760484Sobrien csym = symbol_find (cname); 128860484Sobrien 128960484Sobrien /* GCFIXME: should check that we don't have two .vtable_inherits for 129060484Sobrien the same child symbol. Also, we can currently only do this if the 129160484Sobrien child symbol is already exists and is placed in a fragment. */ 129260484Sobrien 129360484Sobrien if (csym == NULL || symbol_get_frag (csym) == NULL) 129460484Sobrien { 129560484Sobrien as_bad ("expected `%s' to have already been set for .vtable_inherit", 129660484Sobrien cname); 129760484Sobrien bad = 1; 129860484Sobrien } 129960484Sobrien 130060484Sobrien *input_line_pointer = c; 130160484Sobrien 130260484Sobrien SKIP_WHITESPACE (); 130360484Sobrien if (*input_line_pointer != ',') 130460484Sobrien { 130560484Sobrien as_bad ("expected comma after name in .vtable_inherit"); 130660484Sobrien ignore_rest_of_line (); 130777298Sobrien return NULL; 130860484Sobrien } 130960484Sobrien 131060484Sobrien ++input_line_pointer; 131160484Sobrien SKIP_WHITESPACE (); 131260484Sobrien 131360484Sobrien if (*input_line_pointer == '#') 131460484Sobrien ++input_line_pointer; 131560484Sobrien 131660484Sobrien if (input_line_pointer[0] == '0' 131760484Sobrien && (input_line_pointer[1] == '\0' 131889857Sobrien || ISSPACE (input_line_pointer[1]))) 131960484Sobrien { 132060484Sobrien psym = section_symbol (absolute_section); 132160484Sobrien ++input_line_pointer; 132260484Sobrien } 132360484Sobrien else 132460484Sobrien { 132560484Sobrien pname = input_line_pointer; 132660484Sobrien c = get_symbol_end (); 132760484Sobrien psym = symbol_find_or_make (pname); 132860484Sobrien *input_line_pointer = c; 132960484Sobrien } 133060484Sobrien 133160484Sobrien demand_empty_rest_of_line (); 133260484Sobrien 133360484Sobrien if (bad) 133477298Sobrien return NULL; 133560484Sobrien 133660484Sobrien assert (symbol_get_value_expression (csym)->X_op == O_constant); 133777298Sobrien return fix_new (symbol_get_frag (csym), 133877298Sobrien symbol_get_value_expression (csym)->X_add_number, 133977298Sobrien 0, psym, 0, 0, BFD_RELOC_VTABLE_INHERIT); 134060484Sobrien} 134160484Sobrien 134260484Sobrien/* This handles the .vtable_entry pseudo-op, which is used to indicate 134360484Sobrien to the linker that a vtable slot was used. The syntax is 134460484Sobrien ".vtable_entry tablename, offset". */ 134560484Sobrien 134677298Sobrienstruct fix * 134760484Sobrienobj_elf_vtable_entry (ignore) 134860484Sobrien int ignore ATTRIBUTE_UNUSED; 134960484Sobrien{ 135060484Sobrien char *name; 135160484Sobrien symbolS *sym; 135260484Sobrien offsetT offset; 135360484Sobrien char c; 135460484Sobrien 135560484Sobrien if (*input_line_pointer == '#') 135660484Sobrien ++input_line_pointer; 135760484Sobrien 135860484Sobrien name = input_line_pointer; 135960484Sobrien c = get_symbol_end (); 136060484Sobrien sym = symbol_find_or_make (name); 136160484Sobrien *input_line_pointer = c; 136260484Sobrien 136360484Sobrien SKIP_WHITESPACE (); 136460484Sobrien if (*input_line_pointer != ',') 136560484Sobrien { 136660484Sobrien as_bad ("expected comma after name in .vtable_entry"); 136760484Sobrien ignore_rest_of_line (); 136877298Sobrien return NULL; 136960484Sobrien } 137060484Sobrien 137160484Sobrien ++input_line_pointer; 137260484Sobrien if (*input_line_pointer == '#') 137360484Sobrien ++input_line_pointer; 137460484Sobrien 137560484Sobrien offset = get_absolute_expression (); 137660484Sobrien 137777298Sobrien demand_empty_rest_of_line (); 137860484Sobrien 137977298Sobrien return fix_new (frag_now, frag_now_fix (), 0, sym, offset, 0, 138077298Sobrien BFD_RELOC_VTABLE_ENTRY); 138160484Sobrien} 138260484Sobrien 138333965Sjdpvoid 138460484Sobrienelf_obj_read_begin_hook () 138533965Sjdp{ 138633965Sjdp#ifdef NEED_ECOFF_DEBUG 138733965Sjdp if (ECOFF_DEBUGGING) 138833965Sjdp ecoff_read_begin_hook (); 138933965Sjdp#endif 139033965Sjdp} 139133965Sjdp 139233965Sjdpvoid 139360484Sobrienelf_obj_symbol_new_hook (symbolP) 139433965Sjdp symbolS *symbolP; 139533965Sjdp{ 139660484Sobrien struct elf_obj_sy *sy_obj; 139733965Sjdp 139860484Sobrien sy_obj = symbol_get_obj (symbolP); 139960484Sobrien sy_obj->size = NULL; 140060484Sobrien sy_obj->versioned_name = NULL; 140160484Sobrien 140233965Sjdp#ifdef NEED_ECOFF_DEBUG 140333965Sjdp if (ECOFF_DEBUGGING) 140433965Sjdp ecoff_symbol_new_hook (symbolP); 140533965Sjdp#endif 140633965Sjdp} 140733965Sjdp 140889857Sobrien/* When setting one symbol equal to another, by default we probably 140989857Sobrien want them to have the same "size", whatever it means in the current 141089857Sobrien context. */ 141189857Sobrien 141233965Sjdpvoid 141389857Sobrienelf_copy_symbol_attributes (dest, src) 141489857Sobrien symbolS *dest, *src; 141589857Sobrien{ 141689857Sobrien struct elf_obj_sy *srcelf = symbol_get_obj (src); 141789857Sobrien struct elf_obj_sy *destelf = symbol_get_obj (dest); 141889857Sobrien if (srcelf->size) 141989857Sobrien { 142089857Sobrien if (destelf->size == NULL) 142189857Sobrien destelf->size = 142289857Sobrien (expressionS *) xmalloc (sizeof (expressionS)); 142389857Sobrien *destelf->size = *srcelf->size; 142489857Sobrien } 142589857Sobrien else 142689857Sobrien { 142789857Sobrien if (destelf->size != NULL) 142889857Sobrien free (destelf->size); 142989857Sobrien destelf->size = NULL; 143089857Sobrien } 143189857Sobrien S_SET_SIZE (dest, S_GET_SIZE (src)); 143294536Sobrien /* Don't copy visibility. */ 143394536Sobrien S_SET_OTHER (dest, (ELF_ST_VISIBILITY (S_GET_OTHER (dest)) 143494536Sobrien | (S_GET_OTHER (src) & ~ELF_ST_VISIBILITY (-1)))); 143589857Sobrien} 143689857Sobrien 143789857Sobrienvoid 143833965Sjdpobj_elf_version (ignore) 143960484Sobrien int ignore ATTRIBUTE_UNUSED; 144033965Sjdp{ 144133965Sjdp char *name; 144233965Sjdp unsigned int c; 144333965Sjdp char *p; 144433965Sjdp asection *seg = now_seg; 144533965Sjdp subsegT subseg = now_subseg; 144633965Sjdp Elf_Internal_Note i_note; 144733965Sjdp Elf_External_Note e_note; 144833965Sjdp asection *note_secp = (asection *) NULL; 144989857Sobrien int len; 145033965Sjdp 145133965Sjdp SKIP_WHITESPACE (); 145233965Sjdp if (*input_line_pointer == '\"') 145333965Sjdp { 145477298Sobrien ++input_line_pointer; /* -> 1st char of string. */ 145533965Sjdp name = input_line_pointer; 145633965Sjdp 145733965Sjdp while (is_a_char (c = next_char_of_string ())) 145833965Sjdp ; 145933965Sjdp c = *input_line_pointer; 146033965Sjdp *input_line_pointer = '\0'; 146133965Sjdp *(input_line_pointer - 1) = '\0'; 146233965Sjdp *input_line_pointer = c; 146333965Sjdp 146433965Sjdp /* create the .note section */ 146533965Sjdp 146633965Sjdp note_secp = subseg_new (".note", 0); 146733965Sjdp bfd_set_section_flags (stdoutput, 146833965Sjdp note_secp, 146933965Sjdp SEC_HAS_CONTENTS | SEC_READONLY); 147033965Sjdp 147133965Sjdp /* process the version string */ 147233965Sjdp 147333965Sjdp len = strlen (name); 147433965Sjdp 147533965Sjdp i_note.namesz = ((len + 1) + 3) & ~3; /* round this to word boundary */ 147633965Sjdp i_note.descsz = 0; /* no description */ 147733965Sjdp i_note.type = NT_VERSION; 147833965Sjdp p = frag_more (sizeof (e_note.namesz)); 147989857Sobrien md_number_to_chars (p, (valueT) i_note.namesz, sizeof (e_note.namesz)); 148033965Sjdp p = frag_more (sizeof (e_note.descsz)); 148189857Sobrien md_number_to_chars (p, (valueT) i_note.descsz, sizeof (e_note.descsz)); 148233965Sjdp p = frag_more (sizeof (e_note.type)); 148389857Sobrien md_number_to_chars (p, (valueT) i_note.type, sizeof (e_note.type)); 148489857Sobrien p = frag_more (len + 1); 148589857Sobrien strcpy (p, name); 148633965Sjdp 148733965Sjdp frag_align (2, 0, 0); 148833965Sjdp 148933965Sjdp subseg_set (seg, subseg); 149033965Sjdp } 149133965Sjdp else 149233965Sjdp { 149389857Sobrien as_bad (_("expected quoted string")); 149433965Sjdp } 149533965Sjdp demand_empty_rest_of_line (); 149633965Sjdp} 149733965Sjdp 149833965Sjdpstatic void 149933965Sjdpobj_elf_size (ignore) 150060484Sobrien int ignore ATTRIBUTE_UNUSED; 150133965Sjdp{ 150233965Sjdp char *name = input_line_pointer; 150333965Sjdp char c = get_symbol_end (); 150433965Sjdp char *p; 150533965Sjdp expressionS exp; 150633965Sjdp symbolS *sym; 150733965Sjdp 150833965Sjdp p = input_line_pointer; 150933965Sjdp *p = c; 151033965Sjdp SKIP_WHITESPACE (); 151133965Sjdp if (*input_line_pointer != ',') 151233965Sjdp { 151333965Sjdp *p = 0; 151460484Sobrien as_bad (_("expected comma after name `%s' in .size directive"), name); 151533965Sjdp *p = c; 151633965Sjdp ignore_rest_of_line (); 151733965Sjdp return; 151833965Sjdp } 151933965Sjdp input_line_pointer++; 152033965Sjdp expression (&exp); 152133965Sjdp if (exp.X_op == O_absent) 152233965Sjdp { 152360484Sobrien as_bad (_("missing expression in .size directive")); 152433965Sjdp exp.X_op = O_constant; 152533965Sjdp exp.X_add_number = 0; 152633965Sjdp } 152733965Sjdp *p = 0; 152833965Sjdp sym = symbol_find_or_make (name); 152933965Sjdp *p = c; 153033965Sjdp if (exp.X_op == O_constant) 153189857Sobrien { 153289857Sobrien S_SET_SIZE (sym, exp.X_add_number); 153389857Sobrien if (symbol_get_obj (sym)->size) 153489857Sobrien { 153589857Sobrien xfree (symbol_get_obj (sym)->size); 153689857Sobrien symbol_get_obj (sym)->size = NULL; 153789857Sobrien } 153889857Sobrien } 153933965Sjdp else 154033965Sjdp { 154160484Sobrien symbol_get_obj (sym)->size = 154260484Sobrien (expressionS *) xmalloc (sizeof (expressionS)); 154360484Sobrien *symbol_get_obj (sym)->size = exp; 154433965Sjdp } 154533965Sjdp demand_empty_rest_of_line (); 154633965Sjdp} 154733965Sjdp 154833965Sjdp/* Handle the ELF .type pseudo-op. This sets the type of a symbol. 154977298Sobrien There are five syntaxes: 155060484Sobrien 155160484Sobrien The first (used on Solaris) is 155233965Sjdp .type SYM,#function 155333965Sjdp The second (used on UnixWare) is 155433965Sjdp .type SYM,@function 155533965Sjdp The third (reportedly to be used on Irix 6.0) is 155633965Sjdp .type SYM STT_FUNC 155760484Sobrien The fourth (used on NetBSD/Arm and Linux/ARM) is 155860484Sobrien .type SYM,%function 155977298Sobrien The fifth (used on SVR4/860) is 156077298Sobrien .type SYM,"function" 156133965Sjdp */ 156233965Sjdp 156333965Sjdpstatic void 156433965Sjdpobj_elf_type (ignore) 156560484Sobrien int ignore ATTRIBUTE_UNUSED; 156633965Sjdp{ 156733965Sjdp char *name; 156833965Sjdp char c; 156933965Sjdp int type; 157033965Sjdp const char *typename; 157133965Sjdp symbolS *sym; 157277298Sobrien elf_symbol_type *elfsym; 157333965Sjdp 157433965Sjdp name = input_line_pointer; 157533965Sjdp c = get_symbol_end (); 157633965Sjdp sym = symbol_find_or_make (name); 157777298Sobrien elfsym = (elf_symbol_type *) symbol_get_bfdsym (sym); 157833965Sjdp *input_line_pointer = c; 157933965Sjdp 158033965Sjdp SKIP_WHITESPACE (); 158133965Sjdp if (*input_line_pointer == ',') 158233965Sjdp ++input_line_pointer; 158333965Sjdp 158433965Sjdp SKIP_WHITESPACE (); 158560484Sobrien if ( *input_line_pointer == '#' 158660484Sobrien || *input_line_pointer == '@' 158777298Sobrien || *input_line_pointer == '"' 158860484Sobrien || *input_line_pointer == '%') 158933965Sjdp ++input_line_pointer; 159033965Sjdp 159133965Sjdp typename = input_line_pointer; 159233965Sjdp c = get_symbol_end (); 159333965Sjdp 159433965Sjdp type = 0; 159533965Sjdp if (strcmp (typename, "function") == 0 159633965Sjdp || strcmp (typename, "STT_FUNC") == 0) 159733965Sjdp type = BSF_FUNCTION; 159833965Sjdp else if (strcmp (typename, "object") == 0 159933965Sjdp || strcmp (typename, "STT_OBJECT") == 0) 160033965Sjdp type = BSF_OBJECT; 160177298Sobrien#ifdef md_elf_symbol_type 160277298Sobrien else if ((type = md_elf_symbol_type (typename, sym, elfsym)) != -1) 160377298Sobrien ; 160477298Sobrien#endif 160533965Sjdp else 160689857Sobrien as_bad (_("unrecognized symbol type \"%s\""), typename); 160733965Sjdp 160833965Sjdp *input_line_pointer = c; 160933965Sjdp 161077298Sobrien if (*input_line_pointer == '"') 161177298Sobrien ++input_line_pointer; 161233965Sjdp 161377298Sobrien elfsym->symbol.flags |= type; 161477298Sobrien 161533965Sjdp demand_empty_rest_of_line (); 161633965Sjdp} 161733965Sjdp 161833965Sjdpstatic void 161933965Sjdpobj_elf_ident (ignore) 162060484Sobrien int ignore ATTRIBUTE_UNUSED; 162133965Sjdp{ 162233965Sjdp static segT comment_section; 162333965Sjdp segT old_section = now_seg; 162433965Sjdp int old_subsection = now_subseg; 162533965Sjdp 162660484Sobrien#ifdef md_flush_pending_output 162760484Sobrien md_flush_pending_output (); 162860484Sobrien#endif 162960484Sobrien 163033965Sjdp if (!comment_section) 163133965Sjdp { 163233965Sjdp char *p; 163333965Sjdp comment_section = subseg_new (".comment", 0); 163433965Sjdp bfd_set_section_flags (stdoutput, comment_section, 163533965Sjdp SEC_READONLY | SEC_HAS_CONTENTS); 163633965Sjdp p = frag_more (1); 163733965Sjdp *p = 0; 163833965Sjdp } 163933965Sjdp else 164033965Sjdp subseg_set (comment_section, 0); 164133965Sjdp stringer (1); 164233965Sjdp subseg_set (old_section, old_subsection); 164333965Sjdp} 164433965Sjdp 164533965Sjdp#ifdef INIT_STAB_SECTION 164633965Sjdp 164733965Sjdp/* The first entry in a .stabs section is special. */ 164833965Sjdp 164933965Sjdpvoid 165033965Sjdpobj_elf_init_stab_section (seg) 165133965Sjdp segT seg; 165233965Sjdp{ 165333965Sjdp char *file; 165433965Sjdp char *p; 165533965Sjdp char *stabstr_name; 165633965Sjdp unsigned int stroff; 165733965Sjdp 165833965Sjdp /* Force the section to align to a longword boundary. Without this, 165933965Sjdp UnixWare ar crashes. */ 166033965Sjdp bfd_set_section_alignment (stdoutput, seg, 2); 166133965Sjdp 166277298Sobrien /* Make space for this first symbol. */ 166333965Sjdp p = frag_more (12); 166477298Sobrien /* Zero it out. */ 166533965Sjdp memset (p, 0, 12); 166633965Sjdp as_where (&file, (unsigned int *) NULL); 166789857Sobrien stabstr_name = (char *) xmalloc (strlen (segment_name (seg)) + 4); 166833965Sjdp strcpy (stabstr_name, segment_name (seg)); 166933965Sjdp strcat (stabstr_name, "str"); 167033965Sjdp stroff = get_stab_string_offset (file, stabstr_name); 167133965Sjdp know (stroff == 1); 167233965Sjdp md_number_to_chars (p, stroff, 4); 167333965Sjdp seg_info (seg)->stabu.p = p; 167433965Sjdp} 167533965Sjdp 167633965Sjdp#endif 167733965Sjdp 167833965Sjdp/* Fill in the counts in the first entry in a .stabs section. */ 167933965Sjdp 168033965Sjdpstatic void 168133965Sjdpadjust_stab_sections (abfd, sec, xxx) 168233965Sjdp bfd *abfd; 168333965Sjdp asection *sec; 168460484Sobrien PTR xxx ATTRIBUTE_UNUSED; 168533965Sjdp{ 168633965Sjdp char *name; 168733965Sjdp asection *strsec; 168833965Sjdp char *p; 168933965Sjdp int strsz, nsyms; 169033965Sjdp 169133965Sjdp if (strncmp (".stab", sec->name, 5)) 169233965Sjdp return; 169333965Sjdp if (!strcmp ("str", sec->name + strlen (sec->name) - 3)) 169433965Sjdp return; 169533965Sjdp 169633965Sjdp name = (char *) alloca (strlen (sec->name) + 4); 169733965Sjdp strcpy (name, sec->name); 169833965Sjdp strcat (name, "str"); 169933965Sjdp strsec = bfd_get_section_by_name (abfd, name); 170033965Sjdp if (strsec) 170133965Sjdp strsz = bfd_section_size (abfd, strsec); 170233965Sjdp else 170333965Sjdp strsz = 0; 170433965Sjdp nsyms = bfd_section_size (abfd, sec) / 12 - 1; 170533965Sjdp 170633965Sjdp p = seg_info (sec)->stabu.p; 170733965Sjdp assert (p != 0); 170833965Sjdp 170933965Sjdp bfd_h_put_16 (abfd, (bfd_vma) nsyms, (bfd_byte *) p + 6); 171033965Sjdp bfd_h_put_32 (abfd, (bfd_vma) strsz, (bfd_byte *) p + 8); 171133965Sjdp} 171233965Sjdp 171333965Sjdp#ifdef NEED_ECOFF_DEBUG 171433965Sjdp 171533965Sjdp/* This function is called by the ECOFF code. It is supposed to 171633965Sjdp record the external symbol information so that the backend can 171733965Sjdp write it out correctly. The ELF backend doesn't actually handle 171833965Sjdp this at the moment, so we do it ourselves. We save the information 171933965Sjdp in the symbol. */ 172033965Sjdp 172133965Sjdpvoid 172233965Sjdpelf_ecoff_set_ext (sym, ext) 172333965Sjdp symbolS *sym; 172433965Sjdp struct ecoff_extr *ext; 172533965Sjdp{ 172660484Sobrien symbol_get_bfdsym (sym)->udata.p = (PTR) ext; 172733965Sjdp} 172833965Sjdp 172933965Sjdp/* This function is called by bfd_ecoff_debug_externals. It is 173033965Sjdp supposed to *EXT to the external symbol information, and return 173133965Sjdp whether the symbol should be used at all. */ 173233965Sjdp 173333965Sjdpstatic boolean 173433965Sjdpelf_get_extr (sym, ext) 173533965Sjdp asymbol *sym; 173633965Sjdp EXTR *ext; 173733965Sjdp{ 173833965Sjdp if (sym->udata.p == NULL) 173933965Sjdp return false; 174033965Sjdp *ext = *(EXTR *) sym->udata.p; 174133965Sjdp return true; 174233965Sjdp} 174333965Sjdp 174433965Sjdp/* This function is called by bfd_ecoff_debug_externals. It has 174533965Sjdp nothing to do for ELF. */ 174633965Sjdp 174733965Sjdp/*ARGSUSED*/ 174833965Sjdpstatic void 174933965Sjdpelf_set_index (sym, indx) 175060484Sobrien asymbol *sym ATTRIBUTE_UNUSED; 175160484Sobrien bfd_size_type indx ATTRIBUTE_UNUSED; 175233965Sjdp{ 175333965Sjdp} 175433965Sjdp 175533965Sjdp#endif /* NEED_ECOFF_DEBUG */ 175633965Sjdp 175733965Sjdpvoid 175833965Sjdpelf_frob_symbol (symp, puntp) 175933965Sjdp symbolS *symp; 176033965Sjdp int *puntp; 176133965Sjdp{ 176260484Sobrien struct elf_obj_sy *sy_obj; 176360484Sobrien 176433965Sjdp#ifdef NEED_ECOFF_DEBUG 176533965Sjdp if (ECOFF_DEBUGGING) 176633965Sjdp ecoff_frob_symbol (symp); 176733965Sjdp#endif 176833965Sjdp 176960484Sobrien sy_obj = symbol_get_obj (symp); 177060484Sobrien 177160484Sobrien if (sy_obj->size != NULL) 177233965Sjdp { 177360484Sobrien switch (sy_obj->size->X_op) 177433965Sjdp { 177533965Sjdp case O_subtract: 177633965Sjdp S_SET_SIZE (symp, 177760484Sobrien (S_GET_VALUE (sy_obj->size->X_add_symbol) 177860484Sobrien + sy_obj->size->X_add_number 177960484Sobrien - S_GET_VALUE (sy_obj->size->X_op_symbol))); 178033965Sjdp break; 178133965Sjdp case O_constant: 178233965Sjdp S_SET_SIZE (symp, 178360484Sobrien (S_GET_VALUE (sy_obj->size->X_add_symbol) 178460484Sobrien + sy_obj->size->X_add_number)); 178533965Sjdp break; 178633965Sjdp default: 178760484Sobrien as_bad (_(".size expression too complicated to fix up")); 178833965Sjdp break; 178933965Sjdp } 179060484Sobrien free (sy_obj->size); 179160484Sobrien sy_obj->size = NULL; 179233965Sjdp } 179333965Sjdp 179460484Sobrien if (sy_obj->versioned_name != NULL) 179533965Sjdp { 179677298Sobrien char *p; 179777298Sobrien 179877298Sobrien p = strchr (sy_obj->versioned_name, ELF_VER_CHR); 179977298Sobrien know (p != NULL); 180077298Sobrien 180133965Sjdp /* This symbol was given a new name with the .symver directive. 180233965Sjdp 180333965Sjdp If this is an external reference, just rename the symbol to 180433965Sjdp include the version string. This will make the relocs be 180533965Sjdp against the correct versioned symbol. 180633965Sjdp 180733965Sjdp If this is a definition, add an alias. FIXME: Using an alias 180833965Sjdp will permit the debugging information to refer to the right 180933965Sjdp symbol. However, it's not clear whether it is the best 181033965Sjdp approach. */ 181133965Sjdp 181233965Sjdp if (! S_IS_DEFINED (symp)) 181333965Sjdp { 181433965Sjdp /* Verify that the name isn't using the @@ syntax--this is 181533965Sjdp reserved for definitions of the default version to link 181633965Sjdp against. */ 181733965Sjdp if (p[1] == ELF_VER_CHR) 181833965Sjdp { 181960484Sobrien as_bad (_("invalid attempt to declare external version name as default in symbol `%s'"), 182060484Sobrien sy_obj->versioned_name); 182133965Sjdp *puntp = true; 182233965Sjdp } 182360484Sobrien S_SET_NAME (symp, sy_obj->versioned_name); 182433965Sjdp } 182533965Sjdp else 182633965Sjdp { 182777298Sobrien if (p [1] == ELF_VER_CHR && p [2] == ELF_VER_CHR) 182877298Sobrien { 182977298Sobrien size_t l; 183033965Sjdp 183177298Sobrien /* The @@@ syntax is a special case. It renames the 183277298Sobrien symbol name to versioned_name with one `@' removed. */ 183377298Sobrien l = strlen (&p[3]) + 1; 183477298Sobrien memmove (&p [2], &p[3], l); 183577298Sobrien S_SET_NAME (symp, sy_obj->versioned_name); 183677298Sobrien } 183777298Sobrien else 183877298Sobrien { 183977298Sobrien symbolS *symp2; 184033965Sjdp 184177298Sobrien /* FIXME: Creating a new symbol here is risky. We're 184277298Sobrien in the final loop over the symbol table. We can 184377298Sobrien get away with it only because the symbol goes to 184477298Sobrien the end of the list, where the loop will still see 184577298Sobrien it. It would probably be better to do this in 184677298Sobrien obj_frob_file_before_adjust. */ 184733965Sjdp 184877298Sobrien symp2 = symbol_find_or_make (sy_obj->versioned_name); 184933965Sjdp 185077298Sobrien /* Now we act as though we saw symp2 = sym. */ 185133965Sjdp 185277298Sobrien S_SET_SEGMENT (symp2, S_GET_SEGMENT (symp)); 185333965Sjdp 185477298Sobrien /* Subtracting out the frag address here is a hack 185577298Sobrien because we are in the middle of the final loop. */ 185677298Sobrien S_SET_VALUE (symp2, 185777298Sobrien (S_GET_VALUE (symp) 185877298Sobrien - symbol_get_frag (symp)->fr_address)); 185933965Sjdp 186077298Sobrien symbol_set_frag (symp2, symbol_get_frag (symp)); 186133965Sjdp 186277298Sobrien /* This will copy over the size information. */ 186377298Sobrien copy_symbol_attributes (symp2, symp); 186433965Sjdp 186594536Sobrien S_SET_OTHER (symp2, S_GET_OTHER (symp)); 186694536Sobrien 186777298Sobrien if (S_IS_WEAK (symp)) 186877298Sobrien S_SET_WEAK (symp2); 186977298Sobrien 187077298Sobrien if (S_IS_EXTERNAL (symp)) 187177298Sobrien S_SET_EXTERNAL (symp2); 187277298Sobrien } 187333965Sjdp } 187433965Sjdp } 187533965Sjdp 187633965Sjdp /* Double check weak symbols. */ 187760484Sobrien if (S_IS_WEAK (symp)) 187833965Sjdp { 187933965Sjdp if (S_IS_COMMON (symp)) 188089857Sobrien as_bad (_("symbol `%s' can not be both weak and common"), 188133965Sjdp S_GET_NAME (symp)); 188233965Sjdp } 188333965Sjdp 188433965Sjdp#ifdef TC_MIPS 188533965Sjdp /* The Irix 5 and 6 assemblers set the type of any common symbol and 188638889Sjdp any undefined non-function symbol to STT_OBJECT. We try to be 188738889Sjdp compatible, since newer Irix 5 and 6 linkers care. However, we 188838889Sjdp only set undefined symbols to be STT_OBJECT if we are on Irix, 188938889Sjdp because that is the only time gcc will generate the necessary 189038889Sjdp .global directives to mark functions. */ 189138889Sjdp 189238889Sjdp if (S_IS_COMMON (symp)) 189360484Sobrien symbol_get_bfdsym (symp)->flags |= BSF_OBJECT; 189438889Sjdp 189538889Sjdp if (strstr (TARGET_OS, "irix") != NULL 189660484Sobrien && ! S_IS_DEFINED (symp) 189760484Sobrien && (symbol_get_bfdsym (symp)->flags & BSF_FUNCTION) == 0) 189860484Sobrien symbol_get_bfdsym (symp)->flags |= BSF_OBJECT; 189933965Sjdp#endif 190033965Sjdp 190160484Sobrien#if 0 /* TC_PPC */ 190260484Sobrien /* If TC_PPC is defined, we used to force the type of a symbol to be 190360484Sobrien BSF_OBJECT if it was otherwise unset. This was required by some 190460484Sobrien version of VxWorks. Thomas de Lellis <tdel@windriver.com> says 190560484Sobrien that this is no longer needed, so it is now commented out. */ 190660484Sobrien if ((symbol_get_bfdsym (symp)->flags 190760484Sobrien & (BSF_FUNCTION | BSF_FILE | BSF_SECTION_SYM)) == 0 190833965Sjdp && S_IS_DEFINED (symp)) 190960484Sobrien symbol_get_bfdsym (symp)->flags |= BSF_OBJECT; 191033965Sjdp#endif 191133965Sjdp} 191233965Sjdp 191389857Sobrienstruct group_list 191489857Sobrien{ 191589857Sobrien asection **head; /* Section lists. */ 191689857Sobrien unsigned int *elt_count; /* Number of sections in each list. */ 191789857Sobrien unsigned int num_group; /* Number of lists. */ 191889857Sobrien}; 191989857Sobrien 192089857Sobrien/* Called via bfd_map_over_sections. If SEC is a member of a group, 192189857Sobrien add it to a list of sections belonging to the group. INF is a 192289857Sobrien pointer to a struct group_list, which is where we store the head of 192389857Sobrien each list. */ 192489857Sobrien 192589857Sobrienstatic void 192689857Sobrienbuild_group_lists (abfd, sec, inf) 192789857Sobrien bfd *abfd ATTRIBUTE_UNUSED; 192889857Sobrien asection *sec; 192989857Sobrien PTR inf; 193089857Sobrien{ 193189857Sobrien struct group_list *list = (struct group_list *) inf; 193289857Sobrien const char *group_name = elf_group_name (sec); 193389857Sobrien unsigned int i; 193489857Sobrien 193589857Sobrien if (group_name == NULL) 193689857Sobrien return; 193789857Sobrien 193889857Sobrien /* If this group already has a list, add the section to the head of 193989857Sobrien the list. */ 194089857Sobrien for (i = 0; i < list->num_group; i++) 194189857Sobrien { 194289857Sobrien if (strcmp (group_name, elf_group_name (list->head[i])) == 0) 194389857Sobrien { 194489857Sobrien elf_next_in_group (sec) = list->head[i]; 194589857Sobrien list->head[i] = sec; 194689857Sobrien list->elt_count[i] += 1; 194789857Sobrien return; 194889857Sobrien } 194989857Sobrien } 195089857Sobrien 195189857Sobrien /* New group. Make the arrays bigger in chunks to minimize calls to 195289857Sobrien realloc. */ 195389857Sobrien i = list->num_group; 195489857Sobrien if ((i & 127) == 0) 195589857Sobrien { 195689857Sobrien unsigned int newsize = i + 128; 195789857Sobrien list->head = xrealloc (list->head, newsize * sizeof (*list->head)); 195889857Sobrien list->elt_count = xrealloc (list->elt_count, 195989857Sobrien newsize * sizeof (*list->elt_count)); 196089857Sobrien } 196189857Sobrien list->head[i] = sec; 196289857Sobrien list->elt_count[i] = 1; 196389857Sobrien list->num_group += 1; 196489857Sobrien} 196589857Sobrien 196633965Sjdpvoid 196733965Sjdpelf_frob_file () 196833965Sjdp{ 196989857Sobrien struct group_list list; 197089857Sobrien unsigned int i; 197189857Sobrien 197233965Sjdp bfd_map_over_sections (stdoutput, adjust_stab_sections, (PTR) 0); 197333965Sjdp 197489857Sobrien /* Go find section groups. */ 197589857Sobrien list.num_group = 0; 197689857Sobrien list.head = NULL; 197789857Sobrien list.elt_count = NULL; 197889857Sobrien bfd_map_over_sections (stdoutput, build_group_lists, (PTR) &list); 197989857Sobrien 198089857Sobrien /* Make the SHT_GROUP sections that describe each section group. We 198189857Sobrien can't set up the section contents here yet, because elf section 198289857Sobrien indices have yet to be calculated. elf.c:set_group_contents does 198389857Sobrien the rest of the work. */ 198489857Sobrien for (i = 0; i < list.num_group; i++) 198589857Sobrien { 198689857Sobrien const char *group_name = elf_group_name (list.head[i]); 198789857Sobrien asection *s; 198889857Sobrien flagword flags; 198989857Sobrien 199089857Sobrien s = subseg_force_new (group_name, 0); 199189857Sobrien flags = SEC_READONLY | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_GROUP; 199289857Sobrien if (s == NULL 199389857Sobrien || !bfd_set_section_flags (stdoutput, s, flags) 199489857Sobrien || !bfd_set_section_alignment (stdoutput, s, 2)) 199589857Sobrien { 199689857Sobrien as_fatal (_("can't create group: %s"), 199789857Sobrien bfd_errmsg (bfd_get_error ())); 199889857Sobrien } 199989857Sobrien 200089857Sobrien /* Pass a pointer to the first section in this group. */ 200189857Sobrien elf_next_in_group (s) = list.head[i]; 200289857Sobrien 200389857Sobrien s->_raw_size = 4 * (list.elt_count[i] + 1); 200489857Sobrien s->contents = frag_more (s->_raw_size); 200589857Sobrien frag_now->fr_fix = frag_now_fix_octets (); 200689857Sobrien } 200789857Sobrien 200833965Sjdp#ifdef elf_tc_final_processing 200933965Sjdp elf_tc_final_processing (); 201033965Sjdp#endif 201133965Sjdp} 201233965Sjdp 201377298Sobrien/* It removes any unneeded versioned symbols from the symbol table. */ 201477298Sobrien 201577298Sobrienvoid 201677298Sobrienelf_frob_file_before_adjust () 201777298Sobrien{ 201877298Sobrien if (symbol_rootP) 201977298Sobrien { 202077298Sobrien symbolS *symp; 202177298Sobrien 202277298Sobrien for (symp = symbol_rootP; symp; symp = symbol_next (symp)) 202391041Sobrien if (!S_IS_DEFINED (symp)) 202477298Sobrien { 202591041Sobrien if (symbol_get_obj (symp)->versioned_name) 202677298Sobrien { 202777298Sobrien char *p; 202877298Sobrien 202977298Sobrien /* The @@@ syntax is a special case. If the symbol is 203077298Sobrien not defined, 2 `@'s will be removed from the 203177298Sobrien versioned_name. */ 203277298Sobrien 203377298Sobrien p = strchr (symbol_get_obj (symp)->versioned_name, 203477298Sobrien ELF_VER_CHR); 203577298Sobrien know (p != NULL); 203677298Sobrien if (p [1] == ELF_VER_CHR && p [2] == ELF_VER_CHR) 203777298Sobrien { 203877298Sobrien size_t l = strlen (&p[3]) + 1; 203977298Sobrien memmove (&p [1], &p[3], l); 204077298Sobrien } 204177298Sobrien if (symbol_used_p (symp) == 0 204277298Sobrien && symbol_used_in_reloc_p (symp) == 0) 204377298Sobrien symbol_remove (symp, &symbol_rootP, &symbol_lastP); 204477298Sobrien } 204591041Sobrien 204691041Sobrien /* If there was .weak foo, but foo was neither defined nor 204791041Sobrien used anywhere, remove it. */ 204891041Sobrien 204991041Sobrien else if (S_IS_WEAK (symp) 205091041Sobrien && symbol_used_p (symp) == 0 205191041Sobrien && symbol_used_in_reloc_p (symp) == 0) 205291041Sobrien symbol_remove (symp, &symbol_rootP, &symbol_lastP); 205377298Sobrien } 205477298Sobrien } 205577298Sobrien} 205677298Sobrien 205733965Sjdp/* It is required that we let write_relocs have the opportunity to 205833965Sjdp optimize away fixups before output has begun, since it is possible 205933965Sjdp to eliminate all fixups for a section and thus we never should 206033965Sjdp have generated the relocation section. */ 206133965Sjdp 206233965Sjdpvoid 206333965Sjdpelf_frob_file_after_relocs () 206433965Sjdp{ 206533965Sjdp#ifdef NEED_ECOFF_DEBUG 206633965Sjdp if (ECOFF_DEBUGGING) 206733965Sjdp /* Generate the ECOFF debugging information. */ 206833965Sjdp { 206933965Sjdp const struct ecoff_debug_swap *debug_swap; 207033965Sjdp struct ecoff_debug_info debug; 207133965Sjdp char *buf; 207233965Sjdp asection *sec; 207333965Sjdp 207433965Sjdp debug_swap 207533965Sjdp = get_elf_backend_data (stdoutput)->elf_backend_ecoff_debug_swap; 207633965Sjdp know (debug_swap != (const struct ecoff_debug_swap *) NULL); 207733965Sjdp ecoff_build_debug (&debug.symbolic_header, &buf, debug_swap); 207833965Sjdp 207933965Sjdp /* Set up the pointers in debug. */ 208033965Sjdp#define SET(ptr, offset, type) \ 208133965Sjdp debug.ptr = (type) (buf + debug.symbolic_header.offset) 208233965Sjdp 208333965Sjdp SET (line, cbLineOffset, unsigned char *); 208433965Sjdp SET (external_dnr, cbDnOffset, PTR); 208533965Sjdp SET (external_pdr, cbPdOffset, PTR); 208633965Sjdp SET (external_sym, cbSymOffset, PTR); 208733965Sjdp SET (external_opt, cbOptOffset, PTR); 208833965Sjdp SET (external_aux, cbAuxOffset, union aux_ext *); 208933965Sjdp SET (ss, cbSsOffset, char *); 209033965Sjdp SET (external_fdr, cbFdOffset, PTR); 209133965Sjdp SET (external_rfd, cbRfdOffset, PTR); 209233965Sjdp /* ssext and external_ext are set up just below. */ 209333965Sjdp 209433965Sjdp#undef SET 209533965Sjdp 209633965Sjdp /* Set up the external symbols. */ 209733965Sjdp debug.ssext = debug.ssext_end = NULL; 209833965Sjdp debug.external_ext = debug.external_ext_end = NULL; 209933965Sjdp if (! bfd_ecoff_debug_externals (stdoutput, &debug, debug_swap, true, 210033965Sjdp elf_get_extr, elf_set_index)) 210189857Sobrien as_fatal (_("failed to set up debugging information: %s"), 210233965Sjdp bfd_errmsg (bfd_get_error ())); 210333965Sjdp 210433965Sjdp sec = bfd_get_section_by_name (stdoutput, ".mdebug"); 210533965Sjdp assert (sec != NULL); 210633965Sjdp 210733965Sjdp know (stdoutput->output_has_begun == false); 210833965Sjdp 210933965Sjdp /* We set the size of the section, call bfd_set_section_contents 211033965Sjdp to force the ELF backend to allocate a file position, and then 211133965Sjdp write out the data. FIXME: Is this really the best way to do 211233965Sjdp this? */ 211333965Sjdp sec->_raw_size = bfd_ecoff_debug_size (stdoutput, &debug, debug_swap); 211433965Sjdp 211560484Sobrien /* Pass BUF to bfd_set_section_contents because this will 211660484Sobrien eventually become a call to fwrite, and ISO C prohibits 211760484Sobrien passing a NULL pointer to a stdio function even if the 211860484Sobrien pointer will not be used. */ 211960484Sobrien if (! bfd_set_section_contents (stdoutput, sec, (PTR) buf, 212033965Sjdp (file_ptr) 0, (bfd_size_type) 0)) 212189857Sobrien as_fatal (_("can't start writing .mdebug section: %s"), 212233965Sjdp bfd_errmsg (bfd_get_error ())); 212333965Sjdp 212433965Sjdp know (stdoutput->output_has_begun == true); 212533965Sjdp know (sec->filepos != 0); 212633965Sjdp 212733965Sjdp if (! bfd_ecoff_write_debug (stdoutput, &debug, debug_swap, 212833965Sjdp sec->filepos)) 212989857Sobrien as_fatal (_("could not write .mdebug section: %s"), 213033965Sjdp bfd_errmsg (bfd_get_error ())); 213133965Sjdp } 213233965Sjdp#endif /* NEED_ECOFF_DEBUG */ 213333965Sjdp} 213433965Sjdp 213533965Sjdp#ifdef SCO_ELF 213633965Sjdp 213733965Sjdp/* Heavily plagarized from obj_elf_version. The idea is to emit the 213833965Sjdp SCO specific identifier in the .notes section to satisfy the SCO 213933965Sjdp linker. 214033965Sjdp 214133965Sjdp This looks more complicated than it really is. As opposed to the 214233965Sjdp "obvious" solution, this should handle the cross dev cases 214333965Sjdp correctly. (i.e, hosting on a 64 bit big endian processor, but 214433965Sjdp generating SCO Elf code) Efficiency isn't a concern, as there 214533965Sjdp should be exactly one of these sections per object module. 214633965Sjdp 214733965Sjdp SCO OpenServer 5 identifies it's ELF modules with a standard ELF 214833965Sjdp .note section. 214933965Sjdp 215060484Sobrien int_32 namesz = 4 ; Name size 215160484Sobrien int_32 descsz = 12 ; Descriptive information 215260484Sobrien int_32 type = 1 ; 215360484Sobrien char name[4] = "SCO" ; Originator name ALWAYS SCO + NULL 215433965Sjdp int_32 version = (major ver # << 16) | version of tools ; 215533965Sjdp int_32 source = (tool_id << 16 ) | 1 ; 215633965Sjdp int_32 info = 0 ; These are set by the SCO tools, but we 215760484Sobrien don't know enough about the source 215833965Sjdp environment to set them. SCO ld currently 215933965Sjdp ignores them, and recommends we set them 216033965Sjdp to zero. */ 216133965Sjdp 216233965Sjdp#define SCO_MAJOR_VERSION 0x1 216333965Sjdp#define SCO_MINOR_VERSION 0x1 216433965Sjdp 216533965Sjdpvoid 216633965Sjdpsco_id () 216733965Sjdp{ 216833965Sjdp 216933965Sjdp char *name; 217033965Sjdp unsigned int c; 217133965Sjdp char ch; 217233965Sjdp char *p; 217333965Sjdp asection *seg = now_seg; 217433965Sjdp subsegT subseg = now_subseg; 217533965Sjdp Elf_Internal_Note i_note; 217633965Sjdp Elf_External_Note e_note; 217733965Sjdp asection *note_secp = (asection *) NULL; 217833965Sjdp int i, len; 217933965Sjdp 218033965Sjdp /* create the .note section */ 218133965Sjdp 218233965Sjdp note_secp = subseg_new (".note", 0); 218333965Sjdp bfd_set_section_flags (stdoutput, 218433965Sjdp note_secp, 218533965Sjdp SEC_HAS_CONTENTS | SEC_READONLY); 218633965Sjdp 218733965Sjdp /* process the version string */ 218833965Sjdp 218960484Sobrien i_note.namesz = 4; 219033965Sjdp i_note.descsz = 12; /* 12 descriptive bytes */ 219133965Sjdp i_note.type = NT_VERSION; /* Contains a version string */ 219233965Sjdp 219333965Sjdp p = frag_more (sizeof (i_note.namesz)); 219433965Sjdp md_number_to_chars (p, (valueT) i_note.namesz, 4); 219533965Sjdp 219633965Sjdp p = frag_more (sizeof (i_note.descsz)); 219733965Sjdp md_number_to_chars (p, (valueT) i_note.descsz, 4); 219833965Sjdp 219933965Sjdp p = frag_more (sizeof (i_note.type)); 220033965Sjdp md_number_to_chars (p, (valueT) i_note.type, 4); 220133965Sjdp 220233965Sjdp p = frag_more (4); 220360484Sobrien strcpy (p, "SCO"); 220433965Sjdp 220533965Sjdp /* Note: this is the version number of the ELF we're representing */ 220633965Sjdp p = frag_more (4); 220733965Sjdp md_number_to_chars (p, (SCO_MAJOR_VERSION << 16) | (SCO_MINOR_VERSION), 4); 220833965Sjdp 220933965Sjdp /* Here, we pick a magic number for ourselves (yes, I "registered" 221033965Sjdp it with SCO. The bottom bit shows that we are compat with the 221133965Sjdp SCO ABI. */ 221233965Sjdp p = frag_more (4); 221333965Sjdp md_number_to_chars (p, 0x4c520000 | 0x0001, 4); 221433965Sjdp 221533965Sjdp /* If we knew (or cared) what the source language options were, we'd 221633965Sjdp fill them in here. SCO has given us permission to ignore these 221733965Sjdp and just set them to zero. */ 221833965Sjdp p = frag_more (4); 221933965Sjdp md_number_to_chars (p, 0x0000, 4); 222060484Sobrien 222133965Sjdp frag_align (2, 0, 0); 222233965Sjdp 222333965Sjdp /* We probably can't restore the current segment, for there likely 222433965Sjdp isn't one yet... */ 222533965Sjdp if (seg && subseg) 222633965Sjdp subseg_set (seg, subseg); 222733965Sjdp 222833965Sjdp} 222933965Sjdp 223033965Sjdp#endif /* SCO_ELF */ 223133965Sjdp 223277298Sobrienstatic int 223377298Sobrienelf_separate_stab_sections () 223477298Sobrien{ 223577298Sobrien#ifdef NEED_ECOFF_DEBUG 223677298Sobrien return (!ECOFF_DEBUGGING); 223777298Sobrien#else 223877298Sobrien return 1; 223977298Sobrien#endif 224077298Sobrien} 224177298Sobrien 224277298Sobrienstatic void 224377298Sobrienelf_init_stab_section (seg) 224477298Sobrien segT seg; 224577298Sobrien{ 224677298Sobrien#ifdef NEED_ECOFF_DEBUG 224777298Sobrien if (!ECOFF_DEBUGGING) 224877298Sobrien#endif 224977298Sobrien obj_elf_init_stab_section (seg); 225077298Sobrien} 225177298Sobrien 225233965Sjdpconst struct format_ops elf_format_ops = 225333965Sjdp{ 225433965Sjdp bfd_target_elf_flavour, 225560484Sobrien 0, /* dfl_leading_underscore */ 225660484Sobrien 1, /* emit_section_symbols */ 225777298Sobrien elf_begin, 225877298Sobrien elf_file_symbol, 225933965Sjdp elf_frob_symbol, 226033965Sjdp elf_frob_file, 226177298Sobrien elf_frob_file_before_adjust, 226233965Sjdp elf_frob_file_after_relocs, 226333965Sjdp elf_s_get_size, elf_s_set_size, 226433965Sjdp elf_s_get_align, elf_s_set_align, 226560484Sobrien elf_s_get_other, 226677298Sobrien elf_s_set_other, 226760484Sobrien 0, /* s_get_desc */ 226877298Sobrien 0, /* s_set_desc */ 226977298Sobrien 0, /* s_get_type */ 227077298Sobrien 0, /* s_set_type */ 227133965Sjdp elf_copy_symbol_attributes, 227233965Sjdp#ifdef NEED_ECOFF_DEBUG 227333965Sjdp ecoff_generate_asm_lineno, 227433965Sjdp ecoff_stab, 227533965Sjdp#else 227660484Sobrien 0, /* generate_asm_lineno */ 227760484Sobrien 0, /* process_stab */ 227833965Sjdp#endif 227977298Sobrien elf_separate_stab_sections, 228077298Sobrien elf_init_stab_section, 228133965Sjdp elf_sec_sym_ok_for_reloc, 228233965Sjdp elf_pop_insert, 228333965Sjdp#ifdef NEED_ECOFF_DEBUG 228433965Sjdp elf_ecoff_set_ext, 228533965Sjdp#else 228660484Sobrien 0, /* ecoff_set_ext */ 228733965Sjdp#endif 228860484Sobrien elf_obj_read_begin_hook, 228977298Sobrien elf_obj_symbol_new_hook 229033965Sjdp}; 2291