160484Sobrien/* tc-ppc.c -- Assemble for the PowerPC or POWER (RS/6000) 2130561Sobrien Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 3218822Sdim 2004, 2005, 2006, 2007 Free Software Foundation, Inc. 460484Sobrien Written by Ian Lance Taylor, Cygnus Support. 560484Sobrien 660484Sobrien This file is part of GAS, the GNU Assembler. 760484Sobrien 860484Sobrien GAS is free software; you can redistribute it and/or modify 960484Sobrien it under the terms of the GNU General Public License as published by 1060484Sobrien the Free Software Foundation; either version 2, or (at your option) 1160484Sobrien any later version. 1260484Sobrien 1360484Sobrien GAS is distributed in the hope that it will be useful, 1460484Sobrien but WITHOUT ANY WARRANTY; without even the implied warranty of 1560484Sobrien MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1660484Sobrien GNU General Public License for more details. 1760484Sobrien 1860484Sobrien You should have received a copy of the GNU General Public License 1960484Sobrien 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. */ 2260484Sobrien 2360484Sobrien#include "as.h" 2489857Sobrien#include "safe-ctype.h" 2560484Sobrien#include "subsegs.h" 26130561Sobrien#include "dw2gencfi.h" 2760484Sobrien#include "opcode/ppc.h" 2860484Sobrien 2960484Sobrien#ifdef OBJ_ELF 3060484Sobrien#include "elf/ppc.h" 3177298Sobrien#include "dwarf2dbg.h" 3260484Sobrien#endif 3360484Sobrien 3460484Sobrien#ifdef TE_PE 3560484Sobrien#include "coff/pe.h" 3660484Sobrien#endif 3760484Sobrien 3860484Sobrien/* This is the assembler for the PowerPC or POWER (RS/6000) chips. */ 3960484Sobrien 4060484Sobrien/* Tell the main code what the endianness is. */ 4160484Sobrienextern int target_big_endian; 4260484Sobrien 4360484Sobrien/* Whether or not, we've set target_big_endian. */ 4460484Sobrienstatic int set_target_endian = 0; 4560484Sobrien 4660484Sobrien/* Whether to use user friendly register names. */ 4760484Sobrien#ifndef TARGET_REG_NAMES_P 4860484Sobrien#ifdef TE_PE 49130561Sobrien#define TARGET_REG_NAMES_P TRUE 5060484Sobrien#else 51130561Sobrien#define TARGET_REG_NAMES_P FALSE 5260484Sobrien#endif 5360484Sobrien#endif 5460484Sobrien 5589857Sobrien/* Macros for calculating LO, HI, HA, HIGHER, HIGHERA, HIGHEST, 5689857Sobrien HIGHESTA. */ 5789857Sobrien 5889857Sobrien/* #lo(value) denotes the least significant 16 bits of the indicated. */ 5989857Sobrien#define PPC_LO(v) ((v) & 0xffff) 6089857Sobrien 6189857Sobrien/* #hi(value) denotes bits 16 through 31 of the indicated value. */ 6289857Sobrien#define PPC_HI(v) (((v) >> 16) & 0xffff) 6389857Sobrien 6489857Sobrien/* #ha(value) denotes the high adjusted value: bits 16 through 31 of 6589857Sobrien the indicated value, compensating for #lo() being treated as a 6689857Sobrien signed number. */ 6789857Sobrien#define PPC_HA(v) PPC_HI ((v) + 0x8000) 6889857Sobrien 6989857Sobrien/* #higher(value) denotes bits 32 through 47 of the indicated value. */ 70107492Sobrien#define PPC_HIGHER(v) (((v) >> 16 >> 16) & 0xffff) 7189857Sobrien 7289857Sobrien/* #highera(value) denotes bits 32 through 47 of the indicated value, 7389857Sobrien compensating for #lo() being treated as a signed number. */ 7489857Sobrien#define PPC_HIGHERA(v) PPC_HIGHER ((v) + 0x8000) 7589857Sobrien 7689857Sobrien/* #highest(value) denotes bits 48 through 63 of the indicated value. */ 77107492Sobrien#define PPC_HIGHEST(v) (((v) >> 24 >> 24) & 0xffff) 7889857Sobrien 7989857Sobrien/* #highesta(value) denotes bits 48 through 63 of the indicated value, 8089857Sobrien compensating for #lo being treated as a signed number. */ 8189857Sobrien#define PPC_HIGHESTA(v) PPC_HIGHEST ((v) + 0x8000) 8289857Sobrien 8389857Sobrien#define SEX16(val) ((((val) & 0xffff) ^ 0x8000) - 0x8000) 8489857Sobrien 85130561Sobrienstatic bfd_boolean reg_names_p = TARGET_REG_NAMES_P; 8660484Sobrien 87218822Sdimstatic void ppc_macro (char *, const struct powerpc_macro *); 88218822Sdimstatic void ppc_byte (int); 8989857Sobrien 9089857Sobrien#if defined (OBJ_XCOFF) || defined (OBJ_ELF) 91218822Sdimstatic void ppc_tc (int); 92218822Sdimstatic void ppc_machine (int); 9389857Sobrien#endif 9460484Sobrien 9560484Sobrien#ifdef OBJ_XCOFF 96218822Sdimstatic void ppc_comm (int); 97218822Sdimstatic void ppc_bb (int); 98218822Sdimstatic void ppc_bc (int); 99218822Sdimstatic void ppc_bf (int); 100218822Sdimstatic void ppc_biei (int); 101218822Sdimstatic void ppc_bs (int); 102218822Sdimstatic void ppc_eb (int); 103218822Sdimstatic void ppc_ec (int); 104218822Sdimstatic void ppc_ef (int); 105218822Sdimstatic void ppc_es (int); 106218822Sdimstatic void ppc_csect (int); 107218822Sdimstatic void ppc_change_csect (symbolS *, offsetT); 108218822Sdimstatic void ppc_function (int); 109218822Sdimstatic void ppc_extern (int); 110218822Sdimstatic void ppc_lglobl (int); 111218822Sdimstatic void ppc_section (int); 112218822Sdimstatic void ppc_named_section (int); 113218822Sdimstatic void ppc_stabx (int); 114218822Sdimstatic void ppc_rename (int); 115218822Sdimstatic void ppc_toc (int); 116218822Sdimstatic void ppc_xcoff_cons (int); 117218822Sdimstatic void ppc_vbyte (int); 11860484Sobrien#endif 11960484Sobrien 12060484Sobrien#ifdef OBJ_ELF 121218822Sdimstatic void ppc_elf_cons (int); 122218822Sdimstatic void ppc_elf_rdata (int); 123218822Sdimstatic void ppc_elf_lcomm (int); 12460484Sobrien#endif 12560484Sobrien 12660484Sobrien#ifdef TE_PE 127218822Sdimstatic void ppc_previous (int); 128218822Sdimstatic void ppc_pdata (int); 129218822Sdimstatic void ppc_ydata (int); 130218822Sdimstatic void ppc_reldata (int); 131218822Sdimstatic void ppc_rdata (int); 132218822Sdimstatic void ppc_ualong (int); 133218822Sdimstatic void ppc_znop (int); 134218822Sdimstatic void ppc_pe_comm (int); 135218822Sdimstatic void ppc_pe_section (int); 136218822Sdimstatic void ppc_pe_function (int); 137218822Sdimstatic void ppc_pe_tocd (int); 13860484Sobrien#endif 13960484Sobrien 14060484Sobrien/* Generic assembler global variables which must be defined by all 14160484Sobrien targets. */ 14260484Sobrien 14360484Sobrien#ifdef OBJ_ELF 14460484Sobrien/* This string holds the chars that always start a comment. If the 14560484Sobrien pre-processor is disabled, these aren't very useful. The macro 14660484Sobrien tc_comment_chars points to this. We use this, rather than the 14760484Sobrien usual comment_chars, so that we can switch for Solaris conventions. */ 14860484Sobrienstatic const char ppc_solaris_comment_chars[] = "#!"; 14960484Sobrienstatic const char ppc_eabi_comment_chars[] = "#"; 15060484Sobrien 15160484Sobrien#ifdef TARGET_SOLARIS_COMMENT 15260484Sobrienconst char *ppc_comment_chars = ppc_solaris_comment_chars; 15360484Sobrien#else 15460484Sobrienconst char *ppc_comment_chars = ppc_eabi_comment_chars; 15560484Sobrien#endif 15660484Sobrien#else 15760484Sobrienconst char comment_chars[] = "#"; 15860484Sobrien#endif 15960484Sobrien 16060484Sobrien/* Characters which start a comment at the beginning of a line. */ 16160484Sobrienconst char line_comment_chars[] = "#"; 16260484Sobrien 16360484Sobrien/* Characters which may be used to separate multiple commands on a 16460484Sobrien single line. */ 16560484Sobrienconst char line_separator_chars[] = ";"; 16660484Sobrien 16760484Sobrien/* Characters which are used to indicate an exponent in a floating 16860484Sobrien point number. */ 16960484Sobrienconst char EXP_CHARS[] = "eE"; 17060484Sobrien 17160484Sobrien/* Characters which mean that a number is a floating point constant, 17260484Sobrien as in 0d1.0. */ 17360484Sobrienconst char FLT_CHARS[] = "dD"; 174130561Sobrien 175218822Sdim/* Anything that can start an operand needs to be mentioned here, 176218822Sdim to stop the input scrubber eating whitespace. */ 177218822Sdimconst char ppc_symbol_chars[] = "%["; 178130561Sobrien 179130561Sobrien/* The dwarf2 data alignment, adjusted for 32 or 64 bit. */ 180130561Sobrienint ppc_cie_data_alignment; 18160484Sobrien 18260484Sobrien/* The target specific pseudo-ops which we support. */ 18360484Sobrien 18460484Sobrienconst pseudo_typeS md_pseudo_table[] = 18560484Sobrien{ 18660484Sobrien /* Pseudo-ops which must be overridden. */ 18760484Sobrien { "byte", ppc_byte, 0 }, 18860484Sobrien 18960484Sobrien#ifdef OBJ_XCOFF 19060484Sobrien /* Pseudo-ops specific to the RS/6000 XCOFF format. Some of these 19160484Sobrien legitimately belong in the obj-*.c file. However, XCOFF is based 19260484Sobrien on COFF, and is only implemented for the RS/6000. We just use 19360484Sobrien obj-coff.c, and add what we need here. */ 19460484Sobrien { "comm", ppc_comm, 0 }, 19560484Sobrien { "lcomm", ppc_comm, 1 }, 19660484Sobrien { "bb", ppc_bb, 0 }, 19760484Sobrien { "bc", ppc_bc, 0 }, 19860484Sobrien { "bf", ppc_bf, 0 }, 19960484Sobrien { "bi", ppc_biei, 0 }, 20060484Sobrien { "bs", ppc_bs, 0 }, 20160484Sobrien { "csect", ppc_csect, 0 }, 20260484Sobrien { "data", ppc_section, 'd' }, 20360484Sobrien { "eb", ppc_eb, 0 }, 20460484Sobrien { "ec", ppc_ec, 0 }, 20560484Sobrien { "ef", ppc_ef, 0 }, 20660484Sobrien { "ei", ppc_biei, 1 }, 20760484Sobrien { "es", ppc_es, 0 }, 20860484Sobrien { "extern", ppc_extern, 0 }, 20960484Sobrien { "function", ppc_function, 0 }, 21060484Sobrien { "lglobl", ppc_lglobl, 0 }, 21160484Sobrien { "rename", ppc_rename, 0 }, 21260484Sobrien { "section", ppc_named_section, 0 }, 21360484Sobrien { "stabx", ppc_stabx, 0 }, 21460484Sobrien { "text", ppc_section, 't' }, 21560484Sobrien { "toc", ppc_toc, 0 }, 21660484Sobrien { "long", ppc_xcoff_cons, 2 }, 21777298Sobrien { "llong", ppc_xcoff_cons, 3 }, 21860484Sobrien { "word", ppc_xcoff_cons, 1 }, 21960484Sobrien { "short", ppc_xcoff_cons, 1 }, 22060484Sobrien { "vbyte", ppc_vbyte, 0 }, 22160484Sobrien#endif 22260484Sobrien 22360484Sobrien#ifdef OBJ_ELF 22489857Sobrien { "llong", ppc_elf_cons, 8 }, 22589857Sobrien { "quad", ppc_elf_cons, 8 }, 22660484Sobrien { "long", ppc_elf_cons, 4 }, 22760484Sobrien { "word", ppc_elf_cons, 2 }, 22860484Sobrien { "short", ppc_elf_cons, 2 }, 22960484Sobrien { "rdata", ppc_elf_rdata, 0 }, 23060484Sobrien { "rodata", ppc_elf_rdata, 0 }, 23160484Sobrien { "lcomm", ppc_elf_lcomm, 0 }, 23260484Sobrien#endif 23360484Sobrien 23460484Sobrien#ifdef TE_PE 23589857Sobrien /* Pseudo-ops specific to the Windows NT PowerPC PE (coff) format. */ 23660484Sobrien { "previous", ppc_previous, 0 }, 23760484Sobrien { "pdata", ppc_pdata, 0 }, 23860484Sobrien { "ydata", ppc_ydata, 0 }, 23960484Sobrien { "reldata", ppc_reldata, 0 }, 24060484Sobrien { "rdata", ppc_rdata, 0 }, 24160484Sobrien { "ualong", ppc_ualong, 0 }, 24260484Sobrien { "znop", ppc_znop, 0 }, 24360484Sobrien { "comm", ppc_pe_comm, 0 }, 24460484Sobrien { "lcomm", ppc_pe_comm, 1 }, 24560484Sobrien { "section", ppc_pe_section, 0 }, 24660484Sobrien { "function", ppc_pe_function,0 }, 24760484Sobrien { "tocd", ppc_pe_tocd, 0 }, 24860484Sobrien#endif 24960484Sobrien 25089857Sobrien#if defined (OBJ_XCOFF) || defined (OBJ_ELF) 25160484Sobrien { "tc", ppc_tc, 0 }, 25289857Sobrien { "machine", ppc_machine, 0 }, 25389857Sobrien#endif 25460484Sobrien 25560484Sobrien { NULL, NULL, 0 } 25660484Sobrien}; 25760484Sobrien 25860484Sobrien 25989857Sobrien/* Predefined register names if -mregnames (or default for Windows NT). 26089857Sobrien In general, there are lots of them, in an attempt to be compatible 26189857Sobrien with a number of other Windows NT assemblers. */ 26260484Sobrien 26360484Sobrien/* Structure to hold information about predefined registers. */ 26460484Sobrienstruct pd_reg 26560484Sobrien { 26660484Sobrien char *name; 26760484Sobrien int value; 26860484Sobrien }; 26960484Sobrien 27060484Sobrien/* List of registers that are pre-defined: 27160484Sobrien 27260484Sobrien Each general register has predefined names of the form: 27360484Sobrien 1. r<reg_num> which has the value <reg_num>. 27460484Sobrien 2. r.<reg_num> which has the value <reg_num>. 27560484Sobrien 27660484Sobrien Each floating point register has predefined names of the form: 27760484Sobrien 1. f<reg_num> which has the value <reg_num>. 27860484Sobrien 2. f.<reg_num> which has the value <reg_num>. 27960484Sobrien 28077298Sobrien Each vector unit register has predefined names of the form: 28177298Sobrien 1. v<reg_num> which has the value <reg_num>. 28277298Sobrien 2. v.<reg_num> which has the value <reg_num>. 28377298Sobrien 28460484Sobrien Each condition register has predefined names of the form: 28560484Sobrien 1. cr<reg_num> which has the value <reg_num>. 28660484Sobrien 2. cr.<reg_num> which has the value <reg_num>. 28760484Sobrien 28860484Sobrien There are individual registers as well: 28960484Sobrien sp or r.sp has the value 1 29060484Sobrien rtoc or r.toc has the value 2 29160484Sobrien fpscr has the value 0 29260484Sobrien xer has the value 1 29360484Sobrien lr has the value 8 29460484Sobrien ctr has the value 9 29560484Sobrien pmr has the value 0 29660484Sobrien dar has the value 19 29760484Sobrien dsisr has the value 18 29860484Sobrien dec has the value 22 29960484Sobrien sdr1 has the value 25 30060484Sobrien srr0 has the value 26 30160484Sobrien srr1 has the value 27 30260484Sobrien 30377298Sobrien The table is sorted. Suitable for searching by a binary search. */ 30460484Sobrien 30560484Sobrienstatic const struct pd_reg pre_defined_registers[] = 30660484Sobrien{ 30760484Sobrien { "cr.0", 0 }, /* Condition Registers */ 30860484Sobrien { "cr.1", 1 }, 30960484Sobrien { "cr.2", 2 }, 31060484Sobrien { "cr.3", 3 }, 31160484Sobrien { "cr.4", 4 }, 31260484Sobrien { "cr.5", 5 }, 31360484Sobrien { "cr.6", 6 }, 31460484Sobrien { "cr.7", 7 }, 31560484Sobrien 31660484Sobrien { "cr0", 0 }, 31760484Sobrien { "cr1", 1 }, 31860484Sobrien { "cr2", 2 }, 31960484Sobrien { "cr3", 3 }, 32060484Sobrien { "cr4", 4 }, 32160484Sobrien { "cr5", 5 }, 32260484Sobrien { "cr6", 6 }, 32360484Sobrien { "cr7", 7 }, 32460484Sobrien 32560484Sobrien { "ctr", 9 }, 32660484Sobrien 32760484Sobrien { "dar", 19 }, /* Data Access Register */ 32860484Sobrien { "dec", 22 }, /* Decrementer */ 32960484Sobrien { "dsisr", 18 }, /* Data Storage Interrupt Status Register */ 33060484Sobrien 33160484Sobrien { "f.0", 0 }, /* Floating point registers */ 33277298Sobrien { "f.1", 1 }, 33377298Sobrien { "f.10", 10 }, 33477298Sobrien { "f.11", 11 }, 33577298Sobrien { "f.12", 12 }, 33677298Sobrien { "f.13", 13 }, 33777298Sobrien { "f.14", 14 }, 33877298Sobrien { "f.15", 15 }, 33977298Sobrien { "f.16", 16 }, 34077298Sobrien { "f.17", 17 }, 34177298Sobrien { "f.18", 18 }, 34277298Sobrien { "f.19", 19 }, 34377298Sobrien { "f.2", 2 }, 34477298Sobrien { "f.20", 20 }, 34577298Sobrien { "f.21", 21 }, 34677298Sobrien { "f.22", 22 }, 34777298Sobrien { "f.23", 23 }, 34877298Sobrien { "f.24", 24 }, 34977298Sobrien { "f.25", 25 }, 35077298Sobrien { "f.26", 26 }, 35177298Sobrien { "f.27", 27 }, 35277298Sobrien { "f.28", 28 }, 35377298Sobrien { "f.29", 29 }, 35477298Sobrien { "f.3", 3 }, 35560484Sobrien { "f.30", 30 }, 35660484Sobrien { "f.31", 31 }, 35777298Sobrien { "f.4", 4 }, 35877298Sobrien { "f.5", 5 }, 35977298Sobrien { "f.6", 6 }, 36077298Sobrien { "f.7", 7 }, 36177298Sobrien { "f.8", 8 }, 36277298Sobrien { "f.9", 9 }, 36360484Sobrien 36477298Sobrien { "f0", 0 }, 36577298Sobrien { "f1", 1 }, 36677298Sobrien { "f10", 10 }, 36777298Sobrien { "f11", 11 }, 36877298Sobrien { "f12", 12 }, 36977298Sobrien { "f13", 13 }, 37077298Sobrien { "f14", 14 }, 37177298Sobrien { "f15", 15 }, 37277298Sobrien { "f16", 16 }, 37377298Sobrien { "f17", 17 }, 37477298Sobrien { "f18", 18 }, 37577298Sobrien { "f19", 19 }, 37677298Sobrien { "f2", 2 }, 37777298Sobrien { "f20", 20 }, 37877298Sobrien { "f21", 21 }, 37977298Sobrien { "f22", 22 }, 38077298Sobrien { "f23", 23 }, 38177298Sobrien { "f24", 24 }, 38277298Sobrien { "f25", 25 }, 38377298Sobrien { "f26", 26 }, 38477298Sobrien { "f27", 27 }, 38577298Sobrien { "f28", 28 }, 38677298Sobrien { "f29", 29 }, 38777298Sobrien { "f3", 3 }, 38860484Sobrien { "f30", 30 }, 38960484Sobrien { "f31", 31 }, 39077298Sobrien { "f4", 4 }, 39177298Sobrien { "f5", 5 }, 39277298Sobrien { "f6", 6 }, 39377298Sobrien { "f7", 7 }, 39477298Sobrien { "f8", 8 }, 39577298Sobrien { "f9", 9 }, 39660484Sobrien 39760484Sobrien { "fpscr", 0 }, 39860484Sobrien 39960484Sobrien { "lr", 8 }, /* Link Register */ 40060484Sobrien 40160484Sobrien { "pmr", 0 }, 40260484Sobrien 40360484Sobrien { "r.0", 0 }, /* General Purpose Registers */ 40460484Sobrien { "r.1", 1 }, 40560484Sobrien { "r.10", 10 }, 40660484Sobrien { "r.11", 11 }, 40760484Sobrien { "r.12", 12 }, 40860484Sobrien { "r.13", 13 }, 40960484Sobrien { "r.14", 14 }, 41060484Sobrien { "r.15", 15 }, 41160484Sobrien { "r.16", 16 }, 41260484Sobrien { "r.17", 17 }, 41360484Sobrien { "r.18", 18 }, 41460484Sobrien { "r.19", 19 }, 41560484Sobrien { "r.2", 2 }, 41660484Sobrien { "r.20", 20 }, 41760484Sobrien { "r.21", 21 }, 41860484Sobrien { "r.22", 22 }, 41960484Sobrien { "r.23", 23 }, 42060484Sobrien { "r.24", 24 }, 42160484Sobrien { "r.25", 25 }, 42260484Sobrien { "r.26", 26 }, 42360484Sobrien { "r.27", 27 }, 42460484Sobrien { "r.28", 28 }, 42560484Sobrien { "r.29", 29 }, 42660484Sobrien { "r.3", 3 }, 42760484Sobrien { "r.30", 30 }, 42860484Sobrien { "r.31", 31 }, 42960484Sobrien { "r.4", 4 }, 43060484Sobrien { "r.5", 5 }, 43160484Sobrien { "r.6", 6 }, 43260484Sobrien { "r.7", 7 }, 43360484Sobrien { "r.8", 8 }, 43460484Sobrien { "r.9", 9 }, 43560484Sobrien 43660484Sobrien { "r.sp", 1 }, /* Stack Pointer */ 43760484Sobrien 43860484Sobrien { "r.toc", 2 }, /* Pointer to the table of contents */ 43960484Sobrien 44060484Sobrien { "r0", 0 }, /* More general purpose registers */ 44160484Sobrien { "r1", 1 }, 44260484Sobrien { "r10", 10 }, 44360484Sobrien { "r11", 11 }, 44460484Sobrien { "r12", 12 }, 44560484Sobrien { "r13", 13 }, 44660484Sobrien { "r14", 14 }, 44760484Sobrien { "r15", 15 }, 44860484Sobrien { "r16", 16 }, 44960484Sobrien { "r17", 17 }, 45060484Sobrien { "r18", 18 }, 45160484Sobrien { "r19", 19 }, 45260484Sobrien { "r2", 2 }, 45360484Sobrien { "r20", 20 }, 45460484Sobrien { "r21", 21 }, 45560484Sobrien { "r22", 22 }, 45660484Sobrien { "r23", 23 }, 45760484Sobrien { "r24", 24 }, 45860484Sobrien { "r25", 25 }, 45960484Sobrien { "r26", 26 }, 46060484Sobrien { "r27", 27 }, 46160484Sobrien { "r28", 28 }, 46260484Sobrien { "r29", 29 }, 46360484Sobrien { "r3", 3 }, 46460484Sobrien { "r30", 30 }, 46560484Sobrien { "r31", 31 }, 46660484Sobrien { "r4", 4 }, 46760484Sobrien { "r5", 5 }, 46860484Sobrien { "r6", 6 }, 46960484Sobrien { "r7", 7 }, 47060484Sobrien { "r8", 8 }, 47160484Sobrien { "r9", 9 }, 47260484Sobrien 47360484Sobrien { "rtoc", 2 }, /* Table of contents */ 47460484Sobrien 47560484Sobrien { "sdr1", 25 }, /* Storage Description Register 1 */ 47660484Sobrien 47760484Sobrien { "sp", 1 }, 47860484Sobrien 47960484Sobrien { "srr0", 26 }, /* Machine Status Save/Restore Register 0 */ 48060484Sobrien { "srr1", 27 }, /* Machine Status Save/Restore Register 1 */ 48160484Sobrien 48277298Sobrien { "v.0", 0 }, /* Vector registers */ 48377298Sobrien { "v.1", 1 }, 48477298Sobrien { "v.10", 10 }, 48577298Sobrien { "v.11", 11 }, 48677298Sobrien { "v.12", 12 }, 48777298Sobrien { "v.13", 13 }, 48877298Sobrien { "v.14", 14 }, 48977298Sobrien { "v.15", 15 }, 49077298Sobrien { "v.16", 16 }, 49177298Sobrien { "v.17", 17 }, 49277298Sobrien { "v.18", 18 }, 49377298Sobrien { "v.19", 19 }, 49477298Sobrien { "v.2", 2 }, 49577298Sobrien { "v.20", 20 }, 49677298Sobrien { "v.21", 21 }, 49777298Sobrien { "v.22", 22 }, 49877298Sobrien { "v.23", 23 }, 49977298Sobrien { "v.24", 24 }, 50077298Sobrien { "v.25", 25 }, 50177298Sobrien { "v.26", 26 }, 50277298Sobrien { "v.27", 27 }, 50377298Sobrien { "v.28", 28 }, 50477298Sobrien { "v.29", 29 }, 50577298Sobrien { "v.3", 3 }, 50677298Sobrien { "v.30", 30 }, 50777298Sobrien { "v.31", 31 }, 50877298Sobrien { "v.4", 4 }, 50977298Sobrien { "v.5", 5 }, 51077298Sobrien { "v.6", 6 }, 51177298Sobrien { "v.7", 7 }, 51277298Sobrien { "v.8", 8 }, 51377298Sobrien { "v.9", 9 }, 51477298Sobrien 51577298Sobrien { "v0", 0 }, 51677298Sobrien { "v1", 1 }, 51777298Sobrien { "v10", 10 }, 51877298Sobrien { "v11", 11 }, 51977298Sobrien { "v12", 12 }, 52077298Sobrien { "v13", 13 }, 52177298Sobrien { "v14", 14 }, 52277298Sobrien { "v15", 15 }, 52377298Sobrien { "v16", 16 }, 52477298Sobrien { "v17", 17 }, 52577298Sobrien { "v18", 18 }, 52677298Sobrien { "v19", 19 }, 52777298Sobrien { "v2", 2 }, 52877298Sobrien { "v20", 20 }, 52977298Sobrien { "v21", 21 }, 53077298Sobrien { "v22", 22 }, 53177298Sobrien { "v23", 23 }, 53277298Sobrien { "v24", 24 }, 53377298Sobrien { "v25", 25 }, 53477298Sobrien { "v26", 26 }, 53577298Sobrien { "v27", 27 }, 53677298Sobrien { "v28", 28 }, 53777298Sobrien { "v29", 29 }, 53877298Sobrien { "v3", 3 }, 53977298Sobrien { "v30", 30 }, 54077298Sobrien { "v31", 31 }, 54177298Sobrien { "v4", 4 }, 54277298Sobrien { "v5", 5 }, 54377298Sobrien { "v6", 6 }, 54477298Sobrien { "v7", 7 }, 54577298Sobrien { "v8", 8 }, 54677298Sobrien { "v9", 9 }, 54777298Sobrien 54860484Sobrien { "xer", 1 }, 54960484Sobrien 55060484Sobrien}; 55160484Sobrien 55277298Sobrien#define REG_NAME_CNT (sizeof (pre_defined_registers) / sizeof (struct pd_reg)) 55360484Sobrien 55460484Sobrien/* Given NAME, find the register number associated with that name, return 55560484Sobrien the integer value associated with the given name or -1 on failure. */ 55660484Sobrien 55760484Sobrienstatic int 558218822Sdimreg_name_search (const struct pd_reg *regs, int regcount, const char *name) 55960484Sobrien{ 56060484Sobrien int middle, low, high; 56160484Sobrien int cmp; 56260484Sobrien 56360484Sobrien low = 0; 56460484Sobrien high = regcount - 1; 56560484Sobrien 56660484Sobrien do 56760484Sobrien { 56860484Sobrien middle = (low + high) / 2; 56960484Sobrien cmp = strcasecmp (name, regs[middle].name); 57060484Sobrien if (cmp < 0) 57160484Sobrien high = middle - 1; 57260484Sobrien else if (cmp > 0) 57360484Sobrien low = middle + 1; 57460484Sobrien else 57560484Sobrien return regs[middle].value; 57660484Sobrien } 57760484Sobrien while (low <= high); 57860484Sobrien 57960484Sobrien return -1; 58060484Sobrien} 58160484Sobrien 58260484Sobrien/* 58389857Sobrien * Summary of register_name. 58460484Sobrien * 58560484Sobrien * in: Input_line_pointer points to 1st char of operand. 58660484Sobrien * 58760484Sobrien * out: A expressionS. 58860484Sobrien * The operand may have been a register: in this case, X_op == O_register, 58960484Sobrien * X_add_number is set to the register number, and truth is returned. 59060484Sobrien * Input_line_pointer->(next non-blank) char after operand, or is in its 59160484Sobrien * original state. 59260484Sobrien */ 59360484Sobrien 594130561Sobrienstatic bfd_boolean 595218822Sdimregister_name (expressionS *expressionP) 59660484Sobrien{ 59760484Sobrien int reg_number; 59860484Sobrien char *name; 59960484Sobrien char *start; 60060484Sobrien char c; 60160484Sobrien 60289857Sobrien /* Find the spelling of the operand. */ 60360484Sobrien start = name = input_line_pointer; 60489857Sobrien if (name[0] == '%' && ISALPHA (name[1])) 60560484Sobrien name = ++input_line_pointer; 60660484Sobrien 60789857Sobrien else if (!reg_names_p || !ISALPHA (name[0])) 608130561Sobrien return FALSE; 60960484Sobrien 61060484Sobrien c = get_symbol_end (); 61160484Sobrien reg_number = reg_name_search (pre_defined_registers, REG_NAME_CNT, name); 61260484Sobrien 61389857Sobrien /* Put back the delimiting char. */ 61489857Sobrien *input_line_pointer = c; 61589857Sobrien 61689857Sobrien /* Look to see if it's in the register table. */ 61777298Sobrien if (reg_number >= 0) 61860484Sobrien { 61960484Sobrien expressionP->X_op = O_register; 62060484Sobrien expressionP->X_add_number = reg_number; 62177298Sobrien 62289857Sobrien /* Make the rest nice. */ 62360484Sobrien expressionP->X_add_symbol = NULL; 62460484Sobrien expressionP->X_op_symbol = NULL; 625130561Sobrien return TRUE; 62660484Sobrien } 62789857Sobrien 62889857Sobrien /* Reset the line as if we had not done anything. */ 62989857Sobrien input_line_pointer = start; 630130561Sobrien return FALSE; 63160484Sobrien} 63260484Sobrien 63360484Sobrien/* This function is called for each symbol seen in an expression. It 63460484Sobrien handles the special parsing which PowerPC assemblers are supposed 63560484Sobrien to use for condition codes. */ 63660484Sobrien 63760484Sobrien/* Whether to do the special parsing. */ 638130561Sobrienstatic bfd_boolean cr_operand; 63960484Sobrien 64060484Sobrien/* Names to recognize in a condition code. This table is sorted. */ 64160484Sobrienstatic const struct pd_reg cr_names[] = 64260484Sobrien{ 64360484Sobrien { "cr0", 0 }, 64460484Sobrien { "cr1", 1 }, 64560484Sobrien { "cr2", 2 }, 64660484Sobrien { "cr3", 3 }, 64760484Sobrien { "cr4", 4 }, 64860484Sobrien { "cr5", 5 }, 64960484Sobrien { "cr6", 6 }, 65060484Sobrien { "cr7", 7 }, 65160484Sobrien { "eq", 2 }, 65260484Sobrien { "gt", 1 }, 65360484Sobrien { "lt", 0 }, 65460484Sobrien { "so", 3 }, 65560484Sobrien { "un", 3 } 65660484Sobrien}; 65760484Sobrien 65860484Sobrien/* Parsing function. This returns non-zero if it recognized an 65960484Sobrien expression. */ 66060484Sobrien 66160484Sobrienint 662218822Sdimppc_parse_name (const char *name, expressionS *expr) 66360484Sobrien{ 66460484Sobrien int val; 66560484Sobrien 66660484Sobrien if (! cr_operand) 66760484Sobrien return 0; 66860484Sobrien 66960484Sobrien val = reg_name_search (cr_names, sizeof cr_names / sizeof cr_names[0], 67060484Sobrien name); 67160484Sobrien if (val < 0) 67260484Sobrien return 0; 67360484Sobrien 67460484Sobrien expr->X_op = O_constant; 67560484Sobrien expr->X_add_number = val; 67660484Sobrien 67760484Sobrien return 1; 67860484Sobrien} 67960484Sobrien 68060484Sobrien/* Local variables. */ 68160484Sobrien 68260484Sobrien/* The type of processor we are assembling for. This is one or more 68360484Sobrien of the PPC_OPCODE flags defined in opcode/ppc.h. */ 684104834Sobrienstatic unsigned long ppc_cpu = 0; 68560484Sobrien 686104834Sobrien/* Whether to target xcoff64/elf64. */ 687104834Sobrienstatic unsigned int ppc_obj64 = BFD_DEFAULT_TARGET_SIZE == 64; 68860484Sobrien 68960484Sobrien/* Opcode hash table. */ 69060484Sobrienstatic struct hash_control *ppc_hash; 69160484Sobrien 69260484Sobrien/* Macro hash table. */ 69360484Sobrienstatic struct hash_control *ppc_macro_hash; 69460484Sobrien 69560484Sobrien#ifdef OBJ_ELF 69689857Sobrien/* What type of shared library support to use. */ 69777298Sobrienstatic enum { SHLIB_NONE, SHLIB_PIC, SHLIB_MRELOCATABLE } shlib = SHLIB_NONE; 69860484Sobrien 69989857Sobrien/* Flags to set in the elf header. */ 70060484Sobrienstatic flagword ppc_flags = 0; 70160484Sobrien 70260484Sobrien/* Whether this is Solaris or not. */ 70360484Sobrien#ifdef TARGET_SOLARIS_COMMENT 704130561Sobrien#define SOLARIS_P TRUE 70560484Sobrien#else 706130561Sobrien#define SOLARIS_P FALSE 70760484Sobrien#endif 70860484Sobrien 709130561Sobrienstatic bfd_boolean msolaris = SOLARIS_P; 71060484Sobrien#endif 71160484Sobrien 71260484Sobrien#ifdef OBJ_XCOFF 71360484Sobrien 71460484Sobrien/* The RS/6000 assembler uses the .csect pseudo-op to generate code 71560484Sobrien using a bunch of different sections. These assembler sections, 71660484Sobrien however, are all encompassed within the .text or .data sections of 71760484Sobrien the final output file. We handle this by using different 71860484Sobrien subsegments within these main segments. */ 71960484Sobrien 72060484Sobrien/* Next subsegment to allocate within the .text segment. */ 72160484Sobrienstatic subsegT ppc_text_subsegment = 2; 72260484Sobrien 72360484Sobrien/* Linked list of csects in the text section. */ 72460484Sobrienstatic symbolS *ppc_text_csects; 72560484Sobrien 72660484Sobrien/* Next subsegment to allocate within the .data segment. */ 72760484Sobrienstatic subsegT ppc_data_subsegment = 2; 72860484Sobrien 72960484Sobrien/* Linked list of csects in the data section. */ 73060484Sobrienstatic symbolS *ppc_data_csects; 73160484Sobrien 73260484Sobrien/* The current csect. */ 73360484Sobrienstatic symbolS *ppc_current_csect; 73460484Sobrien 73560484Sobrien/* The RS/6000 assembler uses a TOC which holds addresses of functions 73660484Sobrien and variables. Symbols are put in the TOC with the .tc pseudo-op. 73760484Sobrien A special relocation is used when accessing TOC entries. We handle 73860484Sobrien the TOC as a subsegment within the .data segment. We set it up if 73960484Sobrien we see a .toc pseudo-op, and save the csect symbol here. */ 74060484Sobrienstatic symbolS *ppc_toc_csect; 74160484Sobrien 74260484Sobrien/* The first frag in the TOC subsegment. */ 74360484Sobrienstatic fragS *ppc_toc_frag; 74460484Sobrien 74560484Sobrien/* The first frag in the first subsegment after the TOC in the .data 74660484Sobrien segment. NULL if there are no subsegments after the TOC. */ 74760484Sobrienstatic fragS *ppc_after_toc_frag; 74860484Sobrien 74960484Sobrien/* The current static block. */ 75060484Sobrienstatic symbolS *ppc_current_block; 75160484Sobrien 75260484Sobrien/* The COFF debugging section; set by md_begin. This is not the 75360484Sobrien .debug section, but is instead the secret BFD section which will 75460484Sobrien cause BFD to set the section number of a symbol to N_DEBUG. */ 75560484Sobrienstatic asection *ppc_coff_debug_section; 75660484Sobrien 75760484Sobrien#endif /* OBJ_XCOFF */ 75860484Sobrien 75960484Sobrien#ifdef TE_PE 76060484Sobrien 76160484Sobrien/* Various sections that we need for PE coff support. */ 76260484Sobrienstatic segT ydata_section; 76360484Sobrienstatic segT pdata_section; 76460484Sobrienstatic segT reldata_section; 76560484Sobrienstatic segT rdata_section; 76660484Sobrienstatic segT tocdata_section; 76760484Sobrien 76877298Sobrien/* The current section and the previous section. See ppc_previous. */ 76960484Sobrienstatic segT ppc_previous_section; 77060484Sobrienstatic segT ppc_current_section; 77160484Sobrien 77260484Sobrien#endif /* TE_PE */ 77360484Sobrien 77460484Sobrien#ifdef OBJ_ELF 77560484SobriensymbolS *GOT_symbol; /* Pre-defined "_GLOBAL_OFFSET_TABLE" */ 776130561Sobrien#define PPC_APUINFO_ISEL 0x40 777130561Sobrien#define PPC_APUINFO_PMR 0x41 778130561Sobrien#define PPC_APUINFO_RFMCI 0x42 779130561Sobrien#define PPC_APUINFO_CACHELCK 0x43 780130561Sobrien#define PPC_APUINFO_SPE 0x100 781130561Sobrien#define PPC_APUINFO_EFS 0x101 782130561Sobrien#define PPC_APUINFO_BRLOCK 0x102 783130561Sobrien 784130561Sobrien/* 785130561Sobrien * We keep a list of APUinfo 786130561Sobrien */ 787130561Sobrienunsigned long *ppc_apuinfo_list; 788130561Sobrienunsigned int ppc_apuinfo_num; 789130561Sobrienunsigned int ppc_apuinfo_num_alloc; 79060484Sobrien#endif /* OBJ_ELF */ 79160484Sobrien 79260484Sobrien#ifdef OBJ_ELF 79389857Sobrienconst char *const md_shortopts = "b:l:usm:K:VQ:"; 79460484Sobrien#else 79589857Sobrienconst char *const md_shortopts = "um:"; 79660484Sobrien#endif 79789857Sobrienconst struct option md_longopts[] = { 79860484Sobrien {NULL, no_argument, NULL, 0} 79960484Sobrien}; 80089857Sobrienconst size_t md_longopts_size = sizeof (md_longopts); 80160484Sobrien 802130561Sobrien 803130561Sobrien/* Handle -m options that set cpu type, and .machine arg. */ 804130561Sobrien 805130561Sobrienstatic int 806130561Sobrienparse_cpu (const char *arg) 807130561Sobrien{ 808130561Sobrien /* -mpwrx and -mpwr2 mean to assemble for the IBM POWER/2 809130561Sobrien (RIOS2). */ 810130561Sobrien if (strcmp (arg, "pwrx") == 0 || strcmp (arg, "pwr2") == 0) 811130561Sobrien ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_POWER2 | PPC_OPCODE_32; 812130561Sobrien /* -mpwr means to assemble for the IBM POWER (RIOS1). */ 813130561Sobrien else if (strcmp (arg, "pwr") == 0) 814130561Sobrien ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_32; 815130561Sobrien /* -m601 means to assemble for the PowerPC 601, which includes 816130561Sobrien instructions that are holdovers from the Power. */ 817130561Sobrien else if (strcmp (arg, "601") == 0) 818130561Sobrien ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC 819130561Sobrien | PPC_OPCODE_601 | PPC_OPCODE_32); 820130561Sobrien /* -mppc, -mppc32, -m603, and -m604 mean to assemble for the 821130561Sobrien PowerPC 603/604. */ 822130561Sobrien else if (strcmp (arg, "ppc") == 0 823130561Sobrien || strcmp (arg, "ppc32") == 0 824130561Sobrien || strcmp (arg, "603") == 0 825130561Sobrien || strcmp (arg, "604") == 0) 826130561Sobrien ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32; 827130561Sobrien /* -m403 and -m405 mean to assemble for the PowerPC 403/405. */ 828130561Sobrien else if (strcmp (arg, "403") == 0 829130561Sobrien || strcmp (arg, "405") == 0) 830130561Sobrien ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC 831130561Sobrien | PPC_OPCODE_403 | PPC_OPCODE_32); 832130561Sobrien else if (strcmp (arg, "440") == 0) 833130561Sobrien ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_32 834130561Sobrien | PPC_OPCODE_440 | PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI); 835130561Sobrien else if (strcmp (arg, "7400") == 0 836130561Sobrien || strcmp (arg, "7410") == 0 837130561Sobrien || strcmp (arg, "7450") == 0 838130561Sobrien || strcmp (arg, "7455") == 0) 839130561Sobrien ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC 840130561Sobrien | PPC_OPCODE_ALTIVEC | PPC_OPCODE_32); 841218822Sdim else if (strcmp (arg, "e300") == 0) 842218822Sdim ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32 843218822Sdim | PPC_OPCODE_E300); 844130561Sobrien else if (strcmp (arg, "altivec") == 0) 845130561Sobrien { 846130561Sobrien if (ppc_cpu == 0) 847130561Sobrien ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_ALTIVEC; 848130561Sobrien else 849130561Sobrien ppc_cpu |= PPC_OPCODE_ALTIVEC; 850130561Sobrien } 851130561Sobrien else if (strcmp (arg, "e500") == 0 || strcmp (arg, "e500x2") == 0) 852130561Sobrien { 853130561Sobrien ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_SPE 854130561Sobrien | PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK 855130561Sobrien | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK 856130561Sobrien | PPC_OPCODE_RFMCI); 857130561Sobrien } 858130561Sobrien else if (strcmp (arg, "spe") == 0) 859130561Sobrien { 860130561Sobrien if (ppc_cpu == 0) 861130561Sobrien ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_SPE | PPC_OPCODE_EFS; 862130561Sobrien else 863130561Sobrien ppc_cpu |= PPC_OPCODE_SPE; 864130561Sobrien } 865130561Sobrien /* -mppc64 and -m620 mean to assemble for the 64-bit PowerPC 866130561Sobrien 620. */ 867130561Sobrien else if (strcmp (arg, "ppc64") == 0 || strcmp (arg, "620") == 0) 868130561Sobrien { 869130561Sobrien ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64; 870130561Sobrien } 871130561Sobrien else if (strcmp (arg, "ppc64bridge") == 0) 872130561Sobrien { 873130561Sobrien ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC 874130561Sobrien | PPC_OPCODE_64_BRIDGE | PPC_OPCODE_64); 875130561Sobrien } 876130561Sobrien /* -mbooke/-mbooke32 mean enable 32-bit BookE support. */ 877130561Sobrien else if (strcmp (arg, "booke") == 0 || strcmp (arg, "booke32") == 0) 878130561Sobrien { 879130561Sobrien ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_32; 880130561Sobrien } 881130561Sobrien /* -mbooke64 means enable 64-bit BookE support. */ 882130561Sobrien else if (strcmp (arg, "booke64") == 0) 883130561Sobrien { 884130561Sobrien ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE 885130561Sobrien | PPC_OPCODE_BOOKE64 | PPC_OPCODE_64); 886130561Sobrien } 887130561Sobrien else if (strcmp (arg, "power4") == 0) 888130561Sobrien { 889130561Sobrien ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC 890130561Sobrien | PPC_OPCODE_64 | PPC_OPCODE_POWER4); 891130561Sobrien } 892218822Sdim else if (strcmp (arg, "power5") == 0) 893218822Sdim { 894218822Sdim ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC 895218822Sdim | PPC_OPCODE_64 | PPC_OPCODE_POWER4 896218822Sdim | PPC_OPCODE_POWER5); 897218822Sdim } 898218822Sdim else if (strcmp (arg, "power6") == 0) 899218822Sdim { 900218822Sdim ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC 901218822Sdim | PPC_OPCODE_64 | PPC_OPCODE_POWER4 902218822Sdim | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6); 903218822Sdim } 904218822Sdim else if (strcmp (arg, "cell") == 0) 905218822Sdim { 906218822Sdim ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC 907218822Sdim | PPC_OPCODE_64 | PPC_OPCODE_POWER4 908218822Sdim | PPC_OPCODE_CELL); 909218822Sdim } 910130561Sobrien /* -mcom means assemble for the common intersection between Power 911130561Sobrien and PowerPC. At present, we just allow the union, rather 912130561Sobrien than the intersection. */ 913130561Sobrien else if (strcmp (arg, "com") == 0) 914130561Sobrien ppc_cpu = PPC_OPCODE_COMMON | PPC_OPCODE_32; 915130561Sobrien /* -many means to assemble for any architecture (PWR/PWRX/PPC). */ 916130561Sobrien else if (strcmp (arg, "any") == 0) 917130561Sobrien ppc_cpu |= PPC_OPCODE_ANY; 918130561Sobrien else 919130561Sobrien return 0; 920130561Sobrien 921130561Sobrien return 1; 922130561Sobrien} 923130561Sobrien 92460484Sobrienint 925218822Sdimmd_parse_option (int c, char *arg) 92660484Sobrien{ 92760484Sobrien switch (c) 92860484Sobrien { 92960484Sobrien case 'u': 93060484Sobrien /* -u means that any undefined symbols should be treated as 93160484Sobrien external, which is the default for gas anyhow. */ 93260484Sobrien break; 93360484Sobrien 93460484Sobrien#ifdef OBJ_ELF 93560484Sobrien case 'l': 93660484Sobrien /* Solaris as takes -le (presumably for little endian). For completeness 93789857Sobrien sake, recognize -be also. */ 93860484Sobrien if (strcmp (arg, "e") == 0) 93960484Sobrien { 94060484Sobrien target_big_endian = 0; 94160484Sobrien set_target_endian = 1; 94260484Sobrien } 94360484Sobrien else 94460484Sobrien return 0; 94560484Sobrien 94660484Sobrien break; 94760484Sobrien 94860484Sobrien case 'b': 94960484Sobrien if (strcmp (arg, "e") == 0) 95060484Sobrien { 95160484Sobrien target_big_endian = 1; 95260484Sobrien set_target_endian = 1; 95360484Sobrien } 95460484Sobrien else 95560484Sobrien return 0; 95660484Sobrien 95760484Sobrien break; 95860484Sobrien 95960484Sobrien case 'K': 96089857Sobrien /* Recognize -K PIC. */ 96160484Sobrien if (strcmp (arg, "PIC") == 0 || strcmp (arg, "pic") == 0) 96260484Sobrien { 96360484Sobrien shlib = SHLIB_PIC; 96460484Sobrien ppc_flags |= EF_PPC_RELOCATABLE_LIB; 96560484Sobrien } 96660484Sobrien else 96760484Sobrien return 0; 96860484Sobrien 96960484Sobrien break; 97060484Sobrien#endif 97160484Sobrien 97277298Sobrien /* a64 and a32 determine whether to use XCOFF64 or XCOFF32. */ 97377298Sobrien case 'a': 97477298Sobrien if (strcmp (arg, "64") == 0) 975107492Sobrien { 976107492Sobrien#ifdef BFD64 977107492Sobrien ppc_obj64 = 1; 978107492Sobrien#else 979107492Sobrien as_fatal (_("%s unsupported"), "-a64"); 980107492Sobrien#endif 981107492Sobrien } 98277298Sobrien else if (strcmp (arg, "32") == 0) 983104834Sobrien ppc_obj64 = 0; 98477298Sobrien else 98577298Sobrien return 0; 98677298Sobrien break; 98777298Sobrien 98860484Sobrien case 'm': 989130561Sobrien if (parse_cpu (arg)) 990130561Sobrien ; 99160484Sobrien 99260484Sobrien else if (strcmp (arg, "regnames") == 0) 993130561Sobrien reg_names_p = TRUE; 99460484Sobrien 99560484Sobrien else if (strcmp (arg, "no-regnames") == 0) 996130561Sobrien reg_names_p = FALSE; 99760484Sobrien 99860484Sobrien#ifdef OBJ_ELF 99989857Sobrien /* -mrelocatable/-mrelocatable-lib -- warn about initializations 100089857Sobrien that require relocation. */ 100160484Sobrien else if (strcmp (arg, "relocatable") == 0) 100260484Sobrien { 100377298Sobrien shlib = SHLIB_MRELOCATABLE; 100460484Sobrien ppc_flags |= EF_PPC_RELOCATABLE; 100560484Sobrien } 100660484Sobrien 100760484Sobrien else if (strcmp (arg, "relocatable-lib") == 0) 100860484Sobrien { 100977298Sobrien shlib = SHLIB_MRELOCATABLE; 101060484Sobrien ppc_flags |= EF_PPC_RELOCATABLE_LIB; 101160484Sobrien } 101260484Sobrien 101389857Sobrien /* -memb, set embedded bit. */ 101460484Sobrien else if (strcmp (arg, "emb") == 0) 101560484Sobrien ppc_flags |= EF_PPC_EMB; 101660484Sobrien 101789857Sobrien /* -mlittle/-mbig set the endianess. */ 101889857Sobrien else if (strcmp (arg, "little") == 0 101989857Sobrien || strcmp (arg, "little-endian") == 0) 102060484Sobrien { 102160484Sobrien target_big_endian = 0; 102260484Sobrien set_target_endian = 1; 102360484Sobrien } 102460484Sobrien 102560484Sobrien else if (strcmp (arg, "big") == 0 || strcmp (arg, "big-endian") == 0) 102660484Sobrien { 102760484Sobrien target_big_endian = 1; 102860484Sobrien set_target_endian = 1; 102960484Sobrien } 103060484Sobrien 103160484Sobrien else if (strcmp (arg, "solaris") == 0) 103260484Sobrien { 1033130561Sobrien msolaris = TRUE; 103460484Sobrien ppc_comment_chars = ppc_solaris_comment_chars; 103560484Sobrien } 103660484Sobrien 103760484Sobrien else if (strcmp (arg, "no-solaris") == 0) 103860484Sobrien { 1039130561Sobrien msolaris = FALSE; 104060484Sobrien ppc_comment_chars = ppc_eabi_comment_chars; 104160484Sobrien } 104260484Sobrien#endif 104360484Sobrien else 104460484Sobrien { 104560484Sobrien as_bad (_("invalid switch -m%s"), arg); 104660484Sobrien return 0; 104760484Sobrien } 104860484Sobrien break; 104960484Sobrien 105060484Sobrien#ifdef OBJ_ELF 105160484Sobrien /* -V: SVR4 argument to print version ID. */ 105260484Sobrien case 'V': 105360484Sobrien print_version_id (); 105460484Sobrien break; 105560484Sobrien 105660484Sobrien /* -Qy, -Qn: SVR4 arguments controlling whether a .comment section 105760484Sobrien should be emitted or not. FIXME: Not implemented. */ 105860484Sobrien case 'Q': 105960484Sobrien break; 106060484Sobrien 106160484Sobrien /* Solaris takes -s to specify that .stabs go in a .stabs section, 106260484Sobrien rather than .stabs.excl, which is ignored by the linker. 106360484Sobrien FIXME: Not implemented. */ 106460484Sobrien case 's': 106560484Sobrien if (arg) 106660484Sobrien return 0; 106760484Sobrien 106860484Sobrien break; 106960484Sobrien#endif 107060484Sobrien 107160484Sobrien default: 107260484Sobrien return 0; 107360484Sobrien } 107460484Sobrien 107560484Sobrien return 1; 107660484Sobrien} 107760484Sobrien 107860484Sobrienvoid 1079218822Sdimmd_show_usage (FILE *stream) 108060484Sobrien{ 108177298Sobrien fprintf (stream, _("\ 108260484SobrienPowerPC options:\n\ 1083130561Sobrien-a32 generate ELF32/XCOFF32\n\ 1084130561Sobrien-a64 generate ELF64/XCOFF64\n\ 108560484Sobrien-u ignored\n\ 108692828Sobrien-mpwrx, -mpwr2 generate code for POWER/2 (RIOS2)\n\ 108792828Sobrien-mpwr generate code for POWER (RIOS1)\n\ 108892828Sobrien-m601 generate code for PowerPC 601\n\ 108989857Sobrien-mppc, -mppc32, -m603, -m604\n\ 109092828Sobrien generate code for PowerPC 603/604\n\ 1091130561Sobrien-m403, -m405 generate code for PowerPC 403/405\n\ 1092130561Sobrien-m440 generate code for PowerPC 440\n\ 109389857Sobrien-m7400, -m7410, -m7450, -m7455\n\ 1094130561Sobrien generate code For PowerPC 7400/7410/7450/7455\n")); 1095130561Sobrien fprintf (stream, _("\ 109692828Sobrien-mppc64, -m620 generate code for PowerPC 620/625/630\n\ 109760484Sobrien-mppc64bridge generate code for PowerPC 64, including bridge insns\n\ 109889857Sobrien-mbooke64 generate code for 64-bit PowerPC BookE\n\ 109989857Sobrien-mbooke, mbooke32 generate code for 32-bit PowerPC BookE\n\ 110092828Sobrien-mpower4 generate code for Power4 architecture\n\ 1101218822Sdim-mpower5 generate code for Power5 architecture\n\ 1102218822Sdim-mpower6 generate code for Power6 architecture\n\ 1103218822Sdim-mcell generate code for Cell Broadband Engine architecture\n\ 1104130561Sobrien-mcom generate code Power/PowerPC common instructions\n\ 1105130561Sobrien-many generate code for any architecture (PWR/PWRX/PPC)\n")); 1106130561Sobrien fprintf (stream, _("\ 110789857Sobrien-maltivec generate code for AltiVec\n\ 1108218822Sdim-me300 generate code for PowerPC e300 family\n\ 1109130561Sobrien-me500, -me500x2 generate code for Motorola e500 core complex\n\ 1110130561Sobrien-mspe generate code for Motorola SPE instructions\n\ 111160484Sobrien-mregnames Allow symbolic names for registers\n\ 111260484Sobrien-mno-regnames Do not allow symbolic names for registers\n")); 111360484Sobrien#ifdef OBJ_ELF 111477298Sobrien fprintf (stream, _("\ 111560484Sobrien-mrelocatable support for GCC's -mrelocatble option\n\ 111660484Sobrien-mrelocatable-lib support for GCC's -mrelocatble-lib option\n\ 111760484Sobrien-memb set PPC_EMB bit in ELF flags\n\ 1118130561Sobrien-mlittle, -mlittle-endian, -l, -le\n\ 111960484Sobrien generate code for a little endian machine\n\ 1120130561Sobrien-mbig, -mbig-endian, -b, -be\n\ 1121130561Sobrien generate code for a big endian machine\n\ 112260484Sobrien-msolaris generate code for Solaris\n\ 112360484Sobrien-mno-solaris do not generate code for Solaris\n\ 112460484Sobrien-V print assembler version number\n\ 112560484Sobrien-Qy, -Qn ignored\n")); 112660484Sobrien#endif 112760484Sobrien} 112860484Sobrien 112960484Sobrien/* Set ppc_cpu if it is not already set. */ 113060484Sobrien 113160484Sobrienstatic void 1132218822Sdimppc_set_cpu (void) 113360484Sobrien{ 113460484Sobrien const char *default_os = TARGET_OS; 113560484Sobrien const char *default_cpu = TARGET_CPU; 113660484Sobrien 1137130561Sobrien if ((ppc_cpu & ~PPC_OPCODE_ANY) == 0) 113860484Sobrien { 1139107492Sobrien if (ppc_obj64) 1140130561Sobrien ppc_cpu |= PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64; 1141107492Sobrien else if (strncmp (default_os, "aix", 3) == 0 1142107492Sobrien && default_os[3] >= '4' && default_os[3] <= '9') 1143130561Sobrien ppc_cpu |= PPC_OPCODE_COMMON | PPC_OPCODE_32; 114460484Sobrien else if (strncmp (default_os, "aix3", 4) == 0) 1145130561Sobrien ppc_cpu |= PPC_OPCODE_POWER | PPC_OPCODE_32; 114660484Sobrien else if (strcmp (default_cpu, "rs6000") == 0) 1147130561Sobrien ppc_cpu |= PPC_OPCODE_POWER | PPC_OPCODE_32; 114889857Sobrien else if (strncmp (default_cpu, "powerpc", 7) == 0) 1149218822Sdim ppc_cpu |= PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32; 115060484Sobrien else 115189857Sobrien as_fatal (_("Unknown default cpu = %s, os = %s"), 115289857Sobrien default_cpu, default_os); 115360484Sobrien } 115460484Sobrien} 115560484Sobrien 1156218822Sdim/* Figure out the BFD architecture to use. This function and ppc_mach 1157218822Sdim are called well before md_begin, when the output file is opened. */ 115860484Sobrien 115960484Sobrienenum bfd_architecture 1160218822Sdimppc_arch (void) 116160484Sobrien{ 116260484Sobrien const char *default_cpu = TARGET_CPU; 116360484Sobrien ppc_set_cpu (); 116460484Sobrien 116560484Sobrien if ((ppc_cpu & PPC_OPCODE_PPC) != 0) 116660484Sobrien return bfd_arch_powerpc; 116760484Sobrien else if ((ppc_cpu & PPC_OPCODE_POWER) != 0) 116860484Sobrien return bfd_arch_rs6000; 116960484Sobrien else if ((ppc_cpu & (PPC_OPCODE_COMMON | PPC_OPCODE_ANY)) != 0) 117060484Sobrien { 117160484Sobrien if (strcmp (default_cpu, "rs6000") == 0) 117260484Sobrien return bfd_arch_rs6000; 117389857Sobrien else if (strncmp (default_cpu, "powerpc", 7) == 0) 117460484Sobrien return bfd_arch_powerpc; 117560484Sobrien } 117660484Sobrien 117760484Sobrien as_fatal (_("Neither Power nor PowerPC opcodes were selected.")); 117860484Sobrien return bfd_arch_unknown; 117960484Sobrien} 118060484Sobrien 118177298Sobrienunsigned long 1182218822Sdimppc_mach (void) 118377298Sobrien{ 1184107492Sobrien if (ppc_obj64) 1185107492Sobrien return bfd_mach_ppc64; 1186107492Sobrien else if (ppc_arch () == bfd_arch_rs6000) 1187107492Sobrien return bfd_mach_rs6k; 1188107492Sobrien else 1189107492Sobrien return bfd_mach_ppc; 119077298Sobrien} 119177298Sobrien 119277298Sobrienextern char* 1193218822Sdimppc_target_format (void) 119477298Sobrien{ 119577298Sobrien#ifdef OBJ_COFF 119677298Sobrien#ifdef TE_PE 119789857Sobrien return target_big_endian ? "pe-powerpc" : "pe-powerpcle"; 119877298Sobrien#elif TE_POWERMAC 119989857Sobrien return "xcoff-powermac"; 120077298Sobrien#else 1201104834Sobrien# ifdef TE_AIX5 1202104834Sobrien return (ppc_obj64 ? "aix5coff64-rs6000" : "aixcoff-rs6000"); 1203104834Sobrien# else 1204104834Sobrien return (ppc_obj64 ? "aixcoff64-rs6000" : "aixcoff-rs6000"); 1205104834Sobrien# endif 120677298Sobrien#endif 120777298Sobrien#endif 120877298Sobrien#ifdef OBJ_ELF 1209218822Sdim# ifdef TE_VXWORKS 1210218822Sdim return "elf32-powerpc-vxworks"; 1211218822Sdim# else 121289857Sobrien return (target_big_endian 1213104834Sobrien ? (ppc_obj64 ? "elf64-powerpc" : "elf32-powerpc") 1214104834Sobrien : (ppc_obj64 ? "elf64-powerpcle" : "elf32-powerpcle")); 1215218822Sdim# endif 121677298Sobrien#endif 121777298Sobrien} 121877298Sobrien 1219130561Sobrien/* Insert opcodes and macros into hash tables. Called at startup and 1220130561Sobrien for .cpu pseudo. */ 122160484Sobrien 1222130561Sobrienstatic void 1223130561Sobrienppc_setup_opcodes (void) 122460484Sobrien{ 1225218822Sdim const struct powerpc_opcode *op; 122660484Sobrien const struct powerpc_opcode *op_end; 122760484Sobrien const struct powerpc_macro *macro; 122860484Sobrien const struct powerpc_macro *macro_end; 1229218822Sdim bfd_boolean bad_insn = FALSE; 123060484Sobrien 1231130561Sobrien if (ppc_hash != NULL) 1232130561Sobrien hash_die (ppc_hash); 1233130561Sobrien if (ppc_macro_hash != NULL) 1234130561Sobrien hash_die (ppc_macro_hash); 123560484Sobrien 123660484Sobrien /* Insert the opcodes into a hash table. */ 123760484Sobrien ppc_hash = hash_new (); 123860484Sobrien 1239218822Sdim if (ENABLE_CHECKING) 1240218822Sdim { 1241218822Sdim unsigned int i; 1242218822Sdim 1243218822Sdim /* Check operand masks. Code here and in the disassembler assumes 1244218822Sdim all the 1's in the mask are contiguous. */ 1245218822Sdim for (i = 0; i < num_powerpc_operands; ++i) 1246218822Sdim { 1247218822Sdim unsigned long mask = powerpc_operands[i].bitm; 1248218822Sdim unsigned long right_bit; 1249218822Sdim unsigned int j; 1250218822Sdim 1251218822Sdim right_bit = mask & -mask; 1252218822Sdim mask += right_bit; 1253218822Sdim right_bit = mask & -mask; 1254218822Sdim if (mask != right_bit) 1255218822Sdim { 1256218822Sdim as_bad (_("powerpc_operands[%d].bitm invalid"), i); 1257218822Sdim bad_insn = TRUE; 1258218822Sdim } 1259218822Sdim for (j = i + 1; j < num_powerpc_operands; ++j) 1260218822Sdim if (memcmp (&powerpc_operands[i], &powerpc_operands[j], 1261218822Sdim sizeof (powerpc_operands[0])) == 0) 1262218822Sdim { 1263218822Sdim as_bad (_("powerpc_operands[%d] duplicates powerpc_operands[%d]"), 1264218822Sdim j, i); 1265218822Sdim bad_insn = TRUE; 1266218822Sdim } 1267218822Sdim } 1268218822Sdim } 1269218822Sdim 127060484Sobrien op_end = powerpc_opcodes + powerpc_num_opcodes; 127160484Sobrien for (op = powerpc_opcodes; op < op_end; op++) 127260484Sobrien { 1273218822Sdim if (ENABLE_CHECKING) 1274218822Sdim { 1275218822Sdim const unsigned char *o; 1276218822Sdim unsigned long omask = op->mask; 127760484Sobrien 1278218822Sdim /* The mask had better not trim off opcode bits. */ 1279218822Sdim if ((op->opcode & omask) != op->opcode) 1280218822Sdim { 1281218822Sdim as_bad (_("mask trims opcode bits for %s"), 1282218822Sdim op->name); 1283218822Sdim bad_insn = TRUE; 1284218822Sdim } 1285218822Sdim 1286218822Sdim /* The operands must not overlap the opcode or each other. */ 1287218822Sdim for (o = op->operands; *o; ++o) 1288218822Sdim if (*o >= num_powerpc_operands) 1289218822Sdim { 1290218822Sdim as_bad (_("operand index error for %s"), 1291218822Sdim op->name); 1292218822Sdim bad_insn = TRUE; 1293218822Sdim } 1294218822Sdim else 1295218822Sdim { 1296218822Sdim const struct powerpc_operand *operand = &powerpc_operands[*o]; 1297218822Sdim if (operand->shift >= 0) 1298218822Sdim { 1299218822Sdim unsigned long mask = operand->bitm << operand->shift; 1300218822Sdim if (omask & mask) 1301218822Sdim { 1302218822Sdim as_bad (_("operand %d overlap in %s"), 1303218822Sdim (int) (o - op->operands), op->name); 1304218822Sdim bad_insn = TRUE; 1305218822Sdim } 1306218822Sdim omask |= mask; 1307218822Sdim } 1308218822Sdim } 1309218822Sdim } 1310218822Sdim 1311104834Sobrien if ((op->flags & ppc_cpu & ~(PPC_OPCODE_32 | PPC_OPCODE_64)) != 0 131260484Sobrien && ((op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64)) == 0 1313104834Sobrien || ((op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64)) 1314104834Sobrien == (ppc_cpu & (PPC_OPCODE_32 | PPC_OPCODE_64))) 131592828Sobrien || (ppc_cpu & PPC_OPCODE_64_BRIDGE) != 0) 1316104834Sobrien /* Certain instructions (eg: extsw) do not exist in the 1317104834Sobrien 32-bit BookE instruction set, but they do exist in the 1318104834Sobrien 64-bit BookE instruction set, and other PPC instruction 1319104834Sobrien sets. Check to see if the opcode has the BOOKE64 flag set. 1320104834Sobrien If it does make sure that the target CPU is not the BookE32. */ 1321104834Sobrien && ((op->flags & PPC_OPCODE_BOOKE64) == 0 1322104834Sobrien || (ppc_cpu & PPC_OPCODE_BOOKE64) == PPC_OPCODE_BOOKE64 1323104834Sobrien || (ppc_cpu & PPC_OPCODE_BOOKE) == 0) 132492828Sobrien && ((op->flags & (PPC_OPCODE_POWER4 | PPC_OPCODE_NOPOWER4)) == 0 132592828Sobrien || ((op->flags & PPC_OPCODE_POWER4) 1326218822Sdim == (ppc_cpu & PPC_OPCODE_POWER4))) 1327218822Sdim && ((op->flags & PPC_OPCODE_POWER5) == 0 1328218822Sdim || ((op->flags & PPC_OPCODE_POWER5) 1329218822Sdim == (ppc_cpu & PPC_OPCODE_POWER5))) 1330218822Sdim && ((op->flags & PPC_OPCODE_POWER6) == 0 1331218822Sdim || ((op->flags & PPC_OPCODE_POWER6) 1332218822Sdim == (ppc_cpu & PPC_OPCODE_POWER6)))) 133360484Sobrien { 133460484Sobrien const char *retval; 133560484Sobrien 1336218822Sdim retval = hash_insert (ppc_hash, op->name, (void *) op); 1337130561Sobrien if (retval != NULL) 133860484Sobrien { 133989857Sobrien /* Ignore Power duplicates for -m601. */ 134060484Sobrien if ((ppc_cpu & PPC_OPCODE_601) != 0 134160484Sobrien && (op->flags & PPC_OPCODE_POWER) != 0) 134260484Sobrien continue; 134360484Sobrien 1344218822Sdim as_bad (_("duplicate instruction %s"), 134589857Sobrien op->name); 1346218822Sdim bad_insn = TRUE; 134760484Sobrien } 134860484Sobrien } 134960484Sobrien } 135060484Sobrien 1351130561Sobrien if ((ppc_cpu & PPC_OPCODE_ANY) != 0) 1352130561Sobrien for (op = powerpc_opcodes; op < op_end; op++) 1353218822Sdim hash_insert (ppc_hash, op->name, (void *) op); 1354130561Sobrien 135560484Sobrien /* Insert the macros into a hash table. */ 135660484Sobrien ppc_macro_hash = hash_new (); 135760484Sobrien 135860484Sobrien macro_end = powerpc_macros + powerpc_num_macros; 135960484Sobrien for (macro = powerpc_macros; macro < macro_end; macro++) 136060484Sobrien { 136160484Sobrien if ((macro->flags & ppc_cpu) != 0) 136260484Sobrien { 136360484Sobrien const char *retval; 136460484Sobrien 1365218822Sdim retval = hash_insert (ppc_macro_hash, macro->name, (void *) macro); 136660484Sobrien if (retval != (const char *) NULL) 136760484Sobrien { 1368218822Sdim as_bad (_("duplicate macro %s"), macro->name); 1369218822Sdim bad_insn = TRUE; 137060484Sobrien } 137160484Sobrien } 137260484Sobrien } 137360484Sobrien 1374218822Sdim if (bad_insn) 137560484Sobrien abort (); 1376130561Sobrien} 137760484Sobrien 1378130561Sobrien/* This function is called when the assembler starts up. It is called 1379130561Sobrien after the options have been parsed and the output file has been 1380130561Sobrien opened. */ 1381130561Sobrien 1382130561Sobrienvoid 1383218822Sdimmd_begin (void) 1384130561Sobrien{ 1385130561Sobrien ppc_set_cpu (); 1386130561Sobrien 1387130561Sobrien ppc_cie_data_alignment = ppc_obj64 ? -8 : -4; 1388130561Sobrien 1389130561Sobrien#ifdef OBJ_ELF 1390130561Sobrien /* Set the ELF flags if desired. */ 1391130561Sobrien if (ppc_flags && !msolaris) 1392130561Sobrien bfd_set_private_flags (stdoutput, ppc_flags); 1393130561Sobrien#endif 1394130561Sobrien 1395130561Sobrien ppc_setup_opcodes (); 1396130561Sobrien 1397130561Sobrien /* Tell the main code what the endianness is if it is not overridden 139889857Sobrien by the user. */ 139960484Sobrien if (!set_target_endian) 140060484Sobrien { 140160484Sobrien set_target_endian = 1; 140260484Sobrien target_big_endian = PPC_BIG_ENDIAN; 140360484Sobrien } 140460484Sobrien 140560484Sobrien#ifdef OBJ_XCOFF 140660484Sobrien ppc_coff_debug_section = coff_section_from_bfd_index (stdoutput, N_DEBUG); 140760484Sobrien 140860484Sobrien /* Create dummy symbols to serve as initial csects. This forces the 140960484Sobrien text csects to precede the data csects. These symbols will not 141060484Sobrien be output. */ 141160484Sobrien ppc_text_csects = symbol_make ("dummy\001"); 141260484Sobrien symbol_get_tc (ppc_text_csects)->within = ppc_text_csects; 141360484Sobrien ppc_data_csects = symbol_make ("dummy\001"); 141460484Sobrien symbol_get_tc (ppc_data_csects)->within = ppc_data_csects; 141560484Sobrien#endif 141660484Sobrien 141760484Sobrien#ifdef TE_PE 141860484Sobrien 141960484Sobrien ppc_current_section = text_section; 142077298Sobrien ppc_previous_section = 0; 142160484Sobrien 142260484Sobrien#endif 142360484Sobrien} 142460484Sobrien 1425130561Sobrienvoid 1426218822Sdimppc_cleanup (void) 1427130561Sobrien{ 1428130561Sobrien#ifdef OBJ_ELF 1429130561Sobrien if (ppc_apuinfo_list == NULL) 1430130561Sobrien return; 1431130561Sobrien 1432130561Sobrien /* Ok, so write the section info out. We have this layout: 1433130561Sobrien 1434130561Sobrien byte data what 1435130561Sobrien ---- ---- ---- 1436130561Sobrien 0 8 length of "APUinfo\0" 1437130561Sobrien 4 (n*4) number of APU's (4 bytes each) 1438130561Sobrien 8 2 note type 2 1439130561Sobrien 12 "APUinfo\0" name 1440130561Sobrien 20 APU#1 first APU's info 1441130561Sobrien 24 APU#2 second APU's info 1442130561Sobrien ... ... 1443130561Sobrien */ 1444130561Sobrien { 1445130561Sobrien char *p; 1446130561Sobrien asection *seg = now_seg; 1447130561Sobrien subsegT subseg = now_subseg; 1448130561Sobrien asection *apuinfo_secp = (asection *) NULL; 1449130561Sobrien unsigned int i; 1450130561Sobrien 1451130561Sobrien /* Create the .PPC.EMB.apuinfo section. */ 1452130561Sobrien apuinfo_secp = subseg_new (".PPC.EMB.apuinfo", 0); 1453130561Sobrien bfd_set_section_flags (stdoutput, 1454130561Sobrien apuinfo_secp, 1455130561Sobrien SEC_HAS_CONTENTS | SEC_READONLY); 1456130561Sobrien 1457130561Sobrien p = frag_more (4); 1458130561Sobrien md_number_to_chars (p, (valueT) 8, 4); 1459130561Sobrien 1460130561Sobrien p = frag_more (4); 1461130561Sobrien md_number_to_chars (p, (valueT) ppc_apuinfo_num * 4, 4); 1462130561Sobrien 1463130561Sobrien p = frag_more (4); 1464130561Sobrien md_number_to_chars (p, (valueT) 2, 4); 1465130561Sobrien 1466130561Sobrien p = frag_more (8); 1467130561Sobrien strcpy (p, "APUinfo"); 1468130561Sobrien 1469130561Sobrien for (i = 0; i < ppc_apuinfo_num; i++) 1470130561Sobrien { 1471130561Sobrien p = frag_more (4); 1472130561Sobrien md_number_to_chars (p, (valueT) ppc_apuinfo_list[i], 4); 1473130561Sobrien } 1474130561Sobrien 1475130561Sobrien frag_align (2, 0, 0); 1476130561Sobrien 1477130561Sobrien /* We probably can't restore the current segment, for there likely 1478130561Sobrien isn't one yet... */ 1479130561Sobrien if (seg && subseg) 1480130561Sobrien subseg_set (seg, subseg); 1481130561Sobrien } 1482130561Sobrien#endif 1483130561Sobrien} 1484130561Sobrien 148560484Sobrien/* Insert an operand value into an instruction. */ 148660484Sobrien 148760484Sobrienstatic unsigned long 1488218822Sdimppc_insert_operand (unsigned long insn, 1489218822Sdim const struct powerpc_operand *operand, 1490218822Sdim offsetT val, 1491218822Sdim char *file, 1492218822Sdim unsigned int line) 149360484Sobrien{ 1494218822Sdim long min, max, right; 1495218822Sdim 1496218822Sdim max = operand->bitm; 1497218822Sdim right = max & -max; 1498218822Sdim min = 0; 1499218822Sdim 1500218822Sdim if ((operand->flags & PPC_OPERAND_SIGNED) != 0) 150160484Sobrien { 1502218822Sdim if ((operand->flags & PPC_OPERAND_SIGNOPT) == 0) 1503218822Sdim max = (max >> 1) & -right; 1504218822Sdim min = ~max & -right; 1505218822Sdim } 150660484Sobrien 1507218822Sdim if ((operand->flags & PPC_OPERAND_PLUS1) != 0) 1508218822Sdim max++; 150960484Sobrien 1510218822Sdim if ((operand->flags & PPC_OPERAND_NEGATIVE) != 0) 1511218822Sdim { 1512218822Sdim long tmp = min; 1513218822Sdim min = -max; 1514218822Sdim max = -tmp; 1515218822Sdim } 151660484Sobrien 1517218822Sdim if (min <= max) 1518218822Sdim { 1519218822Sdim /* Some people write constants with the sign extension done by 1520218822Sdim hand but only up to 32 bits. This shouldn't really be valid, 1521218822Sdim but, to permit this code to assemble on a 64-bit host, we 1522218822Sdim sign extend the 32-bit value to 64 bits if so doing makes the 1523218822Sdim value valid. */ 1524218822Sdim if (val > max 1525218822Sdim && (offsetT) (val - 0x80000000 - 0x80000000) >= min 1526218822Sdim && (offsetT) (val - 0x80000000 - 0x80000000) <= max 1527218822Sdim && ((val - 0x80000000 - 0x80000000) & (right - 1)) == 0) 1528218822Sdim val = val - 0x80000000 - 0x80000000; 152960484Sobrien 1530218822Sdim /* Similarly, people write expressions like ~(1<<15), and expect 1531218822Sdim this to be OK for a 32-bit unsigned value. */ 1532218822Sdim else if (val < min 1533218822Sdim && (offsetT) (val + 0x80000000 + 0x80000000) >= min 1534218822Sdim && (offsetT) (val + 0x80000000 + 0x80000000) <= max 1535218822Sdim && ((val + 0x80000000 + 0x80000000) & (right - 1)) == 0) 1536218822Sdim val = val + 0x80000000 + 0x80000000; 153760484Sobrien 1538218822Sdim else if (val < min 1539218822Sdim || val > max 1540218822Sdim || (val & (right - 1)) != 0) 1541218822Sdim as_bad_value_out_of_range (_("operand"), val, min, max, file, line); 154260484Sobrien } 154360484Sobrien 154460484Sobrien if (operand->insert) 154560484Sobrien { 154660484Sobrien const char *errmsg; 154760484Sobrien 154860484Sobrien errmsg = NULL; 1549104834Sobrien insn = (*operand->insert) (insn, (long) val, ppc_cpu, &errmsg); 155060484Sobrien if (errmsg != (const char *) NULL) 155189857Sobrien as_bad_where (file, line, errmsg); 155260484Sobrien } 155360484Sobrien else 1554218822Sdim insn |= ((long) val & operand->bitm) << operand->shift; 155560484Sobrien 155660484Sobrien return insn; 155760484Sobrien} 155860484Sobrien 155960484Sobrien 156060484Sobrien#ifdef OBJ_ELF 156160484Sobrien/* Parse @got, etc. and return the desired relocation. */ 156260484Sobrienstatic bfd_reloc_code_real_type 1563218822Sdimppc_elf_suffix (char **str_p, expressionS *exp_p) 156460484Sobrien{ 156560484Sobrien struct map_bfd { 156660484Sobrien char *string; 1567130561Sobrien unsigned int length : 8; 1568130561Sobrien unsigned int valid32 : 1; 1569130561Sobrien unsigned int valid64 : 1; 1570130561Sobrien unsigned int reloc; 157160484Sobrien }; 157260484Sobrien 157360484Sobrien char ident[20]; 157460484Sobrien char *str = *str_p; 157560484Sobrien char *str2; 157660484Sobrien int ch; 157760484Sobrien int len; 157889857Sobrien const struct map_bfd *ptr; 157960484Sobrien 1580130561Sobrien#define MAP(str, reloc) { str, sizeof (str) - 1, 1, 1, reloc } 1581130561Sobrien#define MAP32(str, reloc) { str, sizeof (str) - 1, 1, 0, reloc } 1582130561Sobrien#define MAP64(str, reloc) { str, sizeof (str) - 1, 0, 1, reloc } 158360484Sobrien 158489857Sobrien static const struct map_bfd mapping[] = { 1585130561Sobrien MAP ("l", BFD_RELOC_LO16), 1586130561Sobrien MAP ("h", BFD_RELOC_HI16), 1587130561Sobrien MAP ("ha", BFD_RELOC_HI16_S), 1588130561Sobrien MAP ("brtaken", BFD_RELOC_PPC_B16_BRTAKEN), 1589130561Sobrien MAP ("brntaken", BFD_RELOC_PPC_B16_BRNTAKEN), 1590130561Sobrien MAP ("got", BFD_RELOC_16_GOTOFF), 1591130561Sobrien MAP ("got@l", BFD_RELOC_LO16_GOTOFF), 1592130561Sobrien MAP ("got@h", BFD_RELOC_HI16_GOTOFF), 1593130561Sobrien MAP ("got@ha", BFD_RELOC_HI16_S_GOTOFF), 1594130561Sobrien MAP ("plt@l", BFD_RELOC_LO16_PLTOFF), 1595130561Sobrien MAP ("plt@h", BFD_RELOC_HI16_PLTOFF), 1596130561Sobrien MAP ("plt@ha", BFD_RELOC_HI16_S_PLTOFF), 1597130561Sobrien MAP ("copy", BFD_RELOC_PPC_COPY), 1598130561Sobrien MAP ("globdat", BFD_RELOC_PPC_GLOB_DAT), 1599130561Sobrien MAP ("sectoff", BFD_RELOC_16_BASEREL), 1600130561Sobrien MAP ("sectoff@l", BFD_RELOC_LO16_BASEREL), 1601130561Sobrien MAP ("sectoff@h", BFD_RELOC_HI16_BASEREL), 1602130561Sobrien MAP ("sectoff@ha", BFD_RELOC_HI16_S_BASEREL), 1603130561Sobrien MAP ("tls", BFD_RELOC_PPC_TLS), 1604130561Sobrien MAP ("dtpmod", BFD_RELOC_PPC_DTPMOD), 1605130561Sobrien MAP ("dtprel", BFD_RELOC_PPC_DTPREL), 1606130561Sobrien MAP ("dtprel@l", BFD_RELOC_PPC_DTPREL16_LO), 1607130561Sobrien MAP ("dtprel@h", BFD_RELOC_PPC_DTPREL16_HI), 1608130561Sobrien MAP ("dtprel@ha", BFD_RELOC_PPC_DTPREL16_HA), 1609130561Sobrien MAP ("tprel", BFD_RELOC_PPC_TPREL), 1610130561Sobrien MAP ("tprel@l", BFD_RELOC_PPC_TPREL16_LO), 1611130561Sobrien MAP ("tprel@h", BFD_RELOC_PPC_TPREL16_HI), 1612130561Sobrien MAP ("tprel@ha", BFD_RELOC_PPC_TPREL16_HA), 1613130561Sobrien MAP ("got@tlsgd", BFD_RELOC_PPC_GOT_TLSGD16), 1614130561Sobrien MAP ("got@tlsgd@l", BFD_RELOC_PPC_GOT_TLSGD16_LO), 1615130561Sobrien MAP ("got@tlsgd@h", BFD_RELOC_PPC_GOT_TLSGD16_HI), 1616130561Sobrien MAP ("got@tlsgd@ha", BFD_RELOC_PPC_GOT_TLSGD16_HA), 1617130561Sobrien MAP ("got@tlsld", BFD_RELOC_PPC_GOT_TLSLD16), 1618130561Sobrien MAP ("got@tlsld@l", BFD_RELOC_PPC_GOT_TLSLD16_LO), 1619130561Sobrien MAP ("got@tlsld@h", BFD_RELOC_PPC_GOT_TLSLD16_HI), 1620130561Sobrien MAP ("got@tlsld@ha", BFD_RELOC_PPC_GOT_TLSLD16_HA), 1621130561Sobrien MAP ("got@dtprel", BFD_RELOC_PPC_GOT_DTPREL16), 1622130561Sobrien MAP ("got@dtprel@l", BFD_RELOC_PPC_GOT_DTPREL16_LO), 1623130561Sobrien MAP ("got@dtprel@h", BFD_RELOC_PPC_GOT_DTPREL16_HI), 1624130561Sobrien MAP ("got@dtprel@ha", BFD_RELOC_PPC_GOT_DTPREL16_HA), 1625130561Sobrien MAP ("got@tprel", BFD_RELOC_PPC_GOT_TPREL16), 1626130561Sobrien MAP ("got@tprel@l", BFD_RELOC_PPC_GOT_TPREL16_LO), 1627130561Sobrien MAP ("got@tprel@h", BFD_RELOC_PPC_GOT_TPREL16_HI), 1628130561Sobrien MAP ("got@tprel@ha", BFD_RELOC_PPC_GOT_TPREL16_HA), 1629130561Sobrien MAP32 ("fixup", BFD_RELOC_CTOR), 1630130561Sobrien MAP32 ("plt", BFD_RELOC_24_PLT_PCREL), 1631130561Sobrien MAP32 ("pltrel24", BFD_RELOC_24_PLT_PCREL), 1632130561Sobrien MAP32 ("local24pc", BFD_RELOC_PPC_LOCAL24PC), 1633130561Sobrien MAP32 ("local", BFD_RELOC_PPC_LOCAL24PC), 1634130561Sobrien MAP32 ("pltrel", BFD_RELOC_32_PLT_PCREL), 1635130561Sobrien MAP32 ("sdarel", BFD_RELOC_GPREL16), 1636130561Sobrien MAP32 ("naddr", BFD_RELOC_PPC_EMB_NADDR32), 1637130561Sobrien MAP32 ("naddr16", BFD_RELOC_PPC_EMB_NADDR16), 1638130561Sobrien MAP32 ("naddr@l", BFD_RELOC_PPC_EMB_NADDR16_LO), 1639130561Sobrien MAP32 ("naddr@h", BFD_RELOC_PPC_EMB_NADDR16_HI), 1640130561Sobrien MAP32 ("naddr@ha", BFD_RELOC_PPC_EMB_NADDR16_HA), 1641130561Sobrien MAP32 ("sdai16", BFD_RELOC_PPC_EMB_SDAI16), 1642130561Sobrien MAP32 ("sda2rel", BFD_RELOC_PPC_EMB_SDA2REL), 1643130561Sobrien MAP32 ("sda2i16", BFD_RELOC_PPC_EMB_SDA2I16), 1644130561Sobrien MAP32 ("sda21", BFD_RELOC_PPC_EMB_SDA21), 1645130561Sobrien MAP32 ("mrkref", BFD_RELOC_PPC_EMB_MRKREF), 1646130561Sobrien MAP32 ("relsect", BFD_RELOC_PPC_EMB_RELSEC16), 1647130561Sobrien MAP32 ("relsect@l", BFD_RELOC_PPC_EMB_RELST_LO), 1648130561Sobrien MAP32 ("relsect@h", BFD_RELOC_PPC_EMB_RELST_HI), 1649130561Sobrien MAP32 ("relsect@ha", BFD_RELOC_PPC_EMB_RELST_HA), 1650130561Sobrien MAP32 ("bitfld", BFD_RELOC_PPC_EMB_BIT_FLD), 1651130561Sobrien MAP32 ("relsda", BFD_RELOC_PPC_EMB_RELSDA), 1652130561Sobrien MAP32 ("xgot", BFD_RELOC_PPC_TOC16), 1653130561Sobrien MAP64 ("higher", BFD_RELOC_PPC64_HIGHER), 1654130561Sobrien MAP64 ("highera", BFD_RELOC_PPC64_HIGHER_S), 1655130561Sobrien MAP64 ("highest", BFD_RELOC_PPC64_HIGHEST), 1656130561Sobrien MAP64 ("highesta", BFD_RELOC_PPC64_HIGHEST_S), 1657130561Sobrien MAP64 ("tocbase", BFD_RELOC_PPC64_TOC), 1658130561Sobrien MAP64 ("toc", BFD_RELOC_PPC_TOC16), 1659130561Sobrien MAP64 ("toc@l", BFD_RELOC_PPC64_TOC16_LO), 1660130561Sobrien MAP64 ("toc@h", BFD_RELOC_PPC64_TOC16_HI), 1661130561Sobrien MAP64 ("toc@ha", BFD_RELOC_PPC64_TOC16_HA), 1662130561Sobrien MAP64 ("dtprel@higher", BFD_RELOC_PPC64_DTPREL16_HIGHER), 1663130561Sobrien MAP64 ("dtprel@highera", BFD_RELOC_PPC64_DTPREL16_HIGHERA), 1664130561Sobrien MAP64 ("dtprel@highest", BFD_RELOC_PPC64_DTPREL16_HIGHEST), 1665130561Sobrien MAP64 ("dtprel@highesta", BFD_RELOC_PPC64_DTPREL16_HIGHESTA), 1666130561Sobrien MAP64 ("tprel@higher", BFD_RELOC_PPC64_TPREL16_HIGHER), 1667130561Sobrien MAP64 ("tprel@highera", BFD_RELOC_PPC64_TPREL16_HIGHERA), 1668130561Sobrien MAP64 ("tprel@highest", BFD_RELOC_PPC64_TPREL16_HIGHEST), 1669130561Sobrien MAP64 ("tprel@highesta", BFD_RELOC_PPC64_TPREL16_HIGHESTA), 1670130561Sobrien { (char *) 0, 0, 0, 0, BFD_RELOC_UNUSED } 167160484Sobrien }; 167260484Sobrien 167360484Sobrien if (*str++ != '@') 167460484Sobrien return BFD_RELOC_UNUSED; 167560484Sobrien 167660484Sobrien for (ch = *str, str2 = ident; 167760484Sobrien (str2 < ident + sizeof (ident) - 1 167889857Sobrien && (ISALNUM (ch) || ch == '@')); 167960484Sobrien ch = *++str) 168060484Sobrien { 168189857Sobrien *str2++ = TOLOWER (ch); 168260484Sobrien } 168360484Sobrien 168460484Sobrien *str2 = '\0'; 168560484Sobrien len = str2 - ident; 168660484Sobrien 168760484Sobrien ch = ident[0]; 168860484Sobrien for (ptr = &mapping[0]; ptr->length > 0; ptr++) 168960484Sobrien if (ch == ptr->string[0] 169060484Sobrien && len == ptr->length 1691130561Sobrien && memcmp (ident, ptr->string, ptr->length) == 0 1692130561Sobrien && (ppc_obj64 ? ptr->valid64 : ptr->valid32)) 169360484Sobrien { 169489857Sobrien int reloc = ptr->reloc; 169589857Sobrien 1696130561Sobrien if (!ppc_obj64) 1697130561Sobrien if (exp_p->X_add_number != 0 1698130561Sobrien && (reloc == (int) BFD_RELOC_16_GOTOFF 1699130561Sobrien || reloc == (int) BFD_RELOC_LO16_GOTOFF 1700130561Sobrien || reloc == (int) BFD_RELOC_HI16_GOTOFF 1701130561Sobrien || reloc == (int) BFD_RELOC_HI16_S_GOTOFF)) 1702130561Sobrien as_warn (_("identifier+constant@got means identifier@got+constant")); 170389857Sobrien 170489857Sobrien /* Now check for identifier@suffix+constant. */ 170560484Sobrien if (*str == '-' || *str == '+') 170660484Sobrien { 170760484Sobrien char *orig_line = input_line_pointer; 170860484Sobrien expressionS new_exp; 170960484Sobrien 171060484Sobrien input_line_pointer = str; 171160484Sobrien expression (&new_exp); 171260484Sobrien if (new_exp.X_op == O_constant) 171360484Sobrien { 171460484Sobrien exp_p->X_add_number += new_exp.X_add_number; 171560484Sobrien str = input_line_pointer; 171660484Sobrien } 171760484Sobrien 171860484Sobrien if (&input_line_pointer != str_p) 171960484Sobrien input_line_pointer = orig_line; 172060484Sobrien } 172189857Sobrien *str_p = str; 172260484Sobrien 1723104834Sobrien if (reloc == (int) BFD_RELOC_PPC64_TOC 1724130561Sobrien && exp_p->X_op == O_symbol 1725130561Sobrien && strcmp (S_GET_NAME (exp_p->X_add_symbol), ".TOC.") == 0) 172689857Sobrien { 1727130561Sobrien /* Change the symbol so that the dummy .TOC. symbol can be 1728130561Sobrien omitted from the object file. */ 172989857Sobrien exp_p->X_add_symbol = &abs_symbol; 173089857Sobrien } 173189857Sobrien 173289857Sobrien return (bfd_reloc_code_real_type) reloc; 173360484Sobrien } 173460484Sobrien 173560484Sobrien return BFD_RELOC_UNUSED; 173660484Sobrien} 173760484Sobrien 173889857Sobrien/* Like normal .long/.short/.word, except support @got, etc. 173989857Sobrien Clobbers input_line_pointer, checks end-of-line. */ 174060484Sobrienstatic void 1741218822Sdimppc_elf_cons (int nbytes /* 1=.byte, 2=.word, 4=.long, 8=.llong */) 174260484Sobrien{ 174360484Sobrien expressionS exp; 174460484Sobrien bfd_reloc_code_real_type reloc; 174560484Sobrien 174660484Sobrien if (is_it_end_of_statement ()) 174760484Sobrien { 174860484Sobrien demand_empty_rest_of_line (); 174960484Sobrien return; 175060484Sobrien } 175160484Sobrien 175260484Sobrien do 175360484Sobrien { 175460484Sobrien expression (&exp); 175560484Sobrien if (exp.X_op == O_symbol 175660484Sobrien && *input_line_pointer == '@' 175789857Sobrien && (reloc = ppc_elf_suffix (&input_line_pointer, 175889857Sobrien &exp)) != BFD_RELOC_UNUSED) 175960484Sobrien { 176089857Sobrien reloc_howto_type *reloc_howto; 176189857Sobrien int size; 176260484Sobrien 176389857Sobrien reloc_howto = bfd_reloc_type_lookup (stdoutput, reloc); 176489857Sobrien size = bfd_get_reloc_size (reloc_howto); 176589857Sobrien 176660484Sobrien if (size > nbytes) 176789857Sobrien { 176889857Sobrien as_bad (_("%s relocations do not fit in %d bytes\n"), 176989857Sobrien reloc_howto->name, nbytes); 177089857Sobrien } 177160484Sobrien else 177260484Sobrien { 177389857Sobrien char *p; 177489857Sobrien int offset; 177560484Sobrien 177689857Sobrien p = frag_more (nbytes); 177789857Sobrien offset = 0; 177889857Sobrien if (target_big_endian) 177989857Sobrien offset = nbytes - size; 178089857Sobrien fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size, 178189857Sobrien &exp, 0, reloc); 178260484Sobrien } 178360484Sobrien } 178460484Sobrien else 178560484Sobrien emit_expr (&exp, (unsigned int) nbytes); 178660484Sobrien } 178760484Sobrien while (*input_line_pointer++ == ','); 178860484Sobrien 178989857Sobrien /* Put terminator back into stream. */ 179089857Sobrien input_line_pointer--; 179160484Sobrien demand_empty_rest_of_line (); 179260484Sobrien} 179360484Sobrien 179460484Sobrien/* Solaris pseduo op to change to the .rodata section. */ 179560484Sobrienstatic void 1796218822Sdimppc_elf_rdata (int xxx) 179760484Sobrien{ 179860484Sobrien char *save_line = input_line_pointer; 179960484Sobrien static char section[] = ".rodata\n"; 180060484Sobrien 180189857Sobrien /* Just pretend this is .section .rodata */ 180260484Sobrien input_line_pointer = section; 180360484Sobrien obj_elf_section (xxx); 180460484Sobrien 180560484Sobrien input_line_pointer = save_line; 180660484Sobrien} 180760484Sobrien 180889857Sobrien/* Pseudo op to make file scope bss items. */ 180960484Sobrienstatic void 1810218822Sdimppc_elf_lcomm (int xxx ATTRIBUTE_UNUSED) 181160484Sobrien{ 1812218822Sdim char *name; 1813218822Sdim char c; 1814218822Sdim char *p; 181560484Sobrien offsetT size; 1816218822Sdim symbolS *symbolP; 181760484Sobrien offsetT align; 181860484Sobrien segT old_sec; 181960484Sobrien int old_subsec; 182060484Sobrien char *pfrag; 182160484Sobrien int align2; 182260484Sobrien 182360484Sobrien name = input_line_pointer; 182460484Sobrien c = get_symbol_end (); 182560484Sobrien 182689857Sobrien /* just after name is now '\0'. */ 182760484Sobrien p = input_line_pointer; 182860484Sobrien *p = c; 182960484Sobrien SKIP_WHITESPACE (); 183060484Sobrien if (*input_line_pointer != ',') 183160484Sobrien { 183260484Sobrien as_bad (_("Expected comma after symbol-name: rest of line ignored.")); 183360484Sobrien ignore_rest_of_line (); 183460484Sobrien return; 183560484Sobrien } 183660484Sobrien 183760484Sobrien input_line_pointer++; /* skip ',' */ 183860484Sobrien if ((size = get_absolute_expression ()) < 0) 183960484Sobrien { 184060484Sobrien as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) size); 184160484Sobrien ignore_rest_of_line (); 184260484Sobrien return; 184360484Sobrien } 184460484Sobrien 184560484Sobrien /* The third argument to .lcomm is the alignment. */ 184660484Sobrien if (*input_line_pointer != ',') 184760484Sobrien align = 8; 184860484Sobrien else 184960484Sobrien { 185060484Sobrien ++input_line_pointer; 185160484Sobrien align = get_absolute_expression (); 185260484Sobrien if (align <= 0) 185360484Sobrien { 185460484Sobrien as_warn (_("ignoring bad alignment")); 185560484Sobrien align = 8; 185660484Sobrien } 185760484Sobrien } 185860484Sobrien 185960484Sobrien *p = 0; 186060484Sobrien symbolP = symbol_find_or_make (name); 186160484Sobrien *p = c; 186260484Sobrien 186360484Sobrien if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) 186460484Sobrien { 186560484Sobrien as_bad (_("Ignoring attempt to re-define symbol `%s'."), 186660484Sobrien S_GET_NAME (symbolP)); 186760484Sobrien ignore_rest_of_line (); 186860484Sobrien return; 186960484Sobrien } 187060484Sobrien 187160484Sobrien if (S_GET_VALUE (symbolP) && S_GET_VALUE (symbolP) != (valueT) size) 187260484Sobrien { 187360484Sobrien as_bad (_("Length of .lcomm \"%s\" is already %ld. Not changed to %ld."), 187460484Sobrien S_GET_NAME (symbolP), 187560484Sobrien (long) S_GET_VALUE (symbolP), 187660484Sobrien (long) size); 187760484Sobrien 187860484Sobrien ignore_rest_of_line (); 187960484Sobrien return; 188060484Sobrien } 188160484Sobrien 188289857Sobrien /* Allocate_bss. */ 188360484Sobrien old_sec = now_seg; 188460484Sobrien old_subsec = now_subseg; 188560484Sobrien if (align) 188660484Sobrien { 188789857Sobrien /* Convert to a power of 2 alignment. */ 188860484Sobrien for (align2 = 0; (align & 1) == 0; align >>= 1, ++align2); 188960484Sobrien if (align != 1) 189060484Sobrien { 189160484Sobrien as_bad (_("Common alignment not a power of 2")); 189260484Sobrien ignore_rest_of_line (); 189360484Sobrien return; 189460484Sobrien } 189560484Sobrien } 189660484Sobrien else 189760484Sobrien align2 = 0; 189860484Sobrien 189960484Sobrien record_alignment (bss_section, align2); 190060484Sobrien subseg_set (bss_section, 0); 190160484Sobrien if (align2) 190260484Sobrien frag_align (align2, 0, 0); 190360484Sobrien if (S_GET_SEGMENT (symbolP) == bss_section) 190460484Sobrien symbol_get_frag (symbolP)->fr_symbol = 0; 190560484Sobrien symbol_set_frag (symbolP, frag_now); 190660484Sobrien pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, size, 190760484Sobrien (char *) 0); 190860484Sobrien *pfrag = 0; 190960484Sobrien S_SET_SIZE (symbolP, size); 191060484Sobrien S_SET_SEGMENT (symbolP, bss_section); 191160484Sobrien subseg_set (old_sec, old_subsec); 191260484Sobrien demand_empty_rest_of_line (); 191360484Sobrien} 191460484Sobrien 191560484Sobrien/* Validate any relocations emitted for -mrelocatable, possibly adding 191660484Sobrien fixups for word relocations in writable segments, so we can adjust 191760484Sobrien them at runtime. */ 191860484Sobrienstatic void 1919218822Sdimppc_elf_validate_fix (fixS *fixp, segT seg) 192060484Sobrien{ 192160484Sobrien if (fixp->fx_done || fixp->fx_pcrel) 192260484Sobrien return; 192360484Sobrien 192460484Sobrien switch (shlib) 192560484Sobrien { 192660484Sobrien case SHLIB_NONE: 192760484Sobrien case SHLIB_PIC: 192860484Sobrien return; 192960484Sobrien 193077298Sobrien case SHLIB_MRELOCATABLE: 193160484Sobrien if (fixp->fx_r_type <= BFD_RELOC_UNUSED 193260484Sobrien && fixp->fx_r_type != BFD_RELOC_16_GOTOFF 193360484Sobrien && fixp->fx_r_type != BFD_RELOC_HI16_GOTOFF 193460484Sobrien && fixp->fx_r_type != BFD_RELOC_LO16_GOTOFF 193560484Sobrien && fixp->fx_r_type != BFD_RELOC_HI16_S_GOTOFF 193699461Sobrien && fixp->fx_r_type != BFD_RELOC_16_BASEREL 193760484Sobrien && fixp->fx_r_type != BFD_RELOC_LO16_BASEREL 193860484Sobrien && fixp->fx_r_type != BFD_RELOC_HI16_BASEREL 193960484Sobrien && fixp->fx_r_type != BFD_RELOC_HI16_S_BASEREL 194089857Sobrien && (seg->flags & SEC_LOAD) != 0 194160484Sobrien && strcmp (segment_name (seg), ".got2") != 0 194260484Sobrien && strcmp (segment_name (seg), ".dtors") != 0 194360484Sobrien && strcmp (segment_name (seg), ".ctors") != 0 194460484Sobrien && strcmp (segment_name (seg), ".fixup") != 0 194560484Sobrien && strcmp (segment_name (seg), ".gcc_except_table") != 0 194660484Sobrien && strcmp (segment_name (seg), ".eh_frame") != 0 194760484Sobrien && strcmp (segment_name (seg), ".ex_shared") != 0) 194860484Sobrien { 194960484Sobrien if ((seg->flags & (SEC_READONLY | SEC_CODE)) != 0 195060484Sobrien || fixp->fx_r_type != BFD_RELOC_CTOR) 195160484Sobrien { 195260484Sobrien as_bad_where (fixp->fx_file, fixp->fx_line, 195360484Sobrien _("Relocation cannot be done when using -mrelocatable")); 195460484Sobrien } 195560484Sobrien } 195660484Sobrien return; 195760484Sobrien } 195860484Sobrien} 195989857Sobrien 1960104834Sobrien/* Prevent elf_frob_file_before_adjust removing a weak undefined 1961104834Sobrien function descriptor sym if the corresponding code sym is used. */ 1962104834Sobrien 1963104834Sobrienvoid 1964218822Sdimppc_frob_file_before_adjust (void) 196589857Sobrien{ 1966104834Sobrien symbolS *symp; 1967218822Sdim asection *toc; 196889857Sobrien 1969104834Sobrien if (!ppc_obj64) 1970104834Sobrien return; 1971104834Sobrien 1972104834Sobrien for (symp = symbol_rootP; symp; symp = symbol_next (symp)) 197389857Sobrien { 1974104834Sobrien const char *name; 1975104834Sobrien char *dotname; 1976104834Sobrien symbolS *dotsym; 1977104834Sobrien size_t len; 1978104834Sobrien 1979104834Sobrien name = S_GET_NAME (symp); 1980104834Sobrien if (name[0] == '.') 1981104834Sobrien continue; 1982104834Sobrien 1983104834Sobrien if (! S_IS_WEAK (symp) 1984104834Sobrien || S_IS_DEFINED (symp)) 1985104834Sobrien continue; 1986104834Sobrien 1987104834Sobrien len = strlen (name) + 1; 1988104834Sobrien dotname = xmalloc (len + 1); 1989104834Sobrien dotname[0] = '.'; 1990104834Sobrien memcpy (dotname + 1, name, len); 1991218822Sdim dotsym = symbol_find_noref (dotname, 1); 1992104834Sobrien free (dotname); 1993104834Sobrien if (dotsym != NULL && (symbol_used_p (dotsym) 1994104834Sobrien || symbol_used_in_reloc_p (dotsym))) 1995218822Sdim symbol_mark_used (symp); 1996218822Sdim 199789857Sobrien } 199889857Sobrien 1999218822Sdim toc = bfd_get_section_by_name (stdoutput, ".toc"); 2000218822Sdim if (toc != NULL 2001218822Sdim && bfd_section_size (stdoutput, toc) > 0x10000) 2002218822Sdim as_warn (_("TOC section size exceeds 64k")); 2003218822Sdim 2004104834Sobrien /* Don't emit .TOC. symbol. */ 2005104834Sobrien symp = symbol_find (".TOC."); 2006104834Sobrien if (symp != NULL) 2007104834Sobrien symbol_remove (symp, &symbol_rootP, &symbol_lastP); 200889857Sobrien} 200960484Sobrien#endif /* OBJ_ELF */ 201060484Sobrien 201160484Sobrien#ifdef TE_PE 201260484Sobrien 201360484Sobrien/* 201489857Sobrien * Summary of parse_toc_entry. 201560484Sobrien * 201660484Sobrien * in: Input_line_pointer points to the '[' in one of: 201760484Sobrien * 201860484Sobrien * [toc] [tocv] [toc32] [toc64] 201960484Sobrien * 202060484Sobrien * Anything else is an error of one kind or another. 202160484Sobrien * 202277298Sobrien * out: 202360484Sobrien * return value: success or failure 202460484Sobrien * toc_kind: kind of toc reference 202560484Sobrien * input_line_pointer: 202660484Sobrien * success: first char after the ']' 202760484Sobrien * failure: unchanged 202860484Sobrien * 202960484Sobrien * settings: 203060484Sobrien * 203160484Sobrien * [toc] - rv == success, toc_kind = default_toc 203260484Sobrien * [tocv] - rv == success, toc_kind = data_in_toc 203360484Sobrien * [toc32] - rv == success, toc_kind = must_be_32 203460484Sobrien * [toc64] - rv == success, toc_kind = must_be_64 203560484Sobrien * 203660484Sobrien */ 203760484Sobrien 203877298Sobrienenum toc_size_qualifier 203977298Sobrien{ 204060484Sobrien default_toc, /* The toc cell constructed should be the system default size */ 204160484Sobrien data_in_toc, /* This is a direct reference to a toc cell */ 204260484Sobrien must_be_32, /* The toc cell constructed must be 32 bits wide */ 204360484Sobrien must_be_64 /* The toc cell constructed must be 64 bits wide */ 204460484Sobrien}; 204560484Sobrien 204660484Sobrienstatic int 2047218822Sdimparse_toc_entry (enum toc_size_qualifier *toc_kind) 204860484Sobrien{ 204960484Sobrien char *start; 205060484Sobrien char *toc_spec; 205160484Sobrien char c; 205260484Sobrien enum toc_size_qualifier t; 205360484Sobrien 205489857Sobrien /* Save the input_line_pointer. */ 205560484Sobrien start = input_line_pointer; 205660484Sobrien 205789857Sobrien /* Skip over the '[' , and whitespace. */ 205860484Sobrien ++input_line_pointer; 205960484Sobrien SKIP_WHITESPACE (); 206077298Sobrien 206189857Sobrien /* Find the spelling of the operand. */ 206260484Sobrien toc_spec = input_line_pointer; 206360484Sobrien c = get_symbol_end (); 206460484Sobrien 206589857Sobrien if (strcmp (toc_spec, "toc") == 0) 206660484Sobrien { 206760484Sobrien t = default_toc; 206860484Sobrien } 206989857Sobrien else if (strcmp (toc_spec, "tocv") == 0) 207060484Sobrien { 207160484Sobrien t = data_in_toc; 207260484Sobrien } 207389857Sobrien else if (strcmp (toc_spec, "toc32") == 0) 207460484Sobrien { 207560484Sobrien t = must_be_32; 207660484Sobrien } 207789857Sobrien else if (strcmp (toc_spec, "toc64") == 0) 207860484Sobrien { 207960484Sobrien t = must_be_64; 208060484Sobrien } 208160484Sobrien else 208260484Sobrien { 208360484Sobrien as_bad (_("syntax error: invalid toc specifier `%s'"), toc_spec); 208489857Sobrien *input_line_pointer = c; 208589857Sobrien input_line_pointer = start; 208660484Sobrien return 0; 208760484Sobrien } 208860484Sobrien 208989857Sobrien /* Now find the ']'. */ 209089857Sobrien *input_line_pointer = c; 209160484Sobrien 209277298Sobrien SKIP_WHITESPACE (); /* leading whitespace could be there. */ 209377298Sobrien c = *input_line_pointer++; /* input_line_pointer->past char in c. */ 209460484Sobrien 209560484Sobrien if (c != ']') 209660484Sobrien { 209760484Sobrien as_bad (_("syntax error: expected `]', found `%c'"), c); 209889857Sobrien input_line_pointer = start; 209960484Sobrien return 0; 210060484Sobrien } 210160484Sobrien 210289857Sobrien *toc_kind = t; 210360484Sobrien return 1; 210460484Sobrien} 210560484Sobrien#endif 210660484Sobrien 210760484Sobrien 2108130561Sobrien#ifdef OBJ_ELF 2109130561Sobrien#define APUID(a,v) ((((a) & 0xffff) << 16) | ((v) & 0xffff)) 2110130561Sobrienstatic void 2111218822Sdimppc_apuinfo_section_add (unsigned int apu, unsigned int version) 2112130561Sobrien{ 2113130561Sobrien unsigned int i; 2114130561Sobrien 2115130561Sobrien /* Check we don't already exist. */ 2116130561Sobrien for (i = 0; i < ppc_apuinfo_num; i++) 2117130561Sobrien if (ppc_apuinfo_list[i] == APUID (apu, version)) 2118130561Sobrien return; 2119130561Sobrien 2120130561Sobrien if (ppc_apuinfo_num == ppc_apuinfo_num_alloc) 2121130561Sobrien { 2122130561Sobrien if (ppc_apuinfo_num_alloc == 0) 2123130561Sobrien { 2124130561Sobrien ppc_apuinfo_num_alloc = 4; 2125130561Sobrien ppc_apuinfo_list = (unsigned long *) 2126130561Sobrien xmalloc (sizeof (unsigned long) * ppc_apuinfo_num_alloc); 2127130561Sobrien } 2128130561Sobrien else 2129130561Sobrien { 2130130561Sobrien ppc_apuinfo_num_alloc += 4; 2131130561Sobrien ppc_apuinfo_list = (unsigned long *) xrealloc (ppc_apuinfo_list, 2132130561Sobrien sizeof (unsigned long) * ppc_apuinfo_num_alloc); 2133130561Sobrien } 2134130561Sobrien } 2135130561Sobrien ppc_apuinfo_list[ppc_apuinfo_num++] = APUID (apu, version); 2136130561Sobrien} 2137130561Sobrien#undef APUID 2138130561Sobrien#endif 2139130561Sobrien 2140130561Sobrien 214160484Sobrien/* We need to keep a list of fixups. We can't simply generate them as 214260484Sobrien we go, because that would require us to first create the frag, and 214360484Sobrien that would screw up references to ``.''. */ 214460484Sobrien 214560484Sobrienstruct ppc_fixup 214660484Sobrien{ 214760484Sobrien expressionS exp; 214860484Sobrien int opindex; 214960484Sobrien bfd_reloc_code_real_type reloc; 215060484Sobrien}; 215160484Sobrien 215260484Sobrien#define MAX_INSN_FIXUPS (5) 215360484Sobrien 215460484Sobrien/* This routine is called for each instruction to be assembled. */ 215560484Sobrien 215660484Sobrienvoid 2157218822Sdimmd_assemble (char *str) 215860484Sobrien{ 215960484Sobrien char *s; 216060484Sobrien const struct powerpc_opcode *opcode; 216160484Sobrien unsigned long insn; 216260484Sobrien const unsigned char *opindex_ptr; 216360484Sobrien int skip_optional; 216460484Sobrien int need_paren; 216560484Sobrien int next_opindex; 216660484Sobrien struct ppc_fixup fixups[MAX_INSN_FIXUPS]; 216760484Sobrien int fc; 216860484Sobrien char *f; 2169218822Sdim int addr_mod; 217060484Sobrien int i; 217160484Sobrien#ifdef OBJ_ELF 217260484Sobrien bfd_reloc_code_real_type reloc; 217360484Sobrien#endif 217460484Sobrien 217560484Sobrien /* Get the opcode. */ 217689857Sobrien for (s = str; *s != '\0' && ! ISSPACE (*s); s++) 217760484Sobrien ; 217860484Sobrien if (*s != '\0') 217960484Sobrien *s++ = '\0'; 218060484Sobrien 218160484Sobrien /* Look up the opcode in the hash table. */ 218260484Sobrien opcode = (const struct powerpc_opcode *) hash_find (ppc_hash, str); 218360484Sobrien if (opcode == (const struct powerpc_opcode *) NULL) 218460484Sobrien { 218560484Sobrien const struct powerpc_macro *macro; 218660484Sobrien 218760484Sobrien macro = (const struct powerpc_macro *) hash_find (ppc_macro_hash, str); 218860484Sobrien if (macro == (const struct powerpc_macro *) NULL) 218960484Sobrien as_bad (_("Unrecognized opcode: `%s'"), str); 219060484Sobrien else 219160484Sobrien ppc_macro (s, macro); 219260484Sobrien 219360484Sobrien return; 219460484Sobrien } 219560484Sobrien 219660484Sobrien insn = opcode->opcode; 219760484Sobrien 219860484Sobrien str = s; 219989857Sobrien while (ISSPACE (*str)) 220060484Sobrien ++str; 220160484Sobrien 220260484Sobrien /* PowerPC operands are just expressions. The only real issue is 220360484Sobrien that a few operand types are optional. All cases which might use 2204130561Sobrien an optional operand separate the operands only with commas (in some 2205130561Sobrien cases parentheses are used, as in ``lwz 1,0(1)'' but such cases never 2206130561Sobrien have optional operands). Most instructions with optional operands 2207130561Sobrien have only one. Those that have more than one optional operand can 2208130561Sobrien take either all their operands or none. So, before we start seriously 2209130561Sobrien parsing the operands, we check to see if we have optional operands, 2210130561Sobrien and if we do, we count the number of commas to see which operands 2211130561Sobrien have been omitted. */ 221260484Sobrien skip_optional = 0; 221360484Sobrien for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++) 221460484Sobrien { 221560484Sobrien const struct powerpc_operand *operand; 221660484Sobrien 221760484Sobrien operand = &powerpc_operands[*opindex_ptr]; 221860484Sobrien if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0) 221960484Sobrien { 222060484Sobrien unsigned int opcount; 2221104834Sobrien unsigned int num_operands_expected; 2222104834Sobrien unsigned int i; 222360484Sobrien 222460484Sobrien /* There is an optional operand. Count the number of 222560484Sobrien commas in the input line. */ 222660484Sobrien if (*str == '\0') 222760484Sobrien opcount = 0; 222860484Sobrien else 222960484Sobrien { 223060484Sobrien opcount = 1; 223160484Sobrien s = str; 223260484Sobrien while ((s = strchr (s, ',')) != (char *) NULL) 223360484Sobrien { 223460484Sobrien ++opcount; 223560484Sobrien ++s; 223660484Sobrien } 223760484Sobrien } 223860484Sobrien 2239104834Sobrien /* Compute the number of expected operands. 2240104834Sobrien Do not count fake operands. */ 2241104834Sobrien for (num_operands_expected = 0, i = 0; opcode->operands[i]; i ++) 2242104834Sobrien if ((powerpc_operands [opcode->operands[i]].flags & PPC_OPERAND_FAKE) == 0) 2243104834Sobrien ++ num_operands_expected; 2244104834Sobrien 224560484Sobrien /* If there are fewer operands in the line then are called 224660484Sobrien for by the instruction, we want to skip the optional 2247130561Sobrien operands. */ 2248104834Sobrien if (opcount < num_operands_expected) 224960484Sobrien skip_optional = 1; 225060484Sobrien 225160484Sobrien break; 225260484Sobrien } 225360484Sobrien } 225460484Sobrien 225560484Sobrien /* Gather the operands. */ 225660484Sobrien need_paren = 0; 225760484Sobrien next_opindex = 0; 225860484Sobrien fc = 0; 225960484Sobrien for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++) 226060484Sobrien { 226160484Sobrien const struct powerpc_operand *operand; 226260484Sobrien const char *errmsg; 226360484Sobrien char *hold; 226460484Sobrien expressionS ex; 226560484Sobrien char endc; 226660484Sobrien 226760484Sobrien if (next_opindex == 0) 226860484Sobrien operand = &powerpc_operands[*opindex_ptr]; 226960484Sobrien else 227060484Sobrien { 227160484Sobrien operand = &powerpc_operands[next_opindex]; 227260484Sobrien next_opindex = 0; 227360484Sobrien } 227460484Sobrien errmsg = NULL; 227560484Sobrien 227660484Sobrien /* If this is a fake operand, then we do not expect anything 227760484Sobrien from the input. */ 227860484Sobrien if ((operand->flags & PPC_OPERAND_FAKE) != 0) 227960484Sobrien { 2280104834Sobrien insn = (*operand->insert) (insn, 0L, ppc_cpu, &errmsg); 228160484Sobrien if (errmsg != (const char *) NULL) 228260484Sobrien as_bad (errmsg); 228360484Sobrien continue; 228460484Sobrien } 228560484Sobrien 228660484Sobrien /* If this is an optional operand, and we are skipping it, just 228760484Sobrien insert a zero. */ 228860484Sobrien if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0 228960484Sobrien && skip_optional) 229060484Sobrien { 229160484Sobrien if (operand->insert) 229260484Sobrien { 2293104834Sobrien insn = (*operand->insert) (insn, 0L, ppc_cpu, &errmsg); 229460484Sobrien if (errmsg != (const char *) NULL) 229560484Sobrien as_bad (errmsg); 229660484Sobrien } 229760484Sobrien if ((operand->flags & PPC_OPERAND_NEXT) != 0) 229860484Sobrien next_opindex = *opindex_ptr + 1; 229960484Sobrien continue; 230060484Sobrien } 230160484Sobrien 230260484Sobrien /* Gather the operand. */ 230360484Sobrien hold = input_line_pointer; 230460484Sobrien input_line_pointer = str; 230560484Sobrien 230660484Sobrien#ifdef TE_PE 230777298Sobrien if (*input_line_pointer == '[') 230860484Sobrien { 230960484Sobrien /* We are expecting something like the second argument here: 231089857Sobrien * 231189857Sobrien * lwz r4,[toc].GS.0.static_int(rtoc) 231289857Sobrien * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 231389857Sobrien * The argument following the `]' must be a symbol name, and the 231489857Sobrien * register must be the toc register: 'rtoc' or '2' 231589857Sobrien * 231689857Sobrien * The effect is to 0 as the displacement field 231789857Sobrien * in the instruction, and issue an IMAGE_REL_PPC_TOCREL16 (or 231889857Sobrien * the appropriate variation) reloc against it based on the symbol. 231989857Sobrien * The linker will build the toc, and insert the resolved toc offset. 232089857Sobrien * 232189857Sobrien * Note: 232289857Sobrien * o The size of the toc entry is currently assumed to be 232389857Sobrien * 32 bits. This should not be assumed to be a hard coded 232489857Sobrien * number. 232589857Sobrien * o In an effort to cope with a change from 32 to 64 bits, 232689857Sobrien * there are also toc entries that are specified to be 232789857Sobrien * either 32 or 64 bits: 232889857Sobrien * lwz r4,[toc32].GS.0.static_int(rtoc) 232989857Sobrien * lwz r4,[toc64].GS.0.static_int(rtoc) 233089857Sobrien * These demand toc entries of the specified size, and the 233189857Sobrien * instruction probably requires it. 233289857Sobrien */ 233360484Sobrien 233460484Sobrien int valid_toc; 233560484Sobrien enum toc_size_qualifier toc_kind; 233660484Sobrien bfd_reloc_code_real_type toc_reloc; 233760484Sobrien 233889857Sobrien /* Go parse off the [tocXX] part. */ 233989857Sobrien valid_toc = parse_toc_entry (&toc_kind); 234060484Sobrien 234177298Sobrien if (!valid_toc) 234260484Sobrien { 234389857Sobrien /* Note: message has already been issued. 234489857Sobrien FIXME: what sort of recovery should we do? 234589857Sobrien demand_rest_of_line (); return; ? */ 234660484Sobrien } 234760484Sobrien 234889857Sobrien /* Now get the symbol following the ']'. */ 234989857Sobrien expression (&ex); 235060484Sobrien 235160484Sobrien switch (toc_kind) 235260484Sobrien { 235360484Sobrien case default_toc: 235489857Sobrien /* In this case, we may not have seen the symbol yet, 235589857Sobrien since it is allowed to appear on a .extern or .globl 235689857Sobrien or just be a label in the .data section. */ 235760484Sobrien toc_reloc = BFD_RELOC_PPC_TOC16; 235860484Sobrien break; 235960484Sobrien case data_in_toc: 236089857Sobrien /* 1. The symbol must be defined and either in the toc 236189857Sobrien section, or a global. 236289857Sobrien 2. The reloc generated must have the TOCDEFN flag set 236389857Sobrien in upper bit mess of the reloc type. 236489857Sobrien FIXME: It's a little confusing what the tocv 236589857Sobrien qualifier can be used for. At the very least, I've 236689857Sobrien seen three uses, only one of which I'm sure I can 236789857Sobrien explain. */ 236877298Sobrien if (ex.X_op == O_symbol) 236977298Sobrien { 237060484Sobrien assert (ex.X_add_symbol != NULL); 237160484Sobrien if (symbol_get_bfdsym (ex.X_add_symbol)->section 237260484Sobrien != tocdata_section) 237360484Sobrien { 237489857Sobrien as_bad (_("[tocv] symbol is not a toc symbol")); 237560484Sobrien } 237660484Sobrien } 237760484Sobrien 237860484Sobrien toc_reloc = BFD_RELOC_PPC_TOC16; 237960484Sobrien break; 238060484Sobrien case must_be_32: 238189857Sobrien /* FIXME: these next two specifically specify 32/64 bit 238289857Sobrien toc entries. We don't support them today. Is this 238389857Sobrien the right way to say that? */ 238460484Sobrien toc_reloc = BFD_RELOC_UNUSED; 238560484Sobrien as_bad (_("Unimplemented toc32 expression modifier")); 238660484Sobrien break; 238760484Sobrien case must_be_64: 238889857Sobrien /* FIXME: see above. */ 238960484Sobrien toc_reloc = BFD_RELOC_UNUSED; 239060484Sobrien as_bad (_("Unimplemented toc64 expression modifier")); 239160484Sobrien break; 239260484Sobrien default: 239377298Sobrien fprintf (stderr, 239489857Sobrien _("Unexpected return value [%d] from parse_toc_entry!\n"), 239589857Sobrien toc_kind); 239677298Sobrien abort (); 239760484Sobrien break; 239860484Sobrien } 239960484Sobrien 240060484Sobrien /* We need to generate a fixup for this expression. */ 240160484Sobrien if (fc >= MAX_INSN_FIXUPS) 240260484Sobrien as_fatal (_("too many fixups")); 240360484Sobrien 240460484Sobrien fixups[fc].reloc = toc_reloc; 240560484Sobrien fixups[fc].exp = ex; 240660484Sobrien fixups[fc].opindex = *opindex_ptr; 240760484Sobrien ++fc; 240860484Sobrien 240989857Sobrien /* Ok. We've set up the fixup for the instruction. Now make it 241089857Sobrien look like the constant 0 was found here. */ 241160484Sobrien ex.X_unsigned = 1; 241260484Sobrien ex.X_op = O_constant; 241360484Sobrien ex.X_add_number = 0; 241460484Sobrien ex.X_add_symbol = NULL; 241560484Sobrien ex.X_op_symbol = NULL; 241660484Sobrien } 241760484Sobrien 241860484Sobrien else 241960484Sobrien#endif /* TE_PE */ 242060484Sobrien { 242160484Sobrien if (! register_name (&ex)) 242260484Sobrien { 242360484Sobrien if ((operand->flags & PPC_OPERAND_CR) != 0) 2424130561Sobrien cr_operand = TRUE; 242560484Sobrien expression (&ex); 2426130561Sobrien cr_operand = FALSE; 242760484Sobrien } 242860484Sobrien } 242960484Sobrien 243060484Sobrien str = input_line_pointer; 243160484Sobrien input_line_pointer = hold; 243260484Sobrien 243360484Sobrien if (ex.X_op == O_illegal) 243460484Sobrien as_bad (_("illegal operand")); 243560484Sobrien else if (ex.X_op == O_absent) 243660484Sobrien as_bad (_("missing operand")); 243760484Sobrien else if (ex.X_op == O_register) 243860484Sobrien { 243960484Sobrien insn = ppc_insert_operand (insn, operand, ex.X_add_number, 244060484Sobrien (char *) NULL, 0); 244160484Sobrien } 244260484Sobrien else if (ex.X_op == O_constant) 244360484Sobrien { 244460484Sobrien#ifdef OBJ_ELF 244577298Sobrien /* Allow @HA, @L, @H on constants. */ 244660484Sobrien char *orig_str = str; 244760484Sobrien 244860484Sobrien if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED) 244960484Sobrien switch (reloc) 245060484Sobrien { 245160484Sobrien default: 245260484Sobrien str = orig_str; 245360484Sobrien break; 245460484Sobrien 245560484Sobrien case BFD_RELOC_LO16: 245660484Sobrien /* X_unsigned is the default, so if the user has done 245789857Sobrien something which cleared it, we always produce a 245889857Sobrien signed value. */ 245989857Sobrien if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED)) 246060484Sobrien ex.X_add_number &= 0xffff; 246160484Sobrien else 246289857Sobrien ex.X_add_number = SEX16 (ex.X_add_number); 246360484Sobrien break; 246460484Sobrien 246560484Sobrien case BFD_RELOC_HI16: 246689857Sobrien if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED)) 246789857Sobrien ex.X_add_number = PPC_HI (ex.X_add_number); 246889857Sobrien else 246989857Sobrien ex.X_add_number = SEX16 (PPC_HI (ex.X_add_number)); 247060484Sobrien break; 247160484Sobrien 247260484Sobrien case BFD_RELOC_HI16_S: 247389857Sobrien if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED)) 247489857Sobrien ex.X_add_number = PPC_HA (ex.X_add_number); 247589857Sobrien else 247689857Sobrien ex.X_add_number = SEX16 (PPC_HA (ex.X_add_number)); 247760484Sobrien break; 247889857Sobrien 247989857Sobrien case BFD_RELOC_PPC64_HIGHER: 248089857Sobrien if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED)) 248189857Sobrien ex.X_add_number = PPC_HIGHER (ex.X_add_number); 248289857Sobrien else 248389857Sobrien ex.X_add_number = SEX16 (PPC_HIGHER (ex.X_add_number)); 248489857Sobrien break; 248589857Sobrien 248689857Sobrien case BFD_RELOC_PPC64_HIGHER_S: 248789857Sobrien if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED)) 248889857Sobrien ex.X_add_number = PPC_HIGHERA (ex.X_add_number); 248989857Sobrien else 249089857Sobrien ex.X_add_number = SEX16 (PPC_HIGHERA (ex.X_add_number)); 249189857Sobrien break; 249289857Sobrien 249389857Sobrien case BFD_RELOC_PPC64_HIGHEST: 249489857Sobrien if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED)) 249589857Sobrien ex.X_add_number = PPC_HIGHEST (ex.X_add_number); 249689857Sobrien else 249789857Sobrien ex.X_add_number = SEX16 (PPC_HIGHEST (ex.X_add_number)); 249889857Sobrien break; 249989857Sobrien 250089857Sobrien case BFD_RELOC_PPC64_HIGHEST_S: 250189857Sobrien if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED)) 250289857Sobrien ex.X_add_number = PPC_HIGHESTA (ex.X_add_number); 250389857Sobrien else 250489857Sobrien ex.X_add_number = SEX16 (PPC_HIGHESTA (ex.X_add_number)); 250589857Sobrien break; 250660484Sobrien } 250789857Sobrien#endif /* OBJ_ELF */ 250860484Sobrien insn = ppc_insert_operand (insn, operand, ex.X_add_number, 250960484Sobrien (char *) NULL, 0); 251060484Sobrien } 251160484Sobrien#ifdef OBJ_ELF 251260484Sobrien else if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED) 251360484Sobrien { 2514130561Sobrien /* Some TLS tweaks. */ 2515130561Sobrien switch (reloc) 2516130561Sobrien { 2517130561Sobrien default: 2518130561Sobrien break; 2519130561Sobrien case BFD_RELOC_PPC_TLS: 2520130561Sobrien insn = ppc_insert_operand (insn, operand, ppc_obj64 ? 13 : 2, 2521130561Sobrien (char *) NULL, 0); 2522130561Sobrien break; 2523130561Sobrien /* We'll only use the 32 (or 64) bit form of these relocations 2524130561Sobrien in constants. Instructions get the 16 bit form. */ 2525130561Sobrien case BFD_RELOC_PPC_DTPREL: 2526130561Sobrien reloc = BFD_RELOC_PPC_DTPREL16; 2527130561Sobrien break; 2528130561Sobrien case BFD_RELOC_PPC_TPREL: 2529130561Sobrien reloc = BFD_RELOC_PPC_TPREL16; 2530130561Sobrien break; 2531130561Sobrien } 2532130561Sobrien 253389857Sobrien /* For the absolute forms of branches, convert the PC 253489857Sobrien relative form back into the absolute. */ 253560484Sobrien if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) 253660484Sobrien { 253760484Sobrien switch (reloc) 253860484Sobrien { 253960484Sobrien case BFD_RELOC_PPC_B26: 254060484Sobrien reloc = BFD_RELOC_PPC_BA26; 254160484Sobrien break; 254260484Sobrien case BFD_RELOC_PPC_B16: 254360484Sobrien reloc = BFD_RELOC_PPC_BA16; 254460484Sobrien break; 254560484Sobrien case BFD_RELOC_PPC_B16_BRTAKEN: 254660484Sobrien reloc = BFD_RELOC_PPC_BA16_BRTAKEN; 254760484Sobrien break; 254860484Sobrien case BFD_RELOC_PPC_B16_BRNTAKEN: 254960484Sobrien reloc = BFD_RELOC_PPC_BA16_BRNTAKEN; 255060484Sobrien break; 255160484Sobrien default: 255260484Sobrien break; 255360484Sobrien } 255460484Sobrien } 255560484Sobrien 2556104834Sobrien if (ppc_obj64 2557130561Sobrien && (operand->flags & (PPC_OPERAND_DS | PPC_OPERAND_DQ)) != 0) 255889857Sobrien { 255989857Sobrien switch (reloc) 256089857Sobrien { 256189857Sobrien case BFD_RELOC_16: 256289857Sobrien reloc = BFD_RELOC_PPC64_ADDR16_DS; 256389857Sobrien break; 256489857Sobrien case BFD_RELOC_LO16: 256589857Sobrien reloc = BFD_RELOC_PPC64_ADDR16_LO_DS; 256689857Sobrien break; 256789857Sobrien case BFD_RELOC_16_GOTOFF: 256889857Sobrien reloc = BFD_RELOC_PPC64_GOT16_DS; 256989857Sobrien break; 257089857Sobrien case BFD_RELOC_LO16_GOTOFF: 257189857Sobrien reloc = BFD_RELOC_PPC64_GOT16_LO_DS; 257289857Sobrien break; 257389857Sobrien case BFD_RELOC_LO16_PLTOFF: 257489857Sobrien reloc = BFD_RELOC_PPC64_PLT16_LO_DS; 257589857Sobrien break; 257699461Sobrien case BFD_RELOC_16_BASEREL: 257789857Sobrien reloc = BFD_RELOC_PPC64_SECTOFF_DS; 257889857Sobrien break; 257989857Sobrien case BFD_RELOC_LO16_BASEREL: 258089857Sobrien reloc = BFD_RELOC_PPC64_SECTOFF_LO_DS; 258189857Sobrien break; 258289857Sobrien case BFD_RELOC_PPC_TOC16: 258389857Sobrien reloc = BFD_RELOC_PPC64_TOC16_DS; 258489857Sobrien break; 258589857Sobrien case BFD_RELOC_PPC64_TOC16_LO: 258689857Sobrien reloc = BFD_RELOC_PPC64_TOC16_LO_DS; 258789857Sobrien break; 258889857Sobrien case BFD_RELOC_PPC64_PLTGOT16: 258989857Sobrien reloc = BFD_RELOC_PPC64_PLTGOT16_DS; 259089857Sobrien break; 259189857Sobrien case BFD_RELOC_PPC64_PLTGOT16_LO: 259289857Sobrien reloc = BFD_RELOC_PPC64_PLTGOT16_LO_DS; 259389857Sobrien break; 2594130561Sobrien case BFD_RELOC_PPC_DTPREL16: 2595130561Sobrien reloc = BFD_RELOC_PPC64_DTPREL16_DS; 2596130561Sobrien break; 2597130561Sobrien case BFD_RELOC_PPC_DTPREL16_LO: 2598130561Sobrien reloc = BFD_RELOC_PPC64_DTPREL16_LO_DS; 2599130561Sobrien break; 2600130561Sobrien case BFD_RELOC_PPC_TPREL16: 2601130561Sobrien reloc = BFD_RELOC_PPC64_TPREL16_DS; 2602130561Sobrien break; 2603130561Sobrien case BFD_RELOC_PPC_TPREL16_LO: 2604130561Sobrien reloc = BFD_RELOC_PPC64_TPREL16_LO_DS; 2605130561Sobrien break; 2606130561Sobrien case BFD_RELOC_PPC_GOT_DTPREL16: 2607130561Sobrien case BFD_RELOC_PPC_GOT_DTPREL16_LO: 2608130561Sobrien case BFD_RELOC_PPC_GOT_TPREL16: 2609130561Sobrien case BFD_RELOC_PPC_GOT_TPREL16_LO: 2610130561Sobrien break; 261189857Sobrien default: 261289857Sobrien as_bad (_("unsupported relocation for DS offset field")); 261389857Sobrien break; 261489857Sobrien } 261589857Sobrien } 261689857Sobrien 261760484Sobrien /* We need to generate a fixup for this expression. */ 261860484Sobrien if (fc >= MAX_INSN_FIXUPS) 261960484Sobrien as_fatal (_("too many fixups")); 262060484Sobrien fixups[fc].exp = ex; 262160484Sobrien fixups[fc].opindex = 0; 262260484Sobrien fixups[fc].reloc = reloc; 262360484Sobrien ++fc; 262460484Sobrien } 262560484Sobrien#endif /* OBJ_ELF */ 262660484Sobrien 262760484Sobrien else 262860484Sobrien { 262960484Sobrien /* We need to generate a fixup for this expression. */ 263060484Sobrien if (fc >= MAX_INSN_FIXUPS) 263160484Sobrien as_fatal (_("too many fixups")); 263260484Sobrien fixups[fc].exp = ex; 263360484Sobrien fixups[fc].opindex = *opindex_ptr; 263460484Sobrien fixups[fc].reloc = BFD_RELOC_UNUSED; 263560484Sobrien ++fc; 263660484Sobrien } 263760484Sobrien 263860484Sobrien if (need_paren) 263960484Sobrien { 264060484Sobrien endc = ')'; 264160484Sobrien need_paren = 0; 264260484Sobrien } 264360484Sobrien else if ((operand->flags & PPC_OPERAND_PARENS) != 0) 264460484Sobrien { 264560484Sobrien endc = '('; 264660484Sobrien need_paren = 1; 264760484Sobrien } 264860484Sobrien else 264960484Sobrien endc = ','; 265060484Sobrien 265160484Sobrien /* The call to expression should have advanced str past any 265260484Sobrien whitespace. */ 265360484Sobrien if (*str != endc 265460484Sobrien && (endc != ',' || *str != '\0')) 265560484Sobrien { 265660484Sobrien as_bad (_("syntax error; found `%c' but expected `%c'"), *str, endc); 265760484Sobrien break; 265860484Sobrien } 265960484Sobrien 266060484Sobrien if (*str != '\0') 266160484Sobrien ++str; 266260484Sobrien } 266360484Sobrien 266489857Sobrien while (ISSPACE (*str)) 266560484Sobrien ++str; 266660484Sobrien 266760484Sobrien if (*str != '\0') 266860484Sobrien as_bad (_("junk at end of line: `%s'"), str); 266960484Sobrien 2670130561Sobrien#ifdef OBJ_ELF 2671130561Sobrien /* Do we need/want a APUinfo section? */ 2672130561Sobrien if (ppc_cpu & (PPC_OPCODE_SPE 2673130561Sobrien | PPC_OPCODE_ISEL | PPC_OPCODE_EFS 2674130561Sobrien | PPC_OPCODE_BRLOCK | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK 2675130561Sobrien | PPC_OPCODE_RFMCI)) 2676130561Sobrien { 2677130561Sobrien /* These are all version "1". */ 2678130561Sobrien if (opcode->flags & PPC_OPCODE_SPE) 2679130561Sobrien ppc_apuinfo_section_add (PPC_APUINFO_SPE, 1); 2680130561Sobrien if (opcode->flags & PPC_OPCODE_ISEL) 2681130561Sobrien ppc_apuinfo_section_add (PPC_APUINFO_ISEL, 1); 2682130561Sobrien if (opcode->flags & PPC_OPCODE_EFS) 2683130561Sobrien ppc_apuinfo_section_add (PPC_APUINFO_EFS, 1); 2684130561Sobrien if (opcode->flags & PPC_OPCODE_BRLOCK) 2685130561Sobrien ppc_apuinfo_section_add (PPC_APUINFO_BRLOCK, 1); 2686130561Sobrien if (opcode->flags & PPC_OPCODE_PMR) 2687130561Sobrien ppc_apuinfo_section_add (PPC_APUINFO_PMR, 1); 2688130561Sobrien if (opcode->flags & PPC_OPCODE_CACHELCK) 2689130561Sobrien ppc_apuinfo_section_add (PPC_APUINFO_CACHELCK, 1); 2690130561Sobrien if (opcode->flags & PPC_OPCODE_RFMCI) 2691130561Sobrien ppc_apuinfo_section_add (PPC_APUINFO_RFMCI, 1); 2692130561Sobrien } 2693130561Sobrien#endif 2694130561Sobrien 269560484Sobrien /* Write out the instruction. */ 269660484Sobrien f = frag_more (4); 2697218822Sdim addr_mod = frag_now_fix () & 3; 2698218822Sdim if (frag_now->has_code && frag_now->insn_addr != addr_mod) 2699218822Sdim as_bad (_("instruction address is not a multiple of 4")); 2700218822Sdim frag_now->insn_addr = addr_mod; 2701218822Sdim frag_now->has_code = 1; 270260484Sobrien md_number_to_chars (f, insn, 4); 270360484Sobrien 270477298Sobrien#ifdef OBJ_ELF 270577298Sobrien dwarf2_emit_insn (4); 270677298Sobrien#endif 270777298Sobrien 270860484Sobrien /* Create any fixups. At this point we do not use a 270960484Sobrien bfd_reloc_code_real_type, but instead just use the 271060484Sobrien BFD_RELOC_UNUSED plus the operand index. This lets us easily 271160484Sobrien handle fixups for any operand type, although that is admittedly 271260484Sobrien not a very exciting feature. We pick a BFD reloc type in 2713218822Sdim md_apply_fix. */ 271460484Sobrien for (i = 0; i < fc; i++) 271560484Sobrien { 271660484Sobrien const struct powerpc_operand *operand; 271760484Sobrien 271860484Sobrien operand = &powerpc_operands[fixups[i].opindex]; 271960484Sobrien if (fixups[i].reloc != BFD_RELOC_UNUSED) 272060484Sobrien { 272189857Sobrien reloc_howto_type *reloc_howto; 272260484Sobrien int size; 272360484Sobrien int offset; 272460484Sobrien fixS *fixP; 272560484Sobrien 272689857Sobrien reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc); 272760484Sobrien if (!reloc_howto) 272860484Sobrien abort (); 272960484Sobrien 273060484Sobrien size = bfd_get_reloc_size (reloc_howto); 273160484Sobrien offset = target_big_endian ? (4 - size) : 0; 273260484Sobrien 273360484Sobrien if (size < 1 || size > 4) 273477298Sobrien abort (); 273560484Sobrien 273689857Sobrien fixP = fix_new_exp (frag_now, 273789857Sobrien f - frag_now->fr_literal + offset, 273889857Sobrien size, 273989857Sobrien &fixups[i].exp, 274089857Sobrien reloc_howto->pc_relative, 274160484Sobrien fixups[i].reloc); 274260484Sobrien 274360484Sobrien /* Turn off complaints that the addend is too large for things like 274460484Sobrien foo+100000@ha. */ 274560484Sobrien switch (fixups[i].reloc) 274660484Sobrien { 274760484Sobrien case BFD_RELOC_16_GOTOFF: 274860484Sobrien case BFD_RELOC_PPC_TOC16: 274960484Sobrien case BFD_RELOC_LO16: 275060484Sobrien case BFD_RELOC_HI16: 275160484Sobrien case BFD_RELOC_HI16_S: 275289857Sobrien#ifdef OBJ_ELF 275389857Sobrien case BFD_RELOC_PPC64_HIGHER: 275489857Sobrien case BFD_RELOC_PPC64_HIGHER_S: 275589857Sobrien case BFD_RELOC_PPC64_HIGHEST: 275689857Sobrien case BFD_RELOC_PPC64_HIGHEST_S: 275789857Sobrien#endif 275860484Sobrien fixP->fx_no_overflow = 1; 275960484Sobrien break; 276060484Sobrien default: 276160484Sobrien break; 276260484Sobrien } 276360484Sobrien } 276460484Sobrien else 276589857Sobrien fix_new_exp (frag_now, 276689857Sobrien f - frag_now->fr_literal, 276789857Sobrien 4, 276860484Sobrien &fixups[i].exp, 276960484Sobrien (operand->flags & PPC_OPERAND_RELATIVE) != 0, 277060484Sobrien ((bfd_reloc_code_real_type) 277189857Sobrien (fixups[i].opindex + (int) BFD_RELOC_UNUSED))); 277260484Sobrien } 277360484Sobrien} 277460484Sobrien 277560484Sobrien/* Handle a macro. Gather all the operands, transform them as 277660484Sobrien described by the macro, and call md_assemble recursively. All the 277760484Sobrien operands are separated by commas; we don't accept parentheses 277860484Sobrien around operands here. */ 277960484Sobrien 278060484Sobrienstatic void 2781218822Sdimppc_macro (char *str, const struct powerpc_macro *macro) 278260484Sobrien{ 278360484Sobrien char *operands[10]; 278460484Sobrien unsigned int count; 278560484Sobrien char *s; 278660484Sobrien unsigned int len; 278760484Sobrien const char *format; 2788218822Sdim unsigned int arg; 278960484Sobrien char *send; 279060484Sobrien char *complete; 279160484Sobrien 279260484Sobrien /* Gather the users operands into the operands array. */ 279360484Sobrien count = 0; 279460484Sobrien s = str; 279560484Sobrien while (1) 279660484Sobrien { 279760484Sobrien if (count >= sizeof operands / sizeof operands[0]) 279860484Sobrien break; 279960484Sobrien operands[count++] = s; 280060484Sobrien s = strchr (s, ','); 280160484Sobrien if (s == (char *) NULL) 280260484Sobrien break; 280360484Sobrien *s++ = '\0'; 280477298Sobrien } 280560484Sobrien 280660484Sobrien if (count != macro->operands) 280760484Sobrien { 280860484Sobrien as_bad (_("wrong number of operands")); 280960484Sobrien return; 281060484Sobrien } 281160484Sobrien 281260484Sobrien /* Work out how large the string must be (the size is unbounded 281360484Sobrien because it includes user input). */ 281460484Sobrien len = 0; 281560484Sobrien format = macro->format; 281660484Sobrien while (*format != '\0') 281760484Sobrien { 281860484Sobrien if (*format != '%') 281960484Sobrien { 282060484Sobrien ++len; 282160484Sobrien ++format; 282260484Sobrien } 282360484Sobrien else 282460484Sobrien { 282560484Sobrien arg = strtol (format + 1, &send, 10); 2826218822Sdim know (send != format && arg < count); 282760484Sobrien len += strlen (operands[arg]); 282860484Sobrien format = send; 282960484Sobrien } 283060484Sobrien } 283160484Sobrien 283260484Sobrien /* Put the string together. */ 283360484Sobrien complete = s = (char *) alloca (len + 1); 283460484Sobrien format = macro->format; 283560484Sobrien while (*format != '\0') 283660484Sobrien { 283760484Sobrien if (*format != '%') 283860484Sobrien *s++ = *format++; 283960484Sobrien else 284060484Sobrien { 284160484Sobrien arg = strtol (format + 1, &send, 10); 284260484Sobrien strcpy (s, operands[arg]); 284360484Sobrien s += strlen (s); 284460484Sobrien format = send; 284560484Sobrien } 284660484Sobrien } 284760484Sobrien *s = '\0'; 284860484Sobrien 284960484Sobrien /* Assemble the constructed instruction. */ 285060484Sobrien md_assemble (complete); 285177298Sobrien} 285260484Sobrien 285360484Sobrien#ifdef OBJ_ELF 285489857Sobrien/* For ELF, add support for SHF_EXCLUDE and SHT_ORDERED. */ 285560484Sobrien 285660484Sobrienint 2857218822Sdimppc_section_letter (int letter, char **ptr_msg) 285860484Sobrien{ 285960484Sobrien if (letter == 'e') 286060484Sobrien return SHF_EXCLUDE; 286160484Sobrien 2862104834Sobrien *ptr_msg = _("Bad .section directive: want a,e,w,x,M,S,G,T in string"); 2863130561Sobrien return -1; 286460484Sobrien} 286560484Sobrien 286660484Sobrienint 2867218822Sdimppc_section_word (char *str, size_t len) 286860484Sobrien{ 286960484Sobrien if (len == 7 && strncmp (str, "exclude", 7) == 0) 287060484Sobrien return SHF_EXCLUDE; 287160484Sobrien 287260484Sobrien return -1; 287360484Sobrien} 287460484Sobrien 287560484Sobrienint 2876218822Sdimppc_section_type (char *str, size_t len) 287760484Sobrien{ 287860484Sobrien if (len == 7 && strncmp (str, "ordered", 7) == 0) 287960484Sobrien return SHT_ORDERED; 288060484Sobrien 288160484Sobrien return -1; 288260484Sobrien} 288360484Sobrien 288460484Sobrienint 2885218822Sdimppc_section_flags (int flags, int attr, int type) 288660484Sobrien{ 288760484Sobrien if (type == SHT_ORDERED) 288860484Sobrien flags |= SEC_ALLOC | SEC_LOAD | SEC_SORT_ENTRIES; 288960484Sobrien 289060484Sobrien if (attr & SHF_EXCLUDE) 289160484Sobrien flags |= SEC_EXCLUDE; 289260484Sobrien 289360484Sobrien return flags; 289460484Sobrien} 289560484Sobrien#endif /* OBJ_ELF */ 289660484Sobrien 289760484Sobrien 289860484Sobrien/* Pseudo-op handling. */ 289960484Sobrien 290060484Sobrien/* The .byte pseudo-op. This is similar to the normal .byte 290160484Sobrien pseudo-op, but it can also take a single ASCII string. */ 290260484Sobrien 290360484Sobrienstatic void 2904218822Sdimppc_byte (int ignore ATTRIBUTE_UNUSED) 290560484Sobrien{ 290660484Sobrien if (*input_line_pointer != '\"') 290760484Sobrien { 290860484Sobrien cons (1); 290960484Sobrien return; 291060484Sobrien } 291160484Sobrien 291260484Sobrien /* Gather characters. A real double quote is doubled. Unusual 291360484Sobrien characters are not permitted. */ 291460484Sobrien ++input_line_pointer; 291560484Sobrien while (1) 291660484Sobrien { 291760484Sobrien char c; 291860484Sobrien 291960484Sobrien c = *input_line_pointer++; 292060484Sobrien 292160484Sobrien if (c == '\"') 292260484Sobrien { 292360484Sobrien if (*input_line_pointer != '\"') 292460484Sobrien break; 292560484Sobrien ++input_line_pointer; 292660484Sobrien } 292760484Sobrien 292860484Sobrien FRAG_APPEND_1_CHAR (c); 292960484Sobrien } 293060484Sobrien 293160484Sobrien demand_empty_rest_of_line (); 293260484Sobrien} 293360484Sobrien 293460484Sobrien#ifdef OBJ_XCOFF 293560484Sobrien 293660484Sobrien/* XCOFF specific pseudo-op handling. */ 293760484Sobrien 293860484Sobrien/* This is set if we are creating a .stabx symbol, since we don't want 293960484Sobrien to handle symbol suffixes for such symbols. */ 2940130561Sobrienstatic bfd_boolean ppc_stab_symbol; 294160484Sobrien 294260484Sobrien/* The .comm and .lcomm pseudo-ops for XCOFF. XCOFF puts common 294360484Sobrien symbols in the .bss segment as though they were local common 2944130561Sobrien symbols, and uses a different smclas. The native Aix 4.3.3 assembler 294580016Sobrien aligns .comm and .lcomm to 4 bytes. */ 294660484Sobrien 294760484Sobrienstatic void 2948218822Sdimppc_comm (int lcomm) 294960484Sobrien{ 295060484Sobrien asection *current_seg = now_seg; 295160484Sobrien subsegT current_subseg = now_subseg; 295260484Sobrien char *name; 295360484Sobrien char endc; 295460484Sobrien char *end_name; 295560484Sobrien offsetT size; 295660484Sobrien offsetT align; 295760484Sobrien symbolS *lcomm_sym = NULL; 295860484Sobrien symbolS *sym; 295960484Sobrien char *pfrag; 296060484Sobrien 296160484Sobrien name = input_line_pointer; 296260484Sobrien endc = get_symbol_end (); 296360484Sobrien end_name = input_line_pointer; 296460484Sobrien *end_name = endc; 296560484Sobrien 296660484Sobrien if (*input_line_pointer != ',') 296760484Sobrien { 296860484Sobrien as_bad (_("missing size")); 296960484Sobrien ignore_rest_of_line (); 297060484Sobrien return; 297160484Sobrien } 297260484Sobrien ++input_line_pointer; 297360484Sobrien 297460484Sobrien size = get_absolute_expression (); 297560484Sobrien if (size < 0) 297660484Sobrien { 297760484Sobrien as_bad (_("negative size")); 297860484Sobrien ignore_rest_of_line (); 297960484Sobrien return; 298060484Sobrien } 298160484Sobrien 298260484Sobrien if (! lcomm) 298360484Sobrien { 298460484Sobrien /* The third argument to .comm is the alignment. */ 298560484Sobrien if (*input_line_pointer != ',') 298680016Sobrien align = 2; 298760484Sobrien else 298860484Sobrien { 298960484Sobrien ++input_line_pointer; 299060484Sobrien align = get_absolute_expression (); 299160484Sobrien if (align <= 0) 299260484Sobrien { 299360484Sobrien as_warn (_("ignoring bad alignment")); 299480016Sobrien align = 2; 299560484Sobrien } 299660484Sobrien } 299760484Sobrien } 299860484Sobrien else 299960484Sobrien { 300060484Sobrien char *lcomm_name; 300160484Sobrien char lcomm_endc; 300260484Sobrien 300380016Sobrien if (size <= 4) 300460484Sobrien align = 2; 300560484Sobrien else 300660484Sobrien align = 3; 300760484Sobrien 300860484Sobrien /* The third argument to .lcomm appears to be the real local 300960484Sobrien common symbol to create. References to the symbol named in 301060484Sobrien the first argument are turned into references to the third 301160484Sobrien argument. */ 301260484Sobrien if (*input_line_pointer != ',') 301360484Sobrien { 301460484Sobrien as_bad (_("missing real symbol name")); 301560484Sobrien ignore_rest_of_line (); 301660484Sobrien return; 301760484Sobrien } 301860484Sobrien ++input_line_pointer; 301960484Sobrien 302060484Sobrien lcomm_name = input_line_pointer; 302160484Sobrien lcomm_endc = get_symbol_end (); 302277298Sobrien 302360484Sobrien lcomm_sym = symbol_find_or_make (lcomm_name); 302460484Sobrien 302560484Sobrien *input_line_pointer = lcomm_endc; 302660484Sobrien } 302760484Sobrien 302860484Sobrien *end_name = '\0'; 302960484Sobrien sym = symbol_find_or_make (name); 303060484Sobrien *end_name = endc; 303160484Sobrien 303260484Sobrien if (S_IS_DEFINED (sym) 303360484Sobrien || S_GET_VALUE (sym) != 0) 303460484Sobrien { 303560484Sobrien as_bad (_("attempt to redefine symbol")); 303660484Sobrien ignore_rest_of_line (); 303760484Sobrien return; 303860484Sobrien } 303977298Sobrien 304060484Sobrien record_alignment (bss_section, align); 304177298Sobrien 304260484Sobrien if (! lcomm 304360484Sobrien || ! S_IS_DEFINED (lcomm_sym)) 304460484Sobrien { 304560484Sobrien symbolS *def_sym; 304660484Sobrien offsetT def_size; 304760484Sobrien 304860484Sobrien if (! lcomm) 304960484Sobrien { 305060484Sobrien def_sym = sym; 305160484Sobrien def_size = size; 305260484Sobrien S_SET_EXTERNAL (sym); 305360484Sobrien } 305460484Sobrien else 305560484Sobrien { 305660484Sobrien symbol_get_tc (lcomm_sym)->output = 1; 305760484Sobrien def_sym = lcomm_sym; 305860484Sobrien def_size = 0; 305960484Sobrien } 306060484Sobrien 306160484Sobrien subseg_set (bss_section, 1); 306260484Sobrien frag_align (align, 0, 0); 306377298Sobrien 306460484Sobrien symbol_set_frag (def_sym, frag_now); 306560484Sobrien pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, def_sym, 306660484Sobrien def_size, (char *) NULL); 306760484Sobrien *pfrag = 0; 306860484Sobrien S_SET_SEGMENT (def_sym, bss_section); 306960484Sobrien symbol_get_tc (def_sym)->align = align; 307060484Sobrien } 307160484Sobrien else if (lcomm) 307260484Sobrien { 307360484Sobrien /* Align the size of lcomm_sym. */ 307460484Sobrien symbol_get_frag (lcomm_sym)->fr_offset = 307560484Sobrien ((symbol_get_frag (lcomm_sym)->fr_offset + (1 << align) - 1) 307660484Sobrien &~ ((1 << align) - 1)); 307760484Sobrien if (align > symbol_get_tc (lcomm_sym)->align) 307860484Sobrien symbol_get_tc (lcomm_sym)->align = align; 307960484Sobrien } 308060484Sobrien 308160484Sobrien if (lcomm) 308260484Sobrien { 308360484Sobrien /* Make sym an offset from lcomm_sym. */ 308460484Sobrien S_SET_SEGMENT (sym, bss_section); 308560484Sobrien symbol_set_frag (sym, symbol_get_frag (lcomm_sym)); 308660484Sobrien S_SET_VALUE (sym, symbol_get_frag (lcomm_sym)->fr_offset); 308760484Sobrien symbol_get_frag (lcomm_sym)->fr_offset += size; 308860484Sobrien } 308960484Sobrien 309060484Sobrien subseg_set (current_seg, current_subseg); 309160484Sobrien 309260484Sobrien demand_empty_rest_of_line (); 309360484Sobrien} 309460484Sobrien 309560484Sobrien/* The .csect pseudo-op. This switches us into a different 309660484Sobrien subsegment. The first argument is a symbol whose value is the 309760484Sobrien start of the .csect. In COFF, csect symbols get special aux 309860484Sobrien entries defined by the x_csect field of union internal_auxent. The 309960484Sobrien optional second argument is the alignment (the default is 2). */ 310060484Sobrien 310160484Sobrienstatic void 3102218822Sdimppc_csect (int ignore ATTRIBUTE_UNUSED) 310360484Sobrien{ 310460484Sobrien char *name; 310560484Sobrien char endc; 310660484Sobrien symbolS *sym; 3107130561Sobrien offsetT align; 310860484Sobrien 310960484Sobrien name = input_line_pointer; 311060484Sobrien endc = get_symbol_end (); 311177298Sobrien 311260484Sobrien sym = symbol_find_or_make (name); 311360484Sobrien 311460484Sobrien *input_line_pointer = endc; 311560484Sobrien 311660484Sobrien if (S_GET_NAME (sym)[0] == '\0') 311760484Sobrien { 311860484Sobrien /* An unnamed csect is assumed to be [PR]. */ 311960484Sobrien symbol_get_tc (sym)->class = XMC_PR; 312060484Sobrien } 312160484Sobrien 3122130561Sobrien align = 2; 312360484Sobrien if (*input_line_pointer == ',') 312460484Sobrien { 312560484Sobrien ++input_line_pointer; 3126130561Sobrien align = get_absolute_expression (); 312760484Sobrien } 312860484Sobrien 3129130561Sobrien ppc_change_csect (sym, align); 3130130561Sobrien 313160484Sobrien demand_empty_rest_of_line (); 313260484Sobrien} 313360484Sobrien 313460484Sobrien/* Change to a different csect. */ 313560484Sobrien 313660484Sobrienstatic void 3137218822Sdimppc_change_csect (symbolS *sym, offsetT align) 313860484Sobrien{ 313960484Sobrien if (S_IS_DEFINED (sym)) 314060484Sobrien subseg_set (S_GET_SEGMENT (sym), symbol_get_tc (sym)->subseg); 314160484Sobrien else 314260484Sobrien { 314360484Sobrien symbolS **list_ptr; 314460484Sobrien int after_toc; 314560484Sobrien int hold_chunksize; 314660484Sobrien symbolS *list; 3147130561Sobrien int is_code; 3148130561Sobrien segT sec; 314960484Sobrien 315060484Sobrien /* This is a new csect. We need to look at the symbol class to 315160484Sobrien figure out whether it should go in the text section or the 315260484Sobrien data section. */ 315360484Sobrien after_toc = 0; 3154130561Sobrien is_code = 0; 315560484Sobrien switch (symbol_get_tc (sym)->class) 315660484Sobrien { 315760484Sobrien case XMC_PR: 315860484Sobrien case XMC_RO: 315960484Sobrien case XMC_DB: 316060484Sobrien case XMC_GL: 316160484Sobrien case XMC_XO: 316260484Sobrien case XMC_SV: 316360484Sobrien case XMC_TI: 316460484Sobrien case XMC_TB: 316560484Sobrien S_SET_SEGMENT (sym, text_section); 316660484Sobrien symbol_get_tc (sym)->subseg = ppc_text_subsegment; 316760484Sobrien ++ppc_text_subsegment; 316860484Sobrien list_ptr = &ppc_text_csects; 3169130561Sobrien is_code = 1; 317060484Sobrien break; 317160484Sobrien case XMC_RW: 317260484Sobrien case XMC_TC0: 317360484Sobrien case XMC_TC: 317460484Sobrien case XMC_DS: 317560484Sobrien case XMC_UA: 317660484Sobrien case XMC_BS: 317760484Sobrien case XMC_UC: 317860484Sobrien if (ppc_toc_csect != NULL 317960484Sobrien && (symbol_get_tc (ppc_toc_csect)->subseg + 1 318060484Sobrien == ppc_data_subsegment)) 318160484Sobrien after_toc = 1; 318260484Sobrien S_SET_SEGMENT (sym, data_section); 318360484Sobrien symbol_get_tc (sym)->subseg = ppc_data_subsegment; 318460484Sobrien ++ppc_data_subsegment; 318560484Sobrien list_ptr = &ppc_data_csects; 318660484Sobrien break; 318760484Sobrien default: 318860484Sobrien abort (); 318960484Sobrien } 319060484Sobrien 319160484Sobrien /* We set the obstack chunk size to a small value before 319289857Sobrien changing subsegments, so that we don't use a lot of memory 319389857Sobrien space for what may be a small section. */ 319460484Sobrien hold_chunksize = chunksize; 319560484Sobrien chunksize = 64; 319660484Sobrien 3197130561Sobrien sec = subseg_new (segment_name (S_GET_SEGMENT (sym)), 3198130561Sobrien symbol_get_tc (sym)->subseg); 319960484Sobrien 320060484Sobrien chunksize = hold_chunksize; 320160484Sobrien 320260484Sobrien if (after_toc) 320360484Sobrien ppc_after_toc_frag = frag_now; 320460484Sobrien 3205130561Sobrien record_alignment (sec, align); 3206130561Sobrien if (is_code) 3207130561Sobrien frag_align_code (align, 0); 3208130561Sobrien else 3209130561Sobrien frag_align (align, 0, 0); 3210130561Sobrien 321160484Sobrien symbol_set_frag (sym, frag_now); 321260484Sobrien S_SET_VALUE (sym, (valueT) frag_now_fix ()); 321360484Sobrien 3214130561Sobrien symbol_get_tc (sym)->align = align; 321560484Sobrien symbol_get_tc (sym)->output = 1; 321660484Sobrien symbol_get_tc (sym)->within = sym; 321777298Sobrien 321860484Sobrien for (list = *list_ptr; 321960484Sobrien symbol_get_tc (list)->next != (symbolS *) NULL; 322060484Sobrien list = symbol_get_tc (list)->next) 322160484Sobrien ; 322260484Sobrien symbol_get_tc (list)->next = sym; 322377298Sobrien 322460484Sobrien symbol_remove (sym, &symbol_rootP, &symbol_lastP); 322560484Sobrien symbol_append (sym, symbol_get_tc (list)->within, &symbol_rootP, 322660484Sobrien &symbol_lastP); 322760484Sobrien } 322860484Sobrien 322960484Sobrien ppc_current_csect = sym; 323060484Sobrien} 323160484Sobrien 323260484Sobrien/* This function handles the .text and .data pseudo-ops. These 323360484Sobrien pseudo-ops aren't really used by XCOFF; we implement them for the 323460484Sobrien convenience of people who aren't used to XCOFF. */ 323560484Sobrien 323660484Sobrienstatic void 3237218822Sdimppc_section (int type) 323860484Sobrien{ 323960484Sobrien const char *name; 324060484Sobrien symbolS *sym; 324160484Sobrien 324260484Sobrien if (type == 't') 324360484Sobrien name = ".text[PR]"; 324460484Sobrien else if (type == 'd') 324560484Sobrien name = ".data[RW]"; 324660484Sobrien else 324760484Sobrien abort (); 324860484Sobrien 324960484Sobrien sym = symbol_find_or_make (name); 325060484Sobrien 3251130561Sobrien ppc_change_csect (sym, 2); 325260484Sobrien 325360484Sobrien demand_empty_rest_of_line (); 325460484Sobrien} 325560484Sobrien 325660484Sobrien/* This function handles the .section pseudo-op. This is mostly to 325760484Sobrien give an error, since XCOFF only supports .text, .data and .bss, but 325860484Sobrien we do permit the user to name the text or data section. */ 325960484Sobrien 326060484Sobrienstatic void 3261218822Sdimppc_named_section (int ignore ATTRIBUTE_UNUSED) 326260484Sobrien{ 326360484Sobrien char *user_name; 326460484Sobrien const char *real_name; 326560484Sobrien char c; 326660484Sobrien symbolS *sym; 326760484Sobrien 326860484Sobrien user_name = input_line_pointer; 326960484Sobrien c = get_symbol_end (); 327060484Sobrien 327160484Sobrien if (strcmp (user_name, ".text") == 0) 327260484Sobrien real_name = ".text[PR]"; 327360484Sobrien else if (strcmp (user_name, ".data") == 0) 327460484Sobrien real_name = ".data[RW]"; 327560484Sobrien else 327660484Sobrien { 327760484Sobrien as_bad (_("The XCOFF file format does not support arbitrary sections")); 327860484Sobrien *input_line_pointer = c; 327960484Sobrien ignore_rest_of_line (); 328060484Sobrien return; 328160484Sobrien } 328260484Sobrien 328360484Sobrien *input_line_pointer = c; 328460484Sobrien 328560484Sobrien sym = symbol_find_or_make (real_name); 328660484Sobrien 3287130561Sobrien ppc_change_csect (sym, 2); 328860484Sobrien 328960484Sobrien demand_empty_rest_of_line (); 329060484Sobrien} 329160484Sobrien 329260484Sobrien/* The .extern pseudo-op. We create an undefined symbol. */ 329360484Sobrien 329460484Sobrienstatic void 3295218822Sdimppc_extern (int ignore ATTRIBUTE_UNUSED) 329660484Sobrien{ 329760484Sobrien char *name; 329860484Sobrien char endc; 329960484Sobrien 330060484Sobrien name = input_line_pointer; 330160484Sobrien endc = get_symbol_end (); 330260484Sobrien 330360484Sobrien (void) symbol_find_or_make (name); 330460484Sobrien 330560484Sobrien *input_line_pointer = endc; 330660484Sobrien 330760484Sobrien demand_empty_rest_of_line (); 330860484Sobrien} 330960484Sobrien 331060484Sobrien/* The .lglobl pseudo-op. Keep the symbol in the symbol table. */ 331160484Sobrien 331260484Sobrienstatic void 3313218822Sdimppc_lglobl (int ignore ATTRIBUTE_UNUSED) 331460484Sobrien{ 331560484Sobrien char *name; 331660484Sobrien char endc; 331760484Sobrien symbolS *sym; 331860484Sobrien 331960484Sobrien name = input_line_pointer; 332060484Sobrien endc = get_symbol_end (); 332160484Sobrien 332260484Sobrien sym = symbol_find_or_make (name); 332360484Sobrien 332460484Sobrien *input_line_pointer = endc; 332560484Sobrien 332660484Sobrien symbol_get_tc (sym)->output = 1; 332760484Sobrien 332860484Sobrien demand_empty_rest_of_line (); 332960484Sobrien} 333060484Sobrien 333160484Sobrien/* The .rename pseudo-op. The RS/6000 assembler can rename symbols, 333260484Sobrien although I don't know why it bothers. */ 333360484Sobrien 333460484Sobrienstatic void 3335218822Sdimppc_rename (int ignore ATTRIBUTE_UNUSED) 333660484Sobrien{ 333760484Sobrien char *name; 333860484Sobrien char endc; 333960484Sobrien symbolS *sym; 334060484Sobrien int len; 334160484Sobrien 334260484Sobrien name = input_line_pointer; 334360484Sobrien endc = get_symbol_end (); 334460484Sobrien 334560484Sobrien sym = symbol_find_or_make (name); 334660484Sobrien 334760484Sobrien *input_line_pointer = endc; 334860484Sobrien 334960484Sobrien if (*input_line_pointer != ',') 335060484Sobrien { 335160484Sobrien as_bad (_("missing rename string")); 335260484Sobrien ignore_rest_of_line (); 335360484Sobrien return; 335460484Sobrien } 335560484Sobrien ++input_line_pointer; 335660484Sobrien 335760484Sobrien symbol_get_tc (sym)->real_name = demand_copy_C_string (&len); 335860484Sobrien 335960484Sobrien demand_empty_rest_of_line (); 336060484Sobrien} 336160484Sobrien 336260484Sobrien/* The .stabx pseudo-op. This is similar to a normal .stabs 336360484Sobrien pseudo-op, but slightly different. A sample is 336460484Sobrien .stabx "main:F-1",.main,142,0 336560484Sobrien The first argument is the symbol name to create. The second is the 336660484Sobrien value, and the third is the storage class. The fourth seems to be 336760484Sobrien always zero, and I am assuming it is the type. */ 336860484Sobrien 336960484Sobrienstatic void 3370218822Sdimppc_stabx (int ignore ATTRIBUTE_UNUSED) 337160484Sobrien{ 337260484Sobrien char *name; 337360484Sobrien int len; 337460484Sobrien symbolS *sym; 337560484Sobrien expressionS exp; 337660484Sobrien 337760484Sobrien name = demand_copy_C_string (&len); 337860484Sobrien 337960484Sobrien if (*input_line_pointer != ',') 338060484Sobrien { 338160484Sobrien as_bad (_("missing value")); 338260484Sobrien return; 338360484Sobrien } 338460484Sobrien ++input_line_pointer; 338560484Sobrien 3386130561Sobrien ppc_stab_symbol = TRUE; 338760484Sobrien sym = symbol_make (name); 3388130561Sobrien ppc_stab_symbol = FALSE; 338960484Sobrien 339060484Sobrien symbol_get_tc (sym)->real_name = name; 339160484Sobrien 339260484Sobrien (void) expression (&exp); 339360484Sobrien 339460484Sobrien switch (exp.X_op) 339560484Sobrien { 339660484Sobrien case O_illegal: 339760484Sobrien case O_absent: 339860484Sobrien case O_big: 339960484Sobrien as_bad (_("illegal .stabx expression; zero assumed")); 340060484Sobrien exp.X_add_number = 0; 340160484Sobrien /* Fall through. */ 340260484Sobrien case O_constant: 340360484Sobrien S_SET_VALUE (sym, (valueT) exp.X_add_number); 340460484Sobrien symbol_set_frag (sym, &zero_address_frag); 340560484Sobrien break; 340660484Sobrien 340760484Sobrien case O_symbol: 340860484Sobrien if (S_GET_SEGMENT (exp.X_add_symbol) == undefined_section) 340960484Sobrien symbol_set_value_expression (sym, &exp); 341060484Sobrien else 341160484Sobrien { 341260484Sobrien S_SET_VALUE (sym, 341360484Sobrien exp.X_add_number + S_GET_VALUE (exp.X_add_symbol)); 341460484Sobrien symbol_set_frag (sym, symbol_get_frag (exp.X_add_symbol)); 341560484Sobrien } 341660484Sobrien break; 341760484Sobrien 341860484Sobrien default: 341960484Sobrien /* The value is some complex expression. This will probably 342089857Sobrien fail at some later point, but this is probably the right 342189857Sobrien thing to do here. */ 342260484Sobrien symbol_set_value_expression (sym, &exp); 342360484Sobrien break; 342460484Sobrien } 342560484Sobrien 342660484Sobrien S_SET_SEGMENT (sym, ppc_coff_debug_section); 342760484Sobrien symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; 342860484Sobrien 342960484Sobrien if (*input_line_pointer != ',') 343060484Sobrien { 343160484Sobrien as_bad (_("missing class")); 343260484Sobrien return; 343360484Sobrien } 343460484Sobrien ++input_line_pointer; 343560484Sobrien 343660484Sobrien S_SET_STORAGE_CLASS (sym, get_absolute_expression ()); 343760484Sobrien 343860484Sobrien if (*input_line_pointer != ',') 343960484Sobrien { 344060484Sobrien as_bad (_("missing type")); 344160484Sobrien return; 344260484Sobrien } 344360484Sobrien ++input_line_pointer; 344460484Sobrien 344560484Sobrien S_SET_DATA_TYPE (sym, get_absolute_expression ()); 344660484Sobrien 344760484Sobrien symbol_get_tc (sym)->output = 1; 344860484Sobrien 344978828Sobrien if (S_GET_STORAGE_CLASS (sym) == C_STSYM) { 345089857Sobrien 345160484Sobrien symbol_get_tc (sym)->within = ppc_current_block; 345260484Sobrien 345378828Sobrien /* In this case : 345489857Sobrien 345578828Sobrien .bs name 345678828Sobrien .stabx "z",arrays_,133,0 345778828Sobrien .es 345889857Sobrien 345978828Sobrien .comm arrays_,13768,3 346089857Sobrien 346178828Sobrien resolve_symbol_value will copy the exp's "within" into sym's when the 346278828Sobrien offset is 0. Since this seems to be corner case problem, 346378828Sobrien only do the correction for storage class C_STSYM. A better solution 346489857Sobrien would be to have the tc field updated in ppc_symbol_new_hook. */ 346589857Sobrien 346689857Sobrien if (exp.X_op == O_symbol) 346778828Sobrien { 346878828Sobrien symbol_get_tc (exp.X_add_symbol)->within = ppc_current_block; 346978828Sobrien } 347078828Sobrien } 347178828Sobrien 347260484Sobrien if (exp.X_op != O_symbol 347360484Sobrien || ! S_IS_EXTERNAL (exp.X_add_symbol) 347460484Sobrien || S_GET_SEGMENT (exp.X_add_symbol) != bss_section) 347560484Sobrien ppc_frob_label (sym); 347660484Sobrien else 347760484Sobrien { 347860484Sobrien symbol_remove (sym, &symbol_rootP, &symbol_lastP); 347960484Sobrien symbol_append (sym, exp.X_add_symbol, &symbol_rootP, &symbol_lastP); 348060484Sobrien if (symbol_get_tc (ppc_current_csect)->within == exp.X_add_symbol) 348160484Sobrien symbol_get_tc (ppc_current_csect)->within = sym; 348260484Sobrien } 348360484Sobrien 348460484Sobrien demand_empty_rest_of_line (); 348560484Sobrien} 348660484Sobrien 348760484Sobrien/* The .function pseudo-op. This takes several arguments. The first 348860484Sobrien argument seems to be the external name of the symbol. The second 3489130561Sobrien argument seems to be the label for the start of the function. gcc 349060484Sobrien uses the same name for both. I have no idea what the third and 349160484Sobrien fourth arguments are meant to be. The optional fifth argument is 349260484Sobrien an expression for the size of the function. In COFF this symbol 349360484Sobrien gets an aux entry like that used for a csect. */ 349460484Sobrien 349560484Sobrienstatic void 3496218822Sdimppc_function (int ignore ATTRIBUTE_UNUSED) 349760484Sobrien{ 349860484Sobrien char *name; 349960484Sobrien char endc; 350060484Sobrien char *s; 350160484Sobrien symbolS *ext_sym; 350260484Sobrien symbolS *lab_sym; 350360484Sobrien 350460484Sobrien name = input_line_pointer; 350560484Sobrien endc = get_symbol_end (); 350660484Sobrien 350760484Sobrien /* Ignore any [PR] suffix. */ 350860484Sobrien name = ppc_canonicalize_symbol_name (name); 350960484Sobrien s = strchr (name, '['); 351060484Sobrien if (s != (char *) NULL 351160484Sobrien && strcmp (s + 1, "PR]") == 0) 351260484Sobrien *s = '\0'; 351360484Sobrien 351460484Sobrien ext_sym = symbol_find_or_make (name); 351560484Sobrien 351660484Sobrien *input_line_pointer = endc; 351760484Sobrien 351860484Sobrien if (*input_line_pointer != ',') 351960484Sobrien { 352060484Sobrien as_bad (_("missing symbol name")); 352160484Sobrien ignore_rest_of_line (); 352260484Sobrien return; 352360484Sobrien } 352460484Sobrien ++input_line_pointer; 352560484Sobrien 352660484Sobrien name = input_line_pointer; 352760484Sobrien endc = get_symbol_end (); 352860484Sobrien 352960484Sobrien lab_sym = symbol_find_or_make (name); 353060484Sobrien 353160484Sobrien *input_line_pointer = endc; 353260484Sobrien 353360484Sobrien if (ext_sym != lab_sym) 353460484Sobrien { 353560484Sobrien expressionS exp; 353660484Sobrien 353760484Sobrien exp.X_op = O_symbol; 353860484Sobrien exp.X_add_symbol = lab_sym; 353960484Sobrien exp.X_op_symbol = NULL; 354060484Sobrien exp.X_add_number = 0; 354160484Sobrien exp.X_unsigned = 0; 354260484Sobrien symbol_set_value_expression (ext_sym, &exp); 354360484Sobrien } 354460484Sobrien 354560484Sobrien if (symbol_get_tc (ext_sym)->class == -1) 354660484Sobrien symbol_get_tc (ext_sym)->class = XMC_PR; 354760484Sobrien symbol_get_tc (ext_sym)->output = 1; 354860484Sobrien 354960484Sobrien if (*input_line_pointer == ',') 355060484Sobrien { 355160484Sobrien expressionS ignore; 355260484Sobrien 355360484Sobrien /* Ignore the third argument. */ 355460484Sobrien ++input_line_pointer; 355560484Sobrien expression (&ignore); 355660484Sobrien if (*input_line_pointer == ',') 355760484Sobrien { 355860484Sobrien /* Ignore the fourth argument. */ 355960484Sobrien ++input_line_pointer; 356060484Sobrien expression (&ignore); 356160484Sobrien if (*input_line_pointer == ',') 356260484Sobrien { 356360484Sobrien /* The fifth argument is the function size. */ 356460484Sobrien ++input_line_pointer; 356560484Sobrien symbol_get_tc (ext_sym)->size = symbol_new ("L0\001", 356660484Sobrien absolute_section, 356760484Sobrien (valueT) 0, 356860484Sobrien &zero_address_frag); 356960484Sobrien pseudo_set (symbol_get_tc (ext_sym)->size); 357060484Sobrien } 357160484Sobrien } 357260484Sobrien } 357360484Sobrien 357460484Sobrien S_SET_DATA_TYPE (ext_sym, DT_FCN << N_BTSHFT); 357560484Sobrien SF_SET_FUNCTION (ext_sym); 357660484Sobrien SF_SET_PROCESS (ext_sym); 357760484Sobrien coff_add_linesym (ext_sym); 357860484Sobrien 357960484Sobrien demand_empty_rest_of_line (); 358060484Sobrien} 358160484Sobrien 358260484Sobrien/* The .bf pseudo-op. This is just like a COFF C_FCN symbol named 358389857Sobrien ".bf". If the pseudo op .bi was seen before .bf, patch the .bi sym 358489857Sobrien with the correct line number */ 3585104834Sobrien 358689857Sobrienstatic symbolS *saved_bi_sym = 0; 358760484Sobrien 358860484Sobrienstatic void 3589218822Sdimppc_bf (int ignore ATTRIBUTE_UNUSED) 359060484Sobrien{ 359160484Sobrien symbolS *sym; 359260484Sobrien 359360484Sobrien sym = symbol_make (".bf"); 359460484Sobrien S_SET_SEGMENT (sym, text_section); 359560484Sobrien symbol_set_frag (sym, frag_now); 359660484Sobrien S_SET_VALUE (sym, frag_now_fix ()); 359760484Sobrien S_SET_STORAGE_CLASS (sym, C_FCN); 359860484Sobrien 359960484Sobrien coff_line_base = get_absolute_expression (); 360060484Sobrien 360160484Sobrien S_SET_NUMBER_AUXILIARY (sym, 1); 360260484Sobrien SA_SET_SYM_LNNO (sym, coff_line_base); 360360484Sobrien 360489857Sobrien /* Line number for bi. */ 3605104834Sobrien if (saved_bi_sym) 360689857Sobrien { 360789857Sobrien S_SET_VALUE (saved_bi_sym, coff_n_line_nos); 360889857Sobrien saved_bi_sym = 0; 360989857Sobrien } 361089857Sobrien 3611104834Sobrien 361260484Sobrien symbol_get_tc (sym)->output = 1; 361360484Sobrien 361460484Sobrien ppc_frob_label (sym); 361560484Sobrien 361660484Sobrien demand_empty_rest_of_line (); 361760484Sobrien} 361860484Sobrien 361960484Sobrien/* The .ef pseudo-op. This is just like a COFF C_FCN symbol named 362060484Sobrien ".ef", except that the line number is absolute, not relative to the 362160484Sobrien most recent ".bf" symbol. */ 362260484Sobrien 362360484Sobrienstatic void 3624218822Sdimppc_ef (int ignore ATTRIBUTE_UNUSED) 362560484Sobrien{ 362660484Sobrien symbolS *sym; 362760484Sobrien 362860484Sobrien sym = symbol_make (".ef"); 362960484Sobrien S_SET_SEGMENT (sym, text_section); 363060484Sobrien symbol_set_frag (sym, frag_now); 363160484Sobrien S_SET_VALUE (sym, frag_now_fix ()); 363260484Sobrien S_SET_STORAGE_CLASS (sym, C_FCN); 363360484Sobrien S_SET_NUMBER_AUXILIARY (sym, 1); 363460484Sobrien SA_SET_SYM_LNNO (sym, get_absolute_expression ()); 363560484Sobrien symbol_get_tc (sym)->output = 1; 363660484Sobrien 363760484Sobrien ppc_frob_label (sym); 363860484Sobrien 363960484Sobrien demand_empty_rest_of_line (); 364060484Sobrien} 364160484Sobrien 364260484Sobrien/* The .bi and .ei pseudo-ops. These take a string argument and 364360484Sobrien generates a C_BINCL or C_EINCL symbol, which goes at the start of 364489857Sobrien the symbol list. The value of .bi will be know when the next .bf 364589857Sobrien is encountered. */ 364660484Sobrien 364760484Sobrienstatic void 3648218822Sdimppc_biei (int ei) 364960484Sobrien{ 365060484Sobrien static symbolS *last_biei; 365160484Sobrien 365260484Sobrien char *name; 365360484Sobrien int len; 365460484Sobrien symbolS *sym; 365560484Sobrien symbolS *look; 365660484Sobrien 365760484Sobrien name = demand_copy_C_string (&len); 365860484Sobrien 365960484Sobrien /* The value of these symbols is actually file offset. Here we set 366060484Sobrien the value to the index into the line number entries. In 366160484Sobrien ppc_frob_symbols we set the fix_line field, which will cause BFD 366260484Sobrien to do the right thing. */ 366360484Sobrien 366460484Sobrien sym = symbol_make (name); 366560484Sobrien /* obj-coff.c currently only handles line numbers correctly in the 366660484Sobrien .text section. */ 366760484Sobrien S_SET_SEGMENT (sym, text_section); 366860484Sobrien S_SET_VALUE (sym, coff_n_line_nos); 366960484Sobrien symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; 367060484Sobrien 367160484Sobrien S_SET_STORAGE_CLASS (sym, ei ? C_EINCL : C_BINCL); 367260484Sobrien symbol_get_tc (sym)->output = 1; 367377298Sobrien 367489857Sobrien /* Save bi. */ 3675104834Sobrien if (ei) 367689857Sobrien saved_bi_sym = 0; 367789857Sobrien else 367889857Sobrien saved_bi_sym = sym; 367989857Sobrien 368060484Sobrien for (look = last_biei ? last_biei : symbol_rootP; 368160484Sobrien (look != (symbolS *) NULL 368260484Sobrien && (S_GET_STORAGE_CLASS (look) == C_FILE 368360484Sobrien || S_GET_STORAGE_CLASS (look) == C_BINCL 368460484Sobrien || S_GET_STORAGE_CLASS (look) == C_EINCL)); 368560484Sobrien look = symbol_next (look)) 368660484Sobrien ; 368760484Sobrien if (look != (symbolS *) NULL) 368860484Sobrien { 368960484Sobrien symbol_remove (sym, &symbol_rootP, &symbol_lastP); 369060484Sobrien symbol_insert (sym, look, &symbol_rootP, &symbol_lastP); 369160484Sobrien last_biei = sym; 369260484Sobrien } 369360484Sobrien 369460484Sobrien demand_empty_rest_of_line (); 369560484Sobrien} 369660484Sobrien 369760484Sobrien/* The .bs pseudo-op. This generates a C_BSTAT symbol named ".bs". 369860484Sobrien There is one argument, which is a csect symbol. The value of the 369960484Sobrien .bs symbol is the index of this csect symbol. */ 370060484Sobrien 370160484Sobrienstatic void 3702218822Sdimppc_bs (int ignore ATTRIBUTE_UNUSED) 370360484Sobrien{ 370460484Sobrien char *name; 370560484Sobrien char endc; 370660484Sobrien symbolS *csect; 370760484Sobrien symbolS *sym; 370860484Sobrien 370960484Sobrien if (ppc_current_block != NULL) 371060484Sobrien as_bad (_("nested .bs blocks")); 371160484Sobrien 371260484Sobrien name = input_line_pointer; 371360484Sobrien endc = get_symbol_end (); 371460484Sobrien 371560484Sobrien csect = symbol_find_or_make (name); 371660484Sobrien 371760484Sobrien *input_line_pointer = endc; 371860484Sobrien 371960484Sobrien sym = symbol_make (".bs"); 372060484Sobrien S_SET_SEGMENT (sym, now_seg); 372160484Sobrien S_SET_STORAGE_CLASS (sym, C_BSTAT); 372260484Sobrien symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; 372360484Sobrien symbol_get_tc (sym)->output = 1; 372460484Sobrien 372560484Sobrien symbol_get_tc (sym)->within = csect; 372660484Sobrien 372760484Sobrien ppc_frob_label (sym); 372860484Sobrien 372960484Sobrien ppc_current_block = sym; 373060484Sobrien 373160484Sobrien demand_empty_rest_of_line (); 373260484Sobrien} 373360484Sobrien 373460484Sobrien/* The .es pseudo-op. Generate a C_ESTART symbol named .es. */ 373560484Sobrien 373660484Sobrienstatic void 3737218822Sdimppc_es (int ignore ATTRIBUTE_UNUSED) 373860484Sobrien{ 373960484Sobrien symbolS *sym; 374060484Sobrien 374160484Sobrien if (ppc_current_block == NULL) 374260484Sobrien as_bad (_(".es without preceding .bs")); 374360484Sobrien 374460484Sobrien sym = symbol_make (".es"); 374560484Sobrien S_SET_SEGMENT (sym, now_seg); 374660484Sobrien S_SET_STORAGE_CLASS (sym, C_ESTAT); 374760484Sobrien symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; 374860484Sobrien symbol_get_tc (sym)->output = 1; 374960484Sobrien 375060484Sobrien ppc_frob_label (sym); 375160484Sobrien 375260484Sobrien ppc_current_block = NULL; 375360484Sobrien 375460484Sobrien demand_empty_rest_of_line (); 375560484Sobrien} 375660484Sobrien 375760484Sobrien/* The .bb pseudo-op. Generate a C_BLOCK symbol named .bb, with a 375860484Sobrien line number. */ 375960484Sobrien 376060484Sobrienstatic void 3761218822Sdimppc_bb (int ignore ATTRIBUTE_UNUSED) 376260484Sobrien{ 376360484Sobrien symbolS *sym; 376460484Sobrien 376560484Sobrien sym = symbol_make (".bb"); 376660484Sobrien S_SET_SEGMENT (sym, text_section); 376760484Sobrien symbol_set_frag (sym, frag_now); 376860484Sobrien S_SET_VALUE (sym, frag_now_fix ()); 376960484Sobrien S_SET_STORAGE_CLASS (sym, C_BLOCK); 377060484Sobrien 377160484Sobrien S_SET_NUMBER_AUXILIARY (sym, 1); 377260484Sobrien SA_SET_SYM_LNNO (sym, get_absolute_expression ()); 377360484Sobrien 377460484Sobrien symbol_get_tc (sym)->output = 1; 377560484Sobrien 377660484Sobrien SF_SET_PROCESS (sym); 377760484Sobrien 377860484Sobrien ppc_frob_label (sym); 377960484Sobrien 378060484Sobrien demand_empty_rest_of_line (); 378160484Sobrien} 378260484Sobrien 378360484Sobrien/* The .eb pseudo-op. Generate a C_BLOCK symbol named .eb, with a 378460484Sobrien line number. */ 378560484Sobrien 378660484Sobrienstatic void 3787218822Sdimppc_eb (int ignore ATTRIBUTE_UNUSED) 378860484Sobrien{ 378960484Sobrien symbolS *sym; 379060484Sobrien 379160484Sobrien sym = symbol_make (".eb"); 379260484Sobrien S_SET_SEGMENT (sym, text_section); 379360484Sobrien symbol_set_frag (sym, frag_now); 379460484Sobrien S_SET_VALUE (sym, frag_now_fix ()); 379560484Sobrien S_SET_STORAGE_CLASS (sym, C_BLOCK); 379660484Sobrien S_SET_NUMBER_AUXILIARY (sym, 1); 379760484Sobrien SA_SET_SYM_LNNO (sym, get_absolute_expression ()); 379860484Sobrien symbol_get_tc (sym)->output = 1; 379960484Sobrien 380060484Sobrien SF_SET_PROCESS (sym); 380160484Sobrien 380260484Sobrien ppc_frob_label (sym); 380360484Sobrien 380460484Sobrien demand_empty_rest_of_line (); 380560484Sobrien} 380660484Sobrien 380760484Sobrien/* The .bc pseudo-op. This just creates a C_BCOMM symbol with a 380860484Sobrien specified name. */ 380960484Sobrien 381060484Sobrienstatic void 3811218822Sdimppc_bc (int ignore ATTRIBUTE_UNUSED) 381260484Sobrien{ 381360484Sobrien char *name; 381460484Sobrien int len; 381560484Sobrien symbolS *sym; 381660484Sobrien 381760484Sobrien name = demand_copy_C_string (&len); 381860484Sobrien sym = symbol_make (name); 381960484Sobrien S_SET_SEGMENT (sym, ppc_coff_debug_section); 382060484Sobrien symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; 382160484Sobrien S_SET_STORAGE_CLASS (sym, C_BCOMM); 382260484Sobrien S_SET_VALUE (sym, 0); 382360484Sobrien symbol_get_tc (sym)->output = 1; 382460484Sobrien 382560484Sobrien ppc_frob_label (sym); 382660484Sobrien 382760484Sobrien demand_empty_rest_of_line (); 382860484Sobrien} 382960484Sobrien 383060484Sobrien/* The .ec pseudo-op. This just creates a C_ECOMM symbol. */ 383160484Sobrien 383260484Sobrienstatic void 3833218822Sdimppc_ec (int ignore ATTRIBUTE_UNUSED) 383460484Sobrien{ 383560484Sobrien symbolS *sym; 383660484Sobrien 383760484Sobrien sym = symbol_make (".ec"); 383860484Sobrien S_SET_SEGMENT (sym, ppc_coff_debug_section); 383960484Sobrien symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; 384060484Sobrien S_SET_STORAGE_CLASS (sym, C_ECOMM); 384160484Sobrien S_SET_VALUE (sym, 0); 384260484Sobrien symbol_get_tc (sym)->output = 1; 384360484Sobrien 384460484Sobrien ppc_frob_label (sym); 384560484Sobrien 384660484Sobrien demand_empty_rest_of_line (); 384760484Sobrien} 384860484Sobrien 384960484Sobrien/* The .toc pseudo-op. Switch to the .toc subsegment. */ 385060484Sobrien 385160484Sobrienstatic void 3852218822Sdimppc_toc (int ignore ATTRIBUTE_UNUSED) 385360484Sobrien{ 385460484Sobrien if (ppc_toc_csect != (symbolS *) NULL) 385560484Sobrien subseg_set (data_section, symbol_get_tc (ppc_toc_csect)->subseg); 385660484Sobrien else 385760484Sobrien { 385860484Sobrien subsegT subseg; 385960484Sobrien symbolS *sym; 386060484Sobrien symbolS *list; 386177298Sobrien 386260484Sobrien subseg = ppc_data_subsegment; 386360484Sobrien ++ppc_data_subsegment; 386460484Sobrien 386560484Sobrien subseg_new (segment_name (data_section), subseg); 386660484Sobrien ppc_toc_frag = frag_now; 386760484Sobrien 386860484Sobrien sym = symbol_find_or_make ("TOC[TC0]"); 386960484Sobrien symbol_set_frag (sym, frag_now); 387060484Sobrien S_SET_SEGMENT (sym, data_section); 387160484Sobrien S_SET_VALUE (sym, (valueT) frag_now_fix ()); 387260484Sobrien symbol_get_tc (sym)->subseg = subseg; 387360484Sobrien symbol_get_tc (sym)->output = 1; 387460484Sobrien symbol_get_tc (sym)->within = sym; 387560484Sobrien 387660484Sobrien ppc_toc_csect = sym; 387777298Sobrien 387860484Sobrien for (list = ppc_data_csects; 387960484Sobrien symbol_get_tc (list)->next != (symbolS *) NULL; 388060484Sobrien list = symbol_get_tc (list)->next) 388160484Sobrien ; 388260484Sobrien symbol_get_tc (list)->next = sym; 388360484Sobrien 388460484Sobrien symbol_remove (sym, &symbol_rootP, &symbol_lastP); 388560484Sobrien symbol_append (sym, symbol_get_tc (list)->within, &symbol_rootP, 388660484Sobrien &symbol_lastP); 388760484Sobrien } 388860484Sobrien 388960484Sobrien ppc_current_csect = ppc_toc_csect; 389060484Sobrien 389160484Sobrien demand_empty_rest_of_line (); 389260484Sobrien} 389360484Sobrien 389460484Sobrien/* The AIX assembler automatically aligns the operands of a .long or 389560484Sobrien .short pseudo-op, and we want to be compatible. */ 389660484Sobrien 389760484Sobrienstatic void 3898218822Sdimppc_xcoff_cons (int log_size) 389960484Sobrien{ 390060484Sobrien frag_align (log_size, 0, 0); 390160484Sobrien record_alignment (now_seg, log_size); 390260484Sobrien cons (1 << log_size); 390360484Sobrien} 390460484Sobrien 390560484Sobrienstatic void 3906218822Sdimppc_vbyte (int dummy ATTRIBUTE_UNUSED) 390760484Sobrien{ 390860484Sobrien expressionS exp; 390960484Sobrien int byte_count; 391060484Sobrien 391160484Sobrien (void) expression (&exp); 391260484Sobrien 391360484Sobrien if (exp.X_op != O_constant) 391460484Sobrien { 391560484Sobrien as_bad (_("non-constant byte count")); 391660484Sobrien return; 391760484Sobrien } 391860484Sobrien 391960484Sobrien byte_count = exp.X_add_number; 392060484Sobrien 392160484Sobrien if (*input_line_pointer != ',') 392260484Sobrien { 392360484Sobrien as_bad (_("missing value")); 392460484Sobrien return; 392560484Sobrien } 392660484Sobrien 392760484Sobrien ++input_line_pointer; 392860484Sobrien cons (byte_count); 392960484Sobrien} 393060484Sobrien 393160484Sobrien#endif /* OBJ_XCOFF */ 393289857Sobrien#if defined (OBJ_XCOFF) || defined (OBJ_ELF) 393360484Sobrien 393460484Sobrien/* The .tc pseudo-op. This is used when generating either XCOFF or 393560484Sobrien ELF. This takes two or more arguments. 393660484Sobrien 393760484Sobrien When generating XCOFF output, the first argument is the name to 393860484Sobrien give to this location in the toc; this will be a symbol with class 393989857Sobrien TC. The rest of the arguments are N-byte values to actually put at 394060484Sobrien this location in the TOC; often there is just one more argument, a 3941130561Sobrien relocatable symbol reference. The size of the value to store 394289857Sobrien depends on target word size. A 32-bit target uses 4-byte values, a 394389857Sobrien 64-bit target uses 8-byte values. 394460484Sobrien 394560484Sobrien When not generating XCOFF output, the arguments are the same, but 394660484Sobrien the first argument is simply ignored. */ 394760484Sobrien 394860484Sobrienstatic void 3949218822Sdimppc_tc (int ignore ATTRIBUTE_UNUSED) 395060484Sobrien{ 395160484Sobrien#ifdef OBJ_XCOFF 395260484Sobrien 395360484Sobrien /* Define the TOC symbol name. */ 395460484Sobrien { 395560484Sobrien char *name; 395660484Sobrien char endc; 395760484Sobrien symbolS *sym; 395860484Sobrien 395960484Sobrien if (ppc_toc_csect == (symbolS *) NULL 396060484Sobrien || ppc_toc_csect != ppc_current_csect) 396160484Sobrien { 396260484Sobrien as_bad (_(".tc not in .toc section")); 396360484Sobrien ignore_rest_of_line (); 396460484Sobrien return; 396560484Sobrien } 396660484Sobrien 396760484Sobrien name = input_line_pointer; 396860484Sobrien endc = get_symbol_end (); 396960484Sobrien 397060484Sobrien sym = symbol_find_or_make (name); 397160484Sobrien 397260484Sobrien *input_line_pointer = endc; 397360484Sobrien 397460484Sobrien if (S_IS_DEFINED (sym)) 397560484Sobrien { 397660484Sobrien symbolS *label; 397760484Sobrien 397860484Sobrien label = symbol_get_tc (ppc_current_csect)->within; 397960484Sobrien if (symbol_get_tc (label)->class != XMC_TC0) 398060484Sobrien { 398160484Sobrien as_bad (_(".tc with no label")); 398260484Sobrien ignore_rest_of_line (); 398360484Sobrien return; 398460484Sobrien } 398560484Sobrien 398660484Sobrien S_SET_SEGMENT (label, S_GET_SEGMENT (sym)); 398760484Sobrien symbol_set_frag (label, symbol_get_frag (sym)); 398860484Sobrien S_SET_VALUE (label, S_GET_VALUE (sym)); 398960484Sobrien 399060484Sobrien while (! is_end_of_line[(unsigned char) *input_line_pointer]) 399160484Sobrien ++input_line_pointer; 399260484Sobrien 399360484Sobrien return; 399460484Sobrien } 399560484Sobrien 399660484Sobrien S_SET_SEGMENT (sym, now_seg); 399760484Sobrien symbol_set_frag (sym, frag_now); 399860484Sobrien S_SET_VALUE (sym, (valueT) frag_now_fix ()); 399960484Sobrien symbol_get_tc (sym)->class = XMC_TC; 400060484Sobrien symbol_get_tc (sym)->output = 1; 400160484Sobrien 400260484Sobrien ppc_frob_label (sym); 400360484Sobrien } 400460484Sobrien 400589857Sobrien#endif /* OBJ_XCOFF */ 400689857Sobrien#ifdef OBJ_ELF 400789857Sobrien int align; 400860484Sobrien 400960484Sobrien /* Skip the TOC symbol name. */ 401060484Sobrien while (is_part_of_name (*input_line_pointer) 401160484Sobrien || *input_line_pointer == '[' 401260484Sobrien || *input_line_pointer == ']' 401360484Sobrien || *input_line_pointer == '{' 401460484Sobrien || *input_line_pointer == '}') 401560484Sobrien ++input_line_pointer; 401660484Sobrien 401789857Sobrien /* Align to a four/eight byte boundary. */ 4018104834Sobrien align = ppc_obj64 ? 3 : 2; 401989857Sobrien frag_align (align, 0, 0); 402089857Sobrien record_alignment (now_seg, align); 402189857Sobrien#endif /* OBJ_ELF */ 402260484Sobrien 402360484Sobrien if (*input_line_pointer != ',') 402460484Sobrien demand_empty_rest_of_line (); 402560484Sobrien else 402660484Sobrien { 402760484Sobrien ++input_line_pointer; 4028104834Sobrien cons (ppc_obj64 ? 8 : 4); 402960484Sobrien } 403060484Sobrien} 403189857Sobrien 403289857Sobrien/* Pseudo-op .machine. */ 403389857Sobrien 403489857Sobrienstatic void 4035218822Sdimppc_machine (int ignore ATTRIBUTE_UNUSED) 403689857Sobrien{ 4037130561Sobrien char *cpu_string; 4038130561Sobrien#define MAX_HISTORY 100 4039130561Sobrien static unsigned long *cpu_history; 4040130561Sobrien static int curr_hist; 4041130561Sobrien 4042130561Sobrien SKIP_WHITESPACE (); 4043130561Sobrien 4044130561Sobrien if (*input_line_pointer == '"') 4045130561Sobrien { 4046130561Sobrien int len; 4047130561Sobrien cpu_string = demand_copy_C_string (&len); 4048130561Sobrien } 4049130561Sobrien else 4050130561Sobrien { 4051130561Sobrien char c; 4052130561Sobrien cpu_string = input_line_pointer; 4053130561Sobrien c = get_symbol_end (); 4054130561Sobrien cpu_string = xstrdup (cpu_string); 4055130561Sobrien *input_line_pointer = c; 4056130561Sobrien } 4057130561Sobrien 4058130561Sobrien if (cpu_string != NULL) 4059130561Sobrien { 4060130561Sobrien unsigned long old_cpu = ppc_cpu; 4061130561Sobrien char *p; 4062130561Sobrien 4063130561Sobrien for (p = cpu_string; *p != 0; p++) 4064130561Sobrien *p = TOLOWER (*p); 4065130561Sobrien 4066130561Sobrien if (strcmp (cpu_string, "push") == 0) 4067130561Sobrien { 4068130561Sobrien if (cpu_history == NULL) 4069130561Sobrien cpu_history = xmalloc (MAX_HISTORY * sizeof (*cpu_history)); 4070130561Sobrien 4071130561Sobrien if (curr_hist >= MAX_HISTORY) 4072130561Sobrien as_bad (_(".machine stack overflow")); 4073130561Sobrien else 4074130561Sobrien cpu_history[curr_hist++] = ppc_cpu; 4075130561Sobrien } 4076130561Sobrien else if (strcmp (cpu_string, "pop") == 0) 4077130561Sobrien { 4078130561Sobrien if (curr_hist <= 0) 4079130561Sobrien as_bad (_(".machine stack underflow")); 4080130561Sobrien else 4081130561Sobrien ppc_cpu = cpu_history[--curr_hist]; 4082130561Sobrien } 4083130561Sobrien else if (parse_cpu (cpu_string)) 4084130561Sobrien ; 4085130561Sobrien else 4086130561Sobrien as_bad (_("invalid machine `%s'"), cpu_string); 4087130561Sobrien 4088130561Sobrien if (ppc_cpu != old_cpu) 4089130561Sobrien ppc_setup_opcodes (); 4090130561Sobrien } 4091130561Sobrien 4092130561Sobrien demand_empty_rest_of_line (); 409389857Sobrien} 409489857Sobrien 409589857Sobrien/* See whether a symbol is in the TOC section. */ 409689857Sobrien 409789857Sobrienstatic int 4098218822Sdimppc_is_toc_sym (symbolS *sym) 409989857Sobrien{ 410089857Sobrien#ifdef OBJ_XCOFF 410189857Sobrien return symbol_get_tc (sym)->class == XMC_TC; 410289857Sobrien#endif 410389857Sobrien#ifdef OBJ_ELF 410489857Sobrien const char *sname = segment_name (S_GET_SEGMENT (sym)); 4105104834Sobrien if (ppc_obj64) 410689857Sobrien return strcmp (sname, ".toc") == 0; 410789857Sobrien else 410889857Sobrien return strcmp (sname, ".got") == 0; 410989857Sobrien#endif 411089857Sobrien} 411189857Sobrien#endif /* defined (OBJ_XCOFF) || defined (OBJ_ELF) */ 411260484Sobrien 411360484Sobrien#ifdef TE_PE 411460484Sobrien 411589857Sobrien/* Pseudo-ops specific to the Windows NT PowerPC PE (coff) format. */ 411660484Sobrien 411760484Sobrien/* Set the current section. */ 411860484Sobrienstatic void 4119218822Sdimppc_set_current_section (segT new) 412060484Sobrien{ 412160484Sobrien ppc_previous_section = ppc_current_section; 412260484Sobrien ppc_current_section = new; 412360484Sobrien} 412460484Sobrien 412560484Sobrien/* pseudo-op: .previous 412660484Sobrien behaviour: toggles the current section with the previous section. 412760484Sobrien errors: None 412889857Sobrien warnings: "No previous section" */ 412989857Sobrien 413060484Sobrienstatic void 4131218822Sdimppc_previous (int ignore ATTRIBUTE_UNUSED) 413260484Sobrien{ 413360484Sobrien symbolS *tmp; 413460484Sobrien 413577298Sobrien if (ppc_previous_section == NULL) 413660484Sobrien { 413789857Sobrien as_warn (_("No previous section to return to. Directive ignored.")); 413860484Sobrien return; 413960484Sobrien } 414060484Sobrien 414189857Sobrien subseg_set (ppc_previous_section, 0); 414260484Sobrien 414389857Sobrien ppc_set_current_section (ppc_previous_section); 414460484Sobrien} 414560484Sobrien 414660484Sobrien/* pseudo-op: .pdata 414760484Sobrien behaviour: predefined read only data section 4148130561Sobrien double word aligned 414960484Sobrien errors: None 415060484Sobrien warnings: None 415160484Sobrien initial: .section .pdata "adr3" 4152130561Sobrien a - don't know -- maybe a misprint 415360484Sobrien d - initialized data 415460484Sobrien r - readable 415560484Sobrien 3 - double word aligned (that would be 4 byte boundary) 415660484Sobrien 415760484Sobrien commentary: 415860484Sobrien Tag index tables (also known as the function table) for exception 415989857Sobrien handling, debugging, etc. */ 416060484Sobrien 416160484Sobrienstatic void 4162218822Sdimppc_pdata (int ignore ATTRIBUTE_UNUSED) 416360484Sobrien{ 416477298Sobrien if (pdata_section == 0) 416560484Sobrien { 416660484Sobrien pdata_section = subseg_new (".pdata", 0); 416777298Sobrien 416860484Sobrien bfd_set_section_flags (stdoutput, pdata_section, 416960484Sobrien (SEC_ALLOC | SEC_LOAD | SEC_RELOC 417060484Sobrien | SEC_READONLY | SEC_DATA )); 417177298Sobrien 417260484Sobrien bfd_set_section_alignment (stdoutput, pdata_section, 2); 417360484Sobrien } 417460484Sobrien else 417560484Sobrien { 417689857Sobrien pdata_section = subseg_new (".pdata", 0); 417760484Sobrien } 417889857Sobrien ppc_set_current_section (pdata_section); 417960484Sobrien} 418060484Sobrien 418160484Sobrien/* pseudo-op: .ydata 418260484Sobrien behaviour: predefined read only data section 4183130561Sobrien double word aligned 418460484Sobrien errors: None 418560484Sobrien warnings: None 418660484Sobrien initial: .section .ydata "drw3" 4187130561Sobrien a - don't know -- maybe a misprint 418860484Sobrien d - initialized data 418960484Sobrien r - readable 419060484Sobrien 3 - double word aligned (that would be 4 byte boundary) 419160484Sobrien commentary: 419260484Sobrien Tag tables (also known as the scope table) for exception handling, 419389857Sobrien debugging, etc. */ 419489857Sobrien 419560484Sobrienstatic void 4196218822Sdimppc_ydata (int ignore ATTRIBUTE_UNUSED) 419760484Sobrien{ 419877298Sobrien if (ydata_section == 0) 419960484Sobrien { 420060484Sobrien ydata_section = subseg_new (".ydata", 0); 420160484Sobrien bfd_set_section_flags (stdoutput, ydata_section, 420289857Sobrien (SEC_ALLOC | SEC_LOAD | SEC_RELOC 420389857Sobrien | SEC_READONLY | SEC_DATA )); 420460484Sobrien 420560484Sobrien bfd_set_section_alignment (stdoutput, ydata_section, 3); 420660484Sobrien } 420760484Sobrien else 420860484Sobrien { 420960484Sobrien ydata_section = subseg_new (".ydata", 0); 421060484Sobrien } 421189857Sobrien ppc_set_current_section (ydata_section); 421260484Sobrien} 421360484Sobrien 421460484Sobrien/* pseudo-op: .reldata 421560484Sobrien behaviour: predefined read write data section 4216130561Sobrien double word aligned (4-byte) 421760484Sobrien FIXME: relocation is applied to it 421860484Sobrien FIXME: what's the difference between this and .data? 421960484Sobrien errors: None 422060484Sobrien warnings: None 422160484Sobrien initial: .section .reldata "drw3" 422260484Sobrien d - initialized data 422360484Sobrien r - readable 422460484Sobrien w - writeable 422560484Sobrien 3 - double word aligned (that would be 8 byte boundary) 422660484Sobrien 422760484Sobrien commentary: 422860484Sobrien Like .data, but intended to hold data subject to relocation, such as 422989857Sobrien function descriptors, etc. */ 423089857Sobrien 423160484Sobrienstatic void 4232218822Sdimppc_reldata (int ignore ATTRIBUTE_UNUSED) 423360484Sobrien{ 423460484Sobrien if (reldata_section == 0) 423560484Sobrien { 423660484Sobrien reldata_section = subseg_new (".reldata", 0); 423760484Sobrien 423860484Sobrien bfd_set_section_flags (stdoutput, reldata_section, 423989857Sobrien (SEC_ALLOC | SEC_LOAD | SEC_RELOC 424089857Sobrien | SEC_DATA)); 424160484Sobrien 424260484Sobrien bfd_set_section_alignment (stdoutput, reldata_section, 2); 424360484Sobrien } 424460484Sobrien else 424560484Sobrien { 424660484Sobrien reldata_section = subseg_new (".reldata", 0); 424760484Sobrien } 424889857Sobrien ppc_set_current_section (reldata_section); 424960484Sobrien} 425060484Sobrien 425160484Sobrien/* pseudo-op: .rdata 425260484Sobrien behaviour: predefined read only data section 4253130561Sobrien double word aligned 425460484Sobrien errors: None 425560484Sobrien warnings: None 425660484Sobrien initial: .section .rdata "dr3" 425760484Sobrien d - initialized data 425860484Sobrien r - readable 425989857Sobrien 3 - double word aligned (that would be 4 byte boundary) */ 426089857Sobrien 426160484Sobrienstatic void 4262218822Sdimppc_rdata (int ignore ATTRIBUTE_UNUSED) 426360484Sobrien{ 426460484Sobrien if (rdata_section == 0) 426560484Sobrien { 426660484Sobrien rdata_section = subseg_new (".rdata", 0); 426760484Sobrien bfd_set_section_flags (stdoutput, rdata_section, 426860484Sobrien (SEC_ALLOC | SEC_LOAD | SEC_RELOC 426960484Sobrien | SEC_READONLY | SEC_DATA )); 427060484Sobrien 427160484Sobrien bfd_set_section_alignment (stdoutput, rdata_section, 2); 427260484Sobrien } 427360484Sobrien else 427460484Sobrien { 427560484Sobrien rdata_section = subseg_new (".rdata", 0); 427660484Sobrien } 427789857Sobrien ppc_set_current_section (rdata_section); 427860484Sobrien} 427960484Sobrien 428060484Sobrien/* pseudo-op: .ualong 428177298Sobrien behaviour: much like .int, with the exception that no alignment is 4282130561Sobrien performed. 428360484Sobrien FIXME: test the alignment statement 428460484Sobrien errors: None 428589857Sobrien warnings: None */ 428689857Sobrien 428760484Sobrienstatic void 4288218822Sdimppc_ualong (int ignore ATTRIBUTE_UNUSED) 428960484Sobrien{ 429089857Sobrien /* Try for long. */ 429189857Sobrien cons (4); 429260484Sobrien} 429360484Sobrien 429460484Sobrien/* pseudo-op: .znop <symbol name> 429560484Sobrien behaviour: Issue a nop instruction 4296130561Sobrien Issue a IMAGE_REL_PPC_IFGLUE relocation against it, using 429760484Sobrien the supplied symbol name. 429860484Sobrien errors: None 429989857Sobrien warnings: Missing symbol name */ 430089857Sobrien 430160484Sobrienstatic void 4302218822Sdimppc_znop (int ignore ATTRIBUTE_UNUSED) 430360484Sobrien{ 430460484Sobrien unsigned long insn; 430560484Sobrien const struct powerpc_opcode *opcode; 430660484Sobrien expressionS ex; 430760484Sobrien char *f; 430860484Sobrien symbolS *sym; 430960484Sobrien char *symbol_name; 431060484Sobrien char c; 431160484Sobrien char *name; 431260484Sobrien unsigned int exp; 431360484Sobrien flagword flags; 431460484Sobrien asection *sec; 431560484Sobrien 431689857Sobrien /* Strip out the symbol name. */ 431760484Sobrien symbol_name = input_line_pointer; 431860484Sobrien c = get_symbol_end (); 431960484Sobrien 432060484Sobrien name = xmalloc (input_line_pointer - symbol_name + 1); 432160484Sobrien strcpy (name, symbol_name); 432260484Sobrien 432360484Sobrien sym = symbol_find_or_make (name); 432460484Sobrien 432560484Sobrien *input_line_pointer = c; 432660484Sobrien 432760484Sobrien SKIP_WHITESPACE (); 432860484Sobrien 432960484Sobrien /* Look up the opcode in the hash table. */ 433060484Sobrien opcode = (const struct powerpc_opcode *) hash_find (ppc_hash, "nop"); 433160484Sobrien 433289857Sobrien /* Stick in the nop. */ 433360484Sobrien insn = opcode->opcode; 433460484Sobrien 433560484Sobrien /* Write out the instruction. */ 433660484Sobrien f = frag_more (4); 433760484Sobrien md_number_to_chars (f, insn, 4); 433860484Sobrien fix_new (frag_now, 433960484Sobrien f - frag_now->fr_literal, 434060484Sobrien 4, 434160484Sobrien sym, 434260484Sobrien 0, 434360484Sobrien 0, 434460484Sobrien BFD_RELOC_16_GOT_PCREL); 434560484Sobrien 434660484Sobrien} 434760484Sobrien 434877298Sobrien/* pseudo-op: 434977298Sobrien behaviour: 435077298Sobrien errors: 435189857Sobrien warnings: */ 435289857Sobrien 435360484Sobrienstatic void 4354218822Sdimppc_pe_comm (int lcomm) 435560484Sobrien{ 4356218822Sdim char *name; 4357218822Sdim char c; 4358218822Sdim char *p; 435960484Sobrien offsetT temp; 4360218822Sdim symbolS *symbolP; 436160484Sobrien offsetT align; 436260484Sobrien 436360484Sobrien name = input_line_pointer; 436460484Sobrien c = get_symbol_end (); 436560484Sobrien 436689857Sobrien /* just after name is now '\0'. */ 436760484Sobrien p = input_line_pointer; 436860484Sobrien *p = c; 436960484Sobrien SKIP_WHITESPACE (); 437060484Sobrien if (*input_line_pointer != ',') 437160484Sobrien { 437260484Sobrien as_bad (_("Expected comma after symbol-name: rest of line ignored.")); 437360484Sobrien ignore_rest_of_line (); 437460484Sobrien return; 437560484Sobrien } 437660484Sobrien 437760484Sobrien input_line_pointer++; /* skip ',' */ 437860484Sobrien if ((temp = get_absolute_expression ()) < 0) 437960484Sobrien { 438060484Sobrien as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) temp); 438160484Sobrien ignore_rest_of_line (); 438260484Sobrien return; 438360484Sobrien } 438460484Sobrien 438560484Sobrien if (! lcomm) 438660484Sobrien { 438760484Sobrien /* The third argument to .comm is the alignment. */ 438860484Sobrien if (*input_line_pointer != ',') 438960484Sobrien align = 3; 439060484Sobrien else 439160484Sobrien { 439260484Sobrien ++input_line_pointer; 439360484Sobrien align = get_absolute_expression (); 439460484Sobrien if (align <= 0) 439560484Sobrien { 439660484Sobrien as_warn (_("ignoring bad alignment")); 439760484Sobrien align = 3; 439860484Sobrien } 439960484Sobrien } 440060484Sobrien } 440160484Sobrien 440260484Sobrien *p = 0; 440360484Sobrien symbolP = symbol_find_or_make (name); 440460484Sobrien 440560484Sobrien *p = c; 440660484Sobrien if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) 440760484Sobrien { 440860484Sobrien as_bad (_("Ignoring attempt to re-define symbol `%s'."), 440960484Sobrien S_GET_NAME (symbolP)); 441060484Sobrien ignore_rest_of_line (); 441160484Sobrien return; 441260484Sobrien } 441360484Sobrien 441460484Sobrien if (S_GET_VALUE (symbolP)) 441560484Sobrien { 441660484Sobrien if (S_GET_VALUE (symbolP) != (valueT) temp) 441760484Sobrien as_bad (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."), 441860484Sobrien S_GET_NAME (symbolP), 441960484Sobrien (long) S_GET_VALUE (symbolP), 442060484Sobrien (long) temp); 442160484Sobrien } 442260484Sobrien else 442360484Sobrien { 442460484Sobrien S_SET_VALUE (symbolP, (valueT) temp); 442560484Sobrien S_SET_EXTERNAL (symbolP); 4426218822Sdim S_SET_SEGMENT (symbolP, bfd_com_section_ptr); 442760484Sobrien } 442860484Sobrien 442960484Sobrien demand_empty_rest_of_line (); 443060484Sobrien} 443160484Sobrien 443260484Sobrien/* 443360484Sobrien * implement the .section pseudo op: 443460484Sobrien * .section name {, "flags"} 443560484Sobrien * ^ ^ 443660484Sobrien * | +--- optional flags: 'b' for bss 443760484Sobrien * | 'i' for info 443860484Sobrien * +-- section name 'l' for lib 443960484Sobrien * 'n' for noload 444060484Sobrien * 'o' for over 444160484Sobrien * 'w' for data 444260484Sobrien * 'd' (apparently m88k for data) 444360484Sobrien * 'x' for text 444460484Sobrien * But if the argument is not a quoted string, treat it as a 444560484Sobrien * subsegment number. 444660484Sobrien * 444760484Sobrien * FIXME: this is a copy of the section processing from obj-coff.c, with 444860484Sobrien * additions/changes for the moto-pas assembler support. There are three 444960484Sobrien * categories: 445060484Sobrien * 445177298Sobrien * FIXME: I just noticed this. This doesn't work at all really. It it 445260484Sobrien * setting bits that bfd probably neither understands or uses. The 445360484Sobrien * correct approach (?) will have to incorporate extra fields attached 445460484Sobrien * to the section to hold the system specific stuff. (krk) 445560484Sobrien * 445660484Sobrien * Section Contents: 445760484Sobrien * 'a' - unknown - referred to in documentation, but no definition supplied 445860484Sobrien * 'c' - section has code 445960484Sobrien * 'd' - section has initialized data 446060484Sobrien * 'u' - section has uninitialized data 446160484Sobrien * 'i' - section contains directives (info) 446260484Sobrien * 'n' - section can be discarded 446360484Sobrien * 'R' - remove section at link time 446460484Sobrien * 446560484Sobrien * Section Protection: 446660484Sobrien * 'r' - section is readable 446760484Sobrien * 'w' - section is writeable 446860484Sobrien * 'x' - section is executable 446960484Sobrien * 's' - section is sharable 447060484Sobrien * 447160484Sobrien * Section Alignment: 447260484Sobrien * '0' - align to byte boundary 447360484Sobrien * '1' - align to halfword undary 447460484Sobrien * '2' - align to word boundary 447560484Sobrien * '3' - align to doubleword boundary 447660484Sobrien * '4' - align to quadword boundary 447760484Sobrien * '5' - align to 32 byte boundary 447860484Sobrien * '6' - align to 64 byte boundary 447960484Sobrien * 448060484Sobrien */ 448160484Sobrien 448260484Sobrienvoid 4483218822Sdimppc_pe_section (int ignore ATTRIBUTE_UNUSED) 448460484Sobrien{ 448589857Sobrien /* Strip out the section name. */ 448660484Sobrien char *section_name; 448760484Sobrien char c; 448860484Sobrien char *name; 448960484Sobrien unsigned int exp; 449060484Sobrien flagword flags; 449160484Sobrien segT sec; 449260484Sobrien int align; 449360484Sobrien 449460484Sobrien section_name = input_line_pointer; 449560484Sobrien c = get_symbol_end (); 449660484Sobrien 449760484Sobrien name = xmalloc (input_line_pointer - section_name + 1); 449860484Sobrien strcpy (name, section_name); 449960484Sobrien 450060484Sobrien *input_line_pointer = c; 450160484Sobrien 450260484Sobrien SKIP_WHITESPACE (); 450360484Sobrien 450460484Sobrien exp = 0; 450560484Sobrien flags = SEC_NO_FLAGS; 450660484Sobrien 450760484Sobrien if (strcmp (name, ".idata$2") == 0) 450860484Sobrien { 450960484Sobrien align = 0; 451060484Sobrien } 451160484Sobrien else if (strcmp (name, ".idata$3") == 0) 451260484Sobrien { 451360484Sobrien align = 0; 451460484Sobrien } 451560484Sobrien else if (strcmp (name, ".idata$4") == 0) 451660484Sobrien { 451760484Sobrien align = 2; 451860484Sobrien } 451960484Sobrien else if (strcmp (name, ".idata$5") == 0) 452060484Sobrien { 452160484Sobrien align = 2; 452260484Sobrien } 452360484Sobrien else if (strcmp (name, ".idata$6") == 0) 452460484Sobrien { 452560484Sobrien align = 1; 452660484Sobrien } 452760484Sobrien else 452889857Sobrien /* Default alignment to 16 byte boundary. */ 452989857Sobrien align = 4; 453060484Sobrien 453160484Sobrien if (*input_line_pointer == ',') 453260484Sobrien { 453360484Sobrien ++input_line_pointer; 453460484Sobrien SKIP_WHITESPACE (); 453560484Sobrien if (*input_line_pointer != '"') 453660484Sobrien exp = get_absolute_expression (); 453760484Sobrien else 453860484Sobrien { 453960484Sobrien ++input_line_pointer; 454060484Sobrien while (*input_line_pointer != '"' 454160484Sobrien && ! is_end_of_line[(unsigned char) *input_line_pointer]) 454260484Sobrien { 454360484Sobrien switch (*input_line_pointer) 454460484Sobrien { 454560484Sobrien /* Section Contents */ 454660484Sobrien case 'a': /* unknown */ 454760484Sobrien as_bad (_("Unsupported section attribute -- 'a'")); 454860484Sobrien break; 454960484Sobrien case 'c': /* code section */ 455077298Sobrien flags |= SEC_CODE; 455160484Sobrien break; 455260484Sobrien case 'd': /* section has initialized data */ 455360484Sobrien flags |= SEC_DATA; 455460484Sobrien break; 455560484Sobrien case 'u': /* section has uninitialized data */ 455660484Sobrien /* FIXME: This is IMAGE_SCN_CNT_UNINITIALIZED_DATA 455760484Sobrien in winnt.h */ 455860484Sobrien flags |= SEC_ROM; 455960484Sobrien break; 456060484Sobrien case 'i': /* section contains directives (info) */ 456160484Sobrien /* FIXME: This is IMAGE_SCN_LNK_INFO 456260484Sobrien in winnt.h */ 456360484Sobrien flags |= SEC_HAS_CONTENTS; 456460484Sobrien break; 456560484Sobrien case 'n': /* section can be discarded */ 456677298Sobrien flags &=~ SEC_LOAD; 456760484Sobrien break; 456860484Sobrien case 'R': /* Remove section at link time */ 456960484Sobrien flags |= SEC_NEVER_LOAD; 457060484Sobrien break; 4571218822Sdim#if IFLICT_BRAIN_DAMAGE 457260484Sobrien /* Section Protection */ 457360484Sobrien case 'r': /* section is readable */ 457460484Sobrien flags |= IMAGE_SCN_MEM_READ; 457560484Sobrien break; 457660484Sobrien case 'w': /* section is writeable */ 457760484Sobrien flags |= IMAGE_SCN_MEM_WRITE; 457860484Sobrien break; 457960484Sobrien case 'x': /* section is executable */ 458060484Sobrien flags |= IMAGE_SCN_MEM_EXECUTE; 458160484Sobrien break; 458260484Sobrien case 's': /* section is sharable */ 458360484Sobrien flags |= IMAGE_SCN_MEM_SHARED; 458460484Sobrien break; 458560484Sobrien 458660484Sobrien /* Section Alignment */ 458760484Sobrien case '0': /* align to byte boundary */ 458860484Sobrien flags |= IMAGE_SCN_ALIGN_1BYTES; 458960484Sobrien align = 0; 459060484Sobrien break; 459160484Sobrien case '1': /* align to halfword boundary */ 459260484Sobrien flags |= IMAGE_SCN_ALIGN_2BYTES; 459360484Sobrien align = 1; 459460484Sobrien break; 459560484Sobrien case '2': /* align to word boundary */ 459660484Sobrien flags |= IMAGE_SCN_ALIGN_4BYTES; 459760484Sobrien align = 2; 459860484Sobrien break; 459960484Sobrien case '3': /* align to doubleword boundary */ 460060484Sobrien flags |= IMAGE_SCN_ALIGN_8BYTES; 460160484Sobrien align = 3; 460260484Sobrien break; 460360484Sobrien case '4': /* align to quadword boundary */ 460460484Sobrien flags |= IMAGE_SCN_ALIGN_16BYTES; 460560484Sobrien align = 4; 460660484Sobrien break; 460760484Sobrien case '5': /* align to 32 byte boundary */ 460860484Sobrien flags |= IMAGE_SCN_ALIGN_32BYTES; 460960484Sobrien align = 5; 461060484Sobrien break; 461160484Sobrien case '6': /* align to 64 byte boundary */ 461260484Sobrien flags |= IMAGE_SCN_ALIGN_64BYTES; 461360484Sobrien align = 6; 461460484Sobrien break; 4615218822Sdim#endif 461660484Sobrien default: 461789857Sobrien as_bad (_("unknown section attribute '%c'"), 461889857Sobrien *input_line_pointer); 461960484Sobrien break; 462060484Sobrien } 462160484Sobrien ++input_line_pointer; 462260484Sobrien } 462360484Sobrien if (*input_line_pointer == '"') 462460484Sobrien ++input_line_pointer; 462560484Sobrien } 462660484Sobrien } 462760484Sobrien 462860484Sobrien sec = subseg_new (name, (subsegT) exp); 462960484Sobrien 463089857Sobrien ppc_set_current_section (sec); 463160484Sobrien 463260484Sobrien if (flags != SEC_NO_FLAGS) 463360484Sobrien { 463460484Sobrien if (! bfd_set_section_flags (stdoutput, sec, flags)) 463560484Sobrien as_bad (_("error setting flags for \"%s\": %s"), 463660484Sobrien bfd_section_name (stdoutput, sec), 463760484Sobrien bfd_errmsg (bfd_get_error ())); 463860484Sobrien } 463960484Sobrien 464089857Sobrien bfd_set_section_alignment (stdoutput, sec, align); 464160484Sobrien} 464260484Sobrien 464360484Sobrienstatic void 4644218822Sdimppc_pe_function (int ignore ATTRIBUTE_UNUSED) 464560484Sobrien{ 464660484Sobrien char *name; 464760484Sobrien char endc; 464860484Sobrien symbolS *ext_sym; 464960484Sobrien 465060484Sobrien name = input_line_pointer; 465160484Sobrien endc = get_symbol_end (); 465260484Sobrien 465360484Sobrien ext_sym = symbol_find_or_make (name); 465460484Sobrien 465560484Sobrien *input_line_pointer = endc; 465660484Sobrien 465760484Sobrien S_SET_DATA_TYPE (ext_sym, DT_FCN << N_BTSHFT); 465860484Sobrien SF_SET_FUNCTION (ext_sym); 465960484Sobrien SF_SET_PROCESS (ext_sym); 466060484Sobrien coff_add_linesym (ext_sym); 466160484Sobrien 466260484Sobrien demand_empty_rest_of_line (); 466360484Sobrien} 466460484Sobrien 466560484Sobrienstatic void 4666218822Sdimppc_pe_tocd (int ignore ATTRIBUTE_UNUSED) 466760484Sobrien{ 466860484Sobrien if (tocdata_section == 0) 466960484Sobrien { 467060484Sobrien tocdata_section = subseg_new (".tocd", 0); 467189857Sobrien /* FIXME: section flags won't work. */ 467260484Sobrien bfd_set_section_flags (stdoutput, tocdata_section, 467360484Sobrien (SEC_ALLOC | SEC_LOAD | SEC_RELOC 467489857Sobrien | SEC_READONLY | SEC_DATA)); 467560484Sobrien 467660484Sobrien bfd_set_section_alignment (stdoutput, tocdata_section, 2); 467760484Sobrien } 467860484Sobrien else 467960484Sobrien { 468060484Sobrien rdata_section = subseg_new (".tocd", 0); 468160484Sobrien } 468260484Sobrien 468389857Sobrien ppc_set_current_section (tocdata_section); 468460484Sobrien 468560484Sobrien demand_empty_rest_of_line (); 468660484Sobrien} 468760484Sobrien 468860484Sobrien/* Don't adjust TOC relocs to use the section symbol. */ 468960484Sobrien 469060484Sobrienint 4691218822Sdimppc_pe_fix_adjustable (fixS *fix) 469260484Sobrien{ 469360484Sobrien return fix->fx_r_type != BFD_RELOC_PPC_TOC16; 469460484Sobrien} 469560484Sobrien 469660484Sobrien#endif 469760484Sobrien 469860484Sobrien#ifdef OBJ_XCOFF 469960484Sobrien 470060484Sobrien/* XCOFF specific symbol and file handling. */ 470160484Sobrien 470260484Sobrien/* Canonicalize the symbol name. We use the to force the suffix, if 470360484Sobrien any, to use square brackets, and to be in upper case. */ 470460484Sobrien 470560484Sobrienchar * 4706218822Sdimppc_canonicalize_symbol_name (char *name) 470760484Sobrien{ 470860484Sobrien char *s; 470960484Sobrien 471060484Sobrien if (ppc_stab_symbol) 471160484Sobrien return name; 471260484Sobrien 471360484Sobrien for (s = name; *s != '\0' && *s != '{' && *s != '['; s++) 471460484Sobrien ; 471560484Sobrien if (*s != '\0') 471660484Sobrien { 471760484Sobrien char brac; 471860484Sobrien 471960484Sobrien if (*s == '[') 472060484Sobrien brac = ']'; 472160484Sobrien else 472260484Sobrien { 472360484Sobrien *s = '['; 472460484Sobrien brac = '}'; 472560484Sobrien } 472660484Sobrien 472760484Sobrien for (s++; *s != '\0' && *s != brac; s++) 472889857Sobrien *s = TOUPPER (*s); 472960484Sobrien 473060484Sobrien if (*s == '\0' || s[1] != '\0') 473160484Sobrien as_bad (_("bad symbol suffix")); 473260484Sobrien 473360484Sobrien *s = ']'; 473460484Sobrien } 473560484Sobrien 473660484Sobrien return name; 473760484Sobrien} 473860484Sobrien 473960484Sobrien/* Set the class of a symbol based on the suffix, if any. This is 474060484Sobrien called whenever a new symbol is created. */ 474160484Sobrien 474260484Sobrienvoid 4743218822Sdimppc_symbol_new_hook (symbolS *sym) 474460484Sobrien{ 474560484Sobrien struct ppc_tc_sy *tc; 474660484Sobrien const char *s; 474760484Sobrien 474860484Sobrien tc = symbol_get_tc (sym); 474960484Sobrien tc->next = NULL; 475060484Sobrien tc->output = 0; 475160484Sobrien tc->class = -1; 475260484Sobrien tc->real_name = NULL; 475360484Sobrien tc->subseg = 0; 475460484Sobrien tc->align = 0; 475560484Sobrien tc->size = NULL; 475660484Sobrien tc->within = NULL; 475760484Sobrien 475860484Sobrien if (ppc_stab_symbol) 475960484Sobrien return; 476060484Sobrien 476160484Sobrien s = strchr (S_GET_NAME (sym), '['); 476260484Sobrien if (s == (const char *) NULL) 476360484Sobrien { 476460484Sobrien /* There is no suffix. */ 476560484Sobrien return; 476660484Sobrien } 476760484Sobrien 476860484Sobrien ++s; 476960484Sobrien 477060484Sobrien switch (s[0]) 477160484Sobrien { 477260484Sobrien case 'B': 477360484Sobrien if (strcmp (s, "BS]") == 0) 477460484Sobrien tc->class = XMC_BS; 477560484Sobrien break; 477660484Sobrien case 'D': 477760484Sobrien if (strcmp (s, "DB]") == 0) 477860484Sobrien tc->class = XMC_DB; 477960484Sobrien else if (strcmp (s, "DS]") == 0) 478060484Sobrien tc->class = XMC_DS; 478160484Sobrien break; 478260484Sobrien case 'G': 478360484Sobrien if (strcmp (s, "GL]") == 0) 478460484Sobrien tc->class = XMC_GL; 478560484Sobrien break; 478660484Sobrien case 'P': 478760484Sobrien if (strcmp (s, "PR]") == 0) 478860484Sobrien tc->class = XMC_PR; 478960484Sobrien break; 479060484Sobrien case 'R': 479160484Sobrien if (strcmp (s, "RO]") == 0) 479260484Sobrien tc->class = XMC_RO; 479360484Sobrien else if (strcmp (s, "RW]") == 0) 479460484Sobrien tc->class = XMC_RW; 479560484Sobrien break; 479660484Sobrien case 'S': 479760484Sobrien if (strcmp (s, "SV]") == 0) 479860484Sobrien tc->class = XMC_SV; 479960484Sobrien break; 480060484Sobrien case 'T': 480160484Sobrien if (strcmp (s, "TC]") == 0) 480260484Sobrien tc->class = XMC_TC; 480360484Sobrien else if (strcmp (s, "TI]") == 0) 480460484Sobrien tc->class = XMC_TI; 480560484Sobrien else if (strcmp (s, "TB]") == 0) 480660484Sobrien tc->class = XMC_TB; 480760484Sobrien else if (strcmp (s, "TC0]") == 0 || strcmp (s, "T0]") == 0) 480860484Sobrien tc->class = XMC_TC0; 480960484Sobrien break; 481060484Sobrien case 'U': 481160484Sobrien if (strcmp (s, "UA]") == 0) 481260484Sobrien tc->class = XMC_UA; 481360484Sobrien else if (strcmp (s, "UC]") == 0) 481460484Sobrien tc->class = XMC_UC; 481560484Sobrien break; 481660484Sobrien case 'X': 481760484Sobrien if (strcmp (s, "XO]") == 0) 481860484Sobrien tc->class = XMC_XO; 481960484Sobrien break; 482060484Sobrien } 482160484Sobrien 482260484Sobrien if (tc->class == -1) 482360484Sobrien as_bad (_("Unrecognized symbol suffix")); 482460484Sobrien} 482560484Sobrien 482660484Sobrien/* Set the class of a label based on where it is defined. This 482760484Sobrien handles symbols without suffixes. Also, move the symbol so that it 482860484Sobrien follows the csect symbol. */ 482960484Sobrien 483060484Sobrienvoid 4831218822Sdimppc_frob_label (symbolS *sym) 483260484Sobrien{ 483360484Sobrien if (ppc_current_csect != (symbolS *) NULL) 483460484Sobrien { 483560484Sobrien if (symbol_get_tc (sym)->class == -1) 483660484Sobrien symbol_get_tc (sym)->class = symbol_get_tc (ppc_current_csect)->class; 483760484Sobrien 483860484Sobrien symbol_remove (sym, &symbol_rootP, &symbol_lastP); 483960484Sobrien symbol_append (sym, symbol_get_tc (ppc_current_csect)->within, 484060484Sobrien &symbol_rootP, &symbol_lastP); 484160484Sobrien symbol_get_tc (ppc_current_csect)->within = sym; 484260484Sobrien } 4843218822Sdim 4844218822Sdim#ifdef OBJ_ELF 4845218822Sdim dwarf2_emit_label (sym); 4846218822Sdim#endif 484760484Sobrien} 484860484Sobrien 484960484Sobrien/* This variable is set by ppc_frob_symbol if any absolute symbols are 485060484Sobrien seen. It tells ppc_adjust_symtab whether it needs to look through 485160484Sobrien the symbols. */ 485260484Sobrien 4853130561Sobrienstatic bfd_boolean ppc_saw_abs; 485460484Sobrien 485560484Sobrien/* Change the name of a symbol just before writing it out. Set the 485660484Sobrien real name if the .rename pseudo-op was used. Otherwise, remove any 485760484Sobrien class suffix. Return 1 if the symbol should not be included in the 485860484Sobrien symbol table. */ 485960484Sobrien 486060484Sobrienint 4861218822Sdimppc_frob_symbol (symbolS *sym) 486260484Sobrien{ 486360484Sobrien static symbolS *ppc_last_function; 486460484Sobrien static symbolS *set_end; 486560484Sobrien 486660484Sobrien /* Discard symbols that should not be included in the output symbol 486760484Sobrien table. */ 486860484Sobrien if (! symbol_used_in_reloc_p (sym) 486960484Sobrien && ((symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) != 0 4870218822Sdim || (! (S_IS_EXTERNAL (sym) || S_IS_WEAK (sym)) 487160484Sobrien && ! symbol_get_tc (sym)->output 487260484Sobrien && S_GET_STORAGE_CLASS (sym) != C_FILE))) 487360484Sobrien return 1; 487460484Sobrien 4875130561Sobrien /* This one will disappear anyway. Don't make a csect sym for it. */ 4876130561Sobrien if (sym == abs_section_sym) 4877130561Sobrien return 1; 4878130561Sobrien 487960484Sobrien if (symbol_get_tc (sym)->real_name != (char *) NULL) 488060484Sobrien S_SET_NAME (sym, symbol_get_tc (sym)->real_name); 488160484Sobrien else 488260484Sobrien { 488360484Sobrien const char *name; 488460484Sobrien const char *s; 488560484Sobrien 488660484Sobrien name = S_GET_NAME (sym); 488760484Sobrien s = strchr (name, '['); 488860484Sobrien if (s != (char *) NULL) 488960484Sobrien { 489060484Sobrien unsigned int len; 489160484Sobrien char *snew; 489260484Sobrien 489360484Sobrien len = s - name; 489460484Sobrien snew = xmalloc (len + 1); 489560484Sobrien memcpy (snew, name, len); 489660484Sobrien snew[len] = '\0'; 489760484Sobrien 489860484Sobrien S_SET_NAME (sym, snew); 489960484Sobrien } 490060484Sobrien } 490160484Sobrien 490260484Sobrien if (set_end != (symbolS *) NULL) 490360484Sobrien { 490460484Sobrien SA_SET_SYM_ENDNDX (set_end, sym); 490560484Sobrien set_end = NULL; 490660484Sobrien } 490760484Sobrien 490860484Sobrien if (SF_GET_FUNCTION (sym)) 490960484Sobrien { 491060484Sobrien if (ppc_last_function != (symbolS *) NULL) 491160484Sobrien as_bad (_("two .function pseudo-ops with no intervening .ef")); 491260484Sobrien ppc_last_function = sym; 491360484Sobrien if (symbol_get_tc (sym)->size != (symbolS *) NULL) 491460484Sobrien { 491589857Sobrien resolve_symbol_value (symbol_get_tc (sym)->size); 491660484Sobrien SA_SET_SYM_FSIZE (sym, 491760484Sobrien (long) S_GET_VALUE (symbol_get_tc (sym)->size)); 491860484Sobrien } 491960484Sobrien } 492060484Sobrien else if (S_GET_STORAGE_CLASS (sym) == C_FCN 492160484Sobrien && strcmp (S_GET_NAME (sym), ".ef") == 0) 492260484Sobrien { 492360484Sobrien if (ppc_last_function == (symbolS *) NULL) 492460484Sobrien as_bad (_(".ef with no preceding .function")); 492560484Sobrien else 492660484Sobrien { 492760484Sobrien set_end = ppc_last_function; 492860484Sobrien ppc_last_function = NULL; 492960484Sobrien 493060484Sobrien /* We don't have a C_EFCN symbol, but we need to force the 493160484Sobrien COFF backend to believe that it has seen one. */ 493260484Sobrien coff_last_function = NULL; 493360484Sobrien } 493460484Sobrien } 493560484Sobrien 4936218822Sdim if (! (S_IS_EXTERNAL (sym) || S_IS_WEAK (sym)) 493760484Sobrien && (symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) == 0 493860484Sobrien && S_GET_STORAGE_CLASS (sym) != C_FILE 493960484Sobrien && S_GET_STORAGE_CLASS (sym) != C_FCN 494060484Sobrien && S_GET_STORAGE_CLASS (sym) != C_BLOCK 494160484Sobrien && S_GET_STORAGE_CLASS (sym) != C_BSTAT 494260484Sobrien && S_GET_STORAGE_CLASS (sym) != C_ESTAT 494360484Sobrien && S_GET_STORAGE_CLASS (sym) != C_BINCL 494460484Sobrien && S_GET_STORAGE_CLASS (sym) != C_EINCL 494560484Sobrien && S_GET_SEGMENT (sym) != ppc_coff_debug_section) 494660484Sobrien S_SET_STORAGE_CLASS (sym, C_HIDEXT); 494760484Sobrien 494860484Sobrien if (S_GET_STORAGE_CLASS (sym) == C_EXT 494960484Sobrien || S_GET_STORAGE_CLASS (sym) == C_HIDEXT) 495060484Sobrien { 495160484Sobrien int i; 495260484Sobrien union internal_auxent *a; 495360484Sobrien 495460484Sobrien /* Create a csect aux. */ 495560484Sobrien i = S_GET_NUMBER_AUXILIARY (sym); 495660484Sobrien S_SET_NUMBER_AUXILIARY (sym, i + 1); 495760484Sobrien a = &coffsymbol (symbol_get_bfdsym (sym))->native[i + 1].u.auxent; 495860484Sobrien if (symbol_get_tc (sym)->class == XMC_TC0) 495960484Sobrien { 496060484Sobrien /* This is the TOC table. */ 496160484Sobrien know (strcmp (S_GET_NAME (sym), "TOC") == 0); 496260484Sobrien a->x_csect.x_scnlen.l = 0; 496360484Sobrien a->x_csect.x_smtyp = (2 << 3) | XTY_SD; 496460484Sobrien } 496560484Sobrien else if (symbol_get_tc (sym)->subseg != 0) 496660484Sobrien { 496760484Sobrien /* This is a csect symbol. x_scnlen is the size of the 496860484Sobrien csect. */ 496960484Sobrien if (symbol_get_tc (sym)->next == (symbolS *) NULL) 497060484Sobrien a->x_csect.x_scnlen.l = (bfd_section_size (stdoutput, 497160484Sobrien S_GET_SEGMENT (sym)) 497260484Sobrien - S_GET_VALUE (sym)); 497360484Sobrien else 497460484Sobrien { 497589857Sobrien resolve_symbol_value (symbol_get_tc (sym)->next); 497660484Sobrien a->x_csect.x_scnlen.l = (S_GET_VALUE (symbol_get_tc (sym)->next) 497760484Sobrien - S_GET_VALUE (sym)); 497860484Sobrien } 497960484Sobrien a->x_csect.x_smtyp = (symbol_get_tc (sym)->align << 3) | XTY_SD; 498060484Sobrien } 498160484Sobrien else if (S_GET_SEGMENT (sym) == bss_section) 498260484Sobrien { 498360484Sobrien /* This is a common symbol. */ 498460484Sobrien a->x_csect.x_scnlen.l = symbol_get_frag (sym)->fr_offset; 498560484Sobrien a->x_csect.x_smtyp = (symbol_get_tc (sym)->align << 3) | XTY_CM; 498660484Sobrien if (S_IS_EXTERNAL (sym)) 498760484Sobrien symbol_get_tc (sym)->class = XMC_RW; 498860484Sobrien else 498960484Sobrien symbol_get_tc (sym)->class = XMC_BS; 499060484Sobrien } 499160484Sobrien else if (S_GET_SEGMENT (sym) == absolute_section) 499260484Sobrien { 499360484Sobrien /* This is an absolute symbol. The csect will be created by 499489857Sobrien ppc_adjust_symtab. */ 4995130561Sobrien ppc_saw_abs = TRUE; 499660484Sobrien a->x_csect.x_smtyp = XTY_LD; 499760484Sobrien if (symbol_get_tc (sym)->class == -1) 499860484Sobrien symbol_get_tc (sym)->class = XMC_XO; 499960484Sobrien } 500060484Sobrien else if (! S_IS_DEFINED (sym)) 500160484Sobrien { 500260484Sobrien /* This is an external symbol. */ 500360484Sobrien a->x_csect.x_scnlen.l = 0; 500460484Sobrien a->x_csect.x_smtyp = XTY_ER; 500560484Sobrien } 500660484Sobrien else if (symbol_get_tc (sym)->class == XMC_TC) 500760484Sobrien { 500860484Sobrien symbolS *next; 500960484Sobrien 501060484Sobrien /* This is a TOC definition. x_scnlen is the size of the 501160484Sobrien TOC entry. */ 501260484Sobrien next = symbol_next (sym); 501360484Sobrien while (symbol_get_tc (next)->class == XMC_TC0) 501460484Sobrien next = symbol_next (next); 501560484Sobrien if (next == (symbolS *) NULL 501660484Sobrien || symbol_get_tc (next)->class != XMC_TC) 501760484Sobrien { 501860484Sobrien if (ppc_after_toc_frag == (fragS *) NULL) 501960484Sobrien a->x_csect.x_scnlen.l = (bfd_section_size (stdoutput, 502060484Sobrien data_section) 502160484Sobrien - S_GET_VALUE (sym)); 502260484Sobrien else 502360484Sobrien a->x_csect.x_scnlen.l = (ppc_after_toc_frag->fr_address 502460484Sobrien - S_GET_VALUE (sym)); 502560484Sobrien } 502660484Sobrien else 502760484Sobrien { 502889857Sobrien resolve_symbol_value (next); 502960484Sobrien a->x_csect.x_scnlen.l = (S_GET_VALUE (next) 503060484Sobrien - S_GET_VALUE (sym)); 503160484Sobrien } 503260484Sobrien a->x_csect.x_smtyp = (2 << 3) | XTY_SD; 503360484Sobrien } 503460484Sobrien else 503560484Sobrien { 503660484Sobrien symbolS *csect; 503760484Sobrien 503860484Sobrien /* This is a normal symbol definition. x_scnlen is the 503960484Sobrien symbol index of the containing csect. */ 504060484Sobrien if (S_GET_SEGMENT (sym) == text_section) 504160484Sobrien csect = ppc_text_csects; 504260484Sobrien else if (S_GET_SEGMENT (sym) == data_section) 504360484Sobrien csect = ppc_data_csects; 504460484Sobrien else 504560484Sobrien abort (); 504660484Sobrien 504760484Sobrien /* Skip the initial dummy symbol. */ 504860484Sobrien csect = symbol_get_tc (csect)->next; 504960484Sobrien 505060484Sobrien if (csect == (symbolS *) NULL) 505160484Sobrien { 505260484Sobrien as_warn (_("warning: symbol %s has no csect"), S_GET_NAME (sym)); 505360484Sobrien a->x_csect.x_scnlen.l = 0; 505460484Sobrien } 505560484Sobrien else 505660484Sobrien { 505760484Sobrien while (symbol_get_tc (csect)->next != (symbolS *) NULL) 505860484Sobrien { 505989857Sobrien resolve_symbol_value (symbol_get_tc (csect)->next); 506060484Sobrien if (S_GET_VALUE (symbol_get_tc (csect)->next) 506160484Sobrien > S_GET_VALUE (sym)) 506260484Sobrien break; 506360484Sobrien csect = symbol_get_tc (csect)->next; 506460484Sobrien } 506560484Sobrien 506660484Sobrien a->x_csect.x_scnlen.p = 506760484Sobrien coffsymbol (symbol_get_bfdsym (csect))->native; 506860484Sobrien coffsymbol (symbol_get_bfdsym (sym))->native[i + 1].fix_scnlen = 506960484Sobrien 1; 507060484Sobrien } 507160484Sobrien a->x_csect.x_smtyp = XTY_LD; 507260484Sobrien } 507377298Sobrien 507460484Sobrien a->x_csect.x_parmhash = 0; 507560484Sobrien a->x_csect.x_snhash = 0; 507660484Sobrien if (symbol_get_tc (sym)->class == -1) 507760484Sobrien a->x_csect.x_smclas = XMC_PR; 507860484Sobrien else 507960484Sobrien a->x_csect.x_smclas = symbol_get_tc (sym)->class; 508060484Sobrien a->x_csect.x_stab = 0; 508160484Sobrien a->x_csect.x_snstab = 0; 508260484Sobrien 508360484Sobrien /* Don't let the COFF backend resort these symbols. */ 508460484Sobrien symbol_get_bfdsym (sym)->flags |= BSF_NOT_AT_END; 508560484Sobrien } 508660484Sobrien else if (S_GET_STORAGE_CLASS (sym) == C_BSTAT) 508760484Sobrien { 508860484Sobrien /* We want the value to be the symbol index of the referenced 508960484Sobrien csect symbol. BFD will do that for us if we set the right 509060484Sobrien flags. */ 5091130561Sobrien asymbol *bsym = symbol_get_bfdsym (symbol_get_tc (sym)->within); 5092130561Sobrien combined_entry_type *c = coffsymbol (bsym)->native; 5093130561Sobrien 5094130561Sobrien S_SET_VALUE (sym, (valueT) (size_t) c); 509560484Sobrien coffsymbol (symbol_get_bfdsym (sym))->native->fix_value = 1; 509660484Sobrien } 509760484Sobrien else if (S_GET_STORAGE_CLASS (sym) == C_STSYM) 509860484Sobrien { 509960484Sobrien symbolS *block; 510060484Sobrien symbolS *csect; 510160484Sobrien 510260484Sobrien /* The value is the offset from the enclosing csect. */ 510360484Sobrien block = symbol_get_tc (sym)->within; 510460484Sobrien csect = symbol_get_tc (block)->within; 510589857Sobrien resolve_symbol_value (csect); 510660484Sobrien S_SET_VALUE (sym, S_GET_VALUE (sym) - S_GET_VALUE (csect)); 510760484Sobrien } 510860484Sobrien else if (S_GET_STORAGE_CLASS (sym) == C_BINCL 510960484Sobrien || S_GET_STORAGE_CLASS (sym) == C_EINCL) 511060484Sobrien { 511160484Sobrien /* We want the value to be a file offset into the line numbers. 511289857Sobrien BFD will do that for us if we set the right flags. We have 511389857Sobrien already set the value correctly. */ 511460484Sobrien coffsymbol (symbol_get_bfdsym (sym))->native->fix_line = 1; 511560484Sobrien } 511660484Sobrien 511760484Sobrien return 0; 511860484Sobrien} 511960484Sobrien 512060484Sobrien/* Adjust the symbol table. This creates csect symbols for all 512160484Sobrien absolute symbols. */ 512260484Sobrien 512360484Sobrienvoid 5124218822Sdimppc_adjust_symtab (void) 512560484Sobrien{ 512660484Sobrien symbolS *sym; 512760484Sobrien 512860484Sobrien if (! ppc_saw_abs) 512960484Sobrien return; 513060484Sobrien 513160484Sobrien for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym)) 513260484Sobrien { 513360484Sobrien symbolS *csect; 513460484Sobrien int i; 513560484Sobrien union internal_auxent *a; 513660484Sobrien 513760484Sobrien if (S_GET_SEGMENT (sym) != absolute_section) 513860484Sobrien continue; 513960484Sobrien 514060484Sobrien csect = symbol_create (".abs[XO]", absolute_section, 514160484Sobrien S_GET_VALUE (sym), &zero_address_frag); 514260484Sobrien symbol_get_bfdsym (csect)->value = S_GET_VALUE (sym); 514360484Sobrien S_SET_STORAGE_CLASS (csect, C_HIDEXT); 514460484Sobrien i = S_GET_NUMBER_AUXILIARY (csect); 514560484Sobrien S_SET_NUMBER_AUXILIARY (csect, i + 1); 514660484Sobrien a = &coffsymbol (symbol_get_bfdsym (csect))->native[i + 1].u.auxent; 514760484Sobrien a->x_csect.x_scnlen.l = 0; 514860484Sobrien a->x_csect.x_smtyp = XTY_SD; 514960484Sobrien a->x_csect.x_parmhash = 0; 515060484Sobrien a->x_csect.x_snhash = 0; 515160484Sobrien a->x_csect.x_smclas = XMC_XO; 515260484Sobrien a->x_csect.x_stab = 0; 515360484Sobrien a->x_csect.x_snstab = 0; 515460484Sobrien 515560484Sobrien symbol_insert (csect, sym, &symbol_rootP, &symbol_lastP); 515660484Sobrien 515760484Sobrien i = S_GET_NUMBER_AUXILIARY (sym); 515860484Sobrien a = &coffsymbol (symbol_get_bfdsym (sym))->native[i].u.auxent; 515960484Sobrien a->x_csect.x_scnlen.p = coffsymbol (symbol_get_bfdsym (csect))->native; 516060484Sobrien coffsymbol (symbol_get_bfdsym (sym))->native[i].fix_scnlen = 1; 516160484Sobrien } 516260484Sobrien 5163130561Sobrien ppc_saw_abs = FALSE; 516460484Sobrien} 516560484Sobrien 516660484Sobrien/* Set the VMA for a section. This is called on all the sections in 516760484Sobrien turn. */ 516860484Sobrien 516960484Sobrienvoid 5170218822Sdimppc_frob_section (asection *sec) 517160484Sobrien{ 5172130561Sobrien static bfd_vma vma = 0; 517360484Sobrien 5174130561Sobrien vma = md_section_align (sec, vma); 517560484Sobrien bfd_set_section_vma (stdoutput, sec, vma); 517660484Sobrien vma += bfd_section_size (stdoutput, sec); 517760484Sobrien} 517860484Sobrien 517960484Sobrien#endif /* OBJ_XCOFF */ 518060484Sobrien 518160484Sobrien/* Turn a string in input_line_pointer into a floating point constant 518277298Sobrien of type TYPE, and store the appropriate bytes in *LITP. The number 518377298Sobrien of LITTLENUMS emitted is stored in *SIZEP. An error message is 518460484Sobrien returned, or NULL on OK. */ 518560484Sobrien 518660484Sobrienchar * 5187218822Sdimmd_atof (int type, char *litp, int *sizep) 518860484Sobrien{ 518960484Sobrien int prec; 519060484Sobrien LITTLENUM_TYPE words[4]; 519160484Sobrien char *t; 519260484Sobrien int i; 519360484Sobrien 519460484Sobrien switch (type) 519560484Sobrien { 519660484Sobrien case 'f': 519760484Sobrien prec = 2; 519860484Sobrien break; 519960484Sobrien 520060484Sobrien case 'd': 520160484Sobrien prec = 4; 520260484Sobrien break; 520360484Sobrien 520460484Sobrien default: 520560484Sobrien *sizep = 0; 520660484Sobrien return _("bad call to md_atof"); 520760484Sobrien } 520860484Sobrien 520960484Sobrien t = atof_ieee (input_line_pointer, type, words); 521060484Sobrien if (t) 521160484Sobrien input_line_pointer = t; 521260484Sobrien 521360484Sobrien *sizep = prec * 2; 521460484Sobrien 521560484Sobrien if (target_big_endian) 521660484Sobrien { 521760484Sobrien for (i = 0; i < prec; i++) 521860484Sobrien { 521960484Sobrien md_number_to_chars (litp, (valueT) words[i], 2); 522060484Sobrien litp += 2; 522160484Sobrien } 522260484Sobrien } 522360484Sobrien else 522460484Sobrien { 522560484Sobrien for (i = prec - 1; i >= 0; i--) 522660484Sobrien { 522760484Sobrien md_number_to_chars (litp, (valueT) words[i], 2); 522860484Sobrien litp += 2; 522960484Sobrien } 523060484Sobrien } 523177298Sobrien 523260484Sobrien return NULL; 523360484Sobrien} 523460484Sobrien 523560484Sobrien/* Write a value out to the object file, using the appropriate 523660484Sobrien endianness. */ 523760484Sobrien 523860484Sobrienvoid 5239218822Sdimmd_number_to_chars (char *buf, valueT val, int n) 524060484Sobrien{ 524160484Sobrien if (target_big_endian) 524260484Sobrien number_to_chars_bigendian (buf, val, n); 524360484Sobrien else 524460484Sobrien number_to_chars_littleendian (buf, val, n); 524560484Sobrien} 524660484Sobrien 524760484Sobrien/* Align a section (I don't know why this is machine dependent). */ 524860484Sobrien 524960484SobrienvalueT 5250218822Sdimmd_section_align (asection *seg ATTRIBUTE_UNUSED, valueT addr) 525160484Sobrien{ 5252218822Sdim#ifdef OBJ_ELF 5253218822Sdim return addr; 5254218822Sdim#else 525560484Sobrien int align = bfd_get_section_alignment (stdoutput, seg); 525660484Sobrien 525760484Sobrien return ((addr + (1 << align) - 1) & (-1 << align)); 5258218822Sdim#endif 525960484Sobrien} 526060484Sobrien 526160484Sobrien/* We don't have any form of relaxing. */ 526260484Sobrien 526360484Sobrienint 5264218822Sdimmd_estimate_size_before_relax (fragS *fragp ATTRIBUTE_UNUSED, 5265218822Sdim asection *seg ATTRIBUTE_UNUSED) 526660484Sobrien{ 526760484Sobrien abort (); 526860484Sobrien return 0; 526960484Sobrien} 527060484Sobrien 527160484Sobrien/* Convert a machine dependent frag. We never generate these. */ 527260484Sobrien 527360484Sobrienvoid 5274218822Sdimmd_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, 5275218822Sdim asection *sec ATTRIBUTE_UNUSED, 5276218822Sdim fragS *fragp ATTRIBUTE_UNUSED) 527760484Sobrien{ 527860484Sobrien abort (); 527960484Sobrien} 528060484Sobrien 528160484Sobrien/* We have no need to default values of symbols. */ 528260484Sobrien 528360484SobriensymbolS * 5284218822Sdimmd_undefined_symbol (char *name ATTRIBUTE_UNUSED) 528560484Sobrien{ 528660484Sobrien return 0; 528760484Sobrien} 528860484Sobrien 528960484Sobrien/* Functions concerning relocs. */ 529060484Sobrien 529160484Sobrien/* The location from which a PC relative jump should be calculated, 529260484Sobrien given a PC relative reloc. */ 529360484Sobrien 529460484Sobrienlong 5295218822Sdimmd_pcrel_from_section (fixS *fixp, segT sec ATTRIBUTE_UNUSED) 529660484Sobrien{ 529760484Sobrien return fixp->fx_frag->fr_address + fixp->fx_where; 529860484Sobrien} 529960484Sobrien 530060484Sobrien#ifdef OBJ_XCOFF 530160484Sobrien 530260484Sobrien/* This is called to see whether a fixup should be adjusted to use a 530360484Sobrien section symbol. We take the opportunity to change a fixup against 530460484Sobrien a symbol in the TOC subsegment into a reloc against the 530560484Sobrien corresponding .tc symbol. */ 530660484Sobrien 530760484Sobrienint 5308218822Sdimppc_fix_adjustable (fixS *fix) 530960484Sobrien{ 5310130561Sobrien valueT val = resolve_symbol_value (fix->fx_addsy); 5311130561Sobrien segT symseg = S_GET_SEGMENT (fix->fx_addsy); 5312130561Sobrien TC_SYMFIELD_TYPE *tc; 531360484Sobrien 5314130561Sobrien if (symseg == absolute_section) 5315130561Sobrien return 0; 5316130561Sobrien 531760484Sobrien if (ppc_toc_csect != (symbolS *) NULL 531860484Sobrien && fix->fx_addsy != ppc_toc_csect 5319130561Sobrien && symseg == data_section 532060484Sobrien && val >= ppc_toc_frag->fr_address 532160484Sobrien && (ppc_after_toc_frag == (fragS *) NULL 532260484Sobrien || val < ppc_after_toc_frag->fr_address)) 532360484Sobrien { 532460484Sobrien symbolS *sy; 532560484Sobrien 532660484Sobrien for (sy = symbol_next (ppc_toc_csect); 532760484Sobrien sy != (symbolS *) NULL; 532860484Sobrien sy = symbol_next (sy)) 532960484Sobrien { 5330130561Sobrien TC_SYMFIELD_TYPE *sy_tc = symbol_get_tc (sy); 5331130561Sobrien 5332130561Sobrien if (sy_tc->class == XMC_TC0) 533360484Sobrien continue; 5334130561Sobrien if (sy_tc->class != XMC_TC) 533560484Sobrien break; 5336130561Sobrien if (val == resolve_symbol_value (sy)) 533760484Sobrien { 533860484Sobrien fix->fx_addsy = sy; 533960484Sobrien fix->fx_addnumber = val - ppc_toc_frag->fr_address; 534060484Sobrien return 0; 534160484Sobrien } 534260484Sobrien } 534360484Sobrien 534460484Sobrien as_bad_where (fix->fx_file, fix->fx_line, 534560484Sobrien _("symbol in .toc does not match any .tc")); 534660484Sobrien } 534760484Sobrien 534860484Sobrien /* Possibly adjust the reloc to be against the csect. */ 5349130561Sobrien tc = symbol_get_tc (fix->fx_addsy); 5350130561Sobrien if (tc->subseg == 0 5351130561Sobrien && tc->class != XMC_TC0 5352130561Sobrien && tc->class != XMC_TC 5353130561Sobrien && symseg != bss_section 535460484Sobrien /* Don't adjust if this is a reloc in the toc section. */ 5355130561Sobrien && (symseg != data_section 535660484Sobrien || ppc_toc_csect == NULL 535760484Sobrien || val < ppc_toc_frag->fr_address 535860484Sobrien || (ppc_after_toc_frag != NULL 535960484Sobrien && val >= ppc_after_toc_frag->fr_address))) 536060484Sobrien { 536160484Sobrien symbolS *csect; 5362130561Sobrien symbolS *next_csect; 536360484Sobrien 5364130561Sobrien if (symseg == text_section) 536560484Sobrien csect = ppc_text_csects; 5366130561Sobrien else if (symseg == data_section) 536760484Sobrien csect = ppc_data_csects; 536860484Sobrien else 536960484Sobrien abort (); 537060484Sobrien 537160484Sobrien /* Skip the initial dummy symbol. */ 537260484Sobrien csect = symbol_get_tc (csect)->next; 537360484Sobrien 537460484Sobrien if (csect != (symbolS *) NULL) 537560484Sobrien { 5376130561Sobrien while ((next_csect = symbol_get_tc (csect)->next) != (symbolS *) NULL 5377130561Sobrien && (symbol_get_frag (next_csect)->fr_address <= val)) 537860484Sobrien { 537960484Sobrien /* If the csect address equals the symbol value, then we 538089857Sobrien have to look through the full symbol table to see 538189857Sobrien whether this is the csect we want. Note that we will 538289857Sobrien only get here if the csect has zero length. */ 5383130561Sobrien if (symbol_get_frag (csect)->fr_address == val 5384130561Sobrien && S_GET_VALUE (csect) == val) 538560484Sobrien { 538660484Sobrien symbolS *scan; 538760484Sobrien 538860484Sobrien for (scan = symbol_next (csect); 538960484Sobrien scan != NULL; 539060484Sobrien scan = symbol_next (scan)) 539160484Sobrien { 539260484Sobrien if (symbol_get_tc (scan)->subseg != 0) 539360484Sobrien break; 539460484Sobrien if (scan == fix->fx_addsy) 539560484Sobrien break; 539660484Sobrien } 539760484Sobrien 539860484Sobrien /* If we found the symbol before the next csect 539989857Sobrien symbol, then this is the csect we want. */ 540060484Sobrien if (scan == fix->fx_addsy) 540160484Sobrien break; 540260484Sobrien } 540360484Sobrien 5404130561Sobrien csect = next_csect; 540560484Sobrien } 540660484Sobrien 5407130561Sobrien fix->fx_offset += val - symbol_get_frag (csect)->fr_address; 540860484Sobrien fix->fx_addsy = csect; 540960484Sobrien } 5410130561Sobrien return 0; 541160484Sobrien } 541260484Sobrien 541360484Sobrien /* Adjust a reloc against a .lcomm symbol to be against the base 541460484Sobrien .lcomm. */ 5415130561Sobrien if (symseg == bss_section 541660484Sobrien && ! S_IS_EXTERNAL (fix->fx_addsy)) 541760484Sobrien { 5418130561Sobrien symbolS *sy = symbol_get_frag (fix->fx_addsy)->fr_symbol; 5419130561Sobrien 5420130561Sobrien fix->fx_offset += val - resolve_symbol_value (sy); 5421130561Sobrien fix->fx_addsy = sy; 542260484Sobrien } 542360484Sobrien 542460484Sobrien return 0; 542560484Sobrien} 542660484Sobrien 542760484Sobrien/* A reloc from one csect to another must be kept. The assembler 542860484Sobrien will, of course, keep relocs between sections, and it will keep 542960484Sobrien absolute relocs, but we need to force it to keep PC relative relocs 543060484Sobrien between two csects in the same section. */ 543160484Sobrien 543260484Sobrienint 5433218822Sdimppc_force_relocation (fixS *fix) 543460484Sobrien{ 543560484Sobrien /* At this point fix->fx_addsy should already have been converted to 543660484Sobrien a csect symbol. If the csect does not include the fragment, then 543760484Sobrien we need to force the relocation. */ 543860484Sobrien if (fix->fx_pcrel 543960484Sobrien && fix->fx_addsy != NULL 544060484Sobrien && symbol_get_tc (fix->fx_addsy)->subseg != 0 544160484Sobrien && ((symbol_get_frag (fix->fx_addsy)->fr_address 544260484Sobrien > fix->fx_frag->fr_address) 544360484Sobrien || (symbol_get_tc (fix->fx_addsy)->next != NULL 544460484Sobrien && (symbol_get_frag (symbol_get_tc (fix->fx_addsy)->next)->fr_address 544560484Sobrien <= fix->fx_frag->fr_address)))) 544660484Sobrien return 1; 544760484Sobrien 5448130561Sobrien return generic_force_reloc (fix); 544960484Sobrien} 545060484Sobrien 545160484Sobrien#endif /* OBJ_XCOFF */ 545260484Sobrien 545389857Sobrien#ifdef OBJ_ELF 5454130561Sobrien/* If this function returns non-zero, it guarantees that a relocation 5455130561Sobrien will be emitted for a fixup. */ 5456130561Sobrien 545789857Sobrienint 5458218822Sdimppc_force_relocation (fixS *fix) 5459130561Sobrien{ 5460130561Sobrien /* Branch prediction relocations must force a relocation, as must 5461130561Sobrien the vtable description relocs. */ 5462130561Sobrien switch (fix->fx_r_type) 5463130561Sobrien { 5464130561Sobrien case BFD_RELOC_PPC_B16_BRTAKEN: 5465130561Sobrien case BFD_RELOC_PPC_B16_BRNTAKEN: 5466130561Sobrien case BFD_RELOC_PPC_BA16_BRTAKEN: 5467130561Sobrien case BFD_RELOC_PPC_BA16_BRNTAKEN: 5468218822Sdim case BFD_RELOC_24_PLT_PCREL: 5469130561Sobrien case BFD_RELOC_PPC64_TOC: 5470130561Sobrien return 1; 5471130561Sobrien default: 5472130561Sobrien break; 5473130561Sobrien } 5474130561Sobrien 5475130561Sobrien if (fix->fx_r_type >= BFD_RELOC_PPC_TLS 5476130561Sobrien && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA) 5477130561Sobrien return 1; 5478130561Sobrien 5479130561Sobrien return generic_force_reloc (fix); 5480130561Sobrien} 5481130561Sobrien 5482130561Sobrienint 5483218822Sdimppc_fix_adjustable (fixS *fix) 548460484Sobrien{ 548589857Sobrien return (fix->fx_r_type != BFD_RELOC_16_GOTOFF 548689857Sobrien && fix->fx_r_type != BFD_RELOC_LO16_GOTOFF 548789857Sobrien && fix->fx_r_type != BFD_RELOC_HI16_GOTOFF 548889857Sobrien && fix->fx_r_type != BFD_RELOC_HI16_S_GOTOFF 548989857Sobrien && fix->fx_r_type != BFD_RELOC_GPREL16 549089857Sobrien && fix->fx_r_type != BFD_RELOC_VTABLE_INHERIT 549189857Sobrien && fix->fx_r_type != BFD_RELOC_VTABLE_ENTRY 5492130561Sobrien && !(fix->fx_r_type >= BFD_RELOC_PPC_TLS 5493218822Sdim && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA)); 549489857Sobrien} 549560484Sobrien#endif 549660484Sobrien 5497218822Sdim/* Implement HANDLE_ALIGN. This writes the NOP pattern into an 5498218822Sdim rs_align_code frag. */ 5499218822Sdim 5500218822Sdimvoid 5501218822Sdimppc_handle_align (struct frag *fragP) 5502218822Sdim{ 5503218822Sdim valueT count = (fragP->fr_next->fr_address 5504218822Sdim - (fragP->fr_address + fragP->fr_fix)); 5505218822Sdim 5506218822Sdim if (count != 0 && (count & 3) == 0) 5507218822Sdim { 5508218822Sdim char *dest = fragP->fr_literal + fragP->fr_fix; 5509218822Sdim 5510218822Sdim fragP->fr_var = 4; 5511218822Sdim md_number_to_chars (dest, 0x60000000, 4); 5512218822Sdim 5513218822Sdim if ((ppc_cpu & PPC_OPCODE_POWER6) != 0) 5514218822Sdim { 5515218822Sdim /* For power6, we want the last nop to be a group terminating 5516218822Sdim one, "ori 1,1,0". Do this by inserting an rs_fill frag 5517218822Sdim immediately after this one, with its address set to the last 5518218822Sdim nop location. This will automatically reduce the number of 5519218822Sdim nops in the current frag by one. */ 5520218822Sdim if (count > 4) 5521218822Sdim { 5522218822Sdim struct frag *group_nop = xmalloc (SIZEOF_STRUCT_FRAG + 4); 5523218822Sdim 5524218822Sdim memcpy (group_nop, fragP, SIZEOF_STRUCT_FRAG); 5525218822Sdim group_nop->fr_address = group_nop->fr_next->fr_address - 4; 5526218822Sdim group_nop->fr_fix = 0; 5527218822Sdim group_nop->fr_offset = 1; 5528218822Sdim group_nop->fr_type = rs_fill; 5529218822Sdim fragP->fr_next = group_nop; 5530218822Sdim dest = group_nop->fr_literal; 5531218822Sdim } 5532218822Sdim 5533218822Sdim md_number_to_chars (dest, 0x60210000, 4); 5534218822Sdim } 5535218822Sdim } 5536218822Sdim} 5537218822Sdim 553860484Sobrien/* Apply a fixup to the object code. This is called for all the 553960484Sobrien fixups we generated by the call to fix_new_exp, above. In the call 554060484Sobrien above we used a reloc code which was the largest legal reloc code 554160484Sobrien plus the operand index. Here we undo that to recover the operand 554260484Sobrien index. At this point all symbol values should be fully resolved, 554360484Sobrien and we attempt to completely resolve the reloc. If we can not do 554460484Sobrien that, we determine the correct reloc code and put it back in the 554560484Sobrien fixup. */ 554660484Sobrien 554789857Sobrienvoid 5548218822Sdimmd_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) 554960484Sobrien{ 555089857Sobrien valueT value = * valP; 555160484Sobrien 555260484Sobrien#ifdef OBJ_ELF 555389857Sobrien if (fixP->fx_addsy != NULL) 555460484Sobrien { 5555130561Sobrien /* Hack around bfd_install_relocation brain damage. */ 555689857Sobrien if (fixP->fx_pcrel) 555789857Sobrien value += fixP->fx_frag->fr_address + fixP->fx_where; 555860484Sobrien } 555960484Sobrien else 556089857Sobrien fixP->fx_done = 1; 556160484Sobrien#else 5562130561Sobrien /* FIXME FIXME FIXME: The value we are passed in *valP includes 5563218822Sdim the symbol values. If we are doing this relocation the code in 5564218822Sdim write.c is going to call bfd_install_relocation, which is also 5565218822Sdim going to use the symbol value. That means that if the reloc is 5566218822Sdim fully resolved we want to use *valP since bfd_install_relocation is 5567218822Sdim not being used. 556860484Sobrien However, if the reloc is not fully resolved we do not want to use 5569130561Sobrien *valP, and must use fx_offset instead. However, if the reloc 5570130561Sobrien is PC relative, we do want to use *valP since it includes the 557160484Sobrien result of md_pcrel_from. This is confusing. */ 557289857Sobrien if (fixP->fx_addsy == (symbolS *) NULL) 557389857Sobrien fixP->fx_done = 1; 557489857Sobrien 557589857Sobrien else if (fixP->fx_pcrel) 557689857Sobrien ; 557789857Sobrien 557860484Sobrien else 5579130561Sobrien value = fixP->fx_offset; 5580130561Sobrien#endif 5581130561Sobrien 5582130561Sobrien if (fixP->fx_subsy != (symbolS *) NULL) 558360484Sobrien { 5584130561Sobrien /* We can't actually support subtracting a symbol. */ 5585130561Sobrien as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex")); 558660484Sobrien } 558760484Sobrien 558889857Sobrien if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED) 558960484Sobrien { 559060484Sobrien int opindex; 559160484Sobrien const struct powerpc_operand *operand; 559260484Sobrien char *where; 559360484Sobrien unsigned long insn; 559460484Sobrien 559589857Sobrien opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED; 559660484Sobrien 559760484Sobrien operand = &powerpc_operands[opindex]; 559860484Sobrien 559960484Sobrien#ifdef OBJ_XCOFF 560089857Sobrien /* An instruction like `lwz 9,sym(30)' when `sym' is not a TOC symbol 560189857Sobrien does not generate a reloc. It uses the offset of `sym' within its 560289857Sobrien csect. Other usages, such as `.long sym', generate relocs. This 560389857Sobrien is the documented behaviour of non-TOC symbols. */ 560460484Sobrien if ((operand->flags & PPC_OPERAND_PARENS) != 0 5605218822Sdim && (operand->bitm & 0xfff0) == 0xfff0 560660484Sobrien && operand->shift == 0 5607104834Sobrien && (operand->insert == NULL || ppc_obj64) 560889857Sobrien && fixP->fx_addsy != NULL 560989857Sobrien && symbol_get_tc (fixP->fx_addsy)->subseg != 0 561089857Sobrien && symbol_get_tc (fixP->fx_addsy)->class != XMC_TC 561189857Sobrien && symbol_get_tc (fixP->fx_addsy)->class != XMC_TC0 561289857Sobrien && S_GET_SEGMENT (fixP->fx_addsy) != bss_section) 561360484Sobrien { 561489857Sobrien value = fixP->fx_offset; 561589857Sobrien fixP->fx_done = 1; 561660484Sobrien } 561760484Sobrien#endif 561860484Sobrien 561960484Sobrien /* Fetch the instruction, insert the fully resolved operand 562060484Sobrien value, and stuff the instruction back again. */ 562189857Sobrien where = fixP->fx_frag->fr_literal + fixP->fx_where; 562260484Sobrien if (target_big_endian) 562360484Sobrien insn = bfd_getb32 ((unsigned char *) where); 562460484Sobrien else 562560484Sobrien insn = bfd_getl32 ((unsigned char *) where); 562660484Sobrien insn = ppc_insert_operand (insn, operand, (offsetT) value, 562789857Sobrien fixP->fx_file, fixP->fx_line); 562860484Sobrien if (target_big_endian) 562960484Sobrien bfd_putb32 ((bfd_vma) insn, (unsigned char *) where); 563060484Sobrien else 563160484Sobrien bfd_putl32 ((bfd_vma) insn, (unsigned char *) where); 563260484Sobrien 563389857Sobrien if (fixP->fx_done) 563489857Sobrien /* Nothing else to do here. */ 563589857Sobrien return; 563660484Sobrien 563789857Sobrien assert (fixP->fx_addsy != NULL); 563889857Sobrien 563960484Sobrien /* Determine a BFD reloc value based on the operand information. 564060484Sobrien We are only prepared to turn a few of the operands into 564189857Sobrien relocs. */ 564260484Sobrien if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 5643218822Sdim && operand->bitm == 0x3fffffc 564460484Sobrien && operand->shift == 0) 564589857Sobrien fixP->fx_r_type = BFD_RELOC_PPC_B26; 564660484Sobrien else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 5647218822Sdim && operand->bitm == 0xfffc 564860484Sobrien && operand->shift == 0) 5649104834Sobrien { 5650104834Sobrien fixP->fx_r_type = BFD_RELOC_PPC_B16; 5651104834Sobrien#ifdef OBJ_XCOFF 5652104834Sobrien fixP->fx_size = 2; 5653104834Sobrien if (target_big_endian) 5654104834Sobrien fixP->fx_where += 2; 5655104834Sobrien#endif 5656104834Sobrien } 565760484Sobrien else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0 5658218822Sdim && operand->bitm == 0x3fffffc 565960484Sobrien && operand->shift == 0) 566089857Sobrien fixP->fx_r_type = BFD_RELOC_PPC_BA26; 566160484Sobrien else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0 5662218822Sdim && operand->bitm == 0xfffc 566360484Sobrien && operand->shift == 0) 5664104834Sobrien { 5665104834Sobrien fixP->fx_r_type = BFD_RELOC_PPC_BA16; 5666104834Sobrien#ifdef OBJ_XCOFF 5667104834Sobrien fixP->fx_size = 2; 5668104834Sobrien if (target_big_endian) 5669104834Sobrien fixP->fx_where += 2; 5670104834Sobrien#endif 5671104834Sobrien } 567289857Sobrien#if defined (OBJ_XCOFF) || defined (OBJ_ELF) 567360484Sobrien else if ((operand->flags & PPC_OPERAND_PARENS) != 0 5674218822Sdim && (operand->bitm & 0xfff0) == 0xfff0 5675130561Sobrien && operand->shift == 0) 567660484Sobrien { 5677130561Sobrien if (ppc_is_toc_sym (fixP->fx_addsy)) 5678130561Sobrien { 5679130561Sobrien fixP->fx_r_type = BFD_RELOC_PPC_TOC16; 568089857Sobrien#ifdef OBJ_ELF 5681130561Sobrien if (ppc_obj64 5682130561Sobrien && (operand->flags & PPC_OPERAND_DS) != 0) 5683130561Sobrien fixP->fx_r_type = BFD_RELOC_PPC64_TOC16_DS; 568489857Sobrien#endif 5685130561Sobrien } 5686130561Sobrien else 5687130561Sobrien { 5688130561Sobrien fixP->fx_r_type = BFD_RELOC_16; 5689130561Sobrien#ifdef OBJ_ELF 5690130561Sobrien if (ppc_obj64 5691130561Sobrien && (operand->flags & PPC_OPERAND_DS) != 0) 5692130561Sobrien fixP->fx_r_type = BFD_RELOC_PPC64_ADDR16_DS; 5693130561Sobrien#endif 5694130561Sobrien } 569589857Sobrien fixP->fx_size = 2; 569660484Sobrien if (target_big_endian) 569789857Sobrien fixP->fx_where += 2; 569860484Sobrien } 569989857Sobrien#endif /* defined (OBJ_XCOFF) || defined (OBJ_ELF) */ 570060484Sobrien else 570160484Sobrien { 570260484Sobrien char *sfile; 570360484Sobrien unsigned int sline; 570460484Sobrien 570560484Sobrien /* Use expr_symbol_where to see if this is an expression 570689857Sobrien symbol. */ 570789857Sobrien if (expr_symbol_where (fixP->fx_addsy, &sfile, &sline)) 570889857Sobrien as_bad_where (fixP->fx_file, fixP->fx_line, 570960484Sobrien _("unresolved expression that must be resolved")); 571060484Sobrien else 571189857Sobrien as_bad_where (fixP->fx_file, fixP->fx_line, 571289857Sobrien _("unsupported relocation against %s"), 571389857Sobrien S_GET_NAME (fixP->fx_addsy)); 571489857Sobrien fixP->fx_done = 1; 571589857Sobrien return; 571660484Sobrien } 571760484Sobrien } 571860484Sobrien else 571960484Sobrien { 572060484Sobrien#ifdef OBJ_ELF 572189857Sobrien ppc_elf_validate_fix (fixP, seg); 572260484Sobrien#endif 572389857Sobrien switch (fixP->fx_r_type) 572460484Sobrien { 572560484Sobrien case BFD_RELOC_CTOR: 5726104834Sobrien if (ppc_obj64) 572789857Sobrien goto ctor64; 572889857Sobrien /* fall through */ 572960484Sobrien 573089857Sobrien case BFD_RELOC_32: 573189857Sobrien if (fixP->fx_pcrel) 573289857Sobrien fixP->fx_r_type = BFD_RELOC_32_PCREL; 573389857Sobrien /* fall through */ 573489857Sobrien 573560484Sobrien case BFD_RELOC_RVA: 573660484Sobrien case BFD_RELOC_32_PCREL: 573760484Sobrien case BFD_RELOC_PPC_EMB_NADDR32: 573889857Sobrien md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 573960484Sobrien value, 4); 574060484Sobrien break; 574160484Sobrien 574277298Sobrien case BFD_RELOC_64: 574389857Sobrien ctor64: 574489857Sobrien if (fixP->fx_pcrel) 574589857Sobrien fixP->fx_r_type = BFD_RELOC_64_PCREL; 574689857Sobrien /* fall through */ 574789857Sobrien 574877298Sobrien case BFD_RELOC_64_PCREL: 574989857Sobrien md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 575077298Sobrien value, 8); 575177298Sobrien break; 575289857Sobrien 575360484Sobrien case BFD_RELOC_GPREL16: 575460484Sobrien case BFD_RELOC_16_GOT_PCREL: 575560484Sobrien case BFD_RELOC_16_GOTOFF: 575660484Sobrien case BFD_RELOC_LO16_GOTOFF: 575760484Sobrien case BFD_RELOC_HI16_GOTOFF: 575860484Sobrien case BFD_RELOC_HI16_S_GOTOFF: 575999461Sobrien case BFD_RELOC_16_BASEREL: 576060484Sobrien case BFD_RELOC_LO16_BASEREL: 576160484Sobrien case BFD_RELOC_HI16_BASEREL: 576260484Sobrien case BFD_RELOC_HI16_S_BASEREL: 576360484Sobrien case BFD_RELOC_PPC_EMB_NADDR16: 576460484Sobrien case BFD_RELOC_PPC_EMB_NADDR16_LO: 576560484Sobrien case BFD_RELOC_PPC_EMB_NADDR16_HI: 576660484Sobrien case BFD_RELOC_PPC_EMB_NADDR16_HA: 576760484Sobrien case BFD_RELOC_PPC_EMB_SDAI16: 576860484Sobrien case BFD_RELOC_PPC_EMB_SDA2REL: 576960484Sobrien case BFD_RELOC_PPC_EMB_SDA2I16: 577060484Sobrien case BFD_RELOC_PPC_EMB_RELSEC16: 577160484Sobrien case BFD_RELOC_PPC_EMB_RELST_LO: 577260484Sobrien case BFD_RELOC_PPC_EMB_RELST_HI: 577360484Sobrien case BFD_RELOC_PPC_EMB_RELST_HA: 577460484Sobrien case BFD_RELOC_PPC_EMB_RELSDA: 577560484Sobrien case BFD_RELOC_PPC_TOC16: 577689857Sobrien#ifdef OBJ_ELF 577789857Sobrien case BFD_RELOC_PPC64_TOC16_LO: 577889857Sobrien case BFD_RELOC_PPC64_TOC16_HI: 577989857Sobrien case BFD_RELOC_PPC64_TOC16_HA: 578089857Sobrien#endif 578189857Sobrien if (fixP->fx_pcrel) 578260484Sobrien { 578389857Sobrien if (fixP->fx_addsy != NULL) 578489857Sobrien as_bad_where (fixP->fx_file, fixP->fx_line, 578560484Sobrien _("cannot emit PC relative %s relocation against %s"), 578689857Sobrien bfd_get_reloc_code_name (fixP->fx_r_type), 578789857Sobrien S_GET_NAME (fixP->fx_addsy)); 578860484Sobrien else 578989857Sobrien as_bad_where (fixP->fx_file, fixP->fx_line, 579060484Sobrien _("cannot emit PC relative %s relocation"), 579189857Sobrien bfd_get_reloc_code_name (fixP->fx_r_type)); 579260484Sobrien } 579360484Sobrien 579489857Sobrien md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 579560484Sobrien value, 2); 579660484Sobrien break; 579760484Sobrien 5798218822Sdim case BFD_RELOC_16: 5799218822Sdim if (fixP->fx_pcrel) 5800218822Sdim fixP->fx_r_type = BFD_RELOC_16_PCREL; 5801218822Sdim /* fall through */ 5802218822Sdim 5803218822Sdim case BFD_RELOC_16_PCREL: 5804218822Sdim md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 5805218822Sdim value, 2); 5806218822Sdim break; 5807218822Sdim 5808218822Sdim case BFD_RELOC_LO16: 5809218822Sdim if (fixP->fx_pcrel) 5810218822Sdim fixP->fx_r_type = BFD_RELOC_LO16_PCREL; 5811218822Sdim /* fall through */ 5812218822Sdim 5813218822Sdim case BFD_RELOC_LO16_PCREL: 5814218822Sdim md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 5815218822Sdim value, 2); 5816218822Sdim break; 5817218822Sdim 581860484Sobrien /* This case happens when you write, for example, 581960484Sobrien lis %r3,(L1-L2)@ha 582060484Sobrien where L1 and L2 are defined later. */ 582160484Sobrien case BFD_RELOC_HI16: 582289857Sobrien if (fixP->fx_pcrel) 5823218822Sdim fixP->fx_r_type = BFD_RELOC_HI16_PCREL; 5824218822Sdim /* fall through */ 5825218822Sdim 5826218822Sdim case BFD_RELOC_HI16_PCREL: 582789857Sobrien md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 582889857Sobrien PPC_HI (value), 2); 582960484Sobrien break; 583089857Sobrien 583160484Sobrien case BFD_RELOC_HI16_S: 583289857Sobrien if (fixP->fx_pcrel) 5833218822Sdim fixP->fx_r_type = BFD_RELOC_HI16_S_PCREL; 5834218822Sdim /* fall through */ 5835218822Sdim 5836218822Sdim case BFD_RELOC_HI16_S_PCREL: 583789857Sobrien md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 583889857Sobrien PPC_HA (value), 2); 583960484Sobrien break; 584060484Sobrien 584189857Sobrien#ifdef OBJ_ELF 584289857Sobrien case BFD_RELOC_PPC64_HIGHER: 584389857Sobrien if (fixP->fx_pcrel) 584489857Sobrien abort (); 584589857Sobrien md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 584689857Sobrien PPC_HIGHER (value), 2); 584789857Sobrien break; 584889857Sobrien 584989857Sobrien case BFD_RELOC_PPC64_HIGHER_S: 585089857Sobrien if (fixP->fx_pcrel) 585189857Sobrien abort (); 585289857Sobrien md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 585389857Sobrien PPC_HIGHERA (value), 2); 585489857Sobrien break; 585589857Sobrien 585689857Sobrien case BFD_RELOC_PPC64_HIGHEST: 585789857Sobrien if (fixP->fx_pcrel) 585889857Sobrien abort (); 585989857Sobrien md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 586089857Sobrien PPC_HIGHEST (value), 2); 586189857Sobrien break; 586289857Sobrien 586389857Sobrien case BFD_RELOC_PPC64_HIGHEST_S: 586489857Sobrien if (fixP->fx_pcrel) 586589857Sobrien abort (); 586689857Sobrien md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 586789857Sobrien PPC_HIGHESTA (value), 2); 586889857Sobrien break; 586989857Sobrien 587089857Sobrien case BFD_RELOC_PPC64_ADDR16_DS: 587189857Sobrien case BFD_RELOC_PPC64_ADDR16_LO_DS: 587289857Sobrien case BFD_RELOC_PPC64_GOT16_DS: 587389857Sobrien case BFD_RELOC_PPC64_GOT16_LO_DS: 587489857Sobrien case BFD_RELOC_PPC64_PLT16_LO_DS: 587589857Sobrien case BFD_RELOC_PPC64_SECTOFF_DS: 587689857Sobrien case BFD_RELOC_PPC64_SECTOFF_LO_DS: 587789857Sobrien case BFD_RELOC_PPC64_TOC16_DS: 587889857Sobrien case BFD_RELOC_PPC64_TOC16_LO_DS: 587989857Sobrien case BFD_RELOC_PPC64_PLTGOT16_DS: 588089857Sobrien case BFD_RELOC_PPC64_PLTGOT16_LO_DS: 588189857Sobrien if (fixP->fx_pcrel) 588289857Sobrien abort (); 588389857Sobrien { 5884218822Sdim char *where = fixP->fx_frag->fr_literal + fixP->fx_where; 5885130561Sobrien unsigned long val, mask; 588689857Sobrien 588789857Sobrien if (target_big_endian) 5888130561Sobrien val = bfd_getb32 (where - 2); 588989857Sobrien else 5890130561Sobrien val = bfd_getl32 (where); 5891130561Sobrien mask = 0xfffc; 5892130561Sobrien /* lq insns reserve the four lsbs. */ 5893130561Sobrien if ((ppc_cpu & PPC_OPCODE_POWER4) != 0 5894130561Sobrien && (val & (0x3f << 26)) == (56u << 26)) 5895130561Sobrien mask = 0xfff0; 5896130561Sobrien val |= value & mask; 589789857Sobrien if (target_big_endian) 589889857Sobrien bfd_putb16 ((bfd_vma) val, where); 589989857Sobrien else 590089857Sobrien bfd_putl16 ((bfd_vma) val, where); 590189857Sobrien } 590289857Sobrien break; 5903130561Sobrien 5904130561Sobrien case BFD_RELOC_PPC_B16_BRTAKEN: 5905130561Sobrien case BFD_RELOC_PPC_B16_BRNTAKEN: 5906130561Sobrien case BFD_RELOC_PPC_BA16_BRTAKEN: 5907130561Sobrien case BFD_RELOC_PPC_BA16_BRNTAKEN: 5908130561Sobrien break; 5909130561Sobrien 5910130561Sobrien case BFD_RELOC_PPC_TLS: 5911218822Sdim break; 5912218822Sdim 5913130561Sobrien case BFD_RELOC_PPC_DTPMOD: 5914130561Sobrien case BFD_RELOC_PPC_TPREL16: 5915130561Sobrien case BFD_RELOC_PPC_TPREL16_LO: 5916130561Sobrien case BFD_RELOC_PPC_TPREL16_HI: 5917130561Sobrien case BFD_RELOC_PPC_TPREL16_HA: 5918130561Sobrien case BFD_RELOC_PPC_TPREL: 5919130561Sobrien case BFD_RELOC_PPC_DTPREL16: 5920130561Sobrien case BFD_RELOC_PPC_DTPREL16_LO: 5921130561Sobrien case BFD_RELOC_PPC_DTPREL16_HI: 5922130561Sobrien case BFD_RELOC_PPC_DTPREL16_HA: 5923130561Sobrien case BFD_RELOC_PPC_DTPREL: 5924130561Sobrien case BFD_RELOC_PPC_GOT_TLSGD16: 5925130561Sobrien case BFD_RELOC_PPC_GOT_TLSGD16_LO: 5926130561Sobrien case BFD_RELOC_PPC_GOT_TLSGD16_HI: 5927130561Sobrien case BFD_RELOC_PPC_GOT_TLSGD16_HA: 5928130561Sobrien case BFD_RELOC_PPC_GOT_TLSLD16: 5929130561Sobrien case BFD_RELOC_PPC_GOT_TLSLD16_LO: 5930130561Sobrien case BFD_RELOC_PPC_GOT_TLSLD16_HI: 5931130561Sobrien case BFD_RELOC_PPC_GOT_TLSLD16_HA: 5932130561Sobrien case BFD_RELOC_PPC_GOT_TPREL16: 5933130561Sobrien case BFD_RELOC_PPC_GOT_TPREL16_LO: 5934130561Sobrien case BFD_RELOC_PPC_GOT_TPREL16_HI: 5935130561Sobrien case BFD_RELOC_PPC_GOT_TPREL16_HA: 5936130561Sobrien case BFD_RELOC_PPC_GOT_DTPREL16: 5937130561Sobrien case BFD_RELOC_PPC_GOT_DTPREL16_LO: 5938130561Sobrien case BFD_RELOC_PPC_GOT_DTPREL16_HI: 5939130561Sobrien case BFD_RELOC_PPC_GOT_DTPREL16_HA: 5940130561Sobrien case BFD_RELOC_PPC64_TPREL16_DS: 5941130561Sobrien case BFD_RELOC_PPC64_TPREL16_LO_DS: 5942130561Sobrien case BFD_RELOC_PPC64_TPREL16_HIGHER: 5943130561Sobrien case BFD_RELOC_PPC64_TPREL16_HIGHERA: 5944130561Sobrien case BFD_RELOC_PPC64_TPREL16_HIGHEST: 5945130561Sobrien case BFD_RELOC_PPC64_TPREL16_HIGHESTA: 5946130561Sobrien case BFD_RELOC_PPC64_DTPREL16_DS: 5947130561Sobrien case BFD_RELOC_PPC64_DTPREL16_LO_DS: 5948130561Sobrien case BFD_RELOC_PPC64_DTPREL16_HIGHER: 5949130561Sobrien case BFD_RELOC_PPC64_DTPREL16_HIGHERA: 5950130561Sobrien case BFD_RELOC_PPC64_DTPREL16_HIGHEST: 5951130561Sobrien case BFD_RELOC_PPC64_DTPREL16_HIGHESTA: 5952218822Sdim S_SET_THREAD_LOCAL (fixP->fx_addsy); 5953130561Sobrien break; 595489857Sobrien#endif 595560484Sobrien /* Because SDA21 modifies the register field, the size is set to 4 595689857Sobrien bytes, rather than 2, so offset it here appropriately. */ 595760484Sobrien case BFD_RELOC_PPC_EMB_SDA21: 595889857Sobrien if (fixP->fx_pcrel) 595960484Sobrien abort (); 596060484Sobrien 596189857Sobrien md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where 596260484Sobrien + ((target_big_endian) ? 2 : 0), 596360484Sobrien value, 2); 596460484Sobrien break; 596560484Sobrien 596660484Sobrien case BFD_RELOC_8: 596789857Sobrien if (fixP->fx_pcrel) 5968130561Sobrien { 5969130561Sobrien /* This can occur if there is a bug in the input assembler, eg: 5970130561Sobrien ".byte <undefined_symbol> - ." */ 5971130561Sobrien if (fixP->fx_addsy) 5972130561Sobrien as_bad (_("Unable to handle reference to symbol %s"), 5973130561Sobrien S_GET_NAME (fixP->fx_addsy)); 5974130561Sobrien else 5975130561Sobrien as_bad (_("Unable to resolve expression")); 5976130561Sobrien fixP->fx_done = 1; 5977130561Sobrien } 5978130561Sobrien else 5979130561Sobrien md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 5980130561Sobrien value, 1); 598160484Sobrien break; 598260484Sobrien 598360484Sobrien case BFD_RELOC_24_PLT_PCREL: 598460484Sobrien case BFD_RELOC_PPC_LOCAL24PC: 598589857Sobrien if (!fixP->fx_pcrel && !fixP->fx_done) 598660484Sobrien abort (); 598760484Sobrien 598889857Sobrien if (fixP->fx_done) 598989857Sobrien { 599089857Sobrien char *where; 599189857Sobrien unsigned long insn; 599277298Sobrien 599389857Sobrien /* Fetch the instruction, insert the fully resolved operand 599489857Sobrien value, and stuff the instruction back again. */ 599589857Sobrien where = fixP->fx_frag->fr_literal + fixP->fx_where; 599689857Sobrien if (target_big_endian) 599789857Sobrien insn = bfd_getb32 ((unsigned char *) where); 599889857Sobrien else 599989857Sobrien insn = bfd_getl32 ((unsigned char *) where); 600089857Sobrien if ((value & 3) != 0) 600189857Sobrien as_bad_where (fixP->fx_file, fixP->fx_line, 600289857Sobrien _("must branch to an address a multiple of 4")); 600389857Sobrien if ((offsetT) value < -0x40000000 600489857Sobrien || (offsetT) value >= 0x40000000) 600589857Sobrien as_bad_where (fixP->fx_file, fixP->fx_line, 600689857Sobrien _("@local or @plt branch destination is too far away, %ld bytes"), 600789857Sobrien (long) value); 600889857Sobrien insn = insn | (value & 0x03fffffc); 600989857Sobrien if (target_big_endian) 601089857Sobrien bfd_putb32 ((bfd_vma) insn, (unsigned char *) where); 601189857Sobrien else 601289857Sobrien bfd_putl32 ((bfd_vma) insn, (unsigned char *) where); 601389857Sobrien } 601460484Sobrien break; 601560484Sobrien 601660484Sobrien case BFD_RELOC_VTABLE_INHERIT: 601789857Sobrien fixP->fx_done = 0; 601889857Sobrien if (fixP->fx_addsy 601989857Sobrien && !S_IS_DEFINED (fixP->fx_addsy) 602089857Sobrien && !S_IS_WEAK (fixP->fx_addsy)) 602189857Sobrien S_SET_WEAK (fixP->fx_addsy); 602260484Sobrien break; 602360484Sobrien 602460484Sobrien case BFD_RELOC_VTABLE_ENTRY: 602589857Sobrien fixP->fx_done = 0; 602660484Sobrien break; 602760484Sobrien 602889857Sobrien#ifdef OBJ_ELF 602989857Sobrien /* Generated by reference to `sym@tocbase'. The sym is 603089857Sobrien ignored by the linker. */ 603189857Sobrien case BFD_RELOC_PPC64_TOC: 603289857Sobrien fixP->fx_done = 0; 603389857Sobrien break; 603489857Sobrien#endif 603560484Sobrien default: 603677298Sobrien fprintf (stderr, 603789857Sobrien _("Gas failure, reloc value %d\n"), fixP->fx_r_type); 603889857Sobrien fflush (stderr); 603960484Sobrien abort (); 604060484Sobrien } 604160484Sobrien } 604260484Sobrien 604360484Sobrien#ifdef OBJ_ELF 604489857Sobrien fixP->fx_addnumber = value; 6045218822Sdim 6046218822Sdim /* PowerPC uses RELA relocs, ie. the reloc addend is stored separately 6047218822Sdim from the section contents. If we are going to be emitting a reloc 6048218822Sdim then the section contents are immaterial, so don't warn if they 6049218822Sdim happen to overflow. Leave such warnings to ld. */ 6050218822Sdim if (!fixP->fx_done) 6051218822Sdim fixP->fx_no_overflow = 1; 605260484Sobrien#else 605389857Sobrien if (fixP->fx_r_type != BFD_RELOC_PPC_TOC16) 605489857Sobrien fixP->fx_addnumber = 0; 605560484Sobrien else 605660484Sobrien { 605760484Sobrien#ifdef TE_PE 605889857Sobrien fixP->fx_addnumber = 0; 605960484Sobrien#else 606060484Sobrien /* We want to use the offset within the data segment of the 606160484Sobrien symbol, not the actual VMA of the symbol. */ 606289857Sobrien fixP->fx_addnumber = 606389857Sobrien - bfd_get_section_vma (stdoutput, S_GET_SEGMENT (fixP->fx_addsy)); 606460484Sobrien#endif 606560484Sobrien } 606660484Sobrien#endif 606760484Sobrien} 606860484Sobrien 606960484Sobrien/* Generate a reloc for a fixup. */ 607060484Sobrien 607160484Sobrienarelent * 6072218822Sdimtc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp) 607360484Sobrien{ 607460484Sobrien arelent *reloc; 607560484Sobrien 607660484Sobrien reloc = (arelent *) xmalloc (sizeof (arelent)); 607760484Sobrien 607860484Sobrien reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); 607960484Sobrien *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); 608060484Sobrien reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; 608160484Sobrien reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); 608260484Sobrien if (reloc->howto == (reloc_howto_type *) NULL) 608360484Sobrien { 608460484Sobrien as_bad_where (fixp->fx_file, fixp->fx_line, 608589857Sobrien _("reloc %d not supported by object file format"), 608689857Sobrien (int) fixp->fx_r_type); 608760484Sobrien return NULL; 608860484Sobrien } 608960484Sobrien reloc->addend = fixp->fx_addnumber; 609060484Sobrien 609160484Sobrien return reloc; 609260484Sobrien} 6093130561Sobrien 6094130561Sobrienvoid 6095218822Sdimppc_cfi_frame_initial_instructions (void) 6096130561Sobrien{ 6097130561Sobrien cfi_add_CFA_def_cfa (1, 0); 6098130561Sobrien} 6099130561Sobrien 6100130561Sobrienint 6101218822Sdimtc_ppc_regname_to_dw2regnum (char *regname) 6102130561Sobrien{ 6103130561Sobrien unsigned int regnum = -1; 6104130561Sobrien unsigned int i; 6105130561Sobrien const char *p; 6106130561Sobrien char *q; 6107130561Sobrien static struct { char *name; int dw2regnum; } regnames[] = 6108130561Sobrien { 6109130561Sobrien { "sp", 1 }, { "r.sp", 1 }, { "rtoc", 2 }, { "r.toc", 2 }, 6110130561Sobrien { "mq", 64 }, { "lr", 65 }, { "ctr", 66 }, { "ap", 67 }, 6111218822Sdim { "cr", 70 }, { "xer", 76 }, { "vrsave", 109 }, { "vscr", 110 }, 6112130561Sobrien { "spe_acc", 111 }, { "spefscr", 112 } 6113130561Sobrien }; 6114130561Sobrien 6115130561Sobrien for (i = 0; i < ARRAY_SIZE (regnames); ++i) 6116130561Sobrien if (strcmp (regnames[i].name, regname) == 0) 6117130561Sobrien return regnames[i].dw2regnum; 6118130561Sobrien 6119130561Sobrien if (regname[0] == 'r' || regname[0] == 'f' || regname[0] == 'v') 6120130561Sobrien { 6121130561Sobrien p = regname + 1 + (regname[1] == '.'); 6122130561Sobrien regnum = strtoul (p, &q, 10); 6123130561Sobrien if (p == q || *q || regnum >= 32) 6124130561Sobrien return -1; 6125130561Sobrien if (regname[0] == 'f') 6126130561Sobrien regnum += 32; 6127130561Sobrien else if (regname[0] == 'v') 6128130561Sobrien regnum += 77; 6129130561Sobrien } 6130130561Sobrien else if (regname[0] == 'c' && regname[1] == 'r') 6131130561Sobrien { 6132130561Sobrien p = regname + 2 + (regname[2] == '.'); 6133130561Sobrien if (p[0] < '0' || p[0] > '7' || p[1]) 6134130561Sobrien return -1; 6135130561Sobrien regnum = p[0] - '0' + 68; 6136130561Sobrien } 6137130561Sobrien return regnum; 6138130561Sobrien} 6139