133965Sjdp/* ELF object file format 2104834Sobrien Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 3218822Sdim 2001, 2002, 2003, 2004, 2005, 2006, 2007 4218822Sdim Free Software Foundation, Inc. 533965Sjdp 633965Sjdp This file is part of GAS, the GNU Assembler. 733965Sjdp 833965Sjdp GAS is free software; you can redistribute it and/or modify 933965Sjdp it under the terms of the GNU General Public License as 1033965Sjdp published by the Free Software Foundation; either version 2, 1133965Sjdp or (at your option) any later version. 1233965Sjdp 1333965Sjdp GAS is distributed in the hope that it will be useful, but 1433965Sjdp WITHOUT ANY WARRANTY; without even the implied warranty of 1533965Sjdp MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 1633965Sjdp the GNU General Public License for more details. 1733965Sjdp 1833965Sjdp You should have received a copy of the GNU General Public License 1933965Sjdp along with GAS; see the file COPYING. If not, write to the Free 20218822Sdim Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 21218822Sdim 02110-1301, USA. */ 2233965Sjdp 2333965Sjdp#define OBJ_HEADER "obj-elf.h" 2433965Sjdp#include "as.h" 2589857Sobrien#include "safe-ctype.h" 2633965Sjdp#include "subsegs.h" 2733965Sjdp#include "obstack.h" 28104834Sobrien#include "struc-symbol.h" 29130561Sobrien#include "dwarf2dbg.h" 3033965Sjdp 3133965Sjdp#ifndef ECOFF_DEBUGGING 3233965Sjdp#define ECOFF_DEBUGGING 0 3333965Sjdp#else 3433965Sjdp#define NEED_ECOFF_DEBUG 3533965Sjdp#endif 3633965Sjdp 3733965Sjdp#ifdef NEED_ECOFF_DEBUG 3833965Sjdp#include "ecoff.h" 3933965Sjdp#endif 4033965Sjdp 4138889Sjdp#ifdef TC_ALPHA 4238889Sjdp#include "elf/alpha.h" 4338889Sjdp#endif 4438889Sjdp 4533965Sjdp#ifdef TC_MIPS 4633965Sjdp#include "elf/mips.h" 4733965Sjdp#endif 4833965Sjdp 4933965Sjdp#ifdef TC_PPC 5033965Sjdp#include "elf/ppc.h" 5133965Sjdp#endif 5233965Sjdp 5360484Sobrien#ifdef TC_I370 5460484Sobrien#include "elf/i370.h" 5560484Sobrien#endif 5660484Sobrien 57218822Sdim#ifdef TC_I386 58218822Sdim#include "elf/x86-64.h" 59218822Sdim#endif 60218822Sdim 61218822Sdim#ifdef TC_MEP 62218822Sdim#include "elf/mep.h" 63218822Sdim#endif 64218822Sdim 65130561Sobrienstatic void obj_elf_line (int); 66130561Sobrienstatic void obj_elf_size (int); 67130561Sobrienstatic void obj_elf_type (int); 68130561Sobrienstatic void obj_elf_ident (int); 69130561Sobrienstatic void obj_elf_weak (int); 70130561Sobrienstatic void obj_elf_local (int); 71130561Sobrienstatic void obj_elf_visibility (int); 72130561Sobrienstatic void obj_elf_symver (int); 73130561Sobrienstatic void obj_elf_subsection (int); 74130561Sobrienstatic void obj_elf_popsection (int); 75130561Sobrienstatic void obj_elf_tls_common (int); 76130561Sobrienstatic void obj_elf_lcomm (int); 77218822Sdimstatic void obj_elf_struct (int); 7833965Sjdp 7933965Sjdpstatic const pseudo_typeS elf_pseudo_table[] = 8033965Sjdp{ 8133965Sjdp {"comm", obj_elf_common, 0}, 8260484Sobrien {"common", obj_elf_common, 1}, 8333965Sjdp {"ident", obj_elf_ident, 0}, 84130561Sobrien {"lcomm", obj_elf_lcomm, 0}, 8533965Sjdp {"local", obj_elf_local, 0}, 8633965Sjdp {"previous", obj_elf_previous, 0}, 8733965Sjdp {"section", obj_elf_section, 0}, 8833965Sjdp {"section.s", obj_elf_section, 0}, 8933965Sjdp {"sect", obj_elf_section, 0}, 9033965Sjdp {"sect.s", obj_elf_section, 0}, 9160484Sobrien {"pushsection", obj_elf_section, 1}, 9260484Sobrien {"popsection", obj_elf_popsection, 0}, 9333965Sjdp {"size", obj_elf_size, 0}, 9433965Sjdp {"type", obj_elf_type, 0}, 9533965Sjdp {"version", obj_elf_version, 0}, 9633965Sjdp {"weak", obj_elf_weak, 0}, 9733965Sjdp 9877298Sobrien /* These define symbol visibility. */ 9960484Sobrien {"internal", obj_elf_visibility, STV_INTERNAL}, 10060484Sobrien {"hidden", obj_elf_visibility, STV_HIDDEN}, 10160484Sobrien {"protected", obj_elf_visibility, STV_PROTECTED}, 10260484Sobrien 10333965Sjdp /* These are used for stabs-in-elf configurations. */ 10433965Sjdp {"line", obj_elf_line, 0}, 10533965Sjdp 10633965Sjdp /* This is a GNU extension to handle symbol versions. */ 10733965Sjdp {"symver", obj_elf_symver, 0}, 10833965Sjdp 10938889Sjdp /* A GNU extension to change subsection only. */ 11038889Sjdp {"subsection", obj_elf_subsection, 0}, 11138889Sjdp 11260484Sobrien /* These are GNU extensions to aid in garbage collecting C++ vtables. */ 113130561Sobrien {"vtable_inherit", (void (*) (int)) &obj_elf_vtable_inherit, 0}, 114130561Sobrien {"vtable_entry", (void (*) (int)) &obj_elf_vtable_entry, 0}, 11560484Sobrien 11677298Sobrien /* These are used for dwarf. */ 11733965Sjdp {"2byte", cons, 2}, 11833965Sjdp {"4byte", cons, 4}, 11933965Sjdp {"8byte", cons, 8}, 120130561Sobrien /* These are used for dwarf2. */ 121130561Sobrien { "file", (void (*) (int)) dwarf2_directive_file, 0 }, 122130561Sobrien { "loc", dwarf2_directive_loc, 0 }, 123218822Sdim { "loc_mark_labels", dwarf2_directive_loc_mark_labels, 0 }, 12433965Sjdp 12533965Sjdp /* We need to trap the section changing calls to handle .previous. */ 12633965Sjdp {"data", obj_elf_data, 0}, 127218822Sdim {"offset", obj_elf_struct, 0}, 128218822Sdim {"struct", obj_elf_struct, 0}, 12933965Sjdp {"text", obj_elf_text, 0}, 13033965Sjdp 131104834Sobrien {"tls_common", obj_elf_tls_common, 0}, 132104834Sobrien 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 187218822Sdimasection *elf_com_section_ptr; 188218822Sdim 18933965Sjdpvoid 190130561Sobrienelf_begin (void) 19133965Sjdp{ 192130561Sobrien asection *s; 193130561Sobrien 19433965Sjdp /* Add symbols for the known sections to the symbol table. */ 195130561Sobrien s = bfd_get_section_by_name (stdoutput, TEXT_SECTION_NAME); 196130561Sobrien symbol_table_insert (section_symbol (s)); 197130561Sobrien s = bfd_get_section_by_name (stdoutput, DATA_SECTION_NAME); 198130561Sobrien symbol_table_insert (section_symbol (s)); 199130561Sobrien s = bfd_get_section_by_name (stdoutput, BSS_SECTION_NAME); 200130561Sobrien symbol_table_insert (section_symbol (s)); 201218822Sdim elf_com_section_ptr = bfd_com_section_ptr; 20233965Sjdp} 20333965Sjdp 20433965Sjdpvoid 205130561Sobrienelf_pop_insert (void) 20633965Sjdp{ 20733965Sjdp pop_insert (elf_pseudo_table); 20833965Sjdp if (ECOFF_DEBUGGING) 20933965Sjdp pop_insert (ecoff_debug_pseudo_table); 21033965Sjdp} 21133965Sjdp 21233965Sjdpstatic bfd_vma 213130561Sobrienelf_s_get_size (symbolS *sym) 21433965Sjdp{ 21533965Sjdp return S_GET_SIZE (sym); 21633965Sjdp} 21733965Sjdp 21833965Sjdpstatic void 219130561Sobrienelf_s_set_size (symbolS *sym, bfd_vma sz) 22033965Sjdp{ 22133965Sjdp S_SET_SIZE (sym, sz); 22233965Sjdp} 22333965Sjdp 22433965Sjdpstatic bfd_vma 225130561Sobrienelf_s_get_align (symbolS *sym) 22633965Sjdp{ 22733965Sjdp return S_GET_ALIGN (sym); 22833965Sjdp} 22933965Sjdp 23033965Sjdpstatic void 231130561Sobrienelf_s_set_align (symbolS *sym, bfd_vma align) 23233965Sjdp{ 23333965Sjdp S_SET_ALIGN (sym, align); 23433965Sjdp} 23533965Sjdp 23660484Sobrienint 237130561Sobrienelf_s_get_other (symbolS *sym) 23860484Sobrien{ 23960484Sobrien return elf_symbol (symbol_get_bfdsym (sym))->internal_elf_sym.st_other; 24060484Sobrien} 24160484Sobrien 24233965Sjdpstatic void 243130561Sobrienelf_s_set_other (symbolS *sym, int other) 24477298Sobrien{ 24577298Sobrien S_SET_OTHER (sym, other); 24677298Sobrien} 24777298Sobrien 24833965Sjdpstatic int 249130561Sobrienelf_sec_sym_ok_for_reloc (asection *sec) 25033965Sjdp{ 25133965Sjdp return obj_sec_sym_ok_for_reloc (sec); 25233965Sjdp} 25333965Sjdp 25433965Sjdpvoid 255218822Sdimelf_file_symbol (const char *s, int appfile) 25633965Sjdp{ 257218822Sdim if (!appfile 258218822Sdim || symbol_rootP == NULL 259218822Sdim || symbol_rootP->bsym == NULL 260218822Sdim || (symbol_rootP->bsym->flags & BSF_FILE) == 0) 261218822Sdim { 262218822Sdim symbolS *sym; 26333965Sjdp 264218822Sdim sym = symbol_new (s, absolute_section, 0, NULL); 265218822Sdim symbol_set_frag (sym, &zero_address_frag); 266218822Sdim symbol_get_bfdsym (sym)->flags |= BSF_FILE; 26733965Sjdp 268218822Sdim if (symbol_rootP != sym) 269218822Sdim { 270218822Sdim symbol_remove (sym, &symbol_rootP, &symbol_lastP); 271218822Sdim symbol_insert (sym, symbol_rootP, &symbol_rootP, &symbol_lastP); 27233965Sjdp#ifdef DEBUG 273218822Sdim verify_symbol_chain (symbol_rootP, symbol_lastP); 27433965Sjdp#endif 275218822Sdim } 27633965Sjdp } 27733965Sjdp 27833965Sjdp#ifdef NEED_ECOFF_DEBUG 279218822Sdim ecoff_new_file (s, appfile); 28033965Sjdp#endif 28133965Sjdp} 28233965Sjdp 283130561Sobrien/* Called from read.c:s_comm after we've parsed .comm symbol, size. 284130561Sobrien Parse a possible alignment value. */ 285130561Sobrien 286218822SdimsymbolS * 287130561Sobrienelf_common_parse (int ignore ATTRIBUTE_UNUSED, symbolS *symbolP, addressT size) 28833965Sjdp{ 289130561Sobrien addressT align = 0; 290130561Sobrien int is_local = symbol_get_obj (symbolP)->local; 29133965Sjdp 292130561Sobrien if (*input_line_pointer == ',') 29360484Sobrien { 294130561Sobrien char *save = input_line_pointer; 29560484Sobrien 29633965Sjdp input_line_pointer++; 29733965Sjdp SKIP_WHITESPACE (); 298130561Sobrien 299130561Sobrien if (*input_line_pointer == '"') 30033965Sjdp { 301130561Sobrien /* For sparc. Accept .common symbol, length, "bss" */ 302130561Sobrien input_line_pointer++; 303130561Sobrien /* Some use the dot, some don't. */ 304130561Sobrien if (*input_line_pointer == '.') 305130561Sobrien input_line_pointer++; 306130561Sobrien /* Some say data, some say bss. */ 307130561Sobrien if (strncmp (input_line_pointer, "bss\"", 4) == 0) 308130561Sobrien input_line_pointer += 4; 309130561Sobrien else if (strncmp (input_line_pointer, "data\"", 5) == 0) 310130561Sobrien input_line_pointer += 5; 311130561Sobrien else 31233965Sjdp { 313130561Sobrien char *p = input_line_pointer; 314130561Sobrien char c; 31533965Sjdp 316130561Sobrien while (*--p != '"') 317130561Sobrien ; 318130561Sobrien while (!is_end_of_line[(unsigned char) *input_line_pointer]) 319130561Sobrien if (*input_line_pointer++ == '"') 320130561Sobrien break; 321130561Sobrien c = *input_line_pointer; 322130561Sobrien *input_line_pointer = '\0'; 323130561Sobrien as_bad (_("bad .common segment %s"), p); 324130561Sobrien *input_line_pointer = c; 325130561Sobrien ignore_rest_of_line (); 326130561Sobrien return NULL; 32733965Sjdp } 328130561Sobrien /* ??? Don't ask me why these are always global. */ 329130561Sobrien is_local = 0; 33033965Sjdp } 33133965Sjdp else 33233965Sjdp { 333130561Sobrien input_line_pointer = save; 334130561Sobrien align = parse_align (is_local); 335130561Sobrien if (align == (addressT) -1) 336130561Sobrien return NULL; 33733965Sjdp } 33833965Sjdp } 339130561Sobrien 340130561Sobrien if (is_local) 341130561Sobrien { 342130561Sobrien bss_alloc (symbolP, size, align); 343130561Sobrien S_CLEAR_EXTERNAL (symbolP); 344130561Sobrien } 34533965Sjdp else 34633965Sjdp { 347130561Sobrien S_SET_VALUE (symbolP, size); 348130561Sobrien S_SET_ALIGN (symbolP, align); 349130561Sobrien S_SET_EXTERNAL (symbolP); 350218822Sdim S_SET_SEGMENT (symbolP, elf_com_section_ptr); 35133965Sjdp } 35233965Sjdp 35360484Sobrien symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT; 35433965Sjdp 355104834Sobrien return symbolP; 35633965Sjdp} 35733965Sjdp 358104834Sobrienvoid 359130561Sobrienobj_elf_common (int is_common) 360104834Sobrien{ 361130561Sobrien if (flag_mri && is_common) 362130561Sobrien s_mri_common (0); 363130561Sobrien else 364130561Sobrien s_comm_internal (0, elf_common_parse); 365104834Sobrien} 366104834Sobrien 36733965Sjdpstatic void 368130561Sobrienobj_elf_tls_common (int ignore ATTRIBUTE_UNUSED) 369104834Sobrien{ 370130561Sobrien symbolS *symbolP = s_comm_internal (0, elf_common_parse); 371104834Sobrien 372104834Sobrien if (symbolP) 373104834Sobrien symbol_get_bfdsym (symbolP)->flags |= BSF_THREAD_LOCAL; 374104834Sobrien} 375104834Sobrien 376104834Sobrienstatic void 377130561Sobrienobj_elf_lcomm (int ignore ATTRIBUTE_UNUSED) 37833965Sjdp{ 379130561Sobrien symbolS *symbolP = s_comm_internal (0, s_lcomm_internal); 380130561Sobrien 381130561Sobrien if (symbolP) 382130561Sobrien symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT; 383130561Sobrien} 384130561Sobrien 385130561Sobrienstatic void 386130561Sobrienobj_elf_local (int ignore ATTRIBUTE_UNUSED) 387130561Sobrien{ 38833965Sjdp char *name; 38933965Sjdp int c; 39033965Sjdp symbolS *symbolP; 39133965Sjdp 39233965Sjdp do 39333965Sjdp { 39433965Sjdp name = input_line_pointer; 39533965Sjdp c = get_symbol_end (); 39633965Sjdp symbolP = symbol_find_or_make (name); 39733965Sjdp *input_line_pointer = c; 39833965Sjdp SKIP_WHITESPACE (); 39933965Sjdp S_CLEAR_EXTERNAL (symbolP); 40060484Sobrien symbol_get_obj (symbolP)->local = 1; 40133965Sjdp if (c == ',') 40233965Sjdp { 40333965Sjdp input_line_pointer++; 40433965Sjdp SKIP_WHITESPACE (); 40533965Sjdp if (*input_line_pointer == '\n') 40633965Sjdp c = '\n'; 40733965Sjdp } 40833965Sjdp } 40933965Sjdp while (c == ','); 41033965Sjdp demand_empty_rest_of_line (); 41133965Sjdp} 41233965Sjdp 41333965Sjdpstatic void 414130561Sobrienobj_elf_weak (int ignore ATTRIBUTE_UNUSED) 41533965Sjdp{ 41633965Sjdp char *name; 41733965Sjdp int c; 41833965Sjdp symbolS *symbolP; 41933965Sjdp 42033965Sjdp do 42133965Sjdp { 42233965Sjdp name = input_line_pointer; 42333965Sjdp c = get_symbol_end (); 42433965Sjdp symbolP = symbol_find_or_make (name); 42533965Sjdp *input_line_pointer = c; 42633965Sjdp SKIP_WHITESPACE (); 42733965Sjdp S_SET_WEAK (symbolP); 42860484Sobrien symbol_get_obj (symbolP)->local = 1; 42933965Sjdp if (c == ',') 43033965Sjdp { 43133965Sjdp input_line_pointer++; 43233965Sjdp SKIP_WHITESPACE (); 43333965Sjdp if (*input_line_pointer == '\n') 43433965Sjdp c = '\n'; 43533965Sjdp } 43633965Sjdp } 43733965Sjdp while (c == ','); 43833965Sjdp demand_empty_rest_of_line (); 43933965Sjdp} 44033965Sjdp 44160484Sobrienstatic void 442130561Sobrienobj_elf_visibility (int visibility) 44360484Sobrien{ 44460484Sobrien char *name; 44560484Sobrien int c; 44660484Sobrien symbolS *symbolP; 44760484Sobrien asymbol *bfdsym; 44860484Sobrien elf_symbol_type *elfsym; 44960484Sobrien 45060484Sobrien do 45160484Sobrien { 45260484Sobrien name = input_line_pointer; 45360484Sobrien c = get_symbol_end (); 45460484Sobrien symbolP = symbol_find_or_make (name); 45560484Sobrien *input_line_pointer = c; 45660484Sobrien 45760484Sobrien SKIP_WHITESPACE (); 45860484Sobrien 45960484Sobrien bfdsym = symbol_get_bfdsym (symbolP); 46060484Sobrien elfsym = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym); 46160484Sobrien 46260484Sobrien assert (elfsym); 46360484Sobrien 464107492Sobrien elfsym->internal_elf_sym.st_other &= ~3; 465107492Sobrien elfsym->internal_elf_sym.st_other |= visibility; 46660484Sobrien 46760484Sobrien if (c == ',') 46860484Sobrien { 46960484Sobrien input_line_pointer ++; 47060484Sobrien 47160484Sobrien SKIP_WHITESPACE (); 47260484Sobrien 47360484Sobrien if (*input_line_pointer == '\n') 47460484Sobrien c = '\n'; 47560484Sobrien } 47660484Sobrien } 47760484Sobrien while (c == ','); 47860484Sobrien 47960484Sobrien demand_empty_rest_of_line (); 48060484Sobrien} 48160484Sobrien 48233965Sjdpstatic segT previous_section; 48333965Sjdpstatic int previous_subsection; 48433965Sjdp 48560484Sobrienstruct section_stack 48660484Sobrien{ 48760484Sobrien struct section_stack *next; 48860484Sobrien segT seg, prev_seg; 48960484Sobrien int subseg, prev_subseg; 49060484Sobrien}; 49160484Sobrien 49260484Sobrienstatic struct section_stack *section_stack; 49360484Sobrien 494218822Sdimstatic bfd_boolean 495218822Sdimget_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf) 496218822Sdim{ 497218822Sdim const char *gname = inf; 498218822Sdim const char *group_name = elf_group_name (sec); 499218822Sdim 500218822Sdim return (group_name == gname 501218822Sdim || (group_name != NULL 502218822Sdim && gname != NULL 503218822Sdim && strcmp (group_name, gname) == 0)); 504218822Sdim} 505218822Sdim 50633965Sjdp/* Handle the .section pseudo-op. This code supports two different 50733965Sjdp syntaxes. 50833965Sjdp 50933965Sjdp The first is found on Solaris, and looks like 51033965Sjdp .section ".sec1",#alloc,#execinstr,#write 51133965Sjdp Here the names after '#' are the SHF_* flags to turn on for the 51233965Sjdp section. I'm not sure how it determines the SHT_* type (BFD 51333965Sjdp doesn't really give us control over the type, anyhow). 51433965Sjdp 51533965Sjdp The second format is found on UnixWare, and probably most SVR4 51633965Sjdp machines, and looks like 51733965Sjdp .section .sec1,"a",@progbits 51833965Sjdp The quoted string may contain any combination of a, w, x, and 51933965Sjdp represents the SHF_* flags to turn on for the section. The string 52033965Sjdp beginning with '@' can be progbits or nobits. There should be 52133965Sjdp other possibilities, but I don't know what they are. In any case, 52233965Sjdp BFD doesn't really let us set the section type. */ 52333965Sjdp 524130561Sobrienvoid 525130561Sobrienobj_elf_change_section (const char *name, 526130561Sobrien int type, 527130561Sobrien int attr, 528130561Sobrien int entsize, 529130561Sobrien const char *group_name, 530130561Sobrien int linkonce, 531130561Sobrien int push) 53233965Sjdp{ 53377298Sobrien asection *old_sec; 53433965Sjdp segT sec; 53577298Sobrien flagword flags; 536218822Sdim const struct elf_backend_data *bed; 537130561Sobrien const struct bfd_elf_special_section *ssect; 53833965Sjdp 53933965Sjdp#ifdef md_flush_pending_output 54033965Sjdp md_flush_pending_output (); 54133965Sjdp#endif 54233965Sjdp 54360484Sobrien /* Switch to the section, creating it if necessary. */ 54460484Sobrien if (push) 54560484Sobrien { 54660484Sobrien struct section_stack *elt; 54760484Sobrien elt = xmalloc (sizeof (struct section_stack)); 54860484Sobrien elt->next = section_stack; 54960484Sobrien elt->seg = now_seg; 55060484Sobrien elt->prev_seg = previous_section; 55160484Sobrien elt->subseg = now_subseg; 55260484Sobrien elt->prev_subseg = previous_subsection; 55360484Sobrien section_stack = elt; 55460484Sobrien } 55560484Sobrien previous_section = now_seg; 55660484Sobrien previous_subsection = now_subseg; 55760484Sobrien 558218822Sdim old_sec = bfd_get_section_by_name_if (stdoutput, name, get_section, 559218822Sdim (void *) group_name); 560218822Sdim if (old_sec) 561218822Sdim { 562218822Sdim sec = old_sec; 563218822Sdim subseg_set (sec, 0); 564218822Sdim } 565218822Sdim else 566218822Sdim sec = subseg_force_new (name, 0); 56760484Sobrien 568218822Sdim bed = get_elf_backend_data (stdoutput); 569218822Sdim ssect = (*bed->get_sec_type_attr) (stdoutput, sec); 570218822Sdim 571130561Sobrien if (ssect != NULL) 572130561Sobrien { 573130561Sobrien bfd_boolean override = FALSE; 574130561Sobrien 575130561Sobrien if (type == SHT_NULL) 576130561Sobrien type = ssect->type; 577130561Sobrien else if (type != ssect->type) 578130561Sobrien { 579130561Sobrien if (old_sec == NULL 580130561Sobrien /* FIXME: gcc, as of 2002-10-22, will emit 581130561Sobrien 582130561Sobrien .section .init_array,"aw",@progbits 583130561Sobrien 584130561Sobrien for __attribute__ ((section (".init_array"))). 585218822Sdim "@progbits" is incorrect. Also for x86-64 large bss 586218822Sdim sections, gcc, as of 2005-07-06, will emit 587218822Sdim 588218822Sdim .section .lbss,"aw",@progbits 589218822Sdim 590130561Sobrien "@progbits" is incorrect. */ 591218822Sdim#ifdef TC_I386 592218822Sdim && (bed->s->arch_size != 64 593218822Sdim || !(ssect->attr & SHF_X86_64_LARGE)) 594218822Sdim#endif 595130561Sobrien && ssect->type != SHT_INIT_ARRAY 596130561Sobrien && ssect->type != SHT_FINI_ARRAY 597130561Sobrien && ssect->type != SHT_PREINIT_ARRAY) 598130561Sobrien { 599130561Sobrien /* We allow to specify any type for a .note section. */ 600130561Sobrien if (ssect->type != SHT_NOTE) 601130561Sobrien as_warn (_("setting incorrect section type for %s"), 602130561Sobrien name); 603130561Sobrien } 604130561Sobrien else 605130561Sobrien { 606130561Sobrien as_warn (_("ignoring incorrect section type for %s"), 607130561Sobrien name); 608130561Sobrien type = ssect->type; 609130561Sobrien } 610130561Sobrien } 611130561Sobrien 612130561Sobrien if (old_sec == NULL && (attr & ~ssect->attr) != 0) 613130561Sobrien { 614130561Sobrien /* As a GNU extension, we permit a .note section to be 615130561Sobrien allocatable. If the linker sees an allocatable .note 616130561Sobrien section, it will create a PT_NOTE segment in the output 617130561Sobrien file. We also allow "x" for .note.GNU-stack. */ 618130561Sobrien if (ssect->type == SHT_NOTE 619130561Sobrien && (attr == SHF_ALLOC || attr == SHF_EXECINSTR)) 620130561Sobrien ; 621130561Sobrien /* Allow different SHF_MERGE and SHF_STRINGS if we have 622130561Sobrien something like .rodata.str. */ 623130561Sobrien else if (ssect->suffix_length == -2 624130561Sobrien && name[ssect->prefix_length] == '.' 625130561Sobrien && (attr 626130561Sobrien & ~ssect->attr 627130561Sobrien & ~SHF_MERGE 628130561Sobrien & ~SHF_STRINGS) == 0) 629130561Sobrien ; 630130561Sobrien /* .interp, .strtab and .symtab can have SHF_ALLOC. */ 631130561Sobrien else if (attr == SHF_ALLOC 632130561Sobrien && (strcmp (name, ".interp") == 0 633130561Sobrien || strcmp (name, ".strtab") == 0 634130561Sobrien || strcmp (name, ".symtab") == 0)) 635130561Sobrien override = TRUE; 636218822Sdim /* .note.GNU-stack can have SHF_EXECINSTR. */ 637218822Sdim else if (attr == SHF_EXECINSTR 638218822Sdim && strcmp (name, ".note.GNU-stack") == 0) 639218822Sdim override = TRUE; 640218822Sdim#ifdef TC_ALPHA 641218822Sdim /* A section on Alpha may have SHF_ALPHA_GPREL. */ 642218822Sdim else if ((attr & ~ssect->attr) == SHF_ALPHA_GPREL) 643218822Sdim override = TRUE; 644218822Sdim#endif 645130561Sobrien else 646130561Sobrien { 647218822Sdim if (group_name == NULL) 648218822Sdim as_warn (_("setting incorrect section attributes for %s"), 649218822Sdim name); 650130561Sobrien override = TRUE; 651130561Sobrien } 652130561Sobrien } 653130561Sobrien if (!override && old_sec == NULL) 654130561Sobrien attr |= ssect->attr; 655130561Sobrien } 65660484Sobrien 65777298Sobrien /* Convert ELF type and flags to BFD flags. */ 65877298Sobrien flags = (SEC_RELOC 65977298Sobrien | ((attr & SHF_WRITE) ? 0 : SEC_READONLY) 66077298Sobrien | ((attr & SHF_ALLOC) ? SEC_ALLOC : 0) 66177298Sobrien | (((attr & SHF_ALLOC) && type != SHT_NOBITS) ? SEC_LOAD : 0) 66289857Sobrien | ((attr & SHF_EXECINSTR) ? SEC_CODE : 0) 66389857Sobrien | ((attr & SHF_MERGE) ? SEC_MERGE : 0) 664104834Sobrien | ((attr & SHF_STRINGS) ? SEC_STRINGS : 0) 665104834Sobrien | ((attr & SHF_TLS) ? SEC_THREAD_LOCAL : 0)); 66660484Sobrien#ifdef md_elf_section_flags 66777298Sobrien flags = md_elf_section_flags (flags, attr, type); 66860484Sobrien#endif 66960484Sobrien 670218822Sdim if (linkonce) 671218822Sdim flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; 672218822Sdim 67377298Sobrien if (old_sec == NULL) 67477298Sobrien { 67577298Sobrien symbolS *secsym; 67677298Sobrien 677218822Sdim elf_section_type (sec) = type; 678218822Sdim elf_section_flags (sec) = attr; 679218822Sdim 68060484Sobrien /* Prevent SEC_HAS_CONTENTS from being inadvertently set. */ 68160484Sobrien if (type == SHT_NOBITS) 682130561Sobrien seg_info (sec)->bss = 1; 68360484Sobrien 68460484Sobrien bfd_set_section_flags (stdoutput, sec, flags); 68589857Sobrien if (flags & SEC_MERGE) 68689857Sobrien sec->entsize = entsize; 68789857Sobrien elf_group_name (sec) = group_name; 68860484Sobrien 68960484Sobrien /* Add a symbol for this section to the symbol table. */ 69060484Sobrien secsym = symbol_find (name); 69160484Sobrien if (secsym != NULL) 69260484Sobrien symbol_set_bfdsym (secsym, sec->symbol); 69360484Sobrien else 694130561Sobrien symbol_table_insert (section_symbol (sec)); 69560484Sobrien } 696218822Sdim else 69777298Sobrien { 698218822Sdim if (type != SHT_NULL 699218822Sdim && (unsigned) type != elf_section_type (old_sec)) 700218822Sdim as_warn (_("ignoring changed section type for %s"), name); 701218822Sdim 702218822Sdim if (attr != 0) 703218822Sdim { 704218822Sdim /* If section attributes are specified the second time we see a 705218822Sdim particular section, then check that they are the same as we 706218822Sdim saw the first time. */ 707218822Sdim if (((old_sec->flags ^ flags) 708218822Sdim & (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE 709218822Sdim | SEC_EXCLUDE | SEC_SORT_ENTRIES | SEC_MERGE | SEC_STRINGS 710218822Sdim | SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD 711218822Sdim | SEC_THREAD_LOCAL))) 712218822Sdim as_warn (_("ignoring changed section attributes for %s"), name); 713218822Sdim if ((flags & SEC_MERGE) && old_sec->entsize != (unsigned) entsize) 714218822Sdim as_warn (_("ignoring changed section entity size for %s"), name); 715218822Sdim } 71677298Sobrien } 71760484Sobrien 71860484Sobrien#ifdef md_elf_section_change_hook 71977298Sobrien md_elf_section_change_hook (); 72060484Sobrien#endif 72160484Sobrien} 72260484Sobrien 72389857Sobrienstatic int 724130561Sobrienobj_elf_parse_section_letters (char *str, size_t len) 72560484Sobrien{ 72660484Sobrien int attr = 0; 72760484Sobrien 72860484Sobrien while (len > 0) 72960484Sobrien { 73060484Sobrien switch (*str) 73160484Sobrien { 73260484Sobrien case 'a': 73360484Sobrien attr |= SHF_ALLOC; 73460484Sobrien break; 73560484Sobrien case 'w': 73660484Sobrien attr |= SHF_WRITE; 73760484Sobrien break; 73860484Sobrien case 'x': 73960484Sobrien attr |= SHF_EXECINSTR; 74060484Sobrien break; 74189857Sobrien case 'M': 74289857Sobrien attr |= SHF_MERGE; 74389857Sobrien break; 74489857Sobrien case 'S': 74589857Sobrien attr |= SHF_STRINGS; 74689857Sobrien break; 74789857Sobrien case 'G': 74889857Sobrien attr |= SHF_GROUP; 74989857Sobrien break; 750104834Sobrien case 'T': 751104834Sobrien attr |= SHF_TLS; 752104834Sobrien break; 75389857Sobrien /* Compatibility. */ 75489857Sobrien case 'm': 75589857Sobrien if (*(str - 1) == 'a') 75689857Sobrien { 75789857Sobrien attr |= SHF_MERGE; 75889857Sobrien if (len > 1 && str[1] == 's') 75989857Sobrien { 76089857Sobrien attr |= SHF_STRINGS; 76189857Sobrien str++, len--; 76289857Sobrien } 76389857Sobrien break; 76489857Sobrien } 76560484Sobrien default: 76660484Sobrien { 767104834Sobrien char *bad_msg = _("unrecognized .section attribute: want a,w,x,M,S,G,T"); 76860484Sobrien#ifdef md_elf_section_letter 76960484Sobrien int md_attr = md_elf_section_letter (*str, &bad_msg); 77060484Sobrien if (md_attr >= 0) 77160484Sobrien attr |= md_attr; 77260484Sobrien else 77360484Sobrien#endif 774130561Sobrien as_fatal ("%s", bad_msg); 77560484Sobrien } 77660484Sobrien break; 77760484Sobrien } 77860484Sobrien str++, len--; 77960484Sobrien } 78060484Sobrien 78160484Sobrien return attr; 78260484Sobrien} 78360484Sobrien 78489857Sobrienstatic int 785130561Sobrienobj_elf_section_word (char *str, size_t len) 78660484Sobrien{ 78760484Sobrien if (len == 5 && strncmp (str, "write", 5) == 0) 78860484Sobrien return SHF_WRITE; 78960484Sobrien if (len == 5 && strncmp (str, "alloc", 5) == 0) 79060484Sobrien return SHF_ALLOC; 79160484Sobrien if (len == 9 && strncmp (str, "execinstr", 9) == 0) 79260484Sobrien return SHF_EXECINSTR; 793130561Sobrien if (len == 3 && strncmp (str, "tls", 3) == 0) 794130561Sobrien return SHF_TLS; 79560484Sobrien 79660484Sobrien#ifdef md_elf_section_word 79760484Sobrien { 79860484Sobrien int md_attr = md_elf_section_word (str, len); 79960484Sobrien if (md_attr >= 0) 80060484Sobrien return md_attr; 80160484Sobrien } 80260484Sobrien#endif 80360484Sobrien 80489857Sobrien as_warn (_("unrecognized section attribute")); 80560484Sobrien return 0; 80660484Sobrien} 80760484Sobrien 80889857Sobrienstatic int 809130561Sobrienobj_elf_section_type (char *str, size_t len) 81060484Sobrien{ 81160484Sobrien if (len == 8 && strncmp (str, "progbits", 8) == 0) 81260484Sobrien return SHT_PROGBITS; 81360484Sobrien if (len == 6 && strncmp (str, "nobits", 6) == 0) 81460484Sobrien return SHT_NOBITS; 815130561Sobrien if (len == 4 && strncmp (str, "note", 4) == 0) 816130561Sobrien return SHT_NOTE; 817218822Sdim if (len == 10 && strncmp (str, "init_array", 10) == 0) 818218822Sdim return SHT_INIT_ARRAY; 819218822Sdim if (len == 10 && strncmp (str, "fini_array", 10) == 0) 820218822Sdim return SHT_FINI_ARRAY; 821218822Sdim if (len == 13 && strncmp (str, "preinit_array", 13) == 0) 822218822Sdim return SHT_PREINIT_ARRAY; 82360484Sobrien 82460484Sobrien#ifdef md_elf_section_type 82560484Sobrien { 82660484Sobrien int md_type = md_elf_section_type (str, len); 82760484Sobrien if (md_type >= 0) 82860484Sobrien return md_type; 82960484Sobrien } 83060484Sobrien#endif 83160484Sobrien 83289857Sobrien as_warn (_("unrecognized section type")); 83360484Sobrien return 0; 83460484Sobrien} 83560484Sobrien 83689857Sobrien/* Get name of section. */ 83789857Sobrienstatic char * 838130561Sobrienobj_elf_section_name (void) 83989857Sobrien{ 84089857Sobrien char *name; 84189857Sobrien 84289857Sobrien SKIP_WHITESPACE (); 84389857Sobrien if (*input_line_pointer == '"') 84489857Sobrien { 84589857Sobrien int dummy; 84689857Sobrien 84789857Sobrien name = demand_copy_C_string (&dummy); 84889857Sobrien if (name == NULL) 84989857Sobrien { 85089857Sobrien ignore_rest_of_line (); 85189857Sobrien return NULL; 85289857Sobrien } 85389857Sobrien } 85489857Sobrien else 85589857Sobrien { 85689857Sobrien char *end = input_line_pointer; 85789857Sobrien 85889857Sobrien while (0 == strchr ("\n\t,; ", *end)) 85989857Sobrien end++; 86089857Sobrien if (end == input_line_pointer) 86189857Sobrien { 862130561Sobrien as_bad (_("missing name")); 86389857Sobrien ignore_rest_of_line (); 86489857Sobrien return NULL; 86589857Sobrien } 86689857Sobrien 86789857Sobrien name = xmalloc (end - input_line_pointer + 1); 86889857Sobrien memcpy (name, input_line_pointer, end - input_line_pointer); 86989857Sobrien name[end - input_line_pointer] = '\0'; 870130561Sobrien#ifdef tc_canonicalize_section_name 871130561Sobrien name = tc_canonicalize_section_name (name); 872130561Sobrien#endif 87389857Sobrien input_line_pointer = end; 87489857Sobrien } 87589857Sobrien SKIP_WHITESPACE (); 87689857Sobrien return name; 87789857Sobrien} 87889857Sobrien 87960484Sobrienvoid 880130561Sobrienobj_elf_section (int push) 88160484Sobrien{ 88289857Sobrien char *name, *group_name, *beg; 88360484Sobrien int type, attr, dummy; 88489857Sobrien int entsize; 885104834Sobrien int linkonce; 88660484Sobrien 88760484Sobrien#ifndef TC_I370 88833965Sjdp if (flag_mri) 88933965Sjdp { 89033965Sjdp char mri_type; 89133965Sjdp 89260484Sobrien#ifdef md_flush_pending_output 89377298Sobrien md_flush_pending_output (); 89460484Sobrien#endif 89560484Sobrien 89633965Sjdp previous_section = now_seg; 89733965Sjdp previous_subsection = now_subseg; 89833965Sjdp 89933965Sjdp s_mri_sect (&mri_type); 90033965Sjdp 90133965Sjdp#ifdef md_elf_section_change_hook 90233965Sjdp md_elf_section_change_hook (); 90333965Sjdp#endif 90433965Sjdp 90533965Sjdp return; 90633965Sjdp } 90760484Sobrien#endif /* ! defined (TC_I370) */ 90833965Sjdp 90989857Sobrien name = obj_elf_section_name (); 91089857Sobrien if (name == NULL) 91189857Sobrien return; 91233965Sjdp type = SHT_NULL; 91333965Sjdp attr = 0; 91489857Sobrien group_name = NULL; 91589857Sobrien entsize = 0; 916104834Sobrien linkonce = 0; 91733965Sjdp 91833965Sjdp if (*input_line_pointer == ',') 91933965Sjdp { 92033965Sjdp /* Skip the comma. */ 92133965Sjdp ++input_line_pointer; 92233965Sjdp SKIP_WHITESPACE (); 92338889Sjdp 92433965Sjdp if (*input_line_pointer == '"') 92533965Sjdp { 92660484Sobrien beg = demand_copy_C_string (&dummy); 92760484Sobrien if (beg == NULL) 92833965Sjdp { 92960484Sobrien ignore_rest_of_line (); 93060484Sobrien return; 93133965Sjdp } 93260484Sobrien attr |= obj_elf_parse_section_letters (beg, strlen (beg)); 93333965Sjdp 93433965Sjdp SKIP_WHITESPACE (); 93533965Sjdp if (*input_line_pointer == ',') 93633965Sjdp { 93760484Sobrien char c; 93889857Sobrien char *save = input_line_pointer; 93989857Sobrien 94033965Sjdp ++input_line_pointer; 94133965Sjdp SKIP_WHITESPACE (); 94260484Sobrien c = *input_line_pointer; 94360484Sobrien if (c == '"') 94433965Sjdp { 94560484Sobrien beg = demand_copy_C_string (&dummy); 94660484Sobrien if (beg == NULL) 94733965Sjdp { 94860484Sobrien ignore_rest_of_line (); 94960484Sobrien return; 95033965Sjdp } 95160484Sobrien type = obj_elf_section_type (beg, strlen (beg)); 95233965Sjdp } 95360484Sobrien else if (c == '@' || c == '%') 95460484Sobrien { 95560484Sobrien beg = ++input_line_pointer; 95660484Sobrien c = get_symbol_end (); 95760484Sobrien *input_line_pointer = c; 95860484Sobrien type = obj_elf_section_type (beg, input_line_pointer - beg); 95960484Sobrien } 96089857Sobrien else 96189857Sobrien input_line_pointer = save; 96233965Sjdp } 96389857Sobrien 96489857Sobrien SKIP_WHITESPACE (); 96589857Sobrien if ((attr & SHF_MERGE) != 0 && *input_line_pointer == ',') 96689857Sobrien { 96789857Sobrien ++input_line_pointer; 96889857Sobrien SKIP_WHITESPACE (); 96989857Sobrien entsize = get_absolute_expression (); 97089857Sobrien SKIP_WHITESPACE (); 97189857Sobrien if (entsize < 0) 97289857Sobrien { 97389857Sobrien as_warn (_("invalid merge entity size")); 97489857Sobrien attr &= ~SHF_MERGE; 97589857Sobrien entsize = 0; 97689857Sobrien } 97789857Sobrien } 97889857Sobrien else if ((attr & SHF_MERGE) != 0) 97989857Sobrien { 98089857Sobrien as_warn (_("entity size for SHF_MERGE not specified")); 98189857Sobrien attr &= ~SHF_MERGE; 98289857Sobrien } 98389857Sobrien 98489857Sobrien if ((attr & SHF_GROUP) != 0 && *input_line_pointer == ',') 98589857Sobrien { 98689857Sobrien ++input_line_pointer; 98789857Sobrien group_name = obj_elf_section_name (); 98889857Sobrien if (group_name == NULL) 98989857Sobrien attr &= ~SHF_GROUP; 990104834Sobrien else if (strncmp (input_line_pointer, ",comdat", 7) == 0) 991104834Sobrien { 992104834Sobrien input_line_pointer += 7; 993104834Sobrien linkonce = 1; 994104834Sobrien } 995104834Sobrien else if (strncmp (name, ".gnu.linkonce", 13) == 0) 996104834Sobrien linkonce = 1; 99789857Sobrien } 99889857Sobrien else if ((attr & SHF_GROUP) != 0) 99989857Sobrien { 100089857Sobrien as_warn (_("group name for SHF_GROUP not specified")); 100189857Sobrien attr &= ~SHF_GROUP; 100289857Sobrien } 100333965Sjdp } 100433965Sjdp else 100533965Sjdp { 100633965Sjdp do 100733965Sjdp { 100860484Sobrien char c; 100960484Sobrien 101033965Sjdp SKIP_WHITESPACE (); 101133965Sjdp if (*input_line_pointer != '#') 101233965Sjdp { 1013130561Sobrien as_bad (_("character following name is not '#'")); 101433965Sjdp ignore_rest_of_line (); 101533965Sjdp return; 101633965Sjdp } 101760484Sobrien beg = ++input_line_pointer; 101860484Sobrien c = get_symbol_end (); 101960484Sobrien *input_line_pointer = c; 102060484Sobrien 102160484Sobrien attr |= obj_elf_section_word (beg, input_line_pointer - beg); 102260484Sobrien 102333965Sjdp SKIP_WHITESPACE (); 102433965Sjdp } 102533965Sjdp while (*input_line_pointer++ == ','); 102633965Sjdp --input_line_pointer; 102733965Sjdp } 102833965Sjdp } 102933965Sjdp 103060484Sobrien demand_empty_rest_of_line (); 103133965Sjdp 1032104834Sobrien obj_elf_change_section (name, type, attr, entsize, group_name, linkonce, push); 103333965Sjdp} 103433965Sjdp 103533965Sjdp/* Change to the .data section. */ 103633965Sjdp 103760484Sobrienvoid 1038130561Sobrienobj_elf_data (int i) 103933965Sjdp{ 104033965Sjdp#ifdef md_flush_pending_output 104133965Sjdp md_flush_pending_output (); 104233965Sjdp#endif 104333965Sjdp 104433965Sjdp previous_section = now_seg; 104533965Sjdp previous_subsection = now_subseg; 104633965Sjdp s_data (i); 104733965Sjdp 104833965Sjdp#ifdef md_elf_section_change_hook 104933965Sjdp md_elf_section_change_hook (); 105033965Sjdp#endif 105133965Sjdp} 105233965Sjdp 105333965Sjdp/* Change to the .text section. */ 105433965Sjdp 105560484Sobrienvoid 1056130561Sobrienobj_elf_text (int i) 105733965Sjdp{ 105833965Sjdp#ifdef md_flush_pending_output 105933965Sjdp md_flush_pending_output (); 106033965Sjdp#endif 106133965Sjdp 106233965Sjdp previous_section = now_seg; 106333965Sjdp previous_subsection = now_subseg; 106433965Sjdp s_text (i); 106533965Sjdp 106633965Sjdp#ifdef md_elf_section_change_hook 106733965Sjdp md_elf_section_change_hook (); 106833965Sjdp#endif 106933965Sjdp} 107033965Sjdp 1071218822Sdim/* Change to the *ABS* section. */ 1072218822Sdim 1073218822Sdimvoid 1074218822Sdimobj_elf_struct (int i) 1075218822Sdim{ 1076218822Sdim#ifdef md_flush_pending_output 1077218822Sdim md_flush_pending_output (); 1078218822Sdim#endif 1079218822Sdim 1080218822Sdim previous_section = now_seg; 1081218822Sdim previous_subsection = now_subseg; 1082218822Sdim s_struct (i); 1083218822Sdim 1084218822Sdim#ifdef md_elf_section_change_hook 1085218822Sdim md_elf_section_change_hook (); 1086218822Sdim#endif 1087218822Sdim} 1088218822Sdim 108938889Sjdpstatic void 1090130561Sobrienobj_elf_subsection (int ignore ATTRIBUTE_UNUSED) 109138889Sjdp{ 109238889Sjdp register int temp; 109338889Sjdp 109438889Sjdp#ifdef md_flush_pending_output 109538889Sjdp md_flush_pending_output (); 109638889Sjdp#endif 109738889Sjdp 109838889Sjdp previous_section = now_seg; 109938889Sjdp previous_subsection = now_subseg; 110038889Sjdp 110138889Sjdp temp = get_absolute_expression (); 110238889Sjdp subseg_set (now_seg, (subsegT) temp); 110338889Sjdp demand_empty_rest_of_line (); 110438889Sjdp 110538889Sjdp#ifdef md_elf_section_change_hook 110638889Sjdp md_elf_section_change_hook (); 110738889Sjdp#endif 110838889Sjdp} 110938889Sjdp 111033965Sjdp/* This can be called from the processor backends if they change 111133965Sjdp sections. */ 111233965Sjdp 111333965Sjdpvoid 1114130561Sobrienobj_elf_section_change_hook (void) 111533965Sjdp{ 111633965Sjdp previous_section = now_seg; 111733965Sjdp previous_subsection = now_subseg; 111833965Sjdp} 111933965Sjdp 112033965Sjdpvoid 1121130561Sobrienobj_elf_previous (int ignore ATTRIBUTE_UNUSED) 112233965Sjdp{ 112360484Sobrien segT new_section; 112460484Sobrien int new_subsection; 112560484Sobrien 112633965Sjdp if (previous_section == 0) 112733965Sjdp { 112889857Sobrien as_warn (_(".previous without corresponding .section; ignored")); 112933965Sjdp return; 113033965Sjdp } 113133965Sjdp 113233965Sjdp#ifdef md_flush_pending_output 113333965Sjdp md_flush_pending_output (); 113433965Sjdp#endif 113533965Sjdp 113660484Sobrien new_section = previous_section; 113760484Sobrien new_subsection = previous_subsection; 113860484Sobrien previous_section = now_seg; 113960484Sobrien previous_subsection = now_subseg; 114060484Sobrien subseg_set (new_section, new_subsection); 114133965Sjdp 114233965Sjdp#ifdef md_elf_section_change_hook 114333965Sjdp md_elf_section_change_hook (); 114433965Sjdp#endif 114533965Sjdp} 114633965Sjdp 114733965Sjdpstatic void 1148130561Sobrienobj_elf_popsection (int xxx ATTRIBUTE_UNUSED) 114960484Sobrien{ 115060484Sobrien struct section_stack *top = section_stack; 115160484Sobrien 115260484Sobrien if (top == NULL) 115360484Sobrien { 115489857Sobrien as_warn (_(".popsection without corresponding .pushsection; ignored")); 115560484Sobrien return; 115660484Sobrien } 115760484Sobrien 115860484Sobrien#ifdef md_flush_pending_output 115960484Sobrien md_flush_pending_output (); 116060484Sobrien#endif 116160484Sobrien 116260484Sobrien section_stack = top->next; 116360484Sobrien previous_section = top->prev_seg; 116460484Sobrien previous_subsection = top->prev_subseg; 116560484Sobrien subseg_set (top->seg, top->subseg); 116660484Sobrien free (top); 116760484Sobrien 116860484Sobrien#ifdef md_elf_section_change_hook 116960484Sobrien md_elf_section_change_hook (); 117060484Sobrien#endif 117160484Sobrien} 117260484Sobrien 117360484Sobrienstatic void 1174130561Sobrienobj_elf_line (int ignore ATTRIBUTE_UNUSED) 117533965Sjdp{ 117633965Sjdp /* Assume delimiter is part of expression. BSD4.2 as fails with 117777298Sobrien delightful bug, so we are not being incompatible here. */ 1178130561Sobrien new_logical_line (NULL, get_absolute_expression ()); 117933965Sjdp demand_empty_rest_of_line (); 118033965Sjdp} 118133965Sjdp 118260484Sobrien/* This handles the .symver pseudo-op, which is used to specify a 118333965Sjdp symbol version. The syntax is ``.symver NAME,SYMVERNAME''. 118433965Sjdp SYMVERNAME may contain ELF_VER_CHR ('@') characters. This 118533965Sjdp pseudo-op causes the assembler to emit a symbol named SYMVERNAME 118633965Sjdp with the same value as the symbol NAME. */ 118733965Sjdp 118833965Sjdpstatic void 1189130561Sobrienobj_elf_symver (int ignore ATTRIBUTE_UNUSED) 119033965Sjdp{ 119133965Sjdp char *name; 119233965Sjdp char c; 119389857Sobrien char old_lexat; 119433965Sjdp symbolS *sym; 119533965Sjdp 119633965Sjdp name = input_line_pointer; 119733965Sjdp c = get_symbol_end (); 119833965Sjdp 119933965Sjdp sym = symbol_find_or_make (name); 120033965Sjdp 120133965Sjdp *input_line_pointer = c; 120233965Sjdp 120333965Sjdp SKIP_WHITESPACE (); 120433965Sjdp if (*input_line_pointer != ',') 120533965Sjdp { 120660484Sobrien as_bad (_("expected comma after name in .symver")); 120733965Sjdp ignore_rest_of_line (); 120833965Sjdp return; 120933965Sjdp } 121033965Sjdp 121133965Sjdp ++input_line_pointer; 1212130561Sobrien SKIP_WHITESPACE (); 121333965Sjdp name = input_line_pointer; 121433965Sjdp 121589857Sobrien /* Temporarily include '@' in symbol names. */ 121689857Sobrien old_lexat = lex_type[(unsigned char) '@']; 121789857Sobrien lex_type[(unsigned char) '@'] |= LEX_NAME; 121889857Sobrien c = get_symbol_end (); 121989857Sobrien lex_type[(unsigned char) '@'] = old_lexat; 122089857Sobrien 122177298Sobrien if (symbol_get_obj (sym)->versioned_name == NULL) 122277298Sobrien { 122377298Sobrien symbol_get_obj (sym)->versioned_name = xstrdup (name); 122433965Sjdp 122577298Sobrien *input_line_pointer = c; 122633965Sjdp 122777298Sobrien if (strchr (symbol_get_obj (sym)->versioned_name, 122877298Sobrien ELF_VER_CHR) == NULL) 122977298Sobrien { 123077298Sobrien as_bad (_("missing version name in `%s' for symbol `%s'"), 123177298Sobrien symbol_get_obj (sym)->versioned_name, 123277298Sobrien S_GET_NAME (sym)); 123377298Sobrien ignore_rest_of_line (); 123477298Sobrien return; 123577298Sobrien } 123677298Sobrien } 123777298Sobrien else 123833965Sjdp { 123977298Sobrien if (strcmp (symbol_get_obj (sym)->versioned_name, name)) 124077298Sobrien { 124177298Sobrien as_bad (_("multiple versions [`%s'|`%s'] for symbol `%s'"), 124277298Sobrien name, symbol_get_obj (sym)->versioned_name, 124377298Sobrien S_GET_NAME (sym)); 124477298Sobrien ignore_rest_of_line (); 124577298Sobrien return; 124677298Sobrien } 124777298Sobrien 124877298Sobrien *input_line_pointer = c; 124933965Sjdp } 125033965Sjdp 125133965Sjdp demand_empty_rest_of_line (); 125233965Sjdp} 125333965Sjdp 125460484Sobrien/* This handles the .vtable_inherit pseudo-op, which is used to indicate 125560484Sobrien to the linker the hierarchy in which a particular table resides. The 125660484Sobrien syntax is ".vtable_inherit CHILDNAME, PARENTNAME". */ 125760484Sobrien 125877298Sobrienstruct fix * 1259130561Sobrienobj_elf_vtable_inherit (int ignore ATTRIBUTE_UNUSED) 126060484Sobrien{ 126160484Sobrien char *cname, *pname; 126260484Sobrien symbolS *csym, *psym; 126360484Sobrien char c, bad = 0; 126460484Sobrien 126560484Sobrien if (*input_line_pointer == '#') 126660484Sobrien ++input_line_pointer; 126760484Sobrien 126860484Sobrien cname = input_line_pointer; 126960484Sobrien c = get_symbol_end (); 127060484Sobrien csym = symbol_find (cname); 127160484Sobrien 127260484Sobrien /* GCFIXME: should check that we don't have two .vtable_inherits for 127360484Sobrien the same child symbol. Also, we can currently only do this if the 127460484Sobrien child symbol is already exists and is placed in a fragment. */ 127560484Sobrien 127660484Sobrien if (csym == NULL || symbol_get_frag (csym) == NULL) 127760484Sobrien { 127860484Sobrien as_bad ("expected `%s' to have already been set for .vtable_inherit", 127960484Sobrien cname); 128060484Sobrien bad = 1; 128160484Sobrien } 128260484Sobrien 128360484Sobrien *input_line_pointer = c; 128460484Sobrien 128560484Sobrien SKIP_WHITESPACE (); 128660484Sobrien if (*input_line_pointer != ',') 128760484Sobrien { 128860484Sobrien as_bad ("expected comma after name in .vtable_inherit"); 128960484Sobrien ignore_rest_of_line (); 129077298Sobrien return NULL; 129160484Sobrien } 129260484Sobrien 129360484Sobrien ++input_line_pointer; 129460484Sobrien SKIP_WHITESPACE (); 129560484Sobrien 129660484Sobrien if (*input_line_pointer == '#') 129760484Sobrien ++input_line_pointer; 129860484Sobrien 129960484Sobrien if (input_line_pointer[0] == '0' 130060484Sobrien && (input_line_pointer[1] == '\0' 130189857Sobrien || ISSPACE (input_line_pointer[1]))) 130260484Sobrien { 130360484Sobrien psym = section_symbol (absolute_section); 130460484Sobrien ++input_line_pointer; 130560484Sobrien } 130660484Sobrien else 130760484Sobrien { 130860484Sobrien pname = input_line_pointer; 130960484Sobrien c = get_symbol_end (); 131060484Sobrien psym = symbol_find_or_make (pname); 131160484Sobrien *input_line_pointer = c; 131260484Sobrien } 131360484Sobrien 131460484Sobrien demand_empty_rest_of_line (); 131560484Sobrien 131660484Sobrien if (bad) 131777298Sobrien return NULL; 131860484Sobrien 131960484Sobrien assert (symbol_get_value_expression (csym)->X_op == O_constant); 132077298Sobrien return fix_new (symbol_get_frag (csym), 132177298Sobrien symbol_get_value_expression (csym)->X_add_number, 132277298Sobrien 0, psym, 0, 0, BFD_RELOC_VTABLE_INHERIT); 132360484Sobrien} 132460484Sobrien 132560484Sobrien/* This handles the .vtable_entry pseudo-op, which is used to indicate 132660484Sobrien to the linker that a vtable slot was used. The syntax is 132760484Sobrien ".vtable_entry tablename, offset". */ 132860484Sobrien 132977298Sobrienstruct fix * 1330130561Sobrienobj_elf_vtable_entry (int ignore ATTRIBUTE_UNUSED) 133160484Sobrien{ 133260484Sobrien char *name; 133360484Sobrien symbolS *sym; 133460484Sobrien offsetT offset; 133560484Sobrien char c; 133660484Sobrien 133760484Sobrien if (*input_line_pointer == '#') 133860484Sobrien ++input_line_pointer; 133960484Sobrien 134060484Sobrien name = input_line_pointer; 134160484Sobrien c = get_symbol_end (); 134260484Sobrien sym = symbol_find_or_make (name); 134360484Sobrien *input_line_pointer = c; 134460484Sobrien 134560484Sobrien SKIP_WHITESPACE (); 134660484Sobrien if (*input_line_pointer != ',') 134760484Sobrien { 134860484Sobrien as_bad ("expected comma after name in .vtable_entry"); 134960484Sobrien ignore_rest_of_line (); 135077298Sobrien return NULL; 135160484Sobrien } 135260484Sobrien 135360484Sobrien ++input_line_pointer; 135460484Sobrien if (*input_line_pointer == '#') 135560484Sobrien ++input_line_pointer; 135660484Sobrien 135760484Sobrien offset = get_absolute_expression (); 135860484Sobrien 135977298Sobrien demand_empty_rest_of_line (); 136060484Sobrien 136177298Sobrien return fix_new (frag_now, frag_now_fix (), 0, sym, offset, 0, 136277298Sobrien BFD_RELOC_VTABLE_ENTRY); 136360484Sobrien} 136460484Sobrien 136533965Sjdpvoid 1366130561Sobrienelf_obj_read_begin_hook (void) 136733965Sjdp{ 136833965Sjdp#ifdef NEED_ECOFF_DEBUG 136933965Sjdp if (ECOFF_DEBUGGING) 137033965Sjdp ecoff_read_begin_hook (); 137133965Sjdp#endif 137233965Sjdp} 137333965Sjdp 137433965Sjdpvoid 1375130561Sobrienelf_obj_symbol_new_hook (symbolS *symbolP) 137633965Sjdp{ 137760484Sobrien struct elf_obj_sy *sy_obj; 137833965Sjdp 137960484Sobrien sy_obj = symbol_get_obj (symbolP); 138060484Sobrien sy_obj->size = NULL; 138160484Sobrien sy_obj->versioned_name = NULL; 138260484Sobrien 138333965Sjdp#ifdef NEED_ECOFF_DEBUG 138433965Sjdp if (ECOFF_DEBUGGING) 138533965Sjdp ecoff_symbol_new_hook (symbolP); 138633965Sjdp#endif 138733965Sjdp} 138833965Sjdp 138989857Sobrien/* When setting one symbol equal to another, by default we probably 139089857Sobrien want them to have the same "size", whatever it means in the current 139189857Sobrien context. */ 139289857Sobrien 139333965Sjdpvoid 1394130561Sobrienelf_copy_symbol_attributes (symbolS *dest, symbolS *src) 139589857Sobrien{ 139689857Sobrien struct elf_obj_sy *srcelf = symbol_get_obj (src); 139789857Sobrien struct elf_obj_sy *destelf = symbol_get_obj (dest); 139889857Sobrien if (srcelf->size) 139989857Sobrien { 140089857Sobrien if (destelf->size == NULL) 1401130561Sobrien destelf->size = xmalloc (sizeof (expressionS)); 140289857Sobrien *destelf->size = *srcelf->size; 140389857Sobrien } 140489857Sobrien else 140589857Sobrien { 140689857Sobrien if (destelf->size != NULL) 140789857Sobrien free (destelf->size); 140889857Sobrien destelf->size = NULL; 140989857Sobrien } 141089857Sobrien S_SET_SIZE (dest, S_GET_SIZE (src)); 141194536Sobrien /* Don't copy visibility. */ 141294536Sobrien S_SET_OTHER (dest, (ELF_ST_VISIBILITY (S_GET_OTHER (dest)) 141394536Sobrien | (S_GET_OTHER (src) & ~ELF_ST_VISIBILITY (-1)))); 141489857Sobrien} 141589857Sobrien 141689857Sobrienvoid 1417130561Sobrienobj_elf_version (int ignore ATTRIBUTE_UNUSED) 141833965Sjdp{ 141933965Sjdp char *name; 142033965Sjdp unsigned int c; 142133965Sjdp char *p; 142233965Sjdp asection *seg = now_seg; 142333965Sjdp subsegT subseg = now_subseg; 142433965Sjdp Elf_Internal_Note i_note; 142533965Sjdp Elf_External_Note e_note; 1426130561Sobrien asection *note_secp = NULL; 142733965Sjdp 142833965Sjdp SKIP_WHITESPACE (); 142933965Sjdp if (*input_line_pointer == '\"') 143033965Sjdp { 1431218822Sdim unsigned int len; 1432218822Sdim 143377298Sobrien ++input_line_pointer; /* -> 1st char of string. */ 143433965Sjdp name = input_line_pointer; 143533965Sjdp 143633965Sjdp while (is_a_char (c = next_char_of_string ())) 143733965Sjdp ; 143833965Sjdp c = *input_line_pointer; 143933965Sjdp *input_line_pointer = '\0'; 144033965Sjdp *(input_line_pointer - 1) = '\0'; 144133965Sjdp *input_line_pointer = c; 144233965Sjdp 1443218822Sdim /* Create the .note section. */ 144433965Sjdp note_secp = subseg_new (".note", 0); 144533965Sjdp bfd_set_section_flags (stdoutput, 144633965Sjdp note_secp, 144733965Sjdp SEC_HAS_CONTENTS | SEC_READONLY); 144833965Sjdp 1449218822Sdim /* Process the version string. */ 1450218822Sdim len = strlen (name) + 1; 145133965Sjdp 1452218822Sdim /* PR 3456: Although the name field is padded out to an 4-byte 1453218822Sdim boundary, the namesz field should not be adjusted. */ 1454218822Sdim i_note.namesz = len; 1455218822Sdim i_note.descsz = 0; /* No description. */ 145633965Sjdp i_note.type = NT_VERSION; 145733965Sjdp p = frag_more (sizeof (e_note.namesz)); 1458130561Sobrien md_number_to_chars (p, i_note.namesz, sizeof (e_note.namesz)); 145933965Sjdp p = frag_more (sizeof (e_note.descsz)); 1460130561Sobrien md_number_to_chars (p, i_note.descsz, sizeof (e_note.descsz)); 146133965Sjdp p = frag_more (sizeof (e_note.type)); 1462130561Sobrien md_number_to_chars (p, i_note.type, sizeof (e_note.type)); 1463218822Sdim p = frag_more (len); 1464218822Sdim memcpy (p, name, len); 146533965Sjdp 146633965Sjdp frag_align (2, 0, 0); 146733965Sjdp 146833965Sjdp subseg_set (seg, subseg); 146933965Sjdp } 147033965Sjdp else 1471218822Sdim as_bad (_("expected quoted string")); 1472218822Sdim 147333965Sjdp demand_empty_rest_of_line (); 147433965Sjdp} 147533965Sjdp 147633965Sjdpstatic void 1477130561Sobrienobj_elf_size (int ignore ATTRIBUTE_UNUSED) 147833965Sjdp{ 147933965Sjdp char *name = input_line_pointer; 148033965Sjdp char c = get_symbol_end (); 148133965Sjdp char *p; 148233965Sjdp expressionS exp; 148333965Sjdp symbolS *sym; 148433965Sjdp 148533965Sjdp p = input_line_pointer; 148633965Sjdp *p = c; 148733965Sjdp SKIP_WHITESPACE (); 148833965Sjdp if (*input_line_pointer != ',') 148933965Sjdp { 149033965Sjdp *p = 0; 149160484Sobrien as_bad (_("expected comma after name `%s' in .size directive"), name); 149233965Sjdp *p = c; 149333965Sjdp ignore_rest_of_line (); 149433965Sjdp return; 149533965Sjdp } 149633965Sjdp input_line_pointer++; 149733965Sjdp expression (&exp); 149833965Sjdp if (exp.X_op == O_absent) 149933965Sjdp { 150060484Sobrien as_bad (_("missing expression in .size directive")); 150133965Sjdp exp.X_op = O_constant; 150233965Sjdp exp.X_add_number = 0; 150333965Sjdp } 150433965Sjdp *p = 0; 150533965Sjdp sym = symbol_find_or_make (name); 150633965Sjdp *p = c; 150733965Sjdp if (exp.X_op == O_constant) 150889857Sobrien { 150989857Sobrien S_SET_SIZE (sym, exp.X_add_number); 151089857Sobrien if (symbol_get_obj (sym)->size) 151189857Sobrien { 151289857Sobrien xfree (symbol_get_obj (sym)->size); 151389857Sobrien symbol_get_obj (sym)->size = NULL; 151489857Sobrien } 151589857Sobrien } 151633965Sjdp else 151733965Sjdp { 1518130561Sobrien symbol_get_obj (sym)->size = xmalloc (sizeof (expressionS)); 151960484Sobrien *symbol_get_obj (sym)->size = exp; 152033965Sjdp } 152133965Sjdp demand_empty_rest_of_line (); 152233965Sjdp} 152333965Sjdp 152433965Sjdp/* Handle the ELF .type pseudo-op. This sets the type of a symbol. 152577298Sobrien There are five syntaxes: 152660484Sobrien 152760484Sobrien The first (used on Solaris) is 152833965Sjdp .type SYM,#function 152933965Sjdp The second (used on UnixWare) is 153033965Sjdp .type SYM,@function 153133965Sjdp The third (reportedly to be used on Irix 6.0) is 153233965Sjdp .type SYM STT_FUNC 153360484Sobrien The fourth (used on NetBSD/Arm and Linux/ARM) is 153460484Sobrien .type SYM,%function 153577298Sobrien The fifth (used on SVR4/860) is 153677298Sobrien .type SYM,"function" 153733965Sjdp */ 153833965Sjdp 153933965Sjdpstatic void 1540130561Sobrienobj_elf_type (int ignore ATTRIBUTE_UNUSED) 154133965Sjdp{ 154233965Sjdp char *name; 154333965Sjdp char c; 154433965Sjdp int type; 154533965Sjdp const char *typename; 154633965Sjdp symbolS *sym; 154777298Sobrien elf_symbol_type *elfsym; 154833965Sjdp 154933965Sjdp name = input_line_pointer; 155033965Sjdp c = get_symbol_end (); 155133965Sjdp sym = symbol_find_or_make (name); 155277298Sobrien elfsym = (elf_symbol_type *) symbol_get_bfdsym (sym); 155333965Sjdp *input_line_pointer = c; 155433965Sjdp 155533965Sjdp SKIP_WHITESPACE (); 155633965Sjdp if (*input_line_pointer == ',') 155733965Sjdp ++input_line_pointer; 155833965Sjdp 155933965Sjdp SKIP_WHITESPACE (); 156060484Sobrien if ( *input_line_pointer == '#' 156160484Sobrien || *input_line_pointer == '@' 156277298Sobrien || *input_line_pointer == '"' 156360484Sobrien || *input_line_pointer == '%') 156433965Sjdp ++input_line_pointer; 156533965Sjdp 156633965Sjdp typename = input_line_pointer; 156733965Sjdp c = get_symbol_end (); 156833965Sjdp 156933965Sjdp type = 0; 157033965Sjdp if (strcmp (typename, "function") == 0 157133965Sjdp || strcmp (typename, "STT_FUNC") == 0) 157233965Sjdp type = BSF_FUNCTION; 157333965Sjdp else if (strcmp (typename, "object") == 0 157433965Sjdp || strcmp (typename, "STT_OBJECT") == 0) 157533965Sjdp type = BSF_OBJECT; 1576130561Sobrien else if (strcmp (typename, "tls_object") == 0 1577130561Sobrien || strcmp (typename, "STT_TLS") == 0) 1578130561Sobrien type = BSF_OBJECT | BSF_THREAD_LOCAL; 1579130561Sobrien else if (strcmp (typename, "notype") == 0 1580130561Sobrien || strcmp (typename, "STT_NOTYPE") == 0) 1581130561Sobrien ; 158277298Sobrien#ifdef md_elf_symbol_type 158377298Sobrien else if ((type = md_elf_symbol_type (typename, sym, elfsym)) != -1) 158477298Sobrien ; 158577298Sobrien#endif 158633965Sjdp else 158789857Sobrien as_bad (_("unrecognized symbol type \"%s\""), typename); 158833965Sjdp 158933965Sjdp *input_line_pointer = c; 159033965Sjdp 159177298Sobrien if (*input_line_pointer == '"') 159277298Sobrien ++input_line_pointer; 159333965Sjdp 159477298Sobrien elfsym->symbol.flags |= type; 159577298Sobrien 159633965Sjdp demand_empty_rest_of_line (); 159733965Sjdp} 159833965Sjdp 159933965Sjdpstatic void 1600130561Sobrienobj_elf_ident (int ignore ATTRIBUTE_UNUSED) 160133965Sjdp{ 160233965Sjdp static segT comment_section; 160333965Sjdp segT old_section = now_seg; 160433965Sjdp int old_subsection = now_subseg; 160533965Sjdp 160660484Sobrien#ifdef md_flush_pending_output 160760484Sobrien md_flush_pending_output (); 160860484Sobrien#endif 160960484Sobrien 161033965Sjdp if (!comment_section) 161133965Sjdp { 161233965Sjdp char *p; 161333965Sjdp comment_section = subseg_new (".comment", 0); 161433965Sjdp bfd_set_section_flags (stdoutput, comment_section, 161533965Sjdp SEC_READONLY | SEC_HAS_CONTENTS); 161633965Sjdp p = frag_more (1); 161733965Sjdp *p = 0; 161833965Sjdp } 161933965Sjdp else 162033965Sjdp subseg_set (comment_section, 0); 162133965Sjdp stringer (1); 162233965Sjdp subseg_set (old_section, old_subsection); 162333965Sjdp} 162433965Sjdp 162533965Sjdp#ifdef INIT_STAB_SECTION 162633965Sjdp 162733965Sjdp/* The first entry in a .stabs section is special. */ 162833965Sjdp 162933965Sjdpvoid 1630130561Sobrienobj_elf_init_stab_section (segT seg) 163133965Sjdp{ 163233965Sjdp char *file; 163333965Sjdp char *p; 163433965Sjdp char *stabstr_name; 163533965Sjdp unsigned int stroff; 163633965Sjdp 163733965Sjdp /* Force the section to align to a longword boundary. Without this, 163833965Sjdp UnixWare ar crashes. */ 1639223262Sbenl (void) bfd_set_section_alignment (stdoutput, seg, 2); 164033965Sjdp 164177298Sobrien /* Make space for this first symbol. */ 164233965Sjdp p = frag_more (12); 164377298Sobrien /* Zero it out. */ 164433965Sjdp memset (p, 0, 12); 1645130561Sobrien as_where (&file, NULL); 1646130561Sobrien stabstr_name = xmalloc (strlen (segment_name (seg)) + 4); 164733965Sjdp strcpy (stabstr_name, segment_name (seg)); 164833965Sjdp strcat (stabstr_name, "str"); 164933965Sjdp stroff = get_stab_string_offset (file, stabstr_name); 165033965Sjdp know (stroff == 1); 165133965Sjdp md_number_to_chars (p, stroff, 4); 165233965Sjdp seg_info (seg)->stabu.p = p; 165333965Sjdp} 165433965Sjdp 165533965Sjdp#endif 165633965Sjdp 165733965Sjdp/* Fill in the counts in the first entry in a .stabs section. */ 165833965Sjdp 165933965Sjdpstatic void 1660130561Sobrienadjust_stab_sections (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED) 166133965Sjdp{ 166233965Sjdp char *name; 166333965Sjdp asection *strsec; 166433965Sjdp char *p; 166533965Sjdp int strsz, nsyms; 166633965Sjdp 166733965Sjdp if (strncmp (".stab", sec->name, 5)) 166833965Sjdp return; 166933965Sjdp if (!strcmp ("str", sec->name + strlen (sec->name) - 3)) 167033965Sjdp return; 167133965Sjdp 1672130561Sobrien name = alloca (strlen (sec->name) + 4); 167333965Sjdp strcpy (name, sec->name); 167433965Sjdp strcat (name, "str"); 167533965Sjdp strsec = bfd_get_section_by_name (abfd, name); 167633965Sjdp if (strsec) 167733965Sjdp strsz = bfd_section_size (abfd, strsec); 167833965Sjdp else 167933965Sjdp strsz = 0; 168033965Sjdp nsyms = bfd_section_size (abfd, sec) / 12 - 1; 168133965Sjdp 168233965Sjdp p = seg_info (sec)->stabu.p; 168333965Sjdp assert (p != 0); 168433965Sjdp 1685130561Sobrien bfd_h_put_16 (abfd, nsyms, p + 6); 1686130561Sobrien bfd_h_put_32 (abfd, strsz, p + 8); 168733965Sjdp} 168833965Sjdp 168933965Sjdp#ifdef NEED_ECOFF_DEBUG 169033965Sjdp 169133965Sjdp/* This function is called by the ECOFF code. It is supposed to 169233965Sjdp record the external symbol information so that the backend can 169333965Sjdp write it out correctly. The ELF backend doesn't actually handle 169433965Sjdp this at the moment, so we do it ourselves. We save the information 169533965Sjdp in the symbol. */ 169633965Sjdp 1697218822Sdim#ifdef OBJ_MAYBE_ELF 1698218822Sdimstatic 1699218822Sdim#endif 170033965Sjdpvoid 1701130561Sobrienelf_ecoff_set_ext (symbolS *sym, struct ecoff_extr *ext) 170233965Sjdp{ 1703130561Sobrien symbol_get_bfdsym (sym)->udata.p = ext; 170433965Sjdp} 170533965Sjdp 170633965Sjdp/* This function is called by bfd_ecoff_debug_externals. It is 170733965Sjdp supposed to *EXT to the external symbol information, and return 170833965Sjdp whether the symbol should be used at all. */ 170933965Sjdp 1710130561Sobrienstatic bfd_boolean 1711130561Sobrienelf_get_extr (asymbol *sym, EXTR *ext) 171233965Sjdp{ 171333965Sjdp if (sym->udata.p == NULL) 1714130561Sobrien return FALSE; 171533965Sjdp *ext = *(EXTR *) sym->udata.p; 1716130561Sobrien return TRUE; 171733965Sjdp} 171833965Sjdp 171933965Sjdp/* This function is called by bfd_ecoff_debug_externals. It has 172033965Sjdp nothing to do for ELF. */ 172133965Sjdp 172233965Sjdpstatic void 1723130561Sobrienelf_set_index (asymbol *sym ATTRIBUTE_UNUSED, 1724130561Sobrien bfd_size_type indx ATTRIBUTE_UNUSED) 172533965Sjdp{ 172633965Sjdp} 172733965Sjdp 172833965Sjdp#endif /* NEED_ECOFF_DEBUG */ 172933965Sjdp 173033965Sjdpvoid 1731130561Sobrienelf_frob_symbol (symbolS *symp, int *puntp) 173233965Sjdp{ 173360484Sobrien struct elf_obj_sy *sy_obj; 173460484Sobrien 173533965Sjdp#ifdef NEED_ECOFF_DEBUG 173633965Sjdp if (ECOFF_DEBUGGING) 173733965Sjdp ecoff_frob_symbol (symp); 173833965Sjdp#endif 173933965Sjdp 174060484Sobrien sy_obj = symbol_get_obj (symp); 174160484Sobrien 174260484Sobrien if (sy_obj->size != NULL) 174333965Sjdp { 174460484Sobrien switch (sy_obj->size->X_op) 174533965Sjdp { 174633965Sjdp case O_subtract: 174733965Sjdp S_SET_SIZE (symp, 174860484Sobrien (S_GET_VALUE (sy_obj->size->X_add_symbol) 174960484Sobrien + sy_obj->size->X_add_number 175060484Sobrien - S_GET_VALUE (sy_obj->size->X_op_symbol))); 175133965Sjdp break; 175233965Sjdp case O_constant: 175333965Sjdp S_SET_SIZE (symp, 175460484Sobrien (S_GET_VALUE (sy_obj->size->X_add_symbol) 175560484Sobrien + sy_obj->size->X_add_number)); 175633965Sjdp break; 175733965Sjdp default: 175860484Sobrien as_bad (_(".size expression too complicated to fix up")); 175933965Sjdp break; 176033965Sjdp } 176160484Sobrien free (sy_obj->size); 176260484Sobrien sy_obj->size = NULL; 176333965Sjdp } 176433965Sjdp 176560484Sobrien if (sy_obj->versioned_name != NULL) 176633965Sjdp { 176777298Sobrien char *p; 176877298Sobrien 176977298Sobrien p = strchr (sy_obj->versioned_name, ELF_VER_CHR); 177077298Sobrien know (p != NULL); 177177298Sobrien 177233965Sjdp /* This symbol was given a new name with the .symver directive. 177333965Sjdp 1774130561Sobrien If this is an external reference, just rename the symbol to 1775130561Sobrien include the version string. This will make the relocs be 1776130561Sobrien against the correct versioned symbol. 177733965Sjdp 177833965Sjdp If this is a definition, add an alias. FIXME: Using an alias 177933965Sjdp will permit the debugging information to refer to the right 178033965Sjdp symbol. However, it's not clear whether it is the best 178133965Sjdp approach. */ 178233965Sjdp 178333965Sjdp if (! S_IS_DEFINED (symp)) 178433965Sjdp { 178533965Sjdp /* Verify that the name isn't using the @@ syntax--this is 1786130561Sobrien reserved for definitions of the default version to link 1787130561Sobrien against. */ 178833965Sjdp if (p[1] == ELF_VER_CHR) 178933965Sjdp { 179060484Sobrien as_bad (_("invalid attempt to declare external version name as default in symbol `%s'"), 179160484Sobrien sy_obj->versioned_name); 1792130561Sobrien *puntp = TRUE; 179333965Sjdp } 179460484Sobrien S_SET_NAME (symp, sy_obj->versioned_name); 179533965Sjdp } 179633965Sjdp else 179733965Sjdp { 1798130561Sobrien if (p[1] == ELF_VER_CHR && p[2] == ELF_VER_CHR) 179977298Sobrien { 180077298Sobrien size_t l; 180133965Sjdp 180277298Sobrien /* The @@@ syntax is a special case. It renames the 180377298Sobrien symbol name to versioned_name with one `@' removed. */ 180477298Sobrien l = strlen (&p[3]) + 1; 1805130561Sobrien memmove (&p[2], &p[3], l); 180677298Sobrien S_SET_NAME (symp, sy_obj->versioned_name); 180777298Sobrien } 180877298Sobrien else 180977298Sobrien { 181077298Sobrien symbolS *symp2; 181133965Sjdp 181277298Sobrien /* FIXME: Creating a new symbol here is risky. We're 181377298Sobrien in the final loop over the symbol table. We can 181477298Sobrien get away with it only because the symbol goes to 181577298Sobrien the end of the list, where the loop will still see 181677298Sobrien it. It would probably be better to do this in 181777298Sobrien obj_frob_file_before_adjust. */ 181833965Sjdp 181977298Sobrien symp2 = symbol_find_or_make (sy_obj->versioned_name); 182033965Sjdp 182177298Sobrien /* Now we act as though we saw symp2 = sym. */ 182233965Sjdp 182377298Sobrien S_SET_SEGMENT (symp2, S_GET_SEGMENT (symp)); 182433965Sjdp 182577298Sobrien /* Subtracting out the frag address here is a hack 182677298Sobrien because we are in the middle of the final loop. */ 182777298Sobrien S_SET_VALUE (symp2, 182877298Sobrien (S_GET_VALUE (symp) 182977298Sobrien - symbol_get_frag (symp)->fr_address)); 183033965Sjdp 183177298Sobrien symbol_set_frag (symp2, symbol_get_frag (symp)); 183233965Sjdp 183377298Sobrien /* This will copy over the size information. */ 183477298Sobrien copy_symbol_attributes (symp2, symp); 183533965Sjdp 183694536Sobrien S_SET_OTHER (symp2, S_GET_OTHER (symp)); 183794536Sobrien 183877298Sobrien if (S_IS_WEAK (symp)) 183977298Sobrien S_SET_WEAK (symp2); 184077298Sobrien 184177298Sobrien if (S_IS_EXTERNAL (symp)) 184277298Sobrien S_SET_EXTERNAL (symp2); 184377298Sobrien } 184433965Sjdp } 184533965Sjdp } 184633965Sjdp 184733965Sjdp /* Double check weak symbols. */ 184860484Sobrien if (S_IS_WEAK (symp)) 184933965Sjdp { 185033965Sjdp if (S_IS_COMMON (symp)) 185189857Sobrien as_bad (_("symbol `%s' can not be both weak and common"), 185233965Sjdp S_GET_NAME (symp)); 185333965Sjdp } 185433965Sjdp 185533965Sjdp#ifdef TC_MIPS 185633965Sjdp /* The Irix 5 and 6 assemblers set the type of any common symbol and 185738889Sjdp any undefined non-function symbol to STT_OBJECT. We try to be 185838889Sjdp compatible, since newer Irix 5 and 6 linkers care. However, we 185938889Sjdp only set undefined symbols to be STT_OBJECT if we are on Irix, 186038889Sjdp because that is the only time gcc will generate the necessary 186138889Sjdp .global directives to mark functions. */ 186238889Sjdp 186338889Sjdp if (S_IS_COMMON (symp)) 186460484Sobrien symbol_get_bfdsym (symp)->flags |= BSF_OBJECT; 186538889Sjdp 186638889Sjdp if (strstr (TARGET_OS, "irix") != NULL 186760484Sobrien && ! S_IS_DEFINED (symp) 186860484Sobrien && (symbol_get_bfdsym (symp)->flags & BSF_FUNCTION) == 0) 186960484Sobrien symbol_get_bfdsym (symp)->flags |= BSF_OBJECT; 187033965Sjdp#endif 187133965Sjdp} 187233965Sjdp 187389857Sobrienstruct group_list 187489857Sobrien{ 187589857Sobrien asection **head; /* Section lists. */ 187689857Sobrien unsigned int *elt_count; /* Number of sections in each list. */ 187789857Sobrien unsigned int num_group; /* Number of lists. */ 187889857Sobrien}; 187989857Sobrien 188089857Sobrien/* Called via bfd_map_over_sections. If SEC is a member of a group, 188189857Sobrien add it to a list of sections belonging to the group. INF is a 188289857Sobrien pointer to a struct group_list, which is where we store the head of 188389857Sobrien each list. */ 188489857Sobrien 188589857Sobrienstatic void 1886130561Sobrienbuild_group_lists (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf) 188789857Sobrien{ 1888130561Sobrien struct group_list *list = inf; 188989857Sobrien const char *group_name = elf_group_name (sec); 189089857Sobrien unsigned int i; 189189857Sobrien 189289857Sobrien if (group_name == NULL) 189389857Sobrien return; 189489857Sobrien 189589857Sobrien /* If this group already has a list, add the section to the head of 189689857Sobrien the list. */ 189789857Sobrien for (i = 0; i < list->num_group; i++) 189889857Sobrien { 189989857Sobrien if (strcmp (group_name, elf_group_name (list->head[i])) == 0) 190089857Sobrien { 190189857Sobrien elf_next_in_group (sec) = list->head[i]; 190289857Sobrien list->head[i] = sec; 190389857Sobrien list->elt_count[i] += 1; 190489857Sobrien return; 190589857Sobrien } 190689857Sobrien } 190789857Sobrien 190889857Sobrien /* New group. Make the arrays bigger in chunks to minimize calls to 190989857Sobrien realloc. */ 191089857Sobrien i = list->num_group; 191189857Sobrien if ((i & 127) == 0) 191289857Sobrien { 191389857Sobrien unsigned int newsize = i + 128; 191489857Sobrien list->head = xrealloc (list->head, newsize * sizeof (*list->head)); 191589857Sobrien list->elt_count = xrealloc (list->elt_count, 191689857Sobrien newsize * sizeof (*list->elt_count)); 191789857Sobrien } 191889857Sobrien list->head[i] = sec; 191989857Sobrien list->elt_count[i] = 1; 192089857Sobrien list->num_group += 1; 192189857Sobrien} 192289857Sobrien 192333965Sjdpvoid 1924130561Sobrienelf_frob_file (void) 192533965Sjdp{ 192689857Sobrien struct group_list list; 192789857Sobrien unsigned int i; 192889857Sobrien 1929130561Sobrien bfd_map_over_sections (stdoutput, adjust_stab_sections, NULL); 193033965Sjdp 193189857Sobrien /* Go find section groups. */ 193289857Sobrien list.num_group = 0; 193389857Sobrien list.head = NULL; 193489857Sobrien list.elt_count = NULL; 1935130561Sobrien bfd_map_over_sections (stdoutput, build_group_lists, &list); 193689857Sobrien 193789857Sobrien /* Make the SHT_GROUP sections that describe each section group. We 193889857Sobrien can't set up the section contents here yet, because elf section 193989857Sobrien indices have yet to be calculated. elf.c:set_group_contents does 194089857Sobrien the rest of the work. */ 194189857Sobrien for (i = 0; i < list.num_group; i++) 194289857Sobrien { 194389857Sobrien const char *group_name = elf_group_name (list.head[i]); 1944104834Sobrien const char *sec_name; 194589857Sobrien asection *s; 194689857Sobrien flagword flags; 1947104834Sobrien struct symbol *sy; 1948104834Sobrien int has_sym; 1949218822Sdim bfd_size_type size; 195089857Sobrien 195189857Sobrien flags = SEC_READONLY | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_GROUP; 1952104834Sobrien for (s = list.head[i]; s != NULL; s = elf_next_in_group (s)) 1953130561Sobrien if ((s->flags ^ flags) & SEC_LINK_ONCE) 1954104834Sobrien { 1955104834Sobrien flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; 1956104834Sobrien if (s != list.head[i]) 1957104834Sobrien { 1958104834Sobrien as_warn (_("assuming all members of group `%s' are COMDAT"), 1959104834Sobrien group_name); 1960104834Sobrien break; 1961104834Sobrien } 1962104834Sobrien } 1963104834Sobrien 1964104834Sobrien sec_name = group_name; 1965104834Sobrien sy = symbol_find_exact (group_name); 1966104834Sobrien has_sym = 0; 1967104834Sobrien if (sy != NULL 1968104834Sobrien && (sy == symbol_lastP 1969104834Sobrien || (sy->sy_next != NULL 1970104834Sobrien && sy->sy_next->sy_previous == sy))) 1971104834Sobrien { 1972104834Sobrien has_sym = 1; 1973104834Sobrien sec_name = ".group"; 1974104834Sobrien } 1975104834Sobrien s = subseg_force_new (sec_name, 0); 197689857Sobrien if (s == NULL 197789857Sobrien || !bfd_set_section_flags (stdoutput, s, flags) 197889857Sobrien || !bfd_set_section_alignment (stdoutput, s, 2)) 197989857Sobrien { 198089857Sobrien as_fatal (_("can't create group: %s"), 198189857Sobrien bfd_errmsg (bfd_get_error ())); 198289857Sobrien } 1983130561Sobrien elf_section_type (s) = SHT_GROUP; 198489857Sobrien 198589857Sobrien /* Pass a pointer to the first section in this group. */ 198689857Sobrien elf_next_in_group (s) = list.head[i]; 1987104834Sobrien if (has_sym) 1988104834Sobrien elf_group_id (s) = sy->bsym; 198989857Sobrien 1990218822Sdim size = 4 * (list.elt_count[i] + 1); 1991218822Sdim bfd_set_section_size (stdoutput, s, size); 1992218822Sdim s->contents = (unsigned char *) frag_more (size); 199389857Sobrien frag_now->fr_fix = frag_now_fix_octets (); 1994218822Sdim frag_wane (frag_now); 199589857Sobrien } 199689857Sobrien 199733965Sjdp#ifdef elf_tc_final_processing 199833965Sjdp elf_tc_final_processing (); 199933965Sjdp#endif 200033965Sjdp} 200133965Sjdp 200277298Sobrien/* It removes any unneeded versioned symbols from the symbol table. */ 200377298Sobrien 200477298Sobrienvoid 2005130561Sobrienelf_frob_file_before_adjust (void) 200677298Sobrien{ 200777298Sobrien if (symbol_rootP) 200877298Sobrien { 200977298Sobrien symbolS *symp; 201077298Sobrien 201177298Sobrien for (symp = symbol_rootP; symp; symp = symbol_next (symp)) 201291041Sobrien if (!S_IS_DEFINED (symp)) 201377298Sobrien { 201491041Sobrien if (symbol_get_obj (symp)->versioned_name) 201577298Sobrien { 201677298Sobrien char *p; 201777298Sobrien 201877298Sobrien /* The @@@ syntax is a special case. If the symbol is 201977298Sobrien not defined, 2 `@'s will be removed from the 202077298Sobrien versioned_name. */ 202177298Sobrien 202277298Sobrien p = strchr (symbol_get_obj (symp)->versioned_name, 202377298Sobrien ELF_VER_CHR); 202477298Sobrien know (p != NULL); 2025130561Sobrien if (p[1] == ELF_VER_CHR && p[2] == ELF_VER_CHR) 202677298Sobrien { 202777298Sobrien size_t l = strlen (&p[3]) + 1; 2028130561Sobrien memmove (&p[1], &p[3], l); 202977298Sobrien } 203077298Sobrien if (symbol_used_p (symp) == 0 203177298Sobrien && symbol_used_in_reloc_p (symp) == 0) 203277298Sobrien symbol_remove (symp, &symbol_rootP, &symbol_lastP); 203377298Sobrien } 203491041Sobrien 203591041Sobrien /* If there was .weak foo, but foo was neither defined nor 203691041Sobrien used anywhere, remove it. */ 203791041Sobrien 203891041Sobrien else if (S_IS_WEAK (symp) 203991041Sobrien && symbol_used_p (symp) == 0 204091041Sobrien && symbol_used_in_reloc_p (symp) == 0) 204191041Sobrien symbol_remove (symp, &symbol_rootP, &symbol_lastP); 204277298Sobrien } 204377298Sobrien } 204477298Sobrien} 204577298Sobrien 204633965Sjdp/* It is required that we let write_relocs have the opportunity to 204733965Sjdp optimize away fixups before output has begun, since it is possible 204833965Sjdp to eliminate all fixups for a section and thus we never should 204933965Sjdp have generated the relocation section. */ 205033965Sjdp 205133965Sjdpvoid 2052130561Sobrienelf_frob_file_after_relocs (void) 205333965Sjdp{ 205433965Sjdp#ifdef NEED_ECOFF_DEBUG 205533965Sjdp if (ECOFF_DEBUGGING) 205633965Sjdp /* Generate the ECOFF debugging information. */ 205733965Sjdp { 205833965Sjdp const struct ecoff_debug_swap *debug_swap; 205933965Sjdp struct ecoff_debug_info debug; 206033965Sjdp char *buf; 206133965Sjdp asection *sec; 206233965Sjdp 206333965Sjdp debug_swap 206433965Sjdp = get_elf_backend_data (stdoutput)->elf_backend_ecoff_debug_swap; 2065130561Sobrien know (debug_swap != NULL); 206633965Sjdp ecoff_build_debug (&debug.symbolic_header, &buf, debug_swap); 206733965Sjdp 206833965Sjdp /* Set up the pointers in debug. */ 206933965Sjdp#define SET(ptr, offset, type) \ 207033965Sjdp debug.ptr = (type) (buf + debug.symbolic_header.offset) 207133965Sjdp 207233965Sjdp SET (line, cbLineOffset, unsigned char *); 2073130561Sobrien SET (external_dnr, cbDnOffset, void *); 2074130561Sobrien SET (external_pdr, cbPdOffset, void *); 2075130561Sobrien SET (external_sym, cbSymOffset, void *); 2076130561Sobrien SET (external_opt, cbOptOffset, void *); 207733965Sjdp SET (external_aux, cbAuxOffset, union aux_ext *); 207833965Sjdp SET (ss, cbSsOffset, char *); 2079130561Sobrien SET (external_fdr, cbFdOffset, void *); 2080130561Sobrien SET (external_rfd, cbRfdOffset, void *); 208133965Sjdp /* ssext and external_ext are set up just below. */ 208233965Sjdp 208333965Sjdp#undef SET 208433965Sjdp 208533965Sjdp /* Set up the external symbols. */ 208633965Sjdp debug.ssext = debug.ssext_end = NULL; 208733965Sjdp debug.external_ext = debug.external_ext_end = NULL; 2088130561Sobrien if (! bfd_ecoff_debug_externals (stdoutput, &debug, debug_swap, TRUE, 208933965Sjdp elf_get_extr, elf_set_index)) 209089857Sobrien as_fatal (_("failed to set up debugging information: %s"), 209133965Sjdp bfd_errmsg (bfd_get_error ())); 209233965Sjdp 209333965Sjdp sec = bfd_get_section_by_name (stdoutput, ".mdebug"); 209433965Sjdp assert (sec != NULL); 209533965Sjdp 2096130561Sobrien know (!stdoutput->output_has_begun); 209733965Sjdp 209833965Sjdp /* We set the size of the section, call bfd_set_section_contents 209933965Sjdp to force the ELF backend to allocate a file position, and then 210033965Sjdp write out the data. FIXME: Is this really the best way to do 210133965Sjdp this? */ 2102218822Sdim bfd_set_section_size 2103218822Sdim (stdoutput, sec, bfd_ecoff_debug_size (stdoutput, &debug, debug_swap)); 210433965Sjdp 210560484Sobrien /* Pass BUF to bfd_set_section_contents because this will 2106130561Sobrien eventually become a call to fwrite, and ISO C prohibits 2107130561Sobrien passing a NULL pointer to a stdio function even if the 2108130561Sobrien pointer will not be used. */ 2109130561Sobrien if (! bfd_set_section_contents (stdoutput, sec, buf, 0, 0)) 211089857Sobrien as_fatal (_("can't start writing .mdebug section: %s"), 211133965Sjdp bfd_errmsg (bfd_get_error ())); 211233965Sjdp 2113130561Sobrien know (stdoutput->output_has_begun); 211433965Sjdp know (sec->filepos != 0); 211533965Sjdp 211633965Sjdp if (! bfd_ecoff_write_debug (stdoutput, &debug, debug_swap, 211733965Sjdp sec->filepos)) 211889857Sobrien as_fatal (_("could not write .mdebug section: %s"), 211933965Sjdp bfd_errmsg (bfd_get_error ())); 212033965Sjdp } 212133965Sjdp#endif /* NEED_ECOFF_DEBUG */ 212233965Sjdp} 212333965Sjdp 212433965Sjdp#ifdef SCO_ELF 212533965Sjdp 2126130561Sobrien/* Heavily plagiarized from obj_elf_version. The idea is to emit the 212733965Sjdp SCO specific identifier in the .notes section to satisfy the SCO 212833965Sjdp linker. 212933965Sjdp 213033965Sjdp This looks more complicated than it really is. As opposed to the 213133965Sjdp "obvious" solution, this should handle the cross dev cases 213233965Sjdp correctly. (i.e, hosting on a 64 bit big endian processor, but 213333965Sjdp generating SCO Elf code) Efficiency isn't a concern, as there 213433965Sjdp should be exactly one of these sections per object module. 213533965Sjdp 213633965Sjdp SCO OpenServer 5 identifies it's ELF modules with a standard ELF 213733965Sjdp .note section. 213833965Sjdp 213960484Sobrien int_32 namesz = 4 ; Name size 214060484Sobrien int_32 descsz = 12 ; Descriptive information 214160484Sobrien int_32 type = 1 ; 214260484Sobrien char name[4] = "SCO" ; Originator name ALWAYS SCO + NULL 214333965Sjdp int_32 version = (major ver # << 16) | version of tools ; 214433965Sjdp int_32 source = (tool_id << 16 ) | 1 ; 214533965Sjdp int_32 info = 0 ; These are set by the SCO tools, but we 2146130561Sobrien don't know enough about the source 214733965Sjdp environment to set them. SCO ld currently 214833965Sjdp ignores them, and recommends we set them 214933965Sjdp to zero. */ 215033965Sjdp 215133965Sjdp#define SCO_MAJOR_VERSION 0x1 215233965Sjdp#define SCO_MINOR_VERSION 0x1 215333965Sjdp 215433965Sjdpvoid 2155130561Sobriensco_id (void) 215633965Sjdp{ 215733965Sjdp 215833965Sjdp char *name; 215933965Sjdp unsigned int c; 216033965Sjdp char ch; 216133965Sjdp char *p; 216233965Sjdp asection *seg = now_seg; 216333965Sjdp subsegT subseg = now_subseg; 216433965Sjdp Elf_Internal_Note i_note; 216533965Sjdp Elf_External_Note e_note; 2166130561Sobrien asection *note_secp = NULL; 216733965Sjdp int i, len; 216833965Sjdp 216933965Sjdp /* create the .note section */ 217033965Sjdp 217133965Sjdp note_secp = subseg_new (".note", 0); 217233965Sjdp bfd_set_section_flags (stdoutput, 217333965Sjdp note_secp, 217433965Sjdp SEC_HAS_CONTENTS | SEC_READONLY); 217533965Sjdp 217633965Sjdp /* process the version string */ 217733965Sjdp 217860484Sobrien i_note.namesz = 4; 217933965Sjdp i_note.descsz = 12; /* 12 descriptive bytes */ 218033965Sjdp i_note.type = NT_VERSION; /* Contains a version string */ 218133965Sjdp 218233965Sjdp p = frag_more (sizeof (i_note.namesz)); 2183130561Sobrien md_number_to_chars (p, i_note.namesz, 4); 218433965Sjdp 218533965Sjdp p = frag_more (sizeof (i_note.descsz)); 2186130561Sobrien md_number_to_chars (p, i_note.descsz, 4); 218733965Sjdp 218833965Sjdp p = frag_more (sizeof (i_note.type)); 2189130561Sobrien md_number_to_chars (p, i_note.type, 4); 219033965Sjdp 219133965Sjdp p = frag_more (4); 219260484Sobrien strcpy (p, "SCO"); 219333965Sjdp 219433965Sjdp /* Note: this is the version number of the ELF we're representing */ 219533965Sjdp p = frag_more (4); 219633965Sjdp md_number_to_chars (p, (SCO_MAJOR_VERSION << 16) | (SCO_MINOR_VERSION), 4); 219733965Sjdp 219833965Sjdp /* Here, we pick a magic number for ourselves (yes, I "registered" 219933965Sjdp it with SCO. The bottom bit shows that we are compat with the 220033965Sjdp SCO ABI. */ 220133965Sjdp p = frag_more (4); 220233965Sjdp md_number_to_chars (p, 0x4c520000 | 0x0001, 4); 220333965Sjdp 220433965Sjdp /* If we knew (or cared) what the source language options were, we'd 220533965Sjdp fill them in here. SCO has given us permission to ignore these 220633965Sjdp and just set them to zero. */ 220733965Sjdp p = frag_more (4); 220833965Sjdp md_number_to_chars (p, 0x0000, 4); 220960484Sobrien 221033965Sjdp frag_align (2, 0, 0); 221133965Sjdp 221233965Sjdp /* We probably can't restore the current segment, for there likely 221333965Sjdp isn't one yet... */ 221433965Sjdp if (seg && subseg) 221533965Sjdp subseg_set (seg, subseg); 221633965Sjdp 221733965Sjdp} 221833965Sjdp 221933965Sjdp#endif /* SCO_ELF */ 222033965Sjdp 222177298Sobrienstatic int 2222130561Sobrienelf_separate_stab_sections (void) 222377298Sobrien{ 222477298Sobrien#ifdef NEED_ECOFF_DEBUG 222577298Sobrien return (!ECOFF_DEBUGGING); 222677298Sobrien#else 222777298Sobrien return 1; 222877298Sobrien#endif 222977298Sobrien} 223077298Sobrien 223177298Sobrienstatic void 2232130561Sobrienelf_init_stab_section (segT seg) 223377298Sobrien{ 223477298Sobrien#ifdef NEED_ECOFF_DEBUG 223577298Sobrien if (!ECOFF_DEBUGGING) 223677298Sobrien#endif 223777298Sobrien obj_elf_init_stab_section (seg); 223877298Sobrien} 223977298Sobrien 224033965Sjdpconst struct format_ops elf_format_ops = 224133965Sjdp{ 224233965Sjdp bfd_target_elf_flavour, 224360484Sobrien 0, /* dfl_leading_underscore */ 224460484Sobrien 1, /* emit_section_symbols */ 224577298Sobrien elf_begin, 224677298Sobrien elf_file_symbol, 224733965Sjdp elf_frob_symbol, 224833965Sjdp elf_frob_file, 224977298Sobrien elf_frob_file_before_adjust, 2250130561Sobrien 0, /* obj_frob_file_before_fix */ 225133965Sjdp elf_frob_file_after_relocs, 225233965Sjdp elf_s_get_size, elf_s_set_size, 225333965Sjdp elf_s_get_align, elf_s_set_align, 225460484Sobrien elf_s_get_other, 225577298Sobrien elf_s_set_other, 225660484Sobrien 0, /* s_get_desc */ 225777298Sobrien 0, /* s_set_desc */ 225877298Sobrien 0, /* s_get_type */ 225977298Sobrien 0, /* s_set_type */ 226033965Sjdp elf_copy_symbol_attributes, 226133965Sjdp#ifdef NEED_ECOFF_DEBUG 226233965Sjdp ecoff_generate_asm_lineno, 226333965Sjdp ecoff_stab, 226433965Sjdp#else 226560484Sobrien 0, /* generate_asm_lineno */ 226660484Sobrien 0, /* process_stab */ 226733965Sjdp#endif 226877298Sobrien elf_separate_stab_sections, 226977298Sobrien elf_init_stab_section, 227033965Sjdp elf_sec_sym_ok_for_reloc, 227133965Sjdp elf_pop_insert, 227233965Sjdp#ifdef NEED_ECOFF_DEBUG 227333965Sjdp elf_ecoff_set_ext, 227433965Sjdp#else 227560484Sobrien 0, /* ecoff_set_ext */ 227633965Sjdp#endif 227760484Sobrien elf_obj_read_begin_hook, 227877298Sobrien elf_obj_symbol_new_hook 227933965Sjdp}; 2280