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. */ 684261422Sjhibbitsstatic unsigned long ppc_cpu = PPC_OPCODE_ANY; 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 1213272888Sbapt ? (ppc_obj64 ? "elf64-powerpc-freebsd" : "elf32-powerpc-freebsd") 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) 1551276346Sdim as_bad_where (file, line, "%s", 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) 2282276346Sdim as_bad ("%s", 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) 2295276346Sdim as_bad ("%s", 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 2512275873Sjhibbits else 251360484Sobrien { 2514275873Sjhibbits if (ex.X_op == O_symbol && str[0] == '(') 2515130561Sobrien { 2516275873Sjhibbits const char *sym_name = S_GET_NAME (ex.X_add_symbol); 2517275873Sjhibbits if (sym_name[0] == '.') 2518275873Sjhibbits ++sym_name; 2519130561Sobrien 2520275873Sjhibbits if (strcasecmp (sym_name, "__tls_get_addr") == 0) 252160484Sobrien { 2522275873Sjhibbits expressionS tls_exp; 2523275873Sjhibbits 2524275873Sjhibbits hold = input_line_pointer; 2525275873Sjhibbits input_line_pointer = str + 1; 2526275873Sjhibbits expression (&tls_exp); 2527275873Sjhibbits if (tls_exp.X_op == O_symbol) 2528275873Sjhibbits { 2529275873Sjhibbits reloc = BFD_RELOC_UNUSED; 2530275873Sjhibbits if (strncasecmp (input_line_pointer, "@tlsgd)", 7) == 0) 2531275873Sjhibbits { 2532275873Sjhibbits reloc = BFD_RELOC_PPC_TLSGD; 2533275873Sjhibbits input_line_pointer += 7; 2534275873Sjhibbits } 2535275873Sjhibbits else if (strncasecmp (input_line_pointer, "@tlsld)", 7) == 0) 2536275873Sjhibbits { 2537275873Sjhibbits reloc = BFD_RELOC_PPC_TLSLD; 2538275873Sjhibbits input_line_pointer += 7; 2539275873Sjhibbits } 2540275873Sjhibbits if (reloc != BFD_RELOC_UNUSED) 2541275873Sjhibbits { 2542275873Sjhibbits SKIP_WHITESPACE (); 2543275873Sjhibbits str = input_line_pointer; 2544275873Sjhibbits 2545275873Sjhibbits if (fc >= MAX_INSN_FIXUPS) 2546275873Sjhibbits as_fatal (_("too many fixups")); 2547275873Sjhibbits fixups[fc].exp = tls_exp; 2548275873Sjhibbits fixups[fc].opindex = *opindex_ptr; 2549275873Sjhibbits fixups[fc].reloc = reloc; 2550275873Sjhibbits ++fc; 2551275873Sjhibbits } 2552275873Sjhibbits } 2553275873Sjhibbits input_line_pointer = hold; 255460484Sobrien } 255560484Sobrien } 255660484Sobrien 2557275873Sjhibbits if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED) 255889857Sobrien { 2559275873Sjhibbits /* Some TLS tweaks. */ 256089857Sobrien switch (reloc) 256189857Sobrien { 2562275873Sjhibbits default: 256389857Sobrien break; 2564275873Sjhibbits 2565275873Sjhibbits case BFD_RELOC_PPC_TLS: 2566275873Sjhibbits insn = ppc_insert_operand (insn, operand, ppc_obj64 ? 13 : 2, 2567275873Sjhibbits (char *) NULL, 0); 256889857Sobrien break; 2569275873Sjhibbits 2570275873Sjhibbits /* We'll only use the 32 (or 64) bit form of these relocations 2571275873Sjhibbits in constants. Instructions get the 16 bit form. */ 2572275873Sjhibbits case BFD_RELOC_PPC_DTPREL: 2573275873Sjhibbits reloc = BFD_RELOC_PPC_DTPREL16; 257489857Sobrien break; 2575275873Sjhibbits case BFD_RELOC_PPC_TPREL: 2576275873Sjhibbits reloc = BFD_RELOC_PPC_TPREL16; 257789857Sobrien break; 257889857Sobrien } 2579275873Sjhibbits 2580275873Sjhibbits /* For the absolute forms of branches, convert the PC 2581275873Sjhibbits relative form back into the absolute. */ 2582275873Sjhibbits if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) 2583275873Sjhibbits { 2584275873Sjhibbits switch (reloc) 2585275873Sjhibbits { 2586275873Sjhibbits case BFD_RELOC_PPC_B26: 2587275873Sjhibbits reloc = BFD_RELOC_PPC_BA26; 2588275873Sjhibbits break; 2589275873Sjhibbits case BFD_RELOC_PPC_B16: 2590275873Sjhibbits reloc = BFD_RELOC_PPC_BA16; 2591275873Sjhibbits break; 2592275873Sjhibbits case BFD_RELOC_PPC_B16_BRTAKEN: 2593275873Sjhibbits reloc = BFD_RELOC_PPC_BA16_BRTAKEN; 2594275873Sjhibbits break; 2595275873Sjhibbits case BFD_RELOC_PPC_B16_BRNTAKEN: 2596275873Sjhibbits reloc = BFD_RELOC_PPC_BA16_BRNTAKEN; 2597275873Sjhibbits break; 2598275873Sjhibbits default: 2599275873Sjhibbits break; 2600275873Sjhibbits } 2601275873Sjhibbits } 2602275873Sjhibbits 2603275873Sjhibbits if (ppc_obj64 2604275873Sjhibbits && (operand->flags & (PPC_OPERAND_DS | PPC_OPERAND_DQ)) != 0) 2605275873Sjhibbits { 2606275873Sjhibbits switch (reloc) 2607275873Sjhibbits { 2608275873Sjhibbits case BFD_RELOC_16: 2609275873Sjhibbits reloc = BFD_RELOC_PPC64_ADDR16_DS; 2610275873Sjhibbits break; 2611275873Sjhibbits case BFD_RELOC_LO16: 2612275873Sjhibbits reloc = BFD_RELOC_PPC64_ADDR16_LO_DS; 2613275873Sjhibbits break; 2614275873Sjhibbits case BFD_RELOC_16_GOTOFF: 2615275873Sjhibbits reloc = BFD_RELOC_PPC64_GOT16_DS; 2616275873Sjhibbits break; 2617275873Sjhibbits case BFD_RELOC_LO16_GOTOFF: 2618275873Sjhibbits reloc = BFD_RELOC_PPC64_GOT16_LO_DS; 2619275873Sjhibbits break; 2620275873Sjhibbits case BFD_RELOC_LO16_PLTOFF: 2621275873Sjhibbits reloc = BFD_RELOC_PPC64_PLT16_LO_DS; 2622275873Sjhibbits break; 2623275873Sjhibbits case BFD_RELOC_16_BASEREL: 2624275873Sjhibbits reloc = BFD_RELOC_PPC64_SECTOFF_DS; 2625275873Sjhibbits break; 2626275873Sjhibbits case BFD_RELOC_LO16_BASEREL: 2627275873Sjhibbits reloc = BFD_RELOC_PPC64_SECTOFF_LO_DS; 2628275873Sjhibbits break; 2629275873Sjhibbits case BFD_RELOC_PPC_TOC16: 2630275873Sjhibbits reloc = BFD_RELOC_PPC64_TOC16_DS; 2631275873Sjhibbits break; 2632275873Sjhibbits case BFD_RELOC_PPC64_TOC16_LO: 2633275873Sjhibbits reloc = BFD_RELOC_PPC64_TOC16_LO_DS; 2634275873Sjhibbits break; 2635275873Sjhibbits case BFD_RELOC_PPC64_PLTGOT16: 2636275873Sjhibbits reloc = BFD_RELOC_PPC64_PLTGOT16_DS; 2637275873Sjhibbits break; 2638275873Sjhibbits case BFD_RELOC_PPC64_PLTGOT16_LO: 2639275873Sjhibbits reloc = BFD_RELOC_PPC64_PLTGOT16_LO_DS; 2640275873Sjhibbits break; 2641275873Sjhibbits case BFD_RELOC_PPC_DTPREL16: 2642275873Sjhibbits reloc = BFD_RELOC_PPC64_DTPREL16_DS; 2643275873Sjhibbits break; 2644275873Sjhibbits case BFD_RELOC_PPC_DTPREL16_LO: 2645275873Sjhibbits reloc = BFD_RELOC_PPC64_DTPREL16_LO_DS; 2646275873Sjhibbits break; 2647275873Sjhibbits case BFD_RELOC_PPC_TPREL16: 2648275873Sjhibbits reloc = BFD_RELOC_PPC64_TPREL16_DS; 2649275873Sjhibbits break; 2650275873Sjhibbits case BFD_RELOC_PPC_TPREL16_LO: 2651275873Sjhibbits reloc = BFD_RELOC_PPC64_TPREL16_LO_DS; 2652275873Sjhibbits break; 2653275873Sjhibbits case BFD_RELOC_PPC_GOT_DTPREL16: 2654275873Sjhibbits case BFD_RELOC_PPC_GOT_DTPREL16_LO: 2655275873Sjhibbits case BFD_RELOC_PPC_GOT_TPREL16: 2656275873Sjhibbits case BFD_RELOC_PPC_GOT_TPREL16_LO: 2657275873Sjhibbits break; 2658275873Sjhibbits default: 2659275873Sjhibbits as_bad (_("unsupported relocation for DS offset field")); 2660275873Sjhibbits break; 2661275873Sjhibbits } 2662275873Sjhibbits } 266389857Sobrien } 266489857Sobrien 266560484Sobrien /* We need to generate a fixup for this expression. */ 266660484Sobrien if (fc >= MAX_INSN_FIXUPS) 266760484Sobrien as_fatal (_("too many fixups")); 266860484Sobrien fixups[fc].exp = ex; 2669275873Sjhibbits fixups[fc].opindex = *opindex_ptr; 267060484Sobrien fixups[fc].reloc = reloc; 267160484Sobrien ++fc; 267260484Sobrien } 2673275873Sjhibbits#else /* OBJ_ELF */ 267460484Sobrien else 267560484Sobrien { 267660484Sobrien /* We need to generate a fixup for this expression. */ 267760484Sobrien if (fc >= MAX_INSN_FIXUPS) 267860484Sobrien as_fatal (_("too many fixups")); 267960484Sobrien fixups[fc].exp = ex; 268060484Sobrien fixups[fc].opindex = *opindex_ptr; 268160484Sobrien fixups[fc].reloc = BFD_RELOC_UNUSED; 268260484Sobrien ++fc; 268360484Sobrien } 2684275873Sjhibbits#endif /* OBJ_ELF */ 268560484Sobrien 268660484Sobrien if (need_paren) 268760484Sobrien { 268860484Sobrien endc = ')'; 268960484Sobrien need_paren = 0; 269060484Sobrien } 269160484Sobrien else if ((operand->flags & PPC_OPERAND_PARENS) != 0) 269260484Sobrien { 269360484Sobrien endc = '('; 269460484Sobrien need_paren = 1; 269560484Sobrien } 269660484Sobrien else 269760484Sobrien endc = ','; 269860484Sobrien 269960484Sobrien /* The call to expression should have advanced str past any 270060484Sobrien whitespace. */ 270160484Sobrien if (*str != endc 270260484Sobrien && (endc != ',' || *str != '\0')) 270360484Sobrien { 270460484Sobrien as_bad (_("syntax error; found `%c' but expected `%c'"), *str, endc); 270560484Sobrien break; 270660484Sobrien } 270760484Sobrien 270860484Sobrien if (*str != '\0') 270960484Sobrien ++str; 271060484Sobrien } 271160484Sobrien 271289857Sobrien while (ISSPACE (*str)) 271360484Sobrien ++str; 271460484Sobrien 271560484Sobrien if (*str != '\0') 271660484Sobrien as_bad (_("junk at end of line: `%s'"), str); 271760484Sobrien 2718130561Sobrien#ifdef OBJ_ELF 2719130561Sobrien /* Do we need/want a APUinfo section? */ 2720130561Sobrien if (ppc_cpu & (PPC_OPCODE_SPE 2721130561Sobrien | PPC_OPCODE_ISEL | PPC_OPCODE_EFS 2722130561Sobrien | PPC_OPCODE_BRLOCK | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK 2723130561Sobrien | PPC_OPCODE_RFMCI)) 2724130561Sobrien { 2725130561Sobrien /* These are all version "1". */ 2726130561Sobrien if (opcode->flags & PPC_OPCODE_SPE) 2727130561Sobrien ppc_apuinfo_section_add (PPC_APUINFO_SPE, 1); 2728130561Sobrien if (opcode->flags & PPC_OPCODE_ISEL) 2729130561Sobrien ppc_apuinfo_section_add (PPC_APUINFO_ISEL, 1); 2730130561Sobrien if (opcode->flags & PPC_OPCODE_EFS) 2731130561Sobrien ppc_apuinfo_section_add (PPC_APUINFO_EFS, 1); 2732130561Sobrien if (opcode->flags & PPC_OPCODE_BRLOCK) 2733130561Sobrien ppc_apuinfo_section_add (PPC_APUINFO_BRLOCK, 1); 2734130561Sobrien if (opcode->flags & PPC_OPCODE_PMR) 2735130561Sobrien ppc_apuinfo_section_add (PPC_APUINFO_PMR, 1); 2736130561Sobrien if (opcode->flags & PPC_OPCODE_CACHELCK) 2737130561Sobrien ppc_apuinfo_section_add (PPC_APUINFO_CACHELCK, 1); 2738130561Sobrien if (opcode->flags & PPC_OPCODE_RFMCI) 2739130561Sobrien ppc_apuinfo_section_add (PPC_APUINFO_RFMCI, 1); 2740130561Sobrien } 2741130561Sobrien#endif 2742130561Sobrien 274360484Sobrien /* Write out the instruction. */ 274460484Sobrien f = frag_more (4); 2745218822Sdim addr_mod = frag_now_fix () & 3; 2746218822Sdim if (frag_now->has_code && frag_now->insn_addr != addr_mod) 2747218822Sdim as_bad (_("instruction address is not a multiple of 4")); 2748218822Sdim frag_now->insn_addr = addr_mod; 2749218822Sdim frag_now->has_code = 1; 275060484Sobrien md_number_to_chars (f, insn, 4); 275160484Sobrien 275277298Sobrien#ifdef OBJ_ELF 275377298Sobrien dwarf2_emit_insn (4); 275477298Sobrien#endif 275577298Sobrien 275660484Sobrien /* Create any fixups. At this point we do not use a 275760484Sobrien bfd_reloc_code_real_type, but instead just use the 275860484Sobrien BFD_RELOC_UNUSED plus the operand index. This lets us easily 275960484Sobrien handle fixups for any operand type, although that is admittedly 276060484Sobrien not a very exciting feature. We pick a BFD reloc type in 2761218822Sdim md_apply_fix. */ 276260484Sobrien for (i = 0; i < fc; i++) 276360484Sobrien { 276460484Sobrien const struct powerpc_operand *operand; 276560484Sobrien 276660484Sobrien operand = &powerpc_operands[fixups[i].opindex]; 276760484Sobrien if (fixups[i].reloc != BFD_RELOC_UNUSED) 276860484Sobrien { 276989857Sobrien reloc_howto_type *reloc_howto; 277060484Sobrien int size; 277160484Sobrien int offset; 277260484Sobrien fixS *fixP; 277360484Sobrien 277489857Sobrien reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc); 277560484Sobrien if (!reloc_howto) 277660484Sobrien abort (); 277760484Sobrien 277860484Sobrien size = bfd_get_reloc_size (reloc_howto); 277960484Sobrien offset = target_big_endian ? (4 - size) : 0; 278060484Sobrien 278160484Sobrien if (size < 1 || size > 4) 278277298Sobrien abort (); 278360484Sobrien 278489857Sobrien fixP = fix_new_exp (frag_now, 278589857Sobrien f - frag_now->fr_literal + offset, 278689857Sobrien size, 278789857Sobrien &fixups[i].exp, 278889857Sobrien reloc_howto->pc_relative, 278960484Sobrien fixups[i].reloc); 279060484Sobrien 279160484Sobrien /* Turn off complaints that the addend is too large for things like 279260484Sobrien foo+100000@ha. */ 279360484Sobrien switch (fixups[i].reloc) 279460484Sobrien { 279560484Sobrien case BFD_RELOC_16_GOTOFF: 279660484Sobrien case BFD_RELOC_PPC_TOC16: 279760484Sobrien case BFD_RELOC_LO16: 279860484Sobrien case BFD_RELOC_HI16: 279960484Sobrien case BFD_RELOC_HI16_S: 280089857Sobrien#ifdef OBJ_ELF 280189857Sobrien case BFD_RELOC_PPC64_HIGHER: 280289857Sobrien case BFD_RELOC_PPC64_HIGHER_S: 280389857Sobrien case BFD_RELOC_PPC64_HIGHEST: 280489857Sobrien case BFD_RELOC_PPC64_HIGHEST_S: 280589857Sobrien#endif 280660484Sobrien fixP->fx_no_overflow = 1; 280760484Sobrien break; 280860484Sobrien default: 280960484Sobrien break; 281060484Sobrien } 281160484Sobrien } 281260484Sobrien else 281389857Sobrien fix_new_exp (frag_now, 281489857Sobrien f - frag_now->fr_literal, 281589857Sobrien 4, 281660484Sobrien &fixups[i].exp, 281760484Sobrien (operand->flags & PPC_OPERAND_RELATIVE) != 0, 281860484Sobrien ((bfd_reloc_code_real_type) 281989857Sobrien (fixups[i].opindex + (int) BFD_RELOC_UNUSED))); 282060484Sobrien } 282160484Sobrien} 282260484Sobrien 282360484Sobrien/* Handle a macro. Gather all the operands, transform them as 282460484Sobrien described by the macro, and call md_assemble recursively. All the 282560484Sobrien operands are separated by commas; we don't accept parentheses 282660484Sobrien around operands here. */ 282760484Sobrien 282860484Sobrienstatic void 2829218822Sdimppc_macro (char *str, const struct powerpc_macro *macro) 283060484Sobrien{ 283160484Sobrien char *operands[10]; 283260484Sobrien unsigned int count; 283360484Sobrien char *s; 283460484Sobrien unsigned int len; 283560484Sobrien const char *format; 2836218822Sdim unsigned int arg; 283760484Sobrien char *send; 283860484Sobrien char *complete; 283960484Sobrien 284060484Sobrien /* Gather the users operands into the operands array. */ 284160484Sobrien count = 0; 284260484Sobrien s = str; 284360484Sobrien while (1) 284460484Sobrien { 284560484Sobrien if (count >= sizeof operands / sizeof operands[0]) 284660484Sobrien break; 284760484Sobrien operands[count++] = s; 284860484Sobrien s = strchr (s, ','); 284960484Sobrien if (s == (char *) NULL) 285060484Sobrien break; 285160484Sobrien *s++ = '\0'; 285277298Sobrien } 285360484Sobrien 285460484Sobrien if (count != macro->operands) 285560484Sobrien { 285660484Sobrien as_bad (_("wrong number of operands")); 285760484Sobrien return; 285860484Sobrien } 285960484Sobrien 286060484Sobrien /* Work out how large the string must be (the size is unbounded 286160484Sobrien because it includes user input). */ 286260484Sobrien len = 0; 286360484Sobrien format = macro->format; 286460484Sobrien while (*format != '\0') 286560484Sobrien { 286660484Sobrien if (*format != '%') 286760484Sobrien { 286860484Sobrien ++len; 286960484Sobrien ++format; 287060484Sobrien } 287160484Sobrien else 287260484Sobrien { 287360484Sobrien arg = strtol (format + 1, &send, 10); 2874218822Sdim know (send != format && arg < count); 287560484Sobrien len += strlen (operands[arg]); 287660484Sobrien format = send; 287760484Sobrien } 287860484Sobrien } 287960484Sobrien 288060484Sobrien /* Put the string together. */ 288160484Sobrien complete = s = (char *) alloca (len + 1); 288260484Sobrien format = macro->format; 288360484Sobrien while (*format != '\0') 288460484Sobrien { 288560484Sobrien if (*format != '%') 288660484Sobrien *s++ = *format++; 288760484Sobrien else 288860484Sobrien { 288960484Sobrien arg = strtol (format + 1, &send, 10); 289060484Sobrien strcpy (s, operands[arg]); 289160484Sobrien s += strlen (s); 289260484Sobrien format = send; 289360484Sobrien } 289460484Sobrien } 289560484Sobrien *s = '\0'; 289660484Sobrien 289760484Sobrien /* Assemble the constructed instruction. */ 289860484Sobrien md_assemble (complete); 289977298Sobrien} 290060484Sobrien 290160484Sobrien#ifdef OBJ_ELF 290289857Sobrien/* For ELF, add support for SHF_EXCLUDE and SHT_ORDERED. */ 290360484Sobrien 290460484Sobrienint 2905218822Sdimppc_section_letter (int letter, char **ptr_msg) 290660484Sobrien{ 290760484Sobrien if (letter == 'e') 290860484Sobrien return SHF_EXCLUDE; 290960484Sobrien 2910104834Sobrien *ptr_msg = _("Bad .section directive: want a,e,w,x,M,S,G,T in string"); 2911130561Sobrien return -1; 291260484Sobrien} 291360484Sobrien 291460484Sobrienint 2915218822Sdimppc_section_word (char *str, size_t len) 291660484Sobrien{ 291760484Sobrien if (len == 7 && strncmp (str, "exclude", 7) == 0) 291860484Sobrien return SHF_EXCLUDE; 291960484Sobrien 292060484Sobrien return -1; 292160484Sobrien} 292260484Sobrien 292360484Sobrienint 2924218822Sdimppc_section_type (char *str, size_t len) 292560484Sobrien{ 292660484Sobrien if (len == 7 && strncmp (str, "ordered", 7) == 0) 292760484Sobrien return SHT_ORDERED; 292860484Sobrien 292960484Sobrien return -1; 293060484Sobrien} 293160484Sobrien 293260484Sobrienint 2933218822Sdimppc_section_flags (int flags, int attr, int type) 293460484Sobrien{ 293560484Sobrien if (type == SHT_ORDERED) 293660484Sobrien flags |= SEC_ALLOC | SEC_LOAD | SEC_SORT_ENTRIES; 293760484Sobrien 293860484Sobrien if (attr & SHF_EXCLUDE) 293960484Sobrien flags |= SEC_EXCLUDE; 294060484Sobrien 294160484Sobrien return flags; 294260484Sobrien} 294360484Sobrien#endif /* OBJ_ELF */ 294460484Sobrien 294560484Sobrien 294660484Sobrien/* Pseudo-op handling. */ 294760484Sobrien 294860484Sobrien/* The .byte pseudo-op. This is similar to the normal .byte 294960484Sobrien pseudo-op, but it can also take a single ASCII string. */ 295060484Sobrien 295160484Sobrienstatic void 2952218822Sdimppc_byte (int ignore ATTRIBUTE_UNUSED) 295360484Sobrien{ 295460484Sobrien if (*input_line_pointer != '\"') 295560484Sobrien { 295660484Sobrien cons (1); 295760484Sobrien return; 295860484Sobrien } 295960484Sobrien 296060484Sobrien /* Gather characters. A real double quote is doubled. Unusual 296160484Sobrien characters are not permitted. */ 296260484Sobrien ++input_line_pointer; 296360484Sobrien while (1) 296460484Sobrien { 296560484Sobrien char c; 296660484Sobrien 296760484Sobrien c = *input_line_pointer++; 296860484Sobrien 296960484Sobrien if (c == '\"') 297060484Sobrien { 297160484Sobrien if (*input_line_pointer != '\"') 297260484Sobrien break; 297360484Sobrien ++input_line_pointer; 297460484Sobrien } 297560484Sobrien 297660484Sobrien FRAG_APPEND_1_CHAR (c); 297760484Sobrien } 297860484Sobrien 297960484Sobrien demand_empty_rest_of_line (); 298060484Sobrien} 298160484Sobrien 298260484Sobrien#ifdef OBJ_XCOFF 298360484Sobrien 298460484Sobrien/* XCOFF specific pseudo-op handling. */ 298560484Sobrien 298660484Sobrien/* This is set if we are creating a .stabx symbol, since we don't want 298760484Sobrien to handle symbol suffixes for such symbols. */ 2988130561Sobrienstatic bfd_boolean ppc_stab_symbol; 298960484Sobrien 299060484Sobrien/* The .comm and .lcomm pseudo-ops for XCOFF. XCOFF puts common 299160484Sobrien symbols in the .bss segment as though they were local common 2992130561Sobrien symbols, and uses a different smclas. The native Aix 4.3.3 assembler 299380016Sobrien aligns .comm and .lcomm to 4 bytes. */ 299460484Sobrien 299560484Sobrienstatic void 2996218822Sdimppc_comm (int lcomm) 299760484Sobrien{ 299860484Sobrien asection *current_seg = now_seg; 299960484Sobrien subsegT current_subseg = now_subseg; 300060484Sobrien char *name; 300160484Sobrien char endc; 300260484Sobrien char *end_name; 300360484Sobrien offsetT size; 300460484Sobrien offsetT align; 300560484Sobrien symbolS *lcomm_sym = NULL; 300660484Sobrien symbolS *sym; 300760484Sobrien char *pfrag; 300860484Sobrien 300960484Sobrien name = input_line_pointer; 301060484Sobrien endc = get_symbol_end (); 301160484Sobrien end_name = input_line_pointer; 301260484Sobrien *end_name = endc; 301360484Sobrien 301460484Sobrien if (*input_line_pointer != ',') 301560484Sobrien { 301660484Sobrien as_bad (_("missing size")); 301760484Sobrien ignore_rest_of_line (); 301860484Sobrien return; 301960484Sobrien } 302060484Sobrien ++input_line_pointer; 302160484Sobrien 302260484Sobrien size = get_absolute_expression (); 302360484Sobrien if (size < 0) 302460484Sobrien { 302560484Sobrien as_bad (_("negative size")); 302660484Sobrien ignore_rest_of_line (); 302760484Sobrien return; 302860484Sobrien } 302960484Sobrien 303060484Sobrien if (! lcomm) 303160484Sobrien { 303260484Sobrien /* The third argument to .comm is the alignment. */ 303360484Sobrien if (*input_line_pointer != ',') 303480016Sobrien align = 2; 303560484Sobrien else 303660484Sobrien { 303760484Sobrien ++input_line_pointer; 303860484Sobrien align = get_absolute_expression (); 303960484Sobrien if (align <= 0) 304060484Sobrien { 304160484Sobrien as_warn (_("ignoring bad alignment")); 304280016Sobrien align = 2; 304360484Sobrien } 304460484Sobrien } 304560484Sobrien } 304660484Sobrien else 304760484Sobrien { 304860484Sobrien char *lcomm_name; 304960484Sobrien char lcomm_endc; 305060484Sobrien 305180016Sobrien if (size <= 4) 305260484Sobrien align = 2; 305360484Sobrien else 305460484Sobrien align = 3; 305560484Sobrien 305660484Sobrien /* The third argument to .lcomm appears to be the real local 305760484Sobrien common symbol to create. References to the symbol named in 305860484Sobrien the first argument are turned into references to the third 305960484Sobrien argument. */ 306060484Sobrien if (*input_line_pointer != ',') 306160484Sobrien { 306260484Sobrien as_bad (_("missing real symbol name")); 306360484Sobrien ignore_rest_of_line (); 306460484Sobrien return; 306560484Sobrien } 306660484Sobrien ++input_line_pointer; 306760484Sobrien 306860484Sobrien lcomm_name = input_line_pointer; 306960484Sobrien lcomm_endc = get_symbol_end (); 307077298Sobrien 307160484Sobrien lcomm_sym = symbol_find_or_make (lcomm_name); 307260484Sobrien 307360484Sobrien *input_line_pointer = lcomm_endc; 307460484Sobrien } 307560484Sobrien 307660484Sobrien *end_name = '\0'; 307760484Sobrien sym = symbol_find_or_make (name); 307860484Sobrien *end_name = endc; 307960484Sobrien 308060484Sobrien if (S_IS_DEFINED (sym) 308160484Sobrien || S_GET_VALUE (sym) != 0) 308260484Sobrien { 308360484Sobrien as_bad (_("attempt to redefine symbol")); 308460484Sobrien ignore_rest_of_line (); 308560484Sobrien return; 308660484Sobrien } 308777298Sobrien 308860484Sobrien record_alignment (bss_section, align); 308977298Sobrien 309060484Sobrien if (! lcomm 309160484Sobrien || ! S_IS_DEFINED (lcomm_sym)) 309260484Sobrien { 309360484Sobrien symbolS *def_sym; 309460484Sobrien offsetT def_size; 309560484Sobrien 309660484Sobrien if (! lcomm) 309760484Sobrien { 309860484Sobrien def_sym = sym; 309960484Sobrien def_size = size; 310060484Sobrien S_SET_EXTERNAL (sym); 310160484Sobrien } 310260484Sobrien else 310360484Sobrien { 310460484Sobrien symbol_get_tc (lcomm_sym)->output = 1; 310560484Sobrien def_sym = lcomm_sym; 310660484Sobrien def_size = 0; 310760484Sobrien } 310860484Sobrien 310960484Sobrien subseg_set (bss_section, 1); 311060484Sobrien frag_align (align, 0, 0); 311177298Sobrien 311260484Sobrien symbol_set_frag (def_sym, frag_now); 311360484Sobrien pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, def_sym, 311460484Sobrien def_size, (char *) NULL); 311560484Sobrien *pfrag = 0; 311660484Sobrien S_SET_SEGMENT (def_sym, bss_section); 311760484Sobrien symbol_get_tc (def_sym)->align = align; 311860484Sobrien } 311960484Sobrien else if (lcomm) 312060484Sobrien { 312160484Sobrien /* Align the size of lcomm_sym. */ 312260484Sobrien symbol_get_frag (lcomm_sym)->fr_offset = 312360484Sobrien ((symbol_get_frag (lcomm_sym)->fr_offset + (1 << align) - 1) 312460484Sobrien &~ ((1 << align) - 1)); 312560484Sobrien if (align > symbol_get_tc (lcomm_sym)->align) 312660484Sobrien symbol_get_tc (lcomm_sym)->align = align; 312760484Sobrien } 312860484Sobrien 312960484Sobrien if (lcomm) 313060484Sobrien { 313160484Sobrien /* Make sym an offset from lcomm_sym. */ 313260484Sobrien S_SET_SEGMENT (sym, bss_section); 313360484Sobrien symbol_set_frag (sym, symbol_get_frag (lcomm_sym)); 313460484Sobrien S_SET_VALUE (sym, symbol_get_frag (lcomm_sym)->fr_offset); 313560484Sobrien symbol_get_frag (lcomm_sym)->fr_offset += size; 313660484Sobrien } 313760484Sobrien 313860484Sobrien subseg_set (current_seg, current_subseg); 313960484Sobrien 314060484Sobrien demand_empty_rest_of_line (); 314160484Sobrien} 314260484Sobrien 314360484Sobrien/* The .csect pseudo-op. This switches us into a different 314460484Sobrien subsegment. The first argument is a symbol whose value is the 314560484Sobrien start of the .csect. In COFF, csect symbols get special aux 314660484Sobrien entries defined by the x_csect field of union internal_auxent. The 314760484Sobrien optional second argument is the alignment (the default is 2). */ 314860484Sobrien 314960484Sobrienstatic void 3150218822Sdimppc_csect (int ignore ATTRIBUTE_UNUSED) 315160484Sobrien{ 315260484Sobrien char *name; 315360484Sobrien char endc; 315460484Sobrien symbolS *sym; 3155130561Sobrien offsetT align; 315660484Sobrien 315760484Sobrien name = input_line_pointer; 315860484Sobrien endc = get_symbol_end (); 315977298Sobrien 316060484Sobrien sym = symbol_find_or_make (name); 316160484Sobrien 316260484Sobrien *input_line_pointer = endc; 316360484Sobrien 316460484Sobrien if (S_GET_NAME (sym)[0] == '\0') 316560484Sobrien { 316660484Sobrien /* An unnamed csect is assumed to be [PR]. */ 316760484Sobrien symbol_get_tc (sym)->class = XMC_PR; 316860484Sobrien } 316960484Sobrien 3170130561Sobrien align = 2; 317160484Sobrien if (*input_line_pointer == ',') 317260484Sobrien { 317360484Sobrien ++input_line_pointer; 3174130561Sobrien align = get_absolute_expression (); 317560484Sobrien } 317660484Sobrien 3177130561Sobrien ppc_change_csect (sym, align); 3178130561Sobrien 317960484Sobrien demand_empty_rest_of_line (); 318060484Sobrien} 318160484Sobrien 318260484Sobrien/* Change to a different csect. */ 318360484Sobrien 318460484Sobrienstatic void 3185218822Sdimppc_change_csect (symbolS *sym, offsetT align) 318660484Sobrien{ 318760484Sobrien if (S_IS_DEFINED (sym)) 318860484Sobrien subseg_set (S_GET_SEGMENT (sym), symbol_get_tc (sym)->subseg); 318960484Sobrien else 319060484Sobrien { 319160484Sobrien symbolS **list_ptr; 319260484Sobrien int after_toc; 319360484Sobrien int hold_chunksize; 319460484Sobrien symbolS *list; 3195130561Sobrien int is_code; 3196130561Sobrien segT sec; 319760484Sobrien 319860484Sobrien /* This is a new csect. We need to look at the symbol class to 319960484Sobrien figure out whether it should go in the text section or the 320060484Sobrien data section. */ 320160484Sobrien after_toc = 0; 3202130561Sobrien is_code = 0; 320360484Sobrien switch (symbol_get_tc (sym)->class) 320460484Sobrien { 320560484Sobrien case XMC_PR: 320660484Sobrien case XMC_RO: 320760484Sobrien case XMC_DB: 320860484Sobrien case XMC_GL: 320960484Sobrien case XMC_XO: 321060484Sobrien case XMC_SV: 321160484Sobrien case XMC_TI: 321260484Sobrien case XMC_TB: 321360484Sobrien S_SET_SEGMENT (sym, text_section); 321460484Sobrien symbol_get_tc (sym)->subseg = ppc_text_subsegment; 321560484Sobrien ++ppc_text_subsegment; 321660484Sobrien list_ptr = &ppc_text_csects; 3217130561Sobrien is_code = 1; 321860484Sobrien break; 321960484Sobrien case XMC_RW: 322060484Sobrien case XMC_TC0: 322160484Sobrien case XMC_TC: 322260484Sobrien case XMC_DS: 322360484Sobrien case XMC_UA: 322460484Sobrien case XMC_BS: 322560484Sobrien case XMC_UC: 322660484Sobrien if (ppc_toc_csect != NULL 322760484Sobrien && (symbol_get_tc (ppc_toc_csect)->subseg + 1 322860484Sobrien == ppc_data_subsegment)) 322960484Sobrien after_toc = 1; 323060484Sobrien S_SET_SEGMENT (sym, data_section); 323160484Sobrien symbol_get_tc (sym)->subseg = ppc_data_subsegment; 323260484Sobrien ++ppc_data_subsegment; 323360484Sobrien list_ptr = &ppc_data_csects; 323460484Sobrien break; 323560484Sobrien default: 323660484Sobrien abort (); 323760484Sobrien } 323860484Sobrien 323960484Sobrien /* We set the obstack chunk size to a small value before 324089857Sobrien changing subsegments, so that we don't use a lot of memory 324189857Sobrien space for what may be a small section. */ 324260484Sobrien hold_chunksize = chunksize; 324360484Sobrien chunksize = 64; 324460484Sobrien 3245130561Sobrien sec = subseg_new (segment_name (S_GET_SEGMENT (sym)), 3246130561Sobrien symbol_get_tc (sym)->subseg); 324760484Sobrien 324860484Sobrien chunksize = hold_chunksize; 324960484Sobrien 325060484Sobrien if (after_toc) 325160484Sobrien ppc_after_toc_frag = frag_now; 325260484Sobrien 3253130561Sobrien record_alignment (sec, align); 3254130561Sobrien if (is_code) 3255130561Sobrien frag_align_code (align, 0); 3256130561Sobrien else 3257130561Sobrien frag_align (align, 0, 0); 3258130561Sobrien 325960484Sobrien symbol_set_frag (sym, frag_now); 326060484Sobrien S_SET_VALUE (sym, (valueT) frag_now_fix ()); 326160484Sobrien 3262130561Sobrien symbol_get_tc (sym)->align = align; 326360484Sobrien symbol_get_tc (sym)->output = 1; 326460484Sobrien symbol_get_tc (sym)->within = sym; 326577298Sobrien 326660484Sobrien for (list = *list_ptr; 326760484Sobrien symbol_get_tc (list)->next != (symbolS *) NULL; 326860484Sobrien list = symbol_get_tc (list)->next) 326960484Sobrien ; 327060484Sobrien symbol_get_tc (list)->next = sym; 327177298Sobrien 327260484Sobrien symbol_remove (sym, &symbol_rootP, &symbol_lastP); 327360484Sobrien symbol_append (sym, symbol_get_tc (list)->within, &symbol_rootP, 327460484Sobrien &symbol_lastP); 327560484Sobrien } 327660484Sobrien 327760484Sobrien ppc_current_csect = sym; 327860484Sobrien} 327960484Sobrien 328060484Sobrien/* This function handles the .text and .data pseudo-ops. These 328160484Sobrien pseudo-ops aren't really used by XCOFF; we implement them for the 328260484Sobrien convenience of people who aren't used to XCOFF. */ 328360484Sobrien 328460484Sobrienstatic void 3285218822Sdimppc_section (int type) 328660484Sobrien{ 328760484Sobrien const char *name; 328860484Sobrien symbolS *sym; 328960484Sobrien 329060484Sobrien if (type == 't') 329160484Sobrien name = ".text[PR]"; 329260484Sobrien else if (type == 'd') 329360484Sobrien name = ".data[RW]"; 329460484Sobrien else 329560484Sobrien abort (); 329660484Sobrien 329760484Sobrien sym = symbol_find_or_make (name); 329860484Sobrien 3299130561Sobrien ppc_change_csect (sym, 2); 330060484Sobrien 330160484Sobrien demand_empty_rest_of_line (); 330260484Sobrien} 330360484Sobrien 330460484Sobrien/* This function handles the .section pseudo-op. This is mostly to 330560484Sobrien give an error, since XCOFF only supports .text, .data and .bss, but 330660484Sobrien we do permit the user to name the text or data section. */ 330760484Sobrien 330860484Sobrienstatic void 3309218822Sdimppc_named_section (int ignore ATTRIBUTE_UNUSED) 331060484Sobrien{ 331160484Sobrien char *user_name; 331260484Sobrien const char *real_name; 331360484Sobrien char c; 331460484Sobrien symbolS *sym; 331560484Sobrien 331660484Sobrien user_name = input_line_pointer; 331760484Sobrien c = get_symbol_end (); 331860484Sobrien 331960484Sobrien if (strcmp (user_name, ".text") == 0) 332060484Sobrien real_name = ".text[PR]"; 332160484Sobrien else if (strcmp (user_name, ".data") == 0) 332260484Sobrien real_name = ".data[RW]"; 332360484Sobrien else 332460484Sobrien { 332560484Sobrien as_bad (_("The XCOFF file format does not support arbitrary sections")); 332660484Sobrien *input_line_pointer = c; 332760484Sobrien ignore_rest_of_line (); 332860484Sobrien return; 332960484Sobrien } 333060484Sobrien 333160484Sobrien *input_line_pointer = c; 333260484Sobrien 333360484Sobrien sym = symbol_find_or_make (real_name); 333460484Sobrien 3335130561Sobrien ppc_change_csect (sym, 2); 333660484Sobrien 333760484Sobrien demand_empty_rest_of_line (); 333860484Sobrien} 333960484Sobrien 334060484Sobrien/* The .extern pseudo-op. We create an undefined symbol. */ 334160484Sobrien 334260484Sobrienstatic void 3343218822Sdimppc_extern (int ignore ATTRIBUTE_UNUSED) 334460484Sobrien{ 334560484Sobrien char *name; 334660484Sobrien char endc; 334760484Sobrien 334860484Sobrien name = input_line_pointer; 334960484Sobrien endc = get_symbol_end (); 335060484Sobrien 335160484Sobrien (void) symbol_find_or_make (name); 335260484Sobrien 335360484Sobrien *input_line_pointer = endc; 335460484Sobrien 335560484Sobrien demand_empty_rest_of_line (); 335660484Sobrien} 335760484Sobrien 335860484Sobrien/* The .lglobl pseudo-op. Keep the symbol in the symbol table. */ 335960484Sobrien 336060484Sobrienstatic void 3361218822Sdimppc_lglobl (int ignore ATTRIBUTE_UNUSED) 336260484Sobrien{ 336360484Sobrien char *name; 336460484Sobrien char endc; 336560484Sobrien symbolS *sym; 336660484Sobrien 336760484Sobrien name = input_line_pointer; 336860484Sobrien endc = get_symbol_end (); 336960484Sobrien 337060484Sobrien sym = symbol_find_or_make (name); 337160484Sobrien 337260484Sobrien *input_line_pointer = endc; 337360484Sobrien 337460484Sobrien symbol_get_tc (sym)->output = 1; 337560484Sobrien 337660484Sobrien demand_empty_rest_of_line (); 337760484Sobrien} 337860484Sobrien 337960484Sobrien/* The .rename pseudo-op. The RS/6000 assembler can rename symbols, 338060484Sobrien although I don't know why it bothers. */ 338160484Sobrien 338260484Sobrienstatic void 3383218822Sdimppc_rename (int ignore ATTRIBUTE_UNUSED) 338460484Sobrien{ 338560484Sobrien char *name; 338660484Sobrien char endc; 338760484Sobrien symbolS *sym; 338860484Sobrien int len; 338960484Sobrien 339060484Sobrien name = input_line_pointer; 339160484Sobrien endc = get_symbol_end (); 339260484Sobrien 339360484Sobrien sym = symbol_find_or_make (name); 339460484Sobrien 339560484Sobrien *input_line_pointer = endc; 339660484Sobrien 339760484Sobrien if (*input_line_pointer != ',') 339860484Sobrien { 339960484Sobrien as_bad (_("missing rename string")); 340060484Sobrien ignore_rest_of_line (); 340160484Sobrien return; 340260484Sobrien } 340360484Sobrien ++input_line_pointer; 340460484Sobrien 340560484Sobrien symbol_get_tc (sym)->real_name = demand_copy_C_string (&len); 340660484Sobrien 340760484Sobrien demand_empty_rest_of_line (); 340860484Sobrien} 340960484Sobrien 341060484Sobrien/* The .stabx pseudo-op. This is similar to a normal .stabs 341160484Sobrien pseudo-op, but slightly different. A sample is 341260484Sobrien .stabx "main:F-1",.main,142,0 341360484Sobrien The first argument is the symbol name to create. The second is the 341460484Sobrien value, and the third is the storage class. The fourth seems to be 341560484Sobrien always zero, and I am assuming it is the type. */ 341660484Sobrien 341760484Sobrienstatic void 3418218822Sdimppc_stabx (int ignore ATTRIBUTE_UNUSED) 341960484Sobrien{ 342060484Sobrien char *name; 342160484Sobrien int len; 342260484Sobrien symbolS *sym; 342360484Sobrien expressionS exp; 342460484Sobrien 342560484Sobrien name = demand_copy_C_string (&len); 342660484Sobrien 342760484Sobrien if (*input_line_pointer != ',') 342860484Sobrien { 342960484Sobrien as_bad (_("missing value")); 343060484Sobrien return; 343160484Sobrien } 343260484Sobrien ++input_line_pointer; 343360484Sobrien 3434130561Sobrien ppc_stab_symbol = TRUE; 343560484Sobrien sym = symbol_make (name); 3436130561Sobrien ppc_stab_symbol = FALSE; 343760484Sobrien 343860484Sobrien symbol_get_tc (sym)->real_name = name; 343960484Sobrien 344060484Sobrien (void) expression (&exp); 344160484Sobrien 344260484Sobrien switch (exp.X_op) 344360484Sobrien { 344460484Sobrien case O_illegal: 344560484Sobrien case O_absent: 344660484Sobrien case O_big: 344760484Sobrien as_bad (_("illegal .stabx expression; zero assumed")); 344860484Sobrien exp.X_add_number = 0; 344960484Sobrien /* Fall through. */ 345060484Sobrien case O_constant: 345160484Sobrien S_SET_VALUE (sym, (valueT) exp.X_add_number); 345260484Sobrien symbol_set_frag (sym, &zero_address_frag); 345360484Sobrien break; 345460484Sobrien 345560484Sobrien case O_symbol: 345660484Sobrien if (S_GET_SEGMENT (exp.X_add_symbol) == undefined_section) 345760484Sobrien symbol_set_value_expression (sym, &exp); 345860484Sobrien else 345960484Sobrien { 346060484Sobrien S_SET_VALUE (sym, 346160484Sobrien exp.X_add_number + S_GET_VALUE (exp.X_add_symbol)); 346260484Sobrien symbol_set_frag (sym, symbol_get_frag (exp.X_add_symbol)); 346360484Sobrien } 346460484Sobrien break; 346560484Sobrien 346660484Sobrien default: 346760484Sobrien /* The value is some complex expression. This will probably 346889857Sobrien fail at some later point, but this is probably the right 346989857Sobrien thing to do here. */ 347060484Sobrien symbol_set_value_expression (sym, &exp); 347160484Sobrien break; 347260484Sobrien } 347360484Sobrien 347460484Sobrien S_SET_SEGMENT (sym, ppc_coff_debug_section); 347560484Sobrien symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; 347660484Sobrien 347760484Sobrien if (*input_line_pointer != ',') 347860484Sobrien { 347960484Sobrien as_bad (_("missing class")); 348060484Sobrien return; 348160484Sobrien } 348260484Sobrien ++input_line_pointer; 348360484Sobrien 348460484Sobrien S_SET_STORAGE_CLASS (sym, get_absolute_expression ()); 348560484Sobrien 348660484Sobrien if (*input_line_pointer != ',') 348760484Sobrien { 348860484Sobrien as_bad (_("missing type")); 348960484Sobrien return; 349060484Sobrien } 349160484Sobrien ++input_line_pointer; 349260484Sobrien 349360484Sobrien S_SET_DATA_TYPE (sym, get_absolute_expression ()); 349460484Sobrien 349560484Sobrien symbol_get_tc (sym)->output = 1; 349660484Sobrien 349778828Sobrien if (S_GET_STORAGE_CLASS (sym) == C_STSYM) { 349889857Sobrien 349960484Sobrien symbol_get_tc (sym)->within = ppc_current_block; 350060484Sobrien 350178828Sobrien /* In this case : 350289857Sobrien 350378828Sobrien .bs name 350478828Sobrien .stabx "z",arrays_,133,0 350578828Sobrien .es 350689857Sobrien 350778828Sobrien .comm arrays_,13768,3 350889857Sobrien 350978828Sobrien resolve_symbol_value will copy the exp's "within" into sym's when the 351078828Sobrien offset is 0. Since this seems to be corner case problem, 351178828Sobrien only do the correction for storage class C_STSYM. A better solution 351289857Sobrien would be to have the tc field updated in ppc_symbol_new_hook. */ 351389857Sobrien 351489857Sobrien if (exp.X_op == O_symbol) 351578828Sobrien { 351678828Sobrien symbol_get_tc (exp.X_add_symbol)->within = ppc_current_block; 351778828Sobrien } 351878828Sobrien } 351978828Sobrien 352060484Sobrien if (exp.X_op != O_symbol 352160484Sobrien || ! S_IS_EXTERNAL (exp.X_add_symbol) 352260484Sobrien || S_GET_SEGMENT (exp.X_add_symbol) != bss_section) 352360484Sobrien ppc_frob_label (sym); 352460484Sobrien else 352560484Sobrien { 352660484Sobrien symbol_remove (sym, &symbol_rootP, &symbol_lastP); 352760484Sobrien symbol_append (sym, exp.X_add_symbol, &symbol_rootP, &symbol_lastP); 352860484Sobrien if (symbol_get_tc (ppc_current_csect)->within == exp.X_add_symbol) 352960484Sobrien symbol_get_tc (ppc_current_csect)->within = sym; 353060484Sobrien } 353160484Sobrien 353260484Sobrien demand_empty_rest_of_line (); 353360484Sobrien} 353460484Sobrien 353560484Sobrien/* The .function pseudo-op. This takes several arguments. The first 353660484Sobrien argument seems to be the external name of the symbol. The second 3537130561Sobrien argument seems to be the label for the start of the function. gcc 353860484Sobrien uses the same name for both. I have no idea what the third and 353960484Sobrien fourth arguments are meant to be. The optional fifth argument is 354060484Sobrien an expression for the size of the function. In COFF this symbol 354160484Sobrien gets an aux entry like that used for a csect. */ 354260484Sobrien 354360484Sobrienstatic void 3544218822Sdimppc_function (int ignore ATTRIBUTE_UNUSED) 354560484Sobrien{ 354660484Sobrien char *name; 354760484Sobrien char endc; 354860484Sobrien char *s; 354960484Sobrien symbolS *ext_sym; 355060484Sobrien symbolS *lab_sym; 355160484Sobrien 355260484Sobrien name = input_line_pointer; 355360484Sobrien endc = get_symbol_end (); 355460484Sobrien 355560484Sobrien /* Ignore any [PR] suffix. */ 355660484Sobrien name = ppc_canonicalize_symbol_name (name); 355760484Sobrien s = strchr (name, '['); 355860484Sobrien if (s != (char *) NULL 355960484Sobrien && strcmp (s + 1, "PR]") == 0) 356060484Sobrien *s = '\0'; 356160484Sobrien 356260484Sobrien ext_sym = symbol_find_or_make (name); 356360484Sobrien 356460484Sobrien *input_line_pointer = endc; 356560484Sobrien 356660484Sobrien if (*input_line_pointer != ',') 356760484Sobrien { 356860484Sobrien as_bad (_("missing symbol name")); 356960484Sobrien ignore_rest_of_line (); 357060484Sobrien return; 357160484Sobrien } 357260484Sobrien ++input_line_pointer; 357360484Sobrien 357460484Sobrien name = input_line_pointer; 357560484Sobrien endc = get_symbol_end (); 357660484Sobrien 357760484Sobrien lab_sym = symbol_find_or_make (name); 357860484Sobrien 357960484Sobrien *input_line_pointer = endc; 358060484Sobrien 358160484Sobrien if (ext_sym != lab_sym) 358260484Sobrien { 358360484Sobrien expressionS exp; 358460484Sobrien 358560484Sobrien exp.X_op = O_symbol; 358660484Sobrien exp.X_add_symbol = lab_sym; 358760484Sobrien exp.X_op_symbol = NULL; 358860484Sobrien exp.X_add_number = 0; 358960484Sobrien exp.X_unsigned = 0; 359060484Sobrien symbol_set_value_expression (ext_sym, &exp); 359160484Sobrien } 359260484Sobrien 359360484Sobrien if (symbol_get_tc (ext_sym)->class == -1) 359460484Sobrien symbol_get_tc (ext_sym)->class = XMC_PR; 359560484Sobrien symbol_get_tc (ext_sym)->output = 1; 359660484Sobrien 359760484Sobrien if (*input_line_pointer == ',') 359860484Sobrien { 359960484Sobrien expressionS ignore; 360060484Sobrien 360160484Sobrien /* Ignore the third argument. */ 360260484Sobrien ++input_line_pointer; 360360484Sobrien expression (&ignore); 360460484Sobrien if (*input_line_pointer == ',') 360560484Sobrien { 360660484Sobrien /* Ignore the fourth argument. */ 360760484Sobrien ++input_line_pointer; 360860484Sobrien expression (&ignore); 360960484Sobrien if (*input_line_pointer == ',') 361060484Sobrien { 361160484Sobrien /* The fifth argument is the function size. */ 361260484Sobrien ++input_line_pointer; 361360484Sobrien symbol_get_tc (ext_sym)->size = symbol_new ("L0\001", 361460484Sobrien absolute_section, 361560484Sobrien (valueT) 0, 361660484Sobrien &zero_address_frag); 361760484Sobrien pseudo_set (symbol_get_tc (ext_sym)->size); 361860484Sobrien } 361960484Sobrien } 362060484Sobrien } 362160484Sobrien 362260484Sobrien S_SET_DATA_TYPE (ext_sym, DT_FCN << N_BTSHFT); 362360484Sobrien SF_SET_FUNCTION (ext_sym); 362460484Sobrien SF_SET_PROCESS (ext_sym); 362560484Sobrien coff_add_linesym (ext_sym); 362660484Sobrien 362760484Sobrien demand_empty_rest_of_line (); 362860484Sobrien} 362960484Sobrien 363060484Sobrien/* The .bf pseudo-op. This is just like a COFF C_FCN symbol named 363189857Sobrien ".bf". If the pseudo op .bi was seen before .bf, patch the .bi sym 363289857Sobrien with the correct line number */ 3633104834Sobrien 363489857Sobrienstatic symbolS *saved_bi_sym = 0; 363560484Sobrien 363660484Sobrienstatic void 3637218822Sdimppc_bf (int ignore ATTRIBUTE_UNUSED) 363860484Sobrien{ 363960484Sobrien symbolS *sym; 364060484Sobrien 364160484Sobrien sym = symbol_make (".bf"); 364260484Sobrien S_SET_SEGMENT (sym, text_section); 364360484Sobrien symbol_set_frag (sym, frag_now); 364460484Sobrien S_SET_VALUE (sym, frag_now_fix ()); 364560484Sobrien S_SET_STORAGE_CLASS (sym, C_FCN); 364660484Sobrien 364760484Sobrien coff_line_base = get_absolute_expression (); 364860484Sobrien 364960484Sobrien S_SET_NUMBER_AUXILIARY (sym, 1); 365060484Sobrien SA_SET_SYM_LNNO (sym, coff_line_base); 365160484Sobrien 365289857Sobrien /* Line number for bi. */ 3653104834Sobrien if (saved_bi_sym) 365489857Sobrien { 365589857Sobrien S_SET_VALUE (saved_bi_sym, coff_n_line_nos); 365689857Sobrien saved_bi_sym = 0; 365789857Sobrien } 365889857Sobrien 3659104834Sobrien 366060484Sobrien symbol_get_tc (sym)->output = 1; 366160484Sobrien 366260484Sobrien ppc_frob_label (sym); 366360484Sobrien 366460484Sobrien demand_empty_rest_of_line (); 366560484Sobrien} 366660484Sobrien 366760484Sobrien/* The .ef pseudo-op. This is just like a COFF C_FCN symbol named 366860484Sobrien ".ef", except that the line number is absolute, not relative to the 366960484Sobrien most recent ".bf" symbol. */ 367060484Sobrien 367160484Sobrienstatic void 3672218822Sdimppc_ef (int ignore ATTRIBUTE_UNUSED) 367360484Sobrien{ 367460484Sobrien symbolS *sym; 367560484Sobrien 367660484Sobrien sym = symbol_make (".ef"); 367760484Sobrien S_SET_SEGMENT (sym, text_section); 367860484Sobrien symbol_set_frag (sym, frag_now); 367960484Sobrien S_SET_VALUE (sym, frag_now_fix ()); 368060484Sobrien S_SET_STORAGE_CLASS (sym, C_FCN); 368160484Sobrien S_SET_NUMBER_AUXILIARY (sym, 1); 368260484Sobrien SA_SET_SYM_LNNO (sym, get_absolute_expression ()); 368360484Sobrien symbol_get_tc (sym)->output = 1; 368460484Sobrien 368560484Sobrien ppc_frob_label (sym); 368660484Sobrien 368760484Sobrien demand_empty_rest_of_line (); 368860484Sobrien} 368960484Sobrien 369060484Sobrien/* The .bi and .ei pseudo-ops. These take a string argument and 369160484Sobrien generates a C_BINCL or C_EINCL symbol, which goes at the start of 369289857Sobrien the symbol list. The value of .bi will be know when the next .bf 369389857Sobrien is encountered. */ 369460484Sobrien 369560484Sobrienstatic void 3696218822Sdimppc_biei (int ei) 369760484Sobrien{ 369860484Sobrien static symbolS *last_biei; 369960484Sobrien 370060484Sobrien char *name; 370160484Sobrien int len; 370260484Sobrien symbolS *sym; 370360484Sobrien symbolS *look; 370460484Sobrien 370560484Sobrien name = demand_copy_C_string (&len); 370660484Sobrien 370760484Sobrien /* The value of these symbols is actually file offset. Here we set 370860484Sobrien the value to the index into the line number entries. In 370960484Sobrien ppc_frob_symbols we set the fix_line field, which will cause BFD 371060484Sobrien to do the right thing. */ 371160484Sobrien 371260484Sobrien sym = symbol_make (name); 371360484Sobrien /* obj-coff.c currently only handles line numbers correctly in the 371460484Sobrien .text section. */ 371560484Sobrien S_SET_SEGMENT (sym, text_section); 371660484Sobrien S_SET_VALUE (sym, coff_n_line_nos); 371760484Sobrien symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; 371860484Sobrien 371960484Sobrien S_SET_STORAGE_CLASS (sym, ei ? C_EINCL : C_BINCL); 372060484Sobrien symbol_get_tc (sym)->output = 1; 372177298Sobrien 372289857Sobrien /* Save bi. */ 3723104834Sobrien if (ei) 372489857Sobrien saved_bi_sym = 0; 372589857Sobrien else 372689857Sobrien saved_bi_sym = sym; 372789857Sobrien 372860484Sobrien for (look = last_biei ? last_biei : symbol_rootP; 372960484Sobrien (look != (symbolS *) NULL 373060484Sobrien && (S_GET_STORAGE_CLASS (look) == C_FILE 373160484Sobrien || S_GET_STORAGE_CLASS (look) == C_BINCL 373260484Sobrien || S_GET_STORAGE_CLASS (look) == C_EINCL)); 373360484Sobrien look = symbol_next (look)) 373460484Sobrien ; 373560484Sobrien if (look != (symbolS *) NULL) 373660484Sobrien { 373760484Sobrien symbol_remove (sym, &symbol_rootP, &symbol_lastP); 373860484Sobrien symbol_insert (sym, look, &symbol_rootP, &symbol_lastP); 373960484Sobrien last_biei = sym; 374060484Sobrien } 374160484Sobrien 374260484Sobrien demand_empty_rest_of_line (); 374360484Sobrien} 374460484Sobrien 374560484Sobrien/* The .bs pseudo-op. This generates a C_BSTAT symbol named ".bs". 374660484Sobrien There is one argument, which is a csect symbol. The value of the 374760484Sobrien .bs symbol is the index of this csect symbol. */ 374860484Sobrien 374960484Sobrienstatic void 3750218822Sdimppc_bs (int ignore ATTRIBUTE_UNUSED) 375160484Sobrien{ 375260484Sobrien char *name; 375360484Sobrien char endc; 375460484Sobrien symbolS *csect; 375560484Sobrien symbolS *sym; 375660484Sobrien 375760484Sobrien if (ppc_current_block != NULL) 375860484Sobrien as_bad (_("nested .bs blocks")); 375960484Sobrien 376060484Sobrien name = input_line_pointer; 376160484Sobrien endc = get_symbol_end (); 376260484Sobrien 376360484Sobrien csect = symbol_find_or_make (name); 376460484Sobrien 376560484Sobrien *input_line_pointer = endc; 376660484Sobrien 376760484Sobrien sym = symbol_make (".bs"); 376860484Sobrien S_SET_SEGMENT (sym, now_seg); 376960484Sobrien S_SET_STORAGE_CLASS (sym, C_BSTAT); 377060484Sobrien symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; 377160484Sobrien symbol_get_tc (sym)->output = 1; 377260484Sobrien 377360484Sobrien symbol_get_tc (sym)->within = csect; 377460484Sobrien 377560484Sobrien ppc_frob_label (sym); 377660484Sobrien 377760484Sobrien ppc_current_block = sym; 377860484Sobrien 377960484Sobrien demand_empty_rest_of_line (); 378060484Sobrien} 378160484Sobrien 378260484Sobrien/* The .es pseudo-op. Generate a C_ESTART symbol named .es. */ 378360484Sobrien 378460484Sobrienstatic void 3785218822Sdimppc_es (int ignore ATTRIBUTE_UNUSED) 378660484Sobrien{ 378760484Sobrien symbolS *sym; 378860484Sobrien 378960484Sobrien if (ppc_current_block == NULL) 379060484Sobrien as_bad (_(".es without preceding .bs")); 379160484Sobrien 379260484Sobrien sym = symbol_make (".es"); 379360484Sobrien S_SET_SEGMENT (sym, now_seg); 379460484Sobrien S_SET_STORAGE_CLASS (sym, C_ESTAT); 379560484Sobrien symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; 379660484Sobrien symbol_get_tc (sym)->output = 1; 379760484Sobrien 379860484Sobrien ppc_frob_label (sym); 379960484Sobrien 380060484Sobrien ppc_current_block = NULL; 380160484Sobrien 380260484Sobrien demand_empty_rest_of_line (); 380360484Sobrien} 380460484Sobrien 380560484Sobrien/* The .bb pseudo-op. Generate a C_BLOCK symbol named .bb, with a 380660484Sobrien line number. */ 380760484Sobrien 380860484Sobrienstatic void 3809218822Sdimppc_bb (int ignore ATTRIBUTE_UNUSED) 381060484Sobrien{ 381160484Sobrien symbolS *sym; 381260484Sobrien 381360484Sobrien sym = symbol_make (".bb"); 381460484Sobrien S_SET_SEGMENT (sym, text_section); 381560484Sobrien symbol_set_frag (sym, frag_now); 381660484Sobrien S_SET_VALUE (sym, frag_now_fix ()); 381760484Sobrien S_SET_STORAGE_CLASS (sym, C_BLOCK); 381860484Sobrien 381960484Sobrien S_SET_NUMBER_AUXILIARY (sym, 1); 382060484Sobrien SA_SET_SYM_LNNO (sym, get_absolute_expression ()); 382160484Sobrien 382260484Sobrien symbol_get_tc (sym)->output = 1; 382360484Sobrien 382460484Sobrien SF_SET_PROCESS (sym); 382560484Sobrien 382660484Sobrien ppc_frob_label (sym); 382760484Sobrien 382860484Sobrien demand_empty_rest_of_line (); 382960484Sobrien} 383060484Sobrien 383160484Sobrien/* The .eb pseudo-op. Generate a C_BLOCK symbol named .eb, with a 383260484Sobrien line number. */ 383360484Sobrien 383460484Sobrienstatic void 3835218822Sdimppc_eb (int ignore ATTRIBUTE_UNUSED) 383660484Sobrien{ 383760484Sobrien symbolS *sym; 383860484Sobrien 383960484Sobrien sym = symbol_make (".eb"); 384060484Sobrien S_SET_SEGMENT (sym, text_section); 384160484Sobrien symbol_set_frag (sym, frag_now); 384260484Sobrien S_SET_VALUE (sym, frag_now_fix ()); 384360484Sobrien S_SET_STORAGE_CLASS (sym, C_BLOCK); 384460484Sobrien S_SET_NUMBER_AUXILIARY (sym, 1); 384560484Sobrien SA_SET_SYM_LNNO (sym, get_absolute_expression ()); 384660484Sobrien symbol_get_tc (sym)->output = 1; 384760484Sobrien 384860484Sobrien SF_SET_PROCESS (sym); 384960484Sobrien 385060484Sobrien ppc_frob_label (sym); 385160484Sobrien 385260484Sobrien demand_empty_rest_of_line (); 385360484Sobrien} 385460484Sobrien 385560484Sobrien/* The .bc pseudo-op. This just creates a C_BCOMM symbol with a 385660484Sobrien specified name. */ 385760484Sobrien 385860484Sobrienstatic void 3859218822Sdimppc_bc (int ignore ATTRIBUTE_UNUSED) 386060484Sobrien{ 386160484Sobrien char *name; 386260484Sobrien int len; 386360484Sobrien symbolS *sym; 386460484Sobrien 386560484Sobrien name = demand_copy_C_string (&len); 386660484Sobrien sym = symbol_make (name); 386760484Sobrien S_SET_SEGMENT (sym, ppc_coff_debug_section); 386860484Sobrien symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; 386960484Sobrien S_SET_STORAGE_CLASS (sym, C_BCOMM); 387060484Sobrien S_SET_VALUE (sym, 0); 387160484Sobrien symbol_get_tc (sym)->output = 1; 387260484Sobrien 387360484Sobrien ppc_frob_label (sym); 387460484Sobrien 387560484Sobrien demand_empty_rest_of_line (); 387660484Sobrien} 387760484Sobrien 387860484Sobrien/* The .ec pseudo-op. This just creates a C_ECOMM symbol. */ 387960484Sobrien 388060484Sobrienstatic void 3881218822Sdimppc_ec (int ignore ATTRIBUTE_UNUSED) 388260484Sobrien{ 388360484Sobrien symbolS *sym; 388460484Sobrien 388560484Sobrien sym = symbol_make (".ec"); 388660484Sobrien S_SET_SEGMENT (sym, ppc_coff_debug_section); 388760484Sobrien symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; 388860484Sobrien S_SET_STORAGE_CLASS (sym, C_ECOMM); 388960484Sobrien S_SET_VALUE (sym, 0); 389060484Sobrien symbol_get_tc (sym)->output = 1; 389160484Sobrien 389260484Sobrien ppc_frob_label (sym); 389360484Sobrien 389460484Sobrien demand_empty_rest_of_line (); 389560484Sobrien} 389660484Sobrien 389760484Sobrien/* The .toc pseudo-op. Switch to the .toc subsegment. */ 389860484Sobrien 389960484Sobrienstatic void 3900218822Sdimppc_toc (int ignore ATTRIBUTE_UNUSED) 390160484Sobrien{ 390260484Sobrien if (ppc_toc_csect != (symbolS *) NULL) 390360484Sobrien subseg_set (data_section, symbol_get_tc (ppc_toc_csect)->subseg); 390460484Sobrien else 390560484Sobrien { 390660484Sobrien subsegT subseg; 390760484Sobrien symbolS *sym; 390860484Sobrien symbolS *list; 390977298Sobrien 391060484Sobrien subseg = ppc_data_subsegment; 391160484Sobrien ++ppc_data_subsegment; 391260484Sobrien 391360484Sobrien subseg_new (segment_name (data_section), subseg); 391460484Sobrien ppc_toc_frag = frag_now; 391560484Sobrien 391660484Sobrien sym = symbol_find_or_make ("TOC[TC0]"); 391760484Sobrien symbol_set_frag (sym, frag_now); 391860484Sobrien S_SET_SEGMENT (sym, data_section); 391960484Sobrien S_SET_VALUE (sym, (valueT) frag_now_fix ()); 392060484Sobrien symbol_get_tc (sym)->subseg = subseg; 392160484Sobrien symbol_get_tc (sym)->output = 1; 392260484Sobrien symbol_get_tc (sym)->within = sym; 392360484Sobrien 392460484Sobrien ppc_toc_csect = sym; 392577298Sobrien 392660484Sobrien for (list = ppc_data_csects; 392760484Sobrien symbol_get_tc (list)->next != (symbolS *) NULL; 392860484Sobrien list = symbol_get_tc (list)->next) 392960484Sobrien ; 393060484Sobrien symbol_get_tc (list)->next = sym; 393160484Sobrien 393260484Sobrien symbol_remove (sym, &symbol_rootP, &symbol_lastP); 393360484Sobrien symbol_append (sym, symbol_get_tc (list)->within, &symbol_rootP, 393460484Sobrien &symbol_lastP); 393560484Sobrien } 393660484Sobrien 393760484Sobrien ppc_current_csect = ppc_toc_csect; 393860484Sobrien 393960484Sobrien demand_empty_rest_of_line (); 394060484Sobrien} 394160484Sobrien 394260484Sobrien/* The AIX assembler automatically aligns the operands of a .long or 394360484Sobrien .short pseudo-op, and we want to be compatible. */ 394460484Sobrien 394560484Sobrienstatic void 3946218822Sdimppc_xcoff_cons (int log_size) 394760484Sobrien{ 394860484Sobrien frag_align (log_size, 0, 0); 394960484Sobrien record_alignment (now_seg, log_size); 395060484Sobrien cons (1 << log_size); 395160484Sobrien} 395260484Sobrien 395360484Sobrienstatic void 3954218822Sdimppc_vbyte (int dummy ATTRIBUTE_UNUSED) 395560484Sobrien{ 395660484Sobrien expressionS exp; 395760484Sobrien int byte_count; 395860484Sobrien 395960484Sobrien (void) expression (&exp); 396060484Sobrien 396160484Sobrien if (exp.X_op != O_constant) 396260484Sobrien { 396360484Sobrien as_bad (_("non-constant byte count")); 396460484Sobrien return; 396560484Sobrien } 396660484Sobrien 396760484Sobrien byte_count = exp.X_add_number; 396860484Sobrien 396960484Sobrien if (*input_line_pointer != ',') 397060484Sobrien { 397160484Sobrien as_bad (_("missing value")); 397260484Sobrien return; 397360484Sobrien } 397460484Sobrien 397560484Sobrien ++input_line_pointer; 397660484Sobrien cons (byte_count); 397760484Sobrien} 397860484Sobrien 397960484Sobrien#endif /* OBJ_XCOFF */ 398089857Sobrien#if defined (OBJ_XCOFF) || defined (OBJ_ELF) 398160484Sobrien 398260484Sobrien/* The .tc pseudo-op. This is used when generating either XCOFF or 398360484Sobrien ELF. This takes two or more arguments. 398460484Sobrien 398560484Sobrien When generating XCOFF output, the first argument is the name to 398660484Sobrien give to this location in the toc; this will be a symbol with class 398789857Sobrien TC. The rest of the arguments are N-byte values to actually put at 398860484Sobrien this location in the TOC; often there is just one more argument, a 3989130561Sobrien relocatable symbol reference. The size of the value to store 399089857Sobrien depends on target word size. A 32-bit target uses 4-byte values, a 399189857Sobrien 64-bit target uses 8-byte values. 399260484Sobrien 399360484Sobrien When not generating XCOFF output, the arguments are the same, but 399460484Sobrien the first argument is simply ignored. */ 399560484Sobrien 399660484Sobrienstatic void 3997218822Sdimppc_tc (int ignore ATTRIBUTE_UNUSED) 399860484Sobrien{ 399960484Sobrien#ifdef OBJ_XCOFF 400060484Sobrien 400160484Sobrien /* Define the TOC symbol name. */ 400260484Sobrien { 400360484Sobrien char *name; 400460484Sobrien char endc; 400560484Sobrien symbolS *sym; 400660484Sobrien 400760484Sobrien if (ppc_toc_csect == (symbolS *) NULL 400860484Sobrien || ppc_toc_csect != ppc_current_csect) 400960484Sobrien { 401060484Sobrien as_bad (_(".tc not in .toc section")); 401160484Sobrien ignore_rest_of_line (); 401260484Sobrien return; 401360484Sobrien } 401460484Sobrien 401560484Sobrien name = input_line_pointer; 401660484Sobrien endc = get_symbol_end (); 401760484Sobrien 401860484Sobrien sym = symbol_find_or_make (name); 401960484Sobrien 402060484Sobrien *input_line_pointer = endc; 402160484Sobrien 402260484Sobrien if (S_IS_DEFINED (sym)) 402360484Sobrien { 402460484Sobrien symbolS *label; 402560484Sobrien 402660484Sobrien label = symbol_get_tc (ppc_current_csect)->within; 402760484Sobrien if (symbol_get_tc (label)->class != XMC_TC0) 402860484Sobrien { 402960484Sobrien as_bad (_(".tc with no label")); 403060484Sobrien ignore_rest_of_line (); 403160484Sobrien return; 403260484Sobrien } 403360484Sobrien 403460484Sobrien S_SET_SEGMENT (label, S_GET_SEGMENT (sym)); 403560484Sobrien symbol_set_frag (label, symbol_get_frag (sym)); 403660484Sobrien S_SET_VALUE (label, S_GET_VALUE (sym)); 403760484Sobrien 403860484Sobrien while (! is_end_of_line[(unsigned char) *input_line_pointer]) 403960484Sobrien ++input_line_pointer; 404060484Sobrien 404160484Sobrien return; 404260484Sobrien } 404360484Sobrien 404460484Sobrien S_SET_SEGMENT (sym, now_seg); 404560484Sobrien symbol_set_frag (sym, frag_now); 404660484Sobrien S_SET_VALUE (sym, (valueT) frag_now_fix ()); 404760484Sobrien symbol_get_tc (sym)->class = XMC_TC; 404860484Sobrien symbol_get_tc (sym)->output = 1; 404960484Sobrien 405060484Sobrien ppc_frob_label (sym); 405160484Sobrien } 405260484Sobrien 405389857Sobrien#endif /* OBJ_XCOFF */ 405489857Sobrien#ifdef OBJ_ELF 405589857Sobrien int align; 405660484Sobrien 405760484Sobrien /* Skip the TOC symbol name. */ 405860484Sobrien while (is_part_of_name (*input_line_pointer) 405960484Sobrien || *input_line_pointer == '[' 406060484Sobrien || *input_line_pointer == ']' 406160484Sobrien || *input_line_pointer == '{' 406260484Sobrien || *input_line_pointer == '}') 406360484Sobrien ++input_line_pointer; 406460484Sobrien 406589857Sobrien /* Align to a four/eight byte boundary. */ 4066104834Sobrien align = ppc_obj64 ? 3 : 2; 406789857Sobrien frag_align (align, 0, 0); 406889857Sobrien record_alignment (now_seg, align); 406989857Sobrien#endif /* OBJ_ELF */ 407060484Sobrien 407160484Sobrien if (*input_line_pointer != ',') 407260484Sobrien demand_empty_rest_of_line (); 407360484Sobrien else 407460484Sobrien { 407560484Sobrien ++input_line_pointer; 4076104834Sobrien cons (ppc_obj64 ? 8 : 4); 407760484Sobrien } 407860484Sobrien} 407989857Sobrien 408089857Sobrien/* Pseudo-op .machine. */ 408189857Sobrien 408289857Sobrienstatic void 4083218822Sdimppc_machine (int ignore ATTRIBUTE_UNUSED) 408489857Sobrien{ 4085130561Sobrien char *cpu_string; 4086130561Sobrien#define MAX_HISTORY 100 4087130561Sobrien static unsigned long *cpu_history; 4088130561Sobrien static int curr_hist; 4089130561Sobrien 4090130561Sobrien SKIP_WHITESPACE (); 4091130561Sobrien 4092130561Sobrien if (*input_line_pointer == '"') 4093130561Sobrien { 4094130561Sobrien int len; 4095130561Sobrien cpu_string = demand_copy_C_string (&len); 4096130561Sobrien } 4097130561Sobrien else 4098130561Sobrien { 4099130561Sobrien char c; 4100130561Sobrien cpu_string = input_line_pointer; 4101130561Sobrien c = get_symbol_end (); 4102130561Sobrien cpu_string = xstrdup (cpu_string); 4103130561Sobrien *input_line_pointer = c; 4104130561Sobrien } 4105130561Sobrien 4106130561Sobrien if (cpu_string != NULL) 4107130561Sobrien { 4108130561Sobrien unsigned long old_cpu = ppc_cpu; 4109130561Sobrien char *p; 4110130561Sobrien 4111130561Sobrien for (p = cpu_string; *p != 0; p++) 4112130561Sobrien *p = TOLOWER (*p); 4113130561Sobrien 4114130561Sobrien if (strcmp (cpu_string, "push") == 0) 4115130561Sobrien { 4116130561Sobrien if (cpu_history == NULL) 4117130561Sobrien cpu_history = xmalloc (MAX_HISTORY * sizeof (*cpu_history)); 4118130561Sobrien 4119130561Sobrien if (curr_hist >= MAX_HISTORY) 4120130561Sobrien as_bad (_(".machine stack overflow")); 4121130561Sobrien else 4122130561Sobrien cpu_history[curr_hist++] = ppc_cpu; 4123130561Sobrien } 4124130561Sobrien else if (strcmp (cpu_string, "pop") == 0) 4125130561Sobrien { 4126130561Sobrien if (curr_hist <= 0) 4127130561Sobrien as_bad (_(".machine stack underflow")); 4128130561Sobrien else 4129130561Sobrien ppc_cpu = cpu_history[--curr_hist]; 4130130561Sobrien } 4131130561Sobrien else if (parse_cpu (cpu_string)) 4132130561Sobrien ; 4133130561Sobrien else 4134130561Sobrien as_bad (_("invalid machine `%s'"), cpu_string); 4135130561Sobrien 4136130561Sobrien if (ppc_cpu != old_cpu) 4137130561Sobrien ppc_setup_opcodes (); 4138130561Sobrien } 4139130561Sobrien 4140130561Sobrien demand_empty_rest_of_line (); 414189857Sobrien} 414289857Sobrien 414389857Sobrien/* See whether a symbol is in the TOC section. */ 414489857Sobrien 414589857Sobrienstatic int 4146218822Sdimppc_is_toc_sym (symbolS *sym) 414789857Sobrien{ 414889857Sobrien#ifdef OBJ_XCOFF 414989857Sobrien return symbol_get_tc (sym)->class == XMC_TC; 415089857Sobrien#endif 415189857Sobrien#ifdef OBJ_ELF 415289857Sobrien const char *sname = segment_name (S_GET_SEGMENT (sym)); 4153104834Sobrien if (ppc_obj64) 415489857Sobrien return strcmp (sname, ".toc") == 0; 415589857Sobrien else 415689857Sobrien return strcmp (sname, ".got") == 0; 415789857Sobrien#endif 415889857Sobrien} 415989857Sobrien#endif /* defined (OBJ_XCOFF) || defined (OBJ_ELF) */ 416060484Sobrien 416160484Sobrien#ifdef TE_PE 416260484Sobrien 416389857Sobrien/* Pseudo-ops specific to the Windows NT PowerPC PE (coff) format. */ 416460484Sobrien 416560484Sobrien/* Set the current section. */ 416660484Sobrienstatic void 4167218822Sdimppc_set_current_section (segT new) 416860484Sobrien{ 416960484Sobrien ppc_previous_section = ppc_current_section; 417060484Sobrien ppc_current_section = new; 417160484Sobrien} 417260484Sobrien 417360484Sobrien/* pseudo-op: .previous 417460484Sobrien behaviour: toggles the current section with the previous section. 417560484Sobrien errors: None 417689857Sobrien warnings: "No previous section" */ 417789857Sobrien 417860484Sobrienstatic void 4179218822Sdimppc_previous (int ignore ATTRIBUTE_UNUSED) 418060484Sobrien{ 418160484Sobrien symbolS *tmp; 418260484Sobrien 418377298Sobrien if (ppc_previous_section == NULL) 418460484Sobrien { 418589857Sobrien as_warn (_("No previous section to return to. Directive ignored.")); 418660484Sobrien return; 418760484Sobrien } 418860484Sobrien 418989857Sobrien subseg_set (ppc_previous_section, 0); 419060484Sobrien 419189857Sobrien ppc_set_current_section (ppc_previous_section); 419260484Sobrien} 419360484Sobrien 419460484Sobrien/* pseudo-op: .pdata 419560484Sobrien behaviour: predefined read only data section 4196130561Sobrien double word aligned 419760484Sobrien errors: None 419860484Sobrien warnings: None 419960484Sobrien initial: .section .pdata "adr3" 4200130561Sobrien a - don't know -- maybe a misprint 420160484Sobrien d - initialized data 420260484Sobrien r - readable 420360484Sobrien 3 - double word aligned (that would be 4 byte boundary) 420460484Sobrien 420560484Sobrien commentary: 420660484Sobrien Tag index tables (also known as the function table) for exception 420789857Sobrien handling, debugging, etc. */ 420860484Sobrien 420960484Sobrienstatic void 4210218822Sdimppc_pdata (int ignore ATTRIBUTE_UNUSED) 421160484Sobrien{ 421277298Sobrien if (pdata_section == 0) 421360484Sobrien { 421460484Sobrien pdata_section = subseg_new (".pdata", 0); 421577298Sobrien 421660484Sobrien bfd_set_section_flags (stdoutput, pdata_section, 421760484Sobrien (SEC_ALLOC | SEC_LOAD | SEC_RELOC 421860484Sobrien | SEC_READONLY | SEC_DATA )); 421977298Sobrien 422060484Sobrien bfd_set_section_alignment (stdoutput, pdata_section, 2); 422160484Sobrien } 422260484Sobrien else 422360484Sobrien { 422489857Sobrien pdata_section = subseg_new (".pdata", 0); 422560484Sobrien } 422689857Sobrien ppc_set_current_section (pdata_section); 422760484Sobrien} 422860484Sobrien 422960484Sobrien/* pseudo-op: .ydata 423060484Sobrien behaviour: predefined read only data section 4231130561Sobrien double word aligned 423260484Sobrien errors: None 423360484Sobrien warnings: None 423460484Sobrien initial: .section .ydata "drw3" 4235130561Sobrien a - don't know -- maybe a misprint 423660484Sobrien d - initialized data 423760484Sobrien r - readable 423860484Sobrien 3 - double word aligned (that would be 4 byte boundary) 423960484Sobrien commentary: 424060484Sobrien Tag tables (also known as the scope table) for exception handling, 424189857Sobrien debugging, etc. */ 424289857Sobrien 424360484Sobrienstatic void 4244218822Sdimppc_ydata (int ignore ATTRIBUTE_UNUSED) 424560484Sobrien{ 424677298Sobrien if (ydata_section == 0) 424760484Sobrien { 424860484Sobrien ydata_section = subseg_new (".ydata", 0); 424960484Sobrien bfd_set_section_flags (stdoutput, ydata_section, 425089857Sobrien (SEC_ALLOC | SEC_LOAD | SEC_RELOC 425189857Sobrien | SEC_READONLY | SEC_DATA )); 425260484Sobrien 425360484Sobrien bfd_set_section_alignment (stdoutput, ydata_section, 3); 425460484Sobrien } 425560484Sobrien else 425660484Sobrien { 425760484Sobrien ydata_section = subseg_new (".ydata", 0); 425860484Sobrien } 425989857Sobrien ppc_set_current_section (ydata_section); 426060484Sobrien} 426160484Sobrien 426260484Sobrien/* pseudo-op: .reldata 426360484Sobrien behaviour: predefined read write data section 4264130561Sobrien double word aligned (4-byte) 426560484Sobrien FIXME: relocation is applied to it 426660484Sobrien FIXME: what's the difference between this and .data? 426760484Sobrien errors: None 426860484Sobrien warnings: None 426960484Sobrien initial: .section .reldata "drw3" 427060484Sobrien d - initialized data 427160484Sobrien r - readable 427260484Sobrien w - writeable 427360484Sobrien 3 - double word aligned (that would be 8 byte boundary) 427460484Sobrien 427560484Sobrien commentary: 427660484Sobrien Like .data, but intended to hold data subject to relocation, such as 427789857Sobrien function descriptors, etc. */ 427889857Sobrien 427960484Sobrienstatic void 4280218822Sdimppc_reldata (int ignore ATTRIBUTE_UNUSED) 428160484Sobrien{ 428260484Sobrien if (reldata_section == 0) 428360484Sobrien { 428460484Sobrien reldata_section = subseg_new (".reldata", 0); 428560484Sobrien 428660484Sobrien bfd_set_section_flags (stdoutput, reldata_section, 428789857Sobrien (SEC_ALLOC | SEC_LOAD | SEC_RELOC 428889857Sobrien | SEC_DATA)); 428960484Sobrien 429060484Sobrien bfd_set_section_alignment (stdoutput, reldata_section, 2); 429160484Sobrien } 429260484Sobrien else 429360484Sobrien { 429460484Sobrien reldata_section = subseg_new (".reldata", 0); 429560484Sobrien } 429689857Sobrien ppc_set_current_section (reldata_section); 429760484Sobrien} 429860484Sobrien 429960484Sobrien/* pseudo-op: .rdata 430060484Sobrien behaviour: predefined read only data section 4301130561Sobrien double word aligned 430260484Sobrien errors: None 430360484Sobrien warnings: None 430460484Sobrien initial: .section .rdata "dr3" 430560484Sobrien d - initialized data 430660484Sobrien r - readable 430789857Sobrien 3 - double word aligned (that would be 4 byte boundary) */ 430889857Sobrien 430960484Sobrienstatic void 4310218822Sdimppc_rdata (int ignore ATTRIBUTE_UNUSED) 431160484Sobrien{ 431260484Sobrien if (rdata_section == 0) 431360484Sobrien { 431460484Sobrien rdata_section = subseg_new (".rdata", 0); 431560484Sobrien bfd_set_section_flags (stdoutput, rdata_section, 431660484Sobrien (SEC_ALLOC | SEC_LOAD | SEC_RELOC 431760484Sobrien | SEC_READONLY | SEC_DATA )); 431860484Sobrien 431960484Sobrien bfd_set_section_alignment (stdoutput, rdata_section, 2); 432060484Sobrien } 432160484Sobrien else 432260484Sobrien { 432360484Sobrien rdata_section = subseg_new (".rdata", 0); 432460484Sobrien } 432589857Sobrien ppc_set_current_section (rdata_section); 432660484Sobrien} 432760484Sobrien 432860484Sobrien/* pseudo-op: .ualong 432977298Sobrien behaviour: much like .int, with the exception that no alignment is 4330130561Sobrien performed. 433160484Sobrien FIXME: test the alignment statement 433260484Sobrien errors: None 433389857Sobrien warnings: None */ 433489857Sobrien 433560484Sobrienstatic void 4336218822Sdimppc_ualong (int ignore ATTRIBUTE_UNUSED) 433760484Sobrien{ 433889857Sobrien /* Try for long. */ 433989857Sobrien cons (4); 434060484Sobrien} 434160484Sobrien 434260484Sobrien/* pseudo-op: .znop <symbol name> 434360484Sobrien behaviour: Issue a nop instruction 4344130561Sobrien Issue a IMAGE_REL_PPC_IFGLUE relocation against it, using 434560484Sobrien the supplied symbol name. 434660484Sobrien errors: None 434789857Sobrien warnings: Missing symbol name */ 434889857Sobrien 434960484Sobrienstatic void 4350218822Sdimppc_znop (int ignore ATTRIBUTE_UNUSED) 435160484Sobrien{ 435260484Sobrien unsigned long insn; 435360484Sobrien const struct powerpc_opcode *opcode; 435460484Sobrien expressionS ex; 435560484Sobrien char *f; 435660484Sobrien symbolS *sym; 435760484Sobrien char *symbol_name; 435860484Sobrien char c; 435960484Sobrien char *name; 436060484Sobrien unsigned int exp; 436160484Sobrien flagword flags; 436260484Sobrien asection *sec; 436360484Sobrien 436489857Sobrien /* Strip out the symbol name. */ 436560484Sobrien symbol_name = input_line_pointer; 436660484Sobrien c = get_symbol_end (); 436760484Sobrien 436860484Sobrien name = xmalloc (input_line_pointer - symbol_name + 1); 436960484Sobrien strcpy (name, symbol_name); 437060484Sobrien 437160484Sobrien sym = symbol_find_or_make (name); 437260484Sobrien 437360484Sobrien *input_line_pointer = c; 437460484Sobrien 437560484Sobrien SKIP_WHITESPACE (); 437660484Sobrien 437760484Sobrien /* Look up the opcode in the hash table. */ 437860484Sobrien opcode = (const struct powerpc_opcode *) hash_find (ppc_hash, "nop"); 437960484Sobrien 438089857Sobrien /* Stick in the nop. */ 438160484Sobrien insn = opcode->opcode; 438260484Sobrien 438360484Sobrien /* Write out the instruction. */ 438460484Sobrien f = frag_more (4); 438560484Sobrien md_number_to_chars (f, insn, 4); 438660484Sobrien fix_new (frag_now, 438760484Sobrien f - frag_now->fr_literal, 438860484Sobrien 4, 438960484Sobrien sym, 439060484Sobrien 0, 439160484Sobrien 0, 439260484Sobrien BFD_RELOC_16_GOT_PCREL); 439360484Sobrien 439460484Sobrien} 439560484Sobrien 439677298Sobrien/* pseudo-op: 439777298Sobrien behaviour: 439877298Sobrien errors: 439989857Sobrien warnings: */ 440089857Sobrien 440160484Sobrienstatic void 4402218822Sdimppc_pe_comm (int lcomm) 440360484Sobrien{ 4404218822Sdim char *name; 4405218822Sdim char c; 4406218822Sdim char *p; 440760484Sobrien offsetT temp; 4408218822Sdim symbolS *symbolP; 440960484Sobrien offsetT align; 441060484Sobrien 441160484Sobrien name = input_line_pointer; 441260484Sobrien c = get_symbol_end (); 441360484Sobrien 441489857Sobrien /* just after name is now '\0'. */ 441560484Sobrien p = input_line_pointer; 441660484Sobrien *p = c; 441760484Sobrien SKIP_WHITESPACE (); 441860484Sobrien if (*input_line_pointer != ',') 441960484Sobrien { 442060484Sobrien as_bad (_("Expected comma after symbol-name: rest of line ignored.")); 442160484Sobrien ignore_rest_of_line (); 442260484Sobrien return; 442360484Sobrien } 442460484Sobrien 442560484Sobrien input_line_pointer++; /* skip ',' */ 442660484Sobrien if ((temp = get_absolute_expression ()) < 0) 442760484Sobrien { 442860484Sobrien as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) temp); 442960484Sobrien ignore_rest_of_line (); 443060484Sobrien return; 443160484Sobrien } 443260484Sobrien 443360484Sobrien if (! lcomm) 443460484Sobrien { 443560484Sobrien /* The third argument to .comm is the alignment. */ 443660484Sobrien if (*input_line_pointer != ',') 443760484Sobrien align = 3; 443860484Sobrien else 443960484Sobrien { 444060484Sobrien ++input_line_pointer; 444160484Sobrien align = get_absolute_expression (); 444260484Sobrien if (align <= 0) 444360484Sobrien { 444460484Sobrien as_warn (_("ignoring bad alignment")); 444560484Sobrien align = 3; 444660484Sobrien } 444760484Sobrien } 444860484Sobrien } 444960484Sobrien 445060484Sobrien *p = 0; 445160484Sobrien symbolP = symbol_find_or_make (name); 445260484Sobrien 445360484Sobrien *p = c; 445460484Sobrien if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) 445560484Sobrien { 445660484Sobrien as_bad (_("Ignoring attempt to re-define symbol `%s'."), 445760484Sobrien S_GET_NAME (symbolP)); 445860484Sobrien ignore_rest_of_line (); 445960484Sobrien return; 446060484Sobrien } 446160484Sobrien 446260484Sobrien if (S_GET_VALUE (symbolP)) 446360484Sobrien { 446460484Sobrien if (S_GET_VALUE (symbolP) != (valueT) temp) 446560484Sobrien as_bad (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."), 446660484Sobrien S_GET_NAME (symbolP), 446760484Sobrien (long) S_GET_VALUE (symbolP), 446860484Sobrien (long) temp); 446960484Sobrien } 447060484Sobrien else 447160484Sobrien { 447260484Sobrien S_SET_VALUE (symbolP, (valueT) temp); 447360484Sobrien S_SET_EXTERNAL (symbolP); 4474218822Sdim S_SET_SEGMENT (symbolP, bfd_com_section_ptr); 447560484Sobrien } 447660484Sobrien 447760484Sobrien demand_empty_rest_of_line (); 447860484Sobrien} 447960484Sobrien 448060484Sobrien/* 448160484Sobrien * implement the .section pseudo op: 448260484Sobrien * .section name {, "flags"} 448360484Sobrien * ^ ^ 448460484Sobrien * | +--- optional flags: 'b' for bss 448560484Sobrien * | 'i' for info 448660484Sobrien * +-- section name 'l' for lib 448760484Sobrien * 'n' for noload 448860484Sobrien * 'o' for over 448960484Sobrien * 'w' for data 449060484Sobrien * 'd' (apparently m88k for data) 449160484Sobrien * 'x' for text 449260484Sobrien * But if the argument is not a quoted string, treat it as a 449360484Sobrien * subsegment number. 449460484Sobrien * 449560484Sobrien * FIXME: this is a copy of the section processing from obj-coff.c, with 449660484Sobrien * additions/changes for the moto-pas assembler support. There are three 449760484Sobrien * categories: 449860484Sobrien * 449977298Sobrien * FIXME: I just noticed this. This doesn't work at all really. It it 450060484Sobrien * setting bits that bfd probably neither understands or uses. The 450160484Sobrien * correct approach (?) will have to incorporate extra fields attached 450260484Sobrien * to the section to hold the system specific stuff. (krk) 450360484Sobrien * 450460484Sobrien * Section Contents: 450560484Sobrien * 'a' - unknown - referred to in documentation, but no definition supplied 450660484Sobrien * 'c' - section has code 450760484Sobrien * 'd' - section has initialized data 450860484Sobrien * 'u' - section has uninitialized data 450960484Sobrien * 'i' - section contains directives (info) 451060484Sobrien * 'n' - section can be discarded 451160484Sobrien * 'R' - remove section at link time 451260484Sobrien * 451360484Sobrien * Section Protection: 451460484Sobrien * 'r' - section is readable 451560484Sobrien * 'w' - section is writeable 451660484Sobrien * 'x' - section is executable 451760484Sobrien * 's' - section is sharable 451860484Sobrien * 451960484Sobrien * Section Alignment: 452060484Sobrien * '0' - align to byte boundary 452160484Sobrien * '1' - align to halfword undary 452260484Sobrien * '2' - align to word boundary 452360484Sobrien * '3' - align to doubleword boundary 452460484Sobrien * '4' - align to quadword boundary 452560484Sobrien * '5' - align to 32 byte boundary 452660484Sobrien * '6' - align to 64 byte boundary 452760484Sobrien * 452860484Sobrien */ 452960484Sobrien 453060484Sobrienvoid 4531218822Sdimppc_pe_section (int ignore ATTRIBUTE_UNUSED) 453260484Sobrien{ 453389857Sobrien /* Strip out the section name. */ 453460484Sobrien char *section_name; 453560484Sobrien char c; 453660484Sobrien char *name; 453760484Sobrien unsigned int exp; 453860484Sobrien flagword flags; 453960484Sobrien segT sec; 454060484Sobrien int align; 454160484Sobrien 454260484Sobrien section_name = input_line_pointer; 454360484Sobrien c = get_symbol_end (); 454460484Sobrien 454560484Sobrien name = xmalloc (input_line_pointer - section_name + 1); 454660484Sobrien strcpy (name, section_name); 454760484Sobrien 454860484Sobrien *input_line_pointer = c; 454960484Sobrien 455060484Sobrien SKIP_WHITESPACE (); 455160484Sobrien 455260484Sobrien exp = 0; 455360484Sobrien flags = SEC_NO_FLAGS; 455460484Sobrien 455560484Sobrien if (strcmp (name, ".idata$2") == 0) 455660484Sobrien { 455760484Sobrien align = 0; 455860484Sobrien } 455960484Sobrien else if (strcmp (name, ".idata$3") == 0) 456060484Sobrien { 456160484Sobrien align = 0; 456260484Sobrien } 456360484Sobrien else if (strcmp (name, ".idata$4") == 0) 456460484Sobrien { 456560484Sobrien align = 2; 456660484Sobrien } 456760484Sobrien else if (strcmp (name, ".idata$5") == 0) 456860484Sobrien { 456960484Sobrien align = 2; 457060484Sobrien } 457160484Sobrien else if (strcmp (name, ".idata$6") == 0) 457260484Sobrien { 457360484Sobrien align = 1; 457460484Sobrien } 457560484Sobrien else 457689857Sobrien /* Default alignment to 16 byte boundary. */ 457789857Sobrien align = 4; 457860484Sobrien 457960484Sobrien if (*input_line_pointer == ',') 458060484Sobrien { 458160484Sobrien ++input_line_pointer; 458260484Sobrien SKIP_WHITESPACE (); 458360484Sobrien if (*input_line_pointer != '"') 458460484Sobrien exp = get_absolute_expression (); 458560484Sobrien else 458660484Sobrien { 458760484Sobrien ++input_line_pointer; 458860484Sobrien while (*input_line_pointer != '"' 458960484Sobrien && ! is_end_of_line[(unsigned char) *input_line_pointer]) 459060484Sobrien { 459160484Sobrien switch (*input_line_pointer) 459260484Sobrien { 459360484Sobrien /* Section Contents */ 459460484Sobrien case 'a': /* unknown */ 459560484Sobrien as_bad (_("Unsupported section attribute -- 'a'")); 459660484Sobrien break; 459760484Sobrien case 'c': /* code section */ 459877298Sobrien flags |= SEC_CODE; 459960484Sobrien break; 460060484Sobrien case 'd': /* section has initialized data */ 460160484Sobrien flags |= SEC_DATA; 460260484Sobrien break; 460360484Sobrien case 'u': /* section has uninitialized data */ 460460484Sobrien /* FIXME: This is IMAGE_SCN_CNT_UNINITIALIZED_DATA 460560484Sobrien in winnt.h */ 460660484Sobrien flags |= SEC_ROM; 460760484Sobrien break; 460860484Sobrien case 'i': /* section contains directives (info) */ 460960484Sobrien /* FIXME: This is IMAGE_SCN_LNK_INFO 461060484Sobrien in winnt.h */ 461160484Sobrien flags |= SEC_HAS_CONTENTS; 461260484Sobrien break; 461360484Sobrien case 'n': /* section can be discarded */ 461477298Sobrien flags &=~ SEC_LOAD; 461560484Sobrien break; 461660484Sobrien case 'R': /* Remove section at link time */ 461760484Sobrien flags |= SEC_NEVER_LOAD; 461860484Sobrien break; 4619218822Sdim#if IFLICT_BRAIN_DAMAGE 462060484Sobrien /* Section Protection */ 462160484Sobrien case 'r': /* section is readable */ 462260484Sobrien flags |= IMAGE_SCN_MEM_READ; 462360484Sobrien break; 462460484Sobrien case 'w': /* section is writeable */ 462560484Sobrien flags |= IMAGE_SCN_MEM_WRITE; 462660484Sobrien break; 462760484Sobrien case 'x': /* section is executable */ 462860484Sobrien flags |= IMAGE_SCN_MEM_EXECUTE; 462960484Sobrien break; 463060484Sobrien case 's': /* section is sharable */ 463160484Sobrien flags |= IMAGE_SCN_MEM_SHARED; 463260484Sobrien break; 463360484Sobrien 463460484Sobrien /* Section Alignment */ 463560484Sobrien case '0': /* align to byte boundary */ 463660484Sobrien flags |= IMAGE_SCN_ALIGN_1BYTES; 463760484Sobrien align = 0; 463860484Sobrien break; 463960484Sobrien case '1': /* align to halfword boundary */ 464060484Sobrien flags |= IMAGE_SCN_ALIGN_2BYTES; 464160484Sobrien align = 1; 464260484Sobrien break; 464360484Sobrien case '2': /* align to word boundary */ 464460484Sobrien flags |= IMAGE_SCN_ALIGN_4BYTES; 464560484Sobrien align = 2; 464660484Sobrien break; 464760484Sobrien case '3': /* align to doubleword boundary */ 464860484Sobrien flags |= IMAGE_SCN_ALIGN_8BYTES; 464960484Sobrien align = 3; 465060484Sobrien break; 465160484Sobrien case '4': /* align to quadword boundary */ 465260484Sobrien flags |= IMAGE_SCN_ALIGN_16BYTES; 465360484Sobrien align = 4; 465460484Sobrien break; 465560484Sobrien case '5': /* align to 32 byte boundary */ 465660484Sobrien flags |= IMAGE_SCN_ALIGN_32BYTES; 465760484Sobrien align = 5; 465860484Sobrien break; 465960484Sobrien case '6': /* align to 64 byte boundary */ 466060484Sobrien flags |= IMAGE_SCN_ALIGN_64BYTES; 466160484Sobrien align = 6; 466260484Sobrien break; 4663218822Sdim#endif 466460484Sobrien default: 466589857Sobrien as_bad (_("unknown section attribute '%c'"), 466689857Sobrien *input_line_pointer); 466760484Sobrien break; 466860484Sobrien } 466960484Sobrien ++input_line_pointer; 467060484Sobrien } 467160484Sobrien if (*input_line_pointer == '"') 467260484Sobrien ++input_line_pointer; 467360484Sobrien } 467460484Sobrien } 467560484Sobrien 467660484Sobrien sec = subseg_new (name, (subsegT) exp); 467760484Sobrien 467889857Sobrien ppc_set_current_section (sec); 467960484Sobrien 468060484Sobrien if (flags != SEC_NO_FLAGS) 468160484Sobrien { 468260484Sobrien if (! bfd_set_section_flags (stdoutput, sec, flags)) 468360484Sobrien as_bad (_("error setting flags for \"%s\": %s"), 468460484Sobrien bfd_section_name (stdoutput, sec), 468560484Sobrien bfd_errmsg (bfd_get_error ())); 468660484Sobrien } 468760484Sobrien 468889857Sobrien bfd_set_section_alignment (stdoutput, sec, align); 468960484Sobrien} 469060484Sobrien 469160484Sobrienstatic void 4692218822Sdimppc_pe_function (int ignore ATTRIBUTE_UNUSED) 469360484Sobrien{ 469460484Sobrien char *name; 469560484Sobrien char endc; 469660484Sobrien symbolS *ext_sym; 469760484Sobrien 469860484Sobrien name = input_line_pointer; 469960484Sobrien endc = get_symbol_end (); 470060484Sobrien 470160484Sobrien ext_sym = symbol_find_or_make (name); 470260484Sobrien 470360484Sobrien *input_line_pointer = endc; 470460484Sobrien 470560484Sobrien S_SET_DATA_TYPE (ext_sym, DT_FCN << N_BTSHFT); 470660484Sobrien SF_SET_FUNCTION (ext_sym); 470760484Sobrien SF_SET_PROCESS (ext_sym); 470860484Sobrien coff_add_linesym (ext_sym); 470960484Sobrien 471060484Sobrien demand_empty_rest_of_line (); 471160484Sobrien} 471260484Sobrien 471360484Sobrienstatic void 4714218822Sdimppc_pe_tocd (int ignore ATTRIBUTE_UNUSED) 471560484Sobrien{ 471660484Sobrien if (tocdata_section == 0) 471760484Sobrien { 471860484Sobrien tocdata_section = subseg_new (".tocd", 0); 471989857Sobrien /* FIXME: section flags won't work. */ 472060484Sobrien bfd_set_section_flags (stdoutput, tocdata_section, 472160484Sobrien (SEC_ALLOC | SEC_LOAD | SEC_RELOC 472289857Sobrien | SEC_READONLY | SEC_DATA)); 472360484Sobrien 472460484Sobrien bfd_set_section_alignment (stdoutput, tocdata_section, 2); 472560484Sobrien } 472660484Sobrien else 472760484Sobrien { 472860484Sobrien rdata_section = subseg_new (".tocd", 0); 472960484Sobrien } 473060484Sobrien 473189857Sobrien ppc_set_current_section (tocdata_section); 473260484Sobrien 473360484Sobrien demand_empty_rest_of_line (); 473460484Sobrien} 473560484Sobrien 473660484Sobrien/* Don't adjust TOC relocs to use the section symbol. */ 473760484Sobrien 473860484Sobrienint 4739218822Sdimppc_pe_fix_adjustable (fixS *fix) 474060484Sobrien{ 474160484Sobrien return fix->fx_r_type != BFD_RELOC_PPC_TOC16; 474260484Sobrien} 474360484Sobrien 474460484Sobrien#endif 474560484Sobrien 474660484Sobrien#ifdef OBJ_XCOFF 474760484Sobrien 474860484Sobrien/* XCOFF specific symbol and file handling. */ 474960484Sobrien 475060484Sobrien/* Canonicalize the symbol name. We use the to force the suffix, if 475160484Sobrien any, to use square brackets, and to be in upper case. */ 475260484Sobrien 475360484Sobrienchar * 4754218822Sdimppc_canonicalize_symbol_name (char *name) 475560484Sobrien{ 475660484Sobrien char *s; 475760484Sobrien 475860484Sobrien if (ppc_stab_symbol) 475960484Sobrien return name; 476060484Sobrien 476160484Sobrien for (s = name; *s != '\0' && *s != '{' && *s != '['; s++) 476260484Sobrien ; 476360484Sobrien if (*s != '\0') 476460484Sobrien { 476560484Sobrien char brac; 476660484Sobrien 476760484Sobrien if (*s == '[') 476860484Sobrien brac = ']'; 476960484Sobrien else 477060484Sobrien { 477160484Sobrien *s = '['; 477260484Sobrien brac = '}'; 477360484Sobrien } 477460484Sobrien 477560484Sobrien for (s++; *s != '\0' && *s != brac; s++) 477689857Sobrien *s = TOUPPER (*s); 477760484Sobrien 477860484Sobrien if (*s == '\0' || s[1] != '\0') 477960484Sobrien as_bad (_("bad symbol suffix")); 478060484Sobrien 478160484Sobrien *s = ']'; 478260484Sobrien } 478360484Sobrien 478460484Sobrien return name; 478560484Sobrien} 478660484Sobrien 478760484Sobrien/* Set the class of a symbol based on the suffix, if any. This is 478860484Sobrien called whenever a new symbol is created. */ 478960484Sobrien 479060484Sobrienvoid 4791218822Sdimppc_symbol_new_hook (symbolS *sym) 479260484Sobrien{ 479360484Sobrien struct ppc_tc_sy *tc; 479460484Sobrien const char *s; 479560484Sobrien 479660484Sobrien tc = symbol_get_tc (sym); 479760484Sobrien tc->next = NULL; 479860484Sobrien tc->output = 0; 479960484Sobrien tc->class = -1; 480060484Sobrien tc->real_name = NULL; 480160484Sobrien tc->subseg = 0; 480260484Sobrien tc->align = 0; 480360484Sobrien tc->size = NULL; 480460484Sobrien tc->within = NULL; 480560484Sobrien 480660484Sobrien if (ppc_stab_symbol) 480760484Sobrien return; 480860484Sobrien 480960484Sobrien s = strchr (S_GET_NAME (sym), '['); 481060484Sobrien if (s == (const char *) NULL) 481160484Sobrien { 481260484Sobrien /* There is no suffix. */ 481360484Sobrien return; 481460484Sobrien } 481560484Sobrien 481660484Sobrien ++s; 481760484Sobrien 481860484Sobrien switch (s[0]) 481960484Sobrien { 482060484Sobrien case 'B': 482160484Sobrien if (strcmp (s, "BS]") == 0) 482260484Sobrien tc->class = XMC_BS; 482360484Sobrien break; 482460484Sobrien case 'D': 482560484Sobrien if (strcmp (s, "DB]") == 0) 482660484Sobrien tc->class = XMC_DB; 482760484Sobrien else if (strcmp (s, "DS]") == 0) 482860484Sobrien tc->class = XMC_DS; 482960484Sobrien break; 483060484Sobrien case 'G': 483160484Sobrien if (strcmp (s, "GL]") == 0) 483260484Sobrien tc->class = XMC_GL; 483360484Sobrien break; 483460484Sobrien case 'P': 483560484Sobrien if (strcmp (s, "PR]") == 0) 483660484Sobrien tc->class = XMC_PR; 483760484Sobrien break; 483860484Sobrien case 'R': 483960484Sobrien if (strcmp (s, "RO]") == 0) 484060484Sobrien tc->class = XMC_RO; 484160484Sobrien else if (strcmp (s, "RW]") == 0) 484260484Sobrien tc->class = XMC_RW; 484360484Sobrien break; 484460484Sobrien case 'S': 484560484Sobrien if (strcmp (s, "SV]") == 0) 484660484Sobrien tc->class = XMC_SV; 484760484Sobrien break; 484860484Sobrien case 'T': 484960484Sobrien if (strcmp (s, "TC]") == 0) 485060484Sobrien tc->class = XMC_TC; 485160484Sobrien else if (strcmp (s, "TI]") == 0) 485260484Sobrien tc->class = XMC_TI; 485360484Sobrien else if (strcmp (s, "TB]") == 0) 485460484Sobrien tc->class = XMC_TB; 485560484Sobrien else if (strcmp (s, "TC0]") == 0 || strcmp (s, "T0]") == 0) 485660484Sobrien tc->class = XMC_TC0; 485760484Sobrien break; 485860484Sobrien case 'U': 485960484Sobrien if (strcmp (s, "UA]") == 0) 486060484Sobrien tc->class = XMC_UA; 486160484Sobrien else if (strcmp (s, "UC]") == 0) 486260484Sobrien tc->class = XMC_UC; 486360484Sobrien break; 486460484Sobrien case 'X': 486560484Sobrien if (strcmp (s, "XO]") == 0) 486660484Sobrien tc->class = XMC_XO; 486760484Sobrien break; 486860484Sobrien } 486960484Sobrien 487060484Sobrien if (tc->class == -1) 487160484Sobrien as_bad (_("Unrecognized symbol suffix")); 487260484Sobrien} 487360484Sobrien 487460484Sobrien/* Set the class of a label based on where it is defined. This 487560484Sobrien handles symbols without suffixes. Also, move the symbol so that it 487660484Sobrien follows the csect symbol. */ 487760484Sobrien 487860484Sobrienvoid 4879218822Sdimppc_frob_label (symbolS *sym) 488060484Sobrien{ 488160484Sobrien if (ppc_current_csect != (symbolS *) NULL) 488260484Sobrien { 488360484Sobrien if (symbol_get_tc (sym)->class == -1) 488460484Sobrien symbol_get_tc (sym)->class = symbol_get_tc (ppc_current_csect)->class; 488560484Sobrien 488660484Sobrien symbol_remove (sym, &symbol_rootP, &symbol_lastP); 488760484Sobrien symbol_append (sym, symbol_get_tc (ppc_current_csect)->within, 488860484Sobrien &symbol_rootP, &symbol_lastP); 488960484Sobrien symbol_get_tc (ppc_current_csect)->within = sym; 489060484Sobrien } 4891218822Sdim 4892218822Sdim#ifdef OBJ_ELF 4893218822Sdim dwarf2_emit_label (sym); 4894218822Sdim#endif 489560484Sobrien} 489660484Sobrien 489760484Sobrien/* This variable is set by ppc_frob_symbol if any absolute symbols are 489860484Sobrien seen. It tells ppc_adjust_symtab whether it needs to look through 489960484Sobrien the symbols. */ 490060484Sobrien 4901130561Sobrienstatic bfd_boolean ppc_saw_abs; 490260484Sobrien 490360484Sobrien/* Change the name of a symbol just before writing it out. Set the 490460484Sobrien real name if the .rename pseudo-op was used. Otherwise, remove any 490560484Sobrien class suffix. Return 1 if the symbol should not be included in the 490660484Sobrien symbol table. */ 490760484Sobrien 490860484Sobrienint 4909218822Sdimppc_frob_symbol (symbolS *sym) 491060484Sobrien{ 491160484Sobrien static symbolS *ppc_last_function; 491260484Sobrien static symbolS *set_end; 491360484Sobrien 491460484Sobrien /* Discard symbols that should not be included in the output symbol 491560484Sobrien table. */ 491660484Sobrien if (! symbol_used_in_reloc_p (sym) 491760484Sobrien && ((symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) != 0 4918218822Sdim || (! (S_IS_EXTERNAL (sym) || S_IS_WEAK (sym)) 491960484Sobrien && ! symbol_get_tc (sym)->output 492060484Sobrien && S_GET_STORAGE_CLASS (sym) != C_FILE))) 492160484Sobrien return 1; 492260484Sobrien 4923130561Sobrien /* This one will disappear anyway. Don't make a csect sym for it. */ 4924130561Sobrien if (sym == abs_section_sym) 4925130561Sobrien return 1; 4926130561Sobrien 492760484Sobrien if (symbol_get_tc (sym)->real_name != (char *) NULL) 492860484Sobrien S_SET_NAME (sym, symbol_get_tc (sym)->real_name); 492960484Sobrien else 493060484Sobrien { 493160484Sobrien const char *name; 493260484Sobrien const char *s; 493360484Sobrien 493460484Sobrien name = S_GET_NAME (sym); 493560484Sobrien s = strchr (name, '['); 493660484Sobrien if (s != (char *) NULL) 493760484Sobrien { 493860484Sobrien unsigned int len; 493960484Sobrien char *snew; 494060484Sobrien 494160484Sobrien len = s - name; 494260484Sobrien snew = xmalloc (len + 1); 494360484Sobrien memcpy (snew, name, len); 494460484Sobrien snew[len] = '\0'; 494560484Sobrien 494660484Sobrien S_SET_NAME (sym, snew); 494760484Sobrien } 494860484Sobrien } 494960484Sobrien 495060484Sobrien if (set_end != (symbolS *) NULL) 495160484Sobrien { 495260484Sobrien SA_SET_SYM_ENDNDX (set_end, sym); 495360484Sobrien set_end = NULL; 495460484Sobrien } 495560484Sobrien 495660484Sobrien if (SF_GET_FUNCTION (sym)) 495760484Sobrien { 495860484Sobrien if (ppc_last_function != (symbolS *) NULL) 495960484Sobrien as_bad (_("two .function pseudo-ops with no intervening .ef")); 496060484Sobrien ppc_last_function = sym; 496160484Sobrien if (symbol_get_tc (sym)->size != (symbolS *) NULL) 496260484Sobrien { 496389857Sobrien resolve_symbol_value (symbol_get_tc (sym)->size); 496460484Sobrien SA_SET_SYM_FSIZE (sym, 496560484Sobrien (long) S_GET_VALUE (symbol_get_tc (sym)->size)); 496660484Sobrien } 496760484Sobrien } 496860484Sobrien else if (S_GET_STORAGE_CLASS (sym) == C_FCN 496960484Sobrien && strcmp (S_GET_NAME (sym), ".ef") == 0) 497060484Sobrien { 497160484Sobrien if (ppc_last_function == (symbolS *) NULL) 497260484Sobrien as_bad (_(".ef with no preceding .function")); 497360484Sobrien else 497460484Sobrien { 497560484Sobrien set_end = ppc_last_function; 497660484Sobrien ppc_last_function = NULL; 497760484Sobrien 497860484Sobrien /* We don't have a C_EFCN symbol, but we need to force the 497960484Sobrien COFF backend to believe that it has seen one. */ 498060484Sobrien coff_last_function = NULL; 498160484Sobrien } 498260484Sobrien } 498360484Sobrien 4984218822Sdim if (! (S_IS_EXTERNAL (sym) || S_IS_WEAK (sym)) 498560484Sobrien && (symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) == 0 498660484Sobrien && S_GET_STORAGE_CLASS (sym) != C_FILE 498760484Sobrien && S_GET_STORAGE_CLASS (sym) != C_FCN 498860484Sobrien && S_GET_STORAGE_CLASS (sym) != C_BLOCK 498960484Sobrien && S_GET_STORAGE_CLASS (sym) != C_BSTAT 499060484Sobrien && S_GET_STORAGE_CLASS (sym) != C_ESTAT 499160484Sobrien && S_GET_STORAGE_CLASS (sym) != C_BINCL 499260484Sobrien && S_GET_STORAGE_CLASS (sym) != C_EINCL 499360484Sobrien && S_GET_SEGMENT (sym) != ppc_coff_debug_section) 499460484Sobrien S_SET_STORAGE_CLASS (sym, C_HIDEXT); 499560484Sobrien 499660484Sobrien if (S_GET_STORAGE_CLASS (sym) == C_EXT 499760484Sobrien || S_GET_STORAGE_CLASS (sym) == C_HIDEXT) 499860484Sobrien { 499960484Sobrien int i; 500060484Sobrien union internal_auxent *a; 500160484Sobrien 500260484Sobrien /* Create a csect aux. */ 500360484Sobrien i = S_GET_NUMBER_AUXILIARY (sym); 500460484Sobrien S_SET_NUMBER_AUXILIARY (sym, i + 1); 500560484Sobrien a = &coffsymbol (symbol_get_bfdsym (sym))->native[i + 1].u.auxent; 500660484Sobrien if (symbol_get_tc (sym)->class == XMC_TC0) 500760484Sobrien { 500860484Sobrien /* This is the TOC table. */ 500960484Sobrien know (strcmp (S_GET_NAME (sym), "TOC") == 0); 501060484Sobrien a->x_csect.x_scnlen.l = 0; 501160484Sobrien a->x_csect.x_smtyp = (2 << 3) | XTY_SD; 501260484Sobrien } 501360484Sobrien else if (symbol_get_tc (sym)->subseg != 0) 501460484Sobrien { 501560484Sobrien /* This is a csect symbol. x_scnlen is the size of the 501660484Sobrien csect. */ 501760484Sobrien if (symbol_get_tc (sym)->next == (symbolS *) NULL) 501860484Sobrien a->x_csect.x_scnlen.l = (bfd_section_size (stdoutput, 501960484Sobrien S_GET_SEGMENT (sym)) 502060484Sobrien - S_GET_VALUE (sym)); 502160484Sobrien else 502260484Sobrien { 502389857Sobrien resolve_symbol_value (symbol_get_tc (sym)->next); 502460484Sobrien a->x_csect.x_scnlen.l = (S_GET_VALUE (symbol_get_tc (sym)->next) 502560484Sobrien - S_GET_VALUE (sym)); 502660484Sobrien } 502760484Sobrien a->x_csect.x_smtyp = (symbol_get_tc (sym)->align << 3) | XTY_SD; 502860484Sobrien } 502960484Sobrien else if (S_GET_SEGMENT (sym) == bss_section) 503060484Sobrien { 503160484Sobrien /* This is a common symbol. */ 503260484Sobrien a->x_csect.x_scnlen.l = symbol_get_frag (sym)->fr_offset; 503360484Sobrien a->x_csect.x_smtyp = (symbol_get_tc (sym)->align << 3) | XTY_CM; 503460484Sobrien if (S_IS_EXTERNAL (sym)) 503560484Sobrien symbol_get_tc (sym)->class = XMC_RW; 503660484Sobrien else 503760484Sobrien symbol_get_tc (sym)->class = XMC_BS; 503860484Sobrien } 503960484Sobrien else if (S_GET_SEGMENT (sym) == absolute_section) 504060484Sobrien { 504160484Sobrien /* This is an absolute symbol. The csect will be created by 504289857Sobrien ppc_adjust_symtab. */ 5043130561Sobrien ppc_saw_abs = TRUE; 504460484Sobrien a->x_csect.x_smtyp = XTY_LD; 504560484Sobrien if (symbol_get_tc (sym)->class == -1) 504660484Sobrien symbol_get_tc (sym)->class = XMC_XO; 504760484Sobrien } 504860484Sobrien else if (! S_IS_DEFINED (sym)) 504960484Sobrien { 505060484Sobrien /* This is an external symbol. */ 505160484Sobrien a->x_csect.x_scnlen.l = 0; 505260484Sobrien a->x_csect.x_smtyp = XTY_ER; 505360484Sobrien } 505460484Sobrien else if (symbol_get_tc (sym)->class == XMC_TC) 505560484Sobrien { 505660484Sobrien symbolS *next; 505760484Sobrien 505860484Sobrien /* This is a TOC definition. x_scnlen is the size of the 505960484Sobrien TOC entry. */ 506060484Sobrien next = symbol_next (sym); 506160484Sobrien while (symbol_get_tc (next)->class == XMC_TC0) 506260484Sobrien next = symbol_next (next); 506360484Sobrien if (next == (symbolS *) NULL 506460484Sobrien || symbol_get_tc (next)->class != XMC_TC) 506560484Sobrien { 506660484Sobrien if (ppc_after_toc_frag == (fragS *) NULL) 506760484Sobrien a->x_csect.x_scnlen.l = (bfd_section_size (stdoutput, 506860484Sobrien data_section) 506960484Sobrien - S_GET_VALUE (sym)); 507060484Sobrien else 507160484Sobrien a->x_csect.x_scnlen.l = (ppc_after_toc_frag->fr_address 507260484Sobrien - S_GET_VALUE (sym)); 507360484Sobrien } 507460484Sobrien else 507560484Sobrien { 507689857Sobrien resolve_symbol_value (next); 507760484Sobrien a->x_csect.x_scnlen.l = (S_GET_VALUE (next) 507860484Sobrien - S_GET_VALUE (sym)); 507960484Sobrien } 508060484Sobrien a->x_csect.x_smtyp = (2 << 3) | XTY_SD; 508160484Sobrien } 508260484Sobrien else 508360484Sobrien { 508460484Sobrien symbolS *csect; 508560484Sobrien 508660484Sobrien /* This is a normal symbol definition. x_scnlen is the 508760484Sobrien symbol index of the containing csect. */ 508860484Sobrien if (S_GET_SEGMENT (sym) == text_section) 508960484Sobrien csect = ppc_text_csects; 509060484Sobrien else if (S_GET_SEGMENT (sym) == data_section) 509160484Sobrien csect = ppc_data_csects; 509260484Sobrien else 509360484Sobrien abort (); 509460484Sobrien 509560484Sobrien /* Skip the initial dummy symbol. */ 509660484Sobrien csect = symbol_get_tc (csect)->next; 509760484Sobrien 509860484Sobrien if (csect == (symbolS *) NULL) 509960484Sobrien { 510060484Sobrien as_warn (_("warning: symbol %s has no csect"), S_GET_NAME (sym)); 510160484Sobrien a->x_csect.x_scnlen.l = 0; 510260484Sobrien } 510360484Sobrien else 510460484Sobrien { 510560484Sobrien while (symbol_get_tc (csect)->next != (symbolS *) NULL) 510660484Sobrien { 510789857Sobrien resolve_symbol_value (symbol_get_tc (csect)->next); 510860484Sobrien if (S_GET_VALUE (symbol_get_tc (csect)->next) 510960484Sobrien > S_GET_VALUE (sym)) 511060484Sobrien break; 511160484Sobrien csect = symbol_get_tc (csect)->next; 511260484Sobrien } 511360484Sobrien 511460484Sobrien a->x_csect.x_scnlen.p = 511560484Sobrien coffsymbol (symbol_get_bfdsym (csect))->native; 511660484Sobrien coffsymbol (symbol_get_bfdsym (sym))->native[i + 1].fix_scnlen = 511760484Sobrien 1; 511860484Sobrien } 511960484Sobrien a->x_csect.x_smtyp = XTY_LD; 512060484Sobrien } 512177298Sobrien 512260484Sobrien a->x_csect.x_parmhash = 0; 512360484Sobrien a->x_csect.x_snhash = 0; 512460484Sobrien if (symbol_get_tc (sym)->class == -1) 512560484Sobrien a->x_csect.x_smclas = XMC_PR; 512660484Sobrien else 512760484Sobrien a->x_csect.x_smclas = symbol_get_tc (sym)->class; 512860484Sobrien a->x_csect.x_stab = 0; 512960484Sobrien a->x_csect.x_snstab = 0; 513060484Sobrien 513160484Sobrien /* Don't let the COFF backend resort these symbols. */ 513260484Sobrien symbol_get_bfdsym (sym)->flags |= BSF_NOT_AT_END; 513360484Sobrien } 513460484Sobrien else if (S_GET_STORAGE_CLASS (sym) == C_BSTAT) 513560484Sobrien { 513660484Sobrien /* We want the value to be the symbol index of the referenced 513760484Sobrien csect symbol. BFD will do that for us if we set the right 513860484Sobrien flags. */ 5139130561Sobrien asymbol *bsym = symbol_get_bfdsym (symbol_get_tc (sym)->within); 5140130561Sobrien combined_entry_type *c = coffsymbol (bsym)->native; 5141130561Sobrien 5142130561Sobrien S_SET_VALUE (sym, (valueT) (size_t) c); 514360484Sobrien coffsymbol (symbol_get_bfdsym (sym))->native->fix_value = 1; 514460484Sobrien } 514560484Sobrien else if (S_GET_STORAGE_CLASS (sym) == C_STSYM) 514660484Sobrien { 514760484Sobrien symbolS *block; 514860484Sobrien symbolS *csect; 514960484Sobrien 515060484Sobrien /* The value is the offset from the enclosing csect. */ 515160484Sobrien block = symbol_get_tc (sym)->within; 515260484Sobrien csect = symbol_get_tc (block)->within; 515389857Sobrien resolve_symbol_value (csect); 515460484Sobrien S_SET_VALUE (sym, S_GET_VALUE (sym) - S_GET_VALUE (csect)); 515560484Sobrien } 515660484Sobrien else if (S_GET_STORAGE_CLASS (sym) == C_BINCL 515760484Sobrien || S_GET_STORAGE_CLASS (sym) == C_EINCL) 515860484Sobrien { 515960484Sobrien /* We want the value to be a file offset into the line numbers. 516089857Sobrien BFD will do that for us if we set the right flags. We have 516189857Sobrien already set the value correctly. */ 516260484Sobrien coffsymbol (symbol_get_bfdsym (sym))->native->fix_line = 1; 516360484Sobrien } 516460484Sobrien 516560484Sobrien return 0; 516660484Sobrien} 516760484Sobrien 516860484Sobrien/* Adjust the symbol table. This creates csect symbols for all 516960484Sobrien absolute symbols. */ 517060484Sobrien 517160484Sobrienvoid 5172218822Sdimppc_adjust_symtab (void) 517360484Sobrien{ 517460484Sobrien symbolS *sym; 517560484Sobrien 517660484Sobrien if (! ppc_saw_abs) 517760484Sobrien return; 517860484Sobrien 517960484Sobrien for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym)) 518060484Sobrien { 518160484Sobrien symbolS *csect; 518260484Sobrien int i; 518360484Sobrien union internal_auxent *a; 518460484Sobrien 518560484Sobrien if (S_GET_SEGMENT (sym) != absolute_section) 518660484Sobrien continue; 518760484Sobrien 518860484Sobrien csect = symbol_create (".abs[XO]", absolute_section, 518960484Sobrien S_GET_VALUE (sym), &zero_address_frag); 519060484Sobrien symbol_get_bfdsym (csect)->value = S_GET_VALUE (sym); 519160484Sobrien S_SET_STORAGE_CLASS (csect, C_HIDEXT); 519260484Sobrien i = S_GET_NUMBER_AUXILIARY (csect); 519360484Sobrien S_SET_NUMBER_AUXILIARY (csect, i + 1); 519460484Sobrien a = &coffsymbol (symbol_get_bfdsym (csect))->native[i + 1].u.auxent; 519560484Sobrien a->x_csect.x_scnlen.l = 0; 519660484Sobrien a->x_csect.x_smtyp = XTY_SD; 519760484Sobrien a->x_csect.x_parmhash = 0; 519860484Sobrien a->x_csect.x_snhash = 0; 519960484Sobrien a->x_csect.x_smclas = XMC_XO; 520060484Sobrien a->x_csect.x_stab = 0; 520160484Sobrien a->x_csect.x_snstab = 0; 520260484Sobrien 520360484Sobrien symbol_insert (csect, sym, &symbol_rootP, &symbol_lastP); 520460484Sobrien 520560484Sobrien i = S_GET_NUMBER_AUXILIARY (sym); 520660484Sobrien a = &coffsymbol (symbol_get_bfdsym (sym))->native[i].u.auxent; 520760484Sobrien a->x_csect.x_scnlen.p = coffsymbol (symbol_get_bfdsym (csect))->native; 520860484Sobrien coffsymbol (symbol_get_bfdsym (sym))->native[i].fix_scnlen = 1; 520960484Sobrien } 521060484Sobrien 5211130561Sobrien ppc_saw_abs = FALSE; 521260484Sobrien} 521360484Sobrien 521460484Sobrien/* Set the VMA for a section. This is called on all the sections in 521560484Sobrien turn. */ 521660484Sobrien 521760484Sobrienvoid 5218218822Sdimppc_frob_section (asection *sec) 521960484Sobrien{ 5220130561Sobrien static bfd_vma vma = 0; 522160484Sobrien 5222130561Sobrien vma = md_section_align (sec, vma); 522360484Sobrien bfd_set_section_vma (stdoutput, sec, vma); 522460484Sobrien vma += bfd_section_size (stdoutput, sec); 522560484Sobrien} 522660484Sobrien 522760484Sobrien#endif /* OBJ_XCOFF */ 522860484Sobrien 522960484Sobrien/* Turn a string in input_line_pointer into a floating point constant 523077298Sobrien of type TYPE, and store the appropriate bytes in *LITP. The number 523177298Sobrien of LITTLENUMS emitted is stored in *SIZEP. An error message is 523260484Sobrien returned, or NULL on OK. */ 523360484Sobrien 523460484Sobrienchar * 5235218822Sdimmd_atof (int type, char *litp, int *sizep) 523660484Sobrien{ 523760484Sobrien int prec; 523860484Sobrien LITTLENUM_TYPE words[4]; 523960484Sobrien char *t; 524060484Sobrien int i; 524160484Sobrien 524260484Sobrien switch (type) 524360484Sobrien { 524460484Sobrien case 'f': 524560484Sobrien prec = 2; 524660484Sobrien break; 524760484Sobrien 524860484Sobrien case 'd': 524960484Sobrien prec = 4; 525060484Sobrien break; 525160484Sobrien 525260484Sobrien default: 525360484Sobrien *sizep = 0; 525460484Sobrien return _("bad call to md_atof"); 525560484Sobrien } 525660484Sobrien 525760484Sobrien t = atof_ieee (input_line_pointer, type, words); 525860484Sobrien if (t) 525960484Sobrien input_line_pointer = t; 526060484Sobrien 526160484Sobrien *sizep = prec * 2; 526260484Sobrien 526360484Sobrien if (target_big_endian) 526460484Sobrien { 526560484Sobrien for (i = 0; i < prec; i++) 526660484Sobrien { 526760484Sobrien md_number_to_chars (litp, (valueT) words[i], 2); 526860484Sobrien litp += 2; 526960484Sobrien } 527060484Sobrien } 527160484Sobrien else 527260484Sobrien { 527360484Sobrien for (i = prec - 1; i >= 0; i--) 527460484Sobrien { 527560484Sobrien md_number_to_chars (litp, (valueT) words[i], 2); 527660484Sobrien litp += 2; 527760484Sobrien } 527860484Sobrien } 527977298Sobrien 528060484Sobrien return NULL; 528160484Sobrien} 528260484Sobrien 528360484Sobrien/* Write a value out to the object file, using the appropriate 528460484Sobrien endianness. */ 528560484Sobrien 528660484Sobrienvoid 5287218822Sdimmd_number_to_chars (char *buf, valueT val, int n) 528860484Sobrien{ 528960484Sobrien if (target_big_endian) 529060484Sobrien number_to_chars_bigendian (buf, val, n); 529160484Sobrien else 529260484Sobrien number_to_chars_littleendian (buf, val, n); 529360484Sobrien} 529460484Sobrien 529560484Sobrien/* Align a section (I don't know why this is machine dependent). */ 529660484Sobrien 529760484SobrienvalueT 5298218822Sdimmd_section_align (asection *seg ATTRIBUTE_UNUSED, valueT addr) 529960484Sobrien{ 5300218822Sdim#ifdef OBJ_ELF 5301218822Sdim return addr; 5302218822Sdim#else 530360484Sobrien int align = bfd_get_section_alignment (stdoutput, seg); 530460484Sobrien 530560484Sobrien return ((addr + (1 << align) - 1) & (-1 << align)); 5306218822Sdim#endif 530760484Sobrien} 530860484Sobrien 530960484Sobrien/* We don't have any form of relaxing. */ 531060484Sobrien 531160484Sobrienint 5312218822Sdimmd_estimate_size_before_relax (fragS *fragp ATTRIBUTE_UNUSED, 5313218822Sdim asection *seg ATTRIBUTE_UNUSED) 531460484Sobrien{ 531560484Sobrien abort (); 531660484Sobrien return 0; 531760484Sobrien} 531860484Sobrien 531960484Sobrien/* Convert a machine dependent frag. We never generate these. */ 532060484Sobrien 532160484Sobrienvoid 5322218822Sdimmd_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, 5323218822Sdim asection *sec ATTRIBUTE_UNUSED, 5324218822Sdim fragS *fragp ATTRIBUTE_UNUSED) 532560484Sobrien{ 532660484Sobrien abort (); 532760484Sobrien} 532860484Sobrien 532960484Sobrien/* We have no need to default values of symbols. */ 533060484Sobrien 533160484SobriensymbolS * 5332218822Sdimmd_undefined_symbol (char *name ATTRIBUTE_UNUSED) 533360484Sobrien{ 533460484Sobrien return 0; 533560484Sobrien} 533660484Sobrien 533760484Sobrien/* Functions concerning relocs. */ 533860484Sobrien 533960484Sobrien/* The location from which a PC relative jump should be calculated, 534060484Sobrien given a PC relative reloc. */ 534160484Sobrien 534260484Sobrienlong 5343218822Sdimmd_pcrel_from_section (fixS *fixp, segT sec ATTRIBUTE_UNUSED) 534460484Sobrien{ 534560484Sobrien return fixp->fx_frag->fr_address + fixp->fx_where; 534660484Sobrien} 534760484Sobrien 534860484Sobrien#ifdef OBJ_XCOFF 534960484Sobrien 535060484Sobrien/* This is called to see whether a fixup should be adjusted to use a 535160484Sobrien section symbol. We take the opportunity to change a fixup against 535260484Sobrien a symbol in the TOC subsegment into a reloc against the 535360484Sobrien corresponding .tc symbol. */ 535460484Sobrien 535560484Sobrienint 5356218822Sdimppc_fix_adjustable (fixS *fix) 535760484Sobrien{ 5358130561Sobrien valueT val = resolve_symbol_value (fix->fx_addsy); 5359130561Sobrien segT symseg = S_GET_SEGMENT (fix->fx_addsy); 5360130561Sobrien TC_SYMFIELD_TYPE *tc; 536160484Sobrien 5362130561Sobrien if (symseg == absolute_section) 5363130561Sobrien return 0; 5364130561Sobrien 536560484Sobrien if (ppc_toc_csect != (symbolS *) NULL 536660484Sobrien && fix->fx_addsy != ppc_toc_csect 5367130561Sobrien && symseg == data_section 536860484Sobrien && val >= ppc_toc_frag->fr_address 536960484Sobrien && (ppc_after_toc_frag == (fragS *) NULL 537060484Sobrien || val < ppc_after_toc_frag->fr_address)) 537160484Sobrien { 537260484Sobrien symbolS *sy; 537360484Sobrien 537460484Sobrien for (sy = symbol_next (ppc_toc_csect); 537560484Sobrien sy != (symbolS *) NULL; 537660484Sobrien sy = symbol_next (sy)) 537760484Sobrien { 5378130561Sobrien TC_SYMFIELD_TYPE *sy_tc = symbol_get_tc (sy); 5379130561Sobrien 5380130561Sobrien if (sy_tc->class == XMC_TC0) 538160484Sobrien continue; 5382130561Sobrien if (sy_tc->class != XMC_TC) 538360484Sobrien break; 5384130561Sobrien if (val == resolve_symbol_value (sy)) 538560484Sobrien { 538660484Sobrien fix->fx_addsy = sy; 538760484Sobrien fix->fx_addnumber = val - ppc_toc_frag->fr_address; 538860484Sobrien return 0; 538960484Sobrien } 539060484Sobrien } 539160484Sobrien 539260484Sobrien as_bad_where (fix->fx_file, fix->fx_line, 539360484Sobrien _("symbol in .toc does not match any .tc")); 539460484Sobrien } 539560484Sobrien 539660484Sobrien /* Possibly adjust the reloc to be against the csect. */ 5397130561Sobrien tc = symbol_get_tc (fix->fx_addsy); 5398130561Sobrien if (tc->subseg == 0 5399130561Sobrien && tc->class != XMC_TC0 5400130561Sobrien && tc->class != XMC_TC 5401130561Sobrien && symseg != bss_section 540260484Sobrien /* Don't adjust if this is a reloc in the toc section. */ 5403130561Sobrien && (symseg != data_section 540460484Sobrien || ppc_toc_csect == NULL 540560484Sobrien || val < ppc_toc_frag->fr_address 540660484Sobrien || (ppc_after_toc_frag != NULL 540760484Sobrien && val >= ppc_after_toc_frag->fr_address))) 540860484Sobrien { 540960484Sobrien symbolS *csect; 5410130561Sobrien symbolS *next_csect; 541160484Sobrien 5412130561Sobrien if (symseg == text_section) 541360484Sobrien csect = ppc_text_csects; 5414130561Sobrien else if (symseg == data_section) 541560484Sobrien csect = ppc_data_csects; 541660484Sobrien else 541760484Sobrien abort (); 541860484Sobrien 541960484Sobrien /* Skip the initial dummy symbol. */ 542060484Sobrien csect = symbol_get_tc (csect)->next; 542160484Sobrien 542260484Sobrien if (csect != (symbolS *) NULL) 542360484Sobrien { 5424130561Sobrien while ((next_csect = symbol_get_tc (csect)->next) != (symbolS *) NULL 5425130561Sobrien && (symbol_get_frag (next_csect)->fr_address <= val)) 542660484Sobrien { 542760484Sobrien /* If the csect address equals the symbol value, then we 542889857Sobrien have to look through the full symbol table to see 542989857Sobrien whether this is the csect we want. Note that we will 543089857Sobrien only get here if the csect has zero length. */ 5431130561Sobrien if (symbol_get_frag (csect)->fr_address == val 5432130561Sobrien && S_GET_VALUE (csect) == val) 543360484Sobrien { 543460484Sobrien symbolS *scan; 543560484Sobrien 543660484Sobrien for (scan = symbol_next (csect); 543760484Sobrien scan != NULL; 543860484Sobrien scan = symbol_next (scan)) 543960484Sobrien { 544060484Sobrien if (symbol_get_tc (scan)->subseg != 0) 544160484Sobrien break; 544260484Sobrien if (scan == fix->fx_addsy) 544360484Sobrien break; 544460484Sobrien } 544560484Sobrien 544660484Sobrien /* If we found the symbol before the next csect 544789857Sobrien symbol, then this is the csect we want. */ 544860484Sobrien if (scan == fix->fx_addsy) 544960484Sobrien break; 545060484Sobrien } 545160484Sobrien 5452130561Sobrien csect = next_csect; 545360484Sobrien } 545460484Sobrien 5455130561Sobrien fix->fx_offset += val - symbol_get_frag (csect)->fr_address; 545660484Sobrien fix->fx_addsy = csect; 545760484Sobrien } 5458130561Sobrien return 0; 545960484Sobrien } 546060484Sobrien 546160484Sobrien /* Adjust a reloc against a .lcomm symbol to be against the base 546260484Sobrien .lcomm. */ 5463130561Sobrien if (symseg == bss_section 546460484Sobrien && ! S_IS_EXTERNAL (fix->fx_addsy)) 546560484Sobrien { 5466130561Sobrien symbolS *sy = symbol_get_frag (fix->fx_addsy)->fr_symbol; 5467130561Sobrien 5468130561Sobrien fix->fx_offset += val - resolve_symbol_value (sy); 5469130561Sobrien fix->fx_addsy = sy; 547060484Sobrien } 547160484Sobrien 547260484Sobrien return 0; 547360484Sobrien} 547460484Sobrien 547560484Sobrien/* A reloc from one csect to another must be kept. The assembler 547660484Sobrien will, of course, keep relocs between sections, and it will keep 547760484Sobrien absolute relocs, but we need to force it to keep PC relative relocs 547860484Sobrien between two csects in the same section. */ 547960484Sobrien 548060484Sobrienint 5481218822Sdimppc_force_relocation (fixS *fix) 548260484Sobrien{ 548360484Sobrien /* At this point fix->fx_addsy should already have been converted to 548460484Sobrien a csect symbol. If the csect does not include the fragment, then 548560484Sobrien we need to force the relocation. */ 548660484Sobrien if (fix->fx_pcrel 548760484Sobrien && fix->fx_addsy != NULL 548860484Sobrien && symbol_get_tc (fix->fx_addsy)->subseg != 0 548960484Sobrien && ((symbol_get_frag (fix->fx_addsy)->fr_address 549060484Sobrien > fix->fx_frag->fr_address) 549160484Sobrien || (symbol_get_tc (fix->fx_addsy)->next != NULL 549260484Sobrien && (symbol_get_frag (symbol_get_tc (fix->fx_addsy)->next)->fr_address 549360484Sobrien <= fix->fx_frag->fr_address)))) 549460484Sobrien return 1; 549560484Sobrien 5496130561Sobrien return generic_force_reloc (fix); 549760484Sobrien} 549860484Sobrien 549960484Sobrien#endif /* OBJ_XCOFF */ 550060484Sobrien 550189857Sobrien#ifdef OBJ_ELF 5502130561Sobrien/* If this function returns non-zero, it guarantees that a relocation 5503130561Sobrien will be emitted for a fixup. */ 5504130561Sobrien 550589857Sobrienint 5506218822Sdimppc_force_relocation (fixS *fix) 5507130561Sobrien{ 5508130561Sobrien /* Branch prediction relocations must force a relocation, as must 5509130561Sobrien the vtable description relocs. */ 5510130561Sobrien switch (fix->fx_r_type) 5511130561Sobrien { 5512130561Sobrien case BFD_RELOC_PPC_B16_BRTAKEN: 5513130561Sobrien case BFD_RELOC_PPC_B16_BRNTAKEN: 5514130561Sobrien case BFD_RELOC_PPC_BA16_BRTAKEN: 5515130561Sobrien case BFD_RELOC_PPC_BA16_BRNTAKEN: 5516218822Sdim case BFD_RELOC_24_PLT_PCREL: 5517130561Sobrien case BFD_RELOC_PPC64_TOC: 5518130561Sobrien return 1; 5519130561Sobrien default: 5520130561Sobrien break; 5521130561Sobrien } 5522130561Sobrien 5523130561Sobrien if (fix->fx_r_type >= BFD_RELOC_PPC_TLS 5524130561Sobrien && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA) 5525130561Sobrien return 1; 5526130561Sobrien 5527130561Sobrien return generic_force_reloc (fix); 5528130561Sobrien} 5529130561Sobrien 5530130561Sobrienint 5531218822Sdimppc_fix_adjustable (fixS *fix) 553260484Sobrien{ 553389857Sobrien return (fix->fx_r_type != BFD_RELOC_16_GOTOFF 553489857Sobrien && fix->fx_r_type != BFD_RELOC_LO16_GOTOFF 553589857Sobrien && fix->fx_r_type != BFD_RELOC_HI16_GOTOFF 553689857Sobrien && fix->fx_r_type != BFD_RELOC_HI16_S_GOTOFF 553789857Sobrien && fix->fx_r_type != BFD_RELOC_GPREL16 553889857Sobrien && fix->fx_r_type != BFD_RELOC_VTABLE_INHERIT 553989857Sobrien && fix->fx_r_type != BFD_RELOC_VTABLE_ENTRY 5540130561Sobrien && !(fix->fx_r_type >= BFD_RELOC_PPC_TLS 5541218822Sdim && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA)); 554289857Sobrien} 554360484Sobrien#endif 554460484Sobrien 5545218822Sdim/* Implement HANDLE_ALIGN. This writes the NOP pattern into an 5546218822Sdim rs_align_code frag. */ 5547218822Sdim 5548218822Sdimvoid 5549218822Sdimppc_handle_align (struct frag *fragP) 5550218822Sdim{ 5551218822Sdim valueT count = (fragP->fr_next->fr_address 5552218822Sdim - (fragP->fr_address + fragP->fr_fix)); 5553218822Sdim 5554218822Sdim if (count != 0 && (count & 3) == 0) 5555218822Sdim { 5556218822Sdim char *dest = fragP->fr_literal + fragP->fr_fix; 5557218822Sdim 5558218822Sdim fragP->fr_var = 4; 5559218822Sdim md_number_to_chars (dest, 0x60000000, 4); 5560218822Sdim 5561218822Sdim if ((ppc_cpu & PPC_OPCODE_POWER6) != 0) 5562218822Sdim { 5563218822Sdim /* For power6, we want the last nop to be a group terminating 5564218822Sdim one, "ori 1,1,0". Do this by inserting an rs_fill frag 5565218822Sdim immediately after this one, with its address set to the last 5566218822Sdim nop location. This will automatically reduce the number of 5567218822Sdim nops in the current frag by one. */ 5568218822Sdim if (count > 4) 5569218822Sdim { 5570218822Sdim struct frag *group_nop = xmalloc (SIZEOF_STRUCT_FRAG + 4); 5571218822Sdim 5572218822Sdim memcpy (group_nop, fragP, SIZEOF_STRUCT_FRAG); 5573218822Sdim group_nop->fr_address = group_nop->fr_next->fr_address - 4; 5574218822Sdim group_nop->fr_fix = 0; 5575218822Sdim group_nop->fr_offset = 1; 5576218822Sdim group_nop->fr_type = rs_fill; 5577218822Sdim fragP->fr_next = group_nop; 5578218822Sdim dest = group_nop->fr_literal; 5579218822Sdim } 5580218822Sdim 5581218822Sdim md_number_to_chars (dest, 0x60210000, 4); 5582218822Sdim } 5583218822Sdim } 5584218822Sdim} 5585218822Sdim 558660484Sobrien/* Apply a fixup to the object code. This is called for all the 558760484Sobrien fixups we generated by the call to fix_new_exp, above. In the call 558860484Sobrien above we used a reloc code which was the largest legal reloc code 558960484Sobrien plus the operand index. Here we undo that to recover the operand 559060484Sobrien index. At this point all symbol values should be fully resolved, 559160484Sobrien and we attempt to completely resolve the reloc. If we can not do 559260484Sobrien that, we determine the correct reloc code and put it back in the 559360484Sobrien fixup. */ 559460484Sobrien 559589857Sobrienvoid 5596218822Sdimmd_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) 559760484Sobrien{ 559889857Sobrien valueT value = * valP; 559960484Sobrien 560060484Sobrien#ifdef OBJ_ELF 560189857Sobrien if (fixP->fx_addsy != NULL) 560260484Sobrien { 5603130561Sobrien /* Hack around bfd_install_relocation brain damage. */ 560489857Sobrien if (fixP->fx_pcrel) 560589857Sobrien value += fixP->fx_frag->fr_address + fixP->fx_where; 560660484Sobrien } 560760484Sobrien else 560889857Sobrien fixP->fx_done = 1; 560960484Sobrien#else 5610130561Sobrien /* FIXME FIXME FIXME: The value we are passed in *valP includes 5611218822Sdim the symbol values. If we are doing this relocation the code in 5612218822Sdim write.c is going to call bfd_install_relocation, which is also 5613218822Sdim going to use the symbol value. That means that if the reloc is 5614218822Sdim fully resolved we want to use *valP since bfd_install_relocation is 5615218822Sdim not being used. 561660484Sobrien However, if the reloc is not fully resolved we do not want to use 5617130561Sobrien *valP, and must use fx_offset instead. However, if the reloc 5618130561Sobrien is PC relative, we do want to use *valP since it includes the 561960484Sobrien result of md_pcrel_from. This is confusing. */ 562089857Sobrien if (fixP->fx_addsy == (symbolS *) NULL) 562189857Sobrien fixP->fx_done = 1; 562289857Sobrien 562389857Sobrien else if (fixP->fx_pcrel) 562489857Sobrien ; 562589857Sobrien 562660484Sobrien else 5627130561Sobrien value = fixP->fx_offset; 5628130561Sobrien#endif 5629130561Sobrien 5630130561Sobrien if (fixP->fx_subsy != (symbolS *) NULL) 563160484Sobrien { 5632130561Sobrien /* We can't actually support subtracting a symbol. */ 5633130561Sobrien as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex")); 563460484Sobrien } 563560484Sobrien 563689857Sobrien if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED) 563760484Sobrien { 563860484Sobrien int opindex; 563960484Sobrien const struct powerpc_operand *operand; 564060484Sobrien char *where; 564160484Sobrien unsigned long insn; 564260484Sobrien 564389857Sobrien opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED; 564460484Sobrien 564560484Sobrien operand = &powerpc_operands[opindex]; 564660484Sobrien 564760484Sobrien#ifdef OBJ_XCOFF 564889857Sobrien /* An instruction like `lwz 9,sym(30)' when `sym' is not a TOC symbol 564989857Sobrien does not generate a reloc. It uses the offset of `sym' within its 565089857Sobrien csect. Other usages, such as `.long sym', generate relocs. This 565189857Sobrien is the documented behaviour of non-TOC symbols. */ 565260484Sobrien if ((operand->flags & PPC_OPERAND_PARENS) != 0 5653218822Sdim && (operand->bitm & 0xfff0) == 0xfff0 565460484Sobrien && operand->shift == 0 5655104834Sobrien && (operand->insert == NULL || ppc_obj64) 565689857Sobrien && fixP->fx_addsy != NULL 565789857Sobrien && symbol_get_tc (fixP->fx_addsy)->subseg != 0 565889857Sobrien && symbol_get_tc (fixP->fx_addsy)->class != XMC_TC 565989857Sobrien && symbol_get_tc (fixP->fx_addsy)->class != XMC_TC0 566089857Sobrien && S_GET_SEGMENT (fixP->fx_addsy) != bss_section) 566160484Sobrien { 566289857Sobrien value = fixP->fx_offset; 566389857Sobrien fixP->fx_done = 1; 566460484Sobrien } 566560484Sobrien#endif 566660484Sobrien 566760484Sobrien /* Fetch the instruction, insert the fully resolved operand 566860484Sobrien value, and stuff the instruction back again. */ 566989857Sobrien where = fixP->fx_frag->fr_literal + fixP->fx_where; 567060484Sobrien if (target_big_endian) 567160484Sobrien insn = bfd_getb32 ((unsigned char *) where); 567260484Sobrien else 567360484Sobrien insn = bfd_getl32 ((unsigned char *) where); 567460484Sobrien insn = ppc_insert_operand (insn, operand, (offsetT) value, 567589857Sobrien fixP->fx_file, fixP->fx_line); 567660484Sobrien if (target_big_endian) 567760484Sobrien bfd_putb32 ((bfd_vma) insn, (unsigned char *) where); 567860484Sobrien else 567960484Sobrien bfd_putl32 ((bfd_vma) insn, (unsigned char *) where); 568060484Sobrien 568189857Sobrien if (fixP->fx_done) 568289857Sobrien /* Nothing else to do here. */ 568389857Sobrien return; 568460484Sobrien 568589857Sobrien assert (fixP->fx_addsy != NULL); 568689857Sobrien 568760484Sobrien /* Determine a BFD reloc value based on the operand information. 568860484Sobrien We are only prepared to turn a few of the operands into 568989857Sobrien relocs. */ 569060484Sobrien if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 5691218822Sdim && operand->bitm == 0x3fffffc 569260484Sobrien && operand->shift == 0) 569389857Sobrien fixP->fx_r_type = BFD_RELOC_PPC_B26; 569460484Sobrien else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 5695218822Sdim && operand->bitm == 0xfffc 569660484Sobrien && operand->shift == 0) 5697104834Sobrien { 5698104834Sobrien fixP->fx_r_type = BFD_RELOC_PPC_B16; 5699104834Sobrien#ifdef OBJ_XCOFF 5700104834Sobrien fixP->fx_size = 2; 5701104834Sobrien if (target_big_endian) 5702104834Sobrien fixP->fx_where += 2; 5703104834Sobrien#endif 5704104834Sobrien } 570560484Sobrien else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0 5706218822Sdim && operand->bitm == 0x3fffffc 570760484Sobrien && operand->shift == 0) 570889857Sobrien fixP->fx_r_type = BFD_RELOC_PPC_BA26; 570960484Sobrien else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0 5710218822Sdim && operand->bitm == 0xfffc 571160484Sobrien && operand->shift == 0) 5712104834Sobrien { 5713104834Sobrien fixP->fx_r_type = BFD_RELOC_PPC_BA16; 5714104834Sobrien#ifdef OBJ_XCOFF 5715104834Sobrien fixP->fx_size = 2; 5716104834Sobrien if (target_big_endian) 5717104834Sobrien fixP->fx_where += 2; 5718104834Sobrien#endif 5719104834Sobrien } 572089857Sobrien#if defined (OBJ_XCOFF) || defined (OBJ_ELF) 572160484Sobrien else if ((operand->flags & PPC_OPERAND_PARENS) != 0 5722218822Sdim && (operand->bitm & 0xfff0) == 0xfff0 5723130561Sobrien && operand->shift == 0) 572460484Sobrien { 5725130561Sobrien if (ppc_is_toc_sym (fixP->fx_addsy)) 5726130561Sobrien { 5727130561Sobrien fixP->fx_r_type = BFD_RELOC_PPC_TOC16; 572889857Sobrien#ifdef OBJ_ELF 5729130561Sobrien if (ppc_obj64 5730130561Sobrien && (operand->flags & PPC_OPERAND_DS) != 0) 5731130561Sobrien fixP->fx_r_type = BFD_RELOC_PPC64_TOC16_DS; 573289857Sobrien#endif 5733130561Sobrien } 5734130561Sobrien else 5735130561Sobrien { 5736130561Sobrien fixP->fx_r_type = BFD_RELOC_16; 5737130561Sobrien#ifdef OBJ_ELF 5738130561Sobrien if (ppc_obj64 5739130561Sobrien && (operand->flags & PPC_OPERAND_DS) != 0) 5740130561Sobrien fixP->fx_r_type = BFD_RELOC_PPC64_ADDR16_DS; 5741130561Sobrien#endif 5742130561Sobrien } 574389857Sobrien fixP->fx_size = 2; 574460484Sobrien if (target_big_endian) 574589857Sobrien fixP->fx_where += 2; 574660484Sobrien } 574789857Sobrien#endif /* defined (OBJ_XCOFF) || defined (OBJ_ELF) */ 574860484Sobrien else 574960484Sobrien { 575060484Sobrien char *sfile; 575160484Sobrien unsigned int sline; 575260484Sobrien 575360484Sobrien /* Use expr_symbol_where to see if this is an expression 575489857Sobrien symbol. */ 575589857Sobrien if (expr_symbol_where (fixP->fx_addsy, &sfile, &sline)) 575689857Sobrien as_bad_where (fixP->fx_file, fixP->fx_line, 575760484Sobrien _("unresolved expression that must be resolved")); 575860484Sobrien else 575989857Sobrien as_bad_where (fixP->fx_file, fixP->fx_line, 576089857Sobrien _("unsupported relocation against %s"), 576189857Sobrien S_GET_NAME (fixP->fx_addsy)); 576289857Sobrien fixP->fx_done = 1; 576389857Sobrien return; 576460484Sobrien } 576560484Sobrien } 576660484Sobrien else 576760484Sobrien { 576860484Sobrien#ifdef OBJ_ELF 576989857Sobrien ppc_elf_validate_fix (fixP, seg); 577060484Sobrien#endif 577189857Sobrien switch (fixP->fx_r_type) 577260484Sobrien { 577360484Sobrien case BFD_RELOC_CTOR: 5774104834Sobrien if (ppc_obj64) 577589857Sobrien goto ctor64; 577689857Sobrien /* fall through */ 577760484Sobrien 577889857Sobrien case BFD_RELOC_32: 577989857Sobrien if (fixP->fx_pcrel) 578089857Sobrien fixP->fx_r_type = BFD_RELOC_32_PCREL; 578189857Sobrien /* fall through */ 578289857Sobrien 578360484Sobrien case BFD_RELOC_RVA: 578460484Sobrien case BFD_RELOC_32_PCREL: 578560484Sobrien case BFD_RELOC_PPC_EMB_NADDR32: 578689857Sobrien md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 578760484Sobrien value, 4); 578860484Sobrien break; 578960484Sobrien 579077298Sobrien case BFD_RELOC_64: 579189857Sobrien ctor64: 579289857Sobrien if (fixP->fx_pcrel) 579389857Sobrien fixP->fx_r_type = BFD_RELOC_64_PCREL; 579489857Sobrien /* fall through */ 579589857Sobrien 579677298Sobrien case BFD_RELOC_64_PCREL: 579789857Sobrien md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 579877298Sobrien value, 8); 579977298Sobrien break; 580089857Sobrien 580160484Sobrien case BFD_RELOC_GPREL16: 580260484Sobrien case BFD_RELOC_16_GOT_PCREL: 580360484Sobrien case BFD_RELOC_16_GOTOFF: 580460484Sobrien case BFD_RELOC_LO16_GOTOFF: 580560484Sobrien case BFD_RELOC_HI16_GOTOFF: 580660484Sobrien case BFD_RELOC_HI16_S_GOTOFF: 580799461Sobrien case BFD_RELOC_16_BASEREL: 580860484Sobrien case BFD_RELOC_LO16_BASEREL: 580960484Sobrien case BFD_RELOC_HI16_BASEREL: 581060484Sobrien case BFD_RELOC_HI16_S_BASEREL: 581160484Sobrien case BFD_RELOC_PPC_EMB_NADDR16: 581260484Sobrien case BFD_RELOC_PPC_EMB_NADDR16_LO: 581360484Sobrien case BFD_RELOC_PPC_EMB_NADDR16_HI: 581460484Sobrien case BFD_RELOC_PPC_EMB_NADDR16_HA: 581560484Sobrien case BFD_RELOC_PPC_EMB_SDAI16: 581660484Sobrien case BFD_RELOC_PPC_EMB_SDA2REL: 581760484Sobrien case BFD_RELOC_PPC_EMB_SDA2I16: 581860484Sobrien case BFD_RELOC_PPC_EMB_RELSEC16: 581960484Sobrien case BFD_RELOC_PPC_EMB_RELST_LO: 582060484Sobrien case BFD_RELOC_PPC_EMB_RELST_HI: 582160484Sobrien case BFD_RELOC_PPC_EMB_RELST_HA: 582260484Sobrien case BFD_RELOC_PPC_EMB_RELSDA: 582360484Sobrien case BFD_RELOC_PPC_TOC16: 582489857Sobrien#ifdef OBJ_ELF 582589857Sobrien case BFD_RELOC_PPC64_TOC16_LO: 582689857Sobrien case BFD_RELOC_PPC64_TOC16_HI: 582789857Sobrien case BFD_RELOC_PPC64_TOC16_HA: 582889857Sobrien#endif 582989857Sobrien if (fixP->fx_pcrel) 583060484Sobrien { 583189857Sobrien if (fixP->fx_addsy != NULL) 583289857Sobrien as_bad_where (fixP->fx_file, fixP->fx_line, 583360484Sobrien _("cannot emit PC relative %s relocation against %s"), 583489857Sobrien bfd_get_reloc_code_name (fixP->fx_r_type), 583589857Sobrien S_GET_NAME (fixP->fx_addsy)); 583660484Sobrien else 583789857Sobrien as_bad_where (fixP->fx_file, fixP->fx_line, 583860484Sobrien _("cannot emit PC relative %s relocation"), 583989857Sobrien bfd_get_reloc_code_name (fixP->fx_r_type)); 584060484Sobrien } 584160484Sobrien 584289857Sobrien md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 584360484Sobrien value, 2); 584460484Sobrien break; 584560484Sobrien 5846218822Sdim case BFD_RELOC_16: 5847218822Sdim if (fixP->fx_pcrel) 5848218822Sdim fixP->fx_r_type = BFD_RELOC_16_PCREL; 5849218822Sdim /* fall through */ 5850218822Sdim 5851218822Sdim case BFD_RELOC_16_PCREL: 5852218822Sdim md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 5853218822Sdim value, 2); 5854218822Sdim break; 5855218822Sdim 5856218822Sdim case BFD_RELOC_LO16: 5857218822Sdim if (fixP->fx_pcrel) 5858218822Sdim fixP->fx_r_type = BFD_RELOC_LO16_PCREL; 5859218822Sdim /* fall through */ 5860218822Sdim 5861218822Sdim case BFD_RELOC_LO16_PCREL: 5862218822Sdim md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 5863218822Sdim value, 2); 5864218822Sdim break; 5865218822Sdim 586660484Sobrien /* This case happens when you write, for example, 586760484Sobrien lis %r3,(L1-L2)@ha 586860484Sobrien where L1 and L2 are defined later. */ 586960484Sobrien case BFD_RELOC_HI16: 587089857Sobrien if (fixP->fx_pcrel) 5871218822Sdim fixP->fx_r_type = BFD_RELOC_HI16_PCREL; 5872218822Sdim /* fall through */ 5873218822Sdim 5874218822Sdim case BFD_RELOC_HI16_PCREL: 587589857Sobrien md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 587689857Sobrien PPC_HI (value), 2); 587760484Sobrien break; 587889857Sobrien 587960484Sobrien case BFD_RELOC_HI16_S: 588089857Sobrien if (fixP->fx_pcrel) 5881218822Sdim fixP->fx_r_type = BFD_RELOC_HI16_S_PCREL; 5882218822Sdim /* fall through */ 5883218822Sdim 5884218822Sdim case BFD_RELOC_HI16_S_PCREL: 588589857Sobrien md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 588689857Sobrien PPC_HA (value), 2); 588760484Sobrien break; 588860484Sobrien 588989857Sobrien#ifdef OBJ_ELF 589089857Sobrien case BFD_RELOC_PPC64_HIGHER: 589189857Sobrien if (fixP->fx_pcrel) 589289857Sobrien abort (); 589389857Sobrien md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 589489857Sobrien PPC_HIGHER (value), 2); 589589857Sobrien break; 589689857Sobrien 589789857Sobrien case BFD_RELOC_PPC64_HIGHER_S: 589889857Sobrien if (fixP->fx_pcrel) 589989857Sobrien abort (); 590089857Sobrien md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 590189857Sobrien PPC_HIGHERA (value), 2); 590289857Sobrien break; 590389857Sobrien 590489857Sobrien case BFD_RELOC_PPC64_HIGHEST: 590589857Sobrien if (fixP->fx_pcrel) 590689857Sobrien abort (); 590789857Sobrien md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 590889857Sobrien PPC_HIGHEST (value), 2); 590989857Sobrien break; 591089857Sobrien 591189857Sobrien case BFD_RELOC_PPC64_HIGHEST_S: 591289857Sobrien if (fixP->fx_pcrel) 591389857Sobrien abort (); 591489857Sobrien md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 591589857Sobrien PPC_HIGHESTA (value), 2); 591689857Sobrien break; 591789857Sobrien 591889857Sobrien case BFD_RELOC_PPC64_ADDR16_DS: 591989857Sobrien case BFD_RELOC_PPC64_ADDR16_LO_DS: 592089857Sobrien case BFD_RELOC_PPC64_GOT16_DS: 592189857Sobrien case BFD_RELOC_PPC64_GOT16_LO_DS: 592289857Sobrien case BFD_RELOC_PPC64_PLT16_LO_DS: 592389857Sobrien case BFD_RELOC_PPC64_SECTOFF_DS: 592489857Sobrien case BFD_RELOC_PPC64_SECTOFF_LO_DS: 592589857Sobrien case BFD_RELOC_PPC64_TOC16_DS: 592689857Sobrien case BFD_RELOC_PPC64_TOC16_LO_DS: 592789857Sobrien case BFD_RELOC_PPC64_PLTGOT16_DS: 592889857Sobrien case BFD_RELOC_PPC64_PLTGOT16_LO_DS: 592989857Sobrien if (fixP->fx_pcrel) 593089857Sobrien abort (); 593189857Sobrien { 5932218822Sdim char *where = fixP->fx_frag->fr_literal + fixP->fx_where; 5933130561Sobrien unsigned long val, mask; 593489857Sobrien 593589857Sobrien if (target_big_endian) 5936130561Sobrien val = bfd_getb32 (where - 2); 593789857Sobrien else 5938130561Sobrien val = bfd_getl32 (where); 5939130561Sobrien mask = 0xfffc; 5940130561Sobrien /* lq insns reserve the four lsbs. */ 5941130561Sobrien if ((ppc_cpu & PPC_OPCODE_POWER4) != 0 5942130561Sobrien && (val & (0x3f << 26)) == (56u << 26)) 5943130561Sobrien mask = 0xfff0; 5944130561Sobrien val |= value & mask; 594589857Sobrien if (target_big_endian) 594689857Sobrien bfd_putb16 ((bfd_vma) val, where); 594789857Sobrien else 594889857Sobrien bfd_putl16 ((bfd_vma) val, where); 594989857Sobrien } 595089857Sobrien break; 5951130561Sobrien 5952130561Sobrien case BFD_RELOC_PPC_B16_BRTAKEN: 5953130561Sobrien case BFD_RELOC_PPC_B16_BRNTAKEN: 5954130561Sobrien case BFD_RELOC_PPC_BA16_BRTAKEN: 5955130561Sobrien case BFD_RELOC_PPC_BA16_BRNTAKEN: 5956130561Sobrien break; 5957130561Sobrien 5958130561Sobrien case BFD_RELOC_PPC_TLS: 5959275873Sjhibbits case BFD_RELOC_PPC_TLSLD: 5960275873Sjhibbits case BFD_RELOC_PPC_TLSGD: 5961218822Sdim break; 5962218822Sdim 5963130561Sobrien case BFD_RELOC_PPC_DTPMOD: 5964130561Sobrien case BFD_RELOC_PPC_TPREL16: 5965130561Sobrien case BFD_RELOC_PPC_TPREL16_LO: 5966130561Sobrien case BFD_RELOC_PPC_TPREL16_HI: 5967130561Sobrien case BFD_RELOC_PPC_TPREL16_HA: 5968130561Sobrien case BFD_RELOC_PPC_TPREL: 5969130561Sobrien case BFD_RELOC_PPC_DTPREL16: 5970130561Sobrien case BFD_RELOC_PPC_DTPREL16_LO: 5971130561Sobrien case BFD_RELOC_PPC_DTPREL16_HI: 5972130561Sobrien case BFD_RELOC_PPC_DTPREL16_HA: 5973130561Sobrien case BFD_RELOC_PPC_DTPREL: 5974130561Sobrien case BFD_RELOC_PPC_GOT_TLSGD16: 5975130561Sobrien case BFD_RELOC_PPC_GOT_TLSGD16_LO: 5976130561Sobrien case BFD_RELOC_PPC_GOT_TLSGD16_HI: 5977130561Sobrien case BFD_RELOC_PPC_GOT_TLSGD16_HA: 5978130561Sobrien case BFD_RELOC_PPC_GOT_TLSLD16: 5979130561Sobrien case BFD_RELOC_PPC_GOT_TLSLD16_LO: 5980130561Sobrien case BFD_RELOC_PPC_GOT_TLSLD16_HI: 5981130561Sobrien case BFD_RELOC_PPC_GOT_TLSLD16_HA: 5982130561Sobrien case BFD_RELOC_PPC_GOT_TPREL16: 5983130561Sobrien case BFD_RELOC_PPC_GOT_TPREL16_LO: 5984130561Sobrien case BFD_RELOC_PPC_GOT_TPREL16_HI: 5985130561Sobrien case BFD_RELOC_PPC_GOT_TPREL16_HA: 5986130561Sobrien case BFD_RELOC_PPC_GOT_DTPREL16: 5987130561Sobrien case BFD_RELOC_PPC_GOT_DTPREL16_LO: 5988130561Sobrien case BFD_RELOC_PPC_GOT_DTPREL16_HI: 5989130561Sobrien case BFD_RELOC_PPC_GOT_DTPREL16_HA: 5990130561Sobrien case BFD_RELOC_PPC64_TPREL16_DS: 5991130561Sobrien case BFD_RELOC_PPC64_TPREL16_LO_DS: 5992130561Sobrien case BFD_RELOC_PPC64_TPREL16_HIGHER: 5993130561Sobrien case BFD_RELOC_PPC64_TPREL16_HIGHERA: 5994130561Sobrien case BFD_RELOC_PPC64_TPREL16_HIGHEST: 5995130561Sobrien case BFD_RELOC_PPC64_TPREL16_HIGHESTA: 5996130561Sobrien case BFD_RELOC_PPC64_DTPREL16_DS: 5997130561Sobrien case BFD_RELOC_PPC64_DTPREL16_LO_DS: 5998130561Sobrien case BFD_RELOC_PPC64_DTPREL16_HIGHER: 5999130561Sobrien case BFD_RELOC_PPC64_DTPREL16_HIGHERA: 6000130561Sobrien case BFD_RELOC_PPC64_DTPREL16_HIGHEST: 6001130561Sobrien case BFD_RELOC_PPC64_DTPREL16_HIGHESTA: 6002218822Sdim S_SET_THREAD_LOCAL (fixP->fx_addsy); 6003130561Sobrien break; 600489857Sobrien#endif 600560484Sobrien /* Because SDA21 modifies the register field, the size is set to 4 600689857Sobrien bytes, rather than 2, so offset it here appropriately. */ 600760484Sobrien case BFD_RELOC_PPC_EMB_SDA21: 600889857Sobrien if (fixP->fx_pcrel) 600960484Sobrien abort (); 601060484Sobrien 601189857Sobrien md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where 601260484Sobrien + ((target_big_endian) ? 2 : 0), 601360484Sobrien value, 2); 601460484Sobrien break; 601560484Sobrien 601660484Sobrien case BFD_RELOC_8: 601789857Sobrien if (fixP->fx_pcrel) 6018130561Sobrien { 6019130561Sobrien /* This can occur if there is a bug in the input assembler, eg: 6020130561Sobrien ".byte <undefined_symbol> - ." */ 6021130561Sobrien if (fixP->fx_addsy) 6022130561Sobrien as_bad (_("Unable to handle reference to symbol %s"), 6023130561Sobrien S_GET_NAME (fixP->fx_addsy)); 6024130561Sobrien else 6025130561Sobrien as_bad (_("Unable to resolve expression")); 6026130561Sobrien fixP->fx_done = 1; 6027130561Sobrien } 6028130561Sobrien else 6029130561Sobrien md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, 6030130561Sobrien value, 1); 603160484Sobrien break; 603260484Sobrien 603360484Sobrien case BFD_RELOC_24_PLT_PCREL: 603460484Sobrien case BFD_RELOC_PPC_LOCAL24PC: 603589857Sobrien if (!fixP->fx_pcrel && !fixP->fx_done) 603660484Sobrien abort (); 603760484Sobrien 603889857Sobrien if (fixP->fx_done) 603989857Sobrien { 604089857Sobrien char *where; 604189857Sobrien unsigned long insn; 604277298Sobrien 604389857Sobrien /* Fetch the instruction, insert the fully resolved operand 604489857Sobrien value, and stuff the instruction back again. */ 604589857Sobrien where = fixP->fx_frag->fr_literal + fixP->fx_where; 604689857Sobrien if (target_big_endian) 604789857Sobrien insn = bfd_getb32 ((unsigned char *) where); 604889857Sobrien else 604989857Sobrien insn = bfd_getl32 ((unsigned char *) where); 605089857Sobrien if ((value & 3) != 0) 605189857Sobrien as_bad_where (fixP->fx_file, fixP->fx_line, 605289857Sobrien _("must branch to an address a multiple of 4")); 605389857Sobrien if ((offsetT) value < -0x40000000 605489857Sobrien || (offsetT) value >= 0x40000000) 605589857Sobrien as_bad_where (fixP->fx_file, fixP->fx_line, 605689857Sobrien _("@local or @plt branch destination is too far away, %ld bytes"), 605789857Sobrien (long) value); 605889857Sobrien insn = insn | (value & 0x03fffffc); 605989857Sobrien if (target_big_endian) 606089857Sobrien bfd_putb32 ((bfd_vma) insn, (unsigned char *) where); 606189857Sobrien else 606289857Sobrien bfd_putl32 ((bfd_vma) insn, (unsigned char *) where); 606389857Sobrien } 606460484Sobrien break; 606560484Sobrien 606660484Sobrien case BFD_RELOC_VTABLE_INHERIT: 606789857Sobrien fixP->fx_done = 0; 606889857Sobrien if (fixP->fx_addsy 606989857Sobrien && !S_IS_DEFINED (fixP->fx_addsy) 607089857Sobrien && !S_IS_WEAK (fixP->fx_addsy)) 607189857Sobrien S_SET_WEAK (fixP->fx_addsy); 607260484Sobrien break; 607360484Sobrien 607460484Sobrien case BFD_RELOC_VTABLE_ENTRY: 607589857Sobrien fixP->fx_done = 0; 607660484Sobrien break; 607760484Sobrien 607889857Sobrien#ifdef OBJ_ELF 607989857Sobrien /* Generated by reference to `sym@tocbase'. The sym is 608089857Sobrien ignored by the linker. */ 608189857Sobrien case BFD_RELOC_PPC64_TOC: 608289857Sobrien fixP->fx_done = 0; 608389857Sobrien break; 608489857Sobrien#endif 608560484Sobrien default: 608677298Sobrien fprintf (stderr, 608789857Sobrien _("Gas failure, reloc value %d\n"), fixP->fx_r_type); 608889857Sobrien fflush (stderr); 608960484Sobrien abort (); 609060484Sobrien } 609160484Sobrien } 609260484Sobrien 609360484Sobrien#ifdef OBJ_ELF 609489857Sobrien fixP->fx_addnumber = value; 6095218822Sdim 6096218822Sdim /* PowerPC uses RELA relocs, ie. the reloc addend is stored separately 6097218822Sdim from the section contents. If we are going to be emitting a reloc 6098218822Sdim then the section contents are immaterial, so don't warn if they 6099218822Sdim happen to overflow. Leave such warnings to ld. */ 6100218822Sdim if (!fixP->fx_done) 6101218822Sdim fixP->fx_no_overflow = 1; 610260484Sobrien#else 610389857Sobrien if (fixP->fx_r_type != BFD_RELOC_PPC_TOC16) 610489857Sobrien fixP->fx_addnumber = 0; 610560484Sobrien else 610660484Sobrien { 610760484Sobrien#ifdef TE_PE 610889857Sobrien fixP->fx_addnumber = 0; 610960484Sobrien#else 611060484Sobrien /* We want to use the offset within the data segment of the 611160484Sobrien symbol, not the actual VMA of the symbol. */ 611289857Sobrien fixP->fx_addnumber = 611389857Sobrien - bfd_get_section_vma (stdoutput, S_GET_SEGMENT (fixP->fx_addsy)); 611460484Sobrien#endif 611560484Sobrien } 611660484Sobrien#endif 611760484Sobrien} 611860484Sobrien 611960484Sobrien/* Generate a reloc for a fixup. */ 612060484Sobrien 612160484Sobrienarelent * 6122218822Sdimtc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp) 612360484Sobrien{ 612460484Sobrien arelent *reloc; 612560484Sobrien 612660484Sobrien reloc = (arelent *) xmalloc (sizeof (arelent)); 612760484Sobrien 612860484Sobrien reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); 612960484Sobrien *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); 613060484Sobrien reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; 613160484Sobrien reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); 613260484Sobrien if (reloc->howto == (reloc_howto_type *) NULL) 613360484Sobrien { 613460484Sobrien as_bad_where (fixp->fx_file, fixp->fx_line, 613589857Sobrien _("reloc %d not supported by object file format"), 613689857Sobrien (int) fixp->fx_r_type); 613760484Sobrien return NULL; 613860484Sobrien } 613960484Sobrien reloc->addend = fixp->fx_addnumber; 614060484Sobrien 614160484Sobrien return reloc; 614260484Sobrien} 6143130561Sobrien 6144130561Sobrienvoid 6145218822Sdimppc_cfi_frame_initial_instructions (void) 6146130561Sobrien{ 6147130561Sobrien cfi_add_CFA_def_cfa (1, 0); 6148130561Sobrien} 6149130561Sobrien 6150130561Sobrienint 6151218822Sdimtc_ppc_regname_to_dw2regnum (char *regname) 6152130561Sobrien{ 6153130561Sobrien unsigned int regnum = -1; 6154130561Sobrien unsigned int i; 6155130561Sobrien const char *p; 6156130561Sobrien char *q; 6157130561Sobrien static struct { char *name; int dw2regnum; } regnames[] = 6158130561Sobrien { 6159130561Sobrien { "sp", 1 }, { "r.sp", 1 }, { "rtoc", 2 }, { "r.toc", 2 }, 6160130561Sobrien { "mq", 64 }, { "lr", 65 }, { "ctr", 66 }, { "ap", 67 }, 6161218822Sdim { "cr", 70 }, { "xer", 76 }, { "vrsave", 109 }, { "vscr", 110 }, 6162130561Sobrien { "spe_acc", 111 }, { "spefscr", 112 } 6163130561Sobrien }; 6164130561Sobrien 6165130561Sobrien for (i = 0; i < ARRAY_SIZE (regnames); ++i) 6166130561Sobrien if (strcmp (regnames[i].name, regname) == 0) 6167130561Sobrien return regnames[i].dw2regnum; 6168130561Sobrien 6169130561Sobrien if (regname[0] == 'r' || regname[0] == 'f' || regname[0] == 'v') 6170130561Sobrien { 6171130561Sobrien p = regname + 1 + (regname[1] == '.'); 6172130561Sobrien regnum = strtoul (p, &q, 10); 6173130561Sobrien if (p == q || *q || regnum >= 32) 6174130561Sobrien return -1; 6175130561Sobrien if (regname[0] == 'f') 6176130561Sobrien regnum += 32; 6177130561Sobrien else if (regname[0] == 'v') 6178130561Sobrien regnum += 77; 6179130561Sobrien } 6180130561Sobrien else if (regname[0] == 'c' && regname[1] == 'r') 6181130561Sobrien { 6182130561Sobrien p = regname + 2 + (regname[2] == '.'); 6183130561Sobrien if (p[0] < '0' || p[0] > '7' || p[1]) 6184130561Sobrien return -1; 6185130561Sobrien regnum = p[0] - '0' + 68; 6186130561Sobrien } 6187130561Sobrien return regnum; 6188130561Sobrien} 6189