diff options
Diffstat (limited to 'binutils-2.24/gas/config/tc-ppc.c')
-rw-r--r-- | binutils-2.24/gas/config/tc-ppc.c | 7174 |
1 files changed, 0 insertions, 7174 deletions
diff --git a/binutils-2.24/gas/config/tc-ppc.c b/binutils-2.24/gas/config/tc-ppc.c deleted file mode 100644 index 7c99e438..00000000 --- a/binutils-2.24/gas/config/tc-ppc.c +++ /dev/null @@ -1,7174 +0,0 @@ -/* tc-ppc.c -- Assemble for the PowerPC or POWER (RS/6000) - Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, - 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 - Free Software Foundation, Inc. - Written by Ian Lance Taylor, Cygnus Support. - - This file is part of GAS, the GNU Assembler. - - GAS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, or (at your option) - any later version. - - GAS is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GAS; see the file COPYING. If not, write to the Free - Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA - 02110-1301, USA. */ - -#include "as.h" -#include "safe-ctype.h" -#include "subsegs.h" -#include "dw2gencfi.h" -#include "opcode/ppc.h" - -#ifdef OBJ_ELF -#include "elf/ppc.h" -#include "elf/ppc64.h" -#include "dwarf2dbg.h" -#endif - -#ifdef TE_PE -#include "coff/pe.h" -#endif - -#ifdef OBJ_XCOFF -#include "coff/xcoff.h" -#include "libxcoff.h" -#endif - -/* This is the assembler for the PowerPC or POWER (RS/6000) chips. */ - -/* Tell the main code what the endianness is. */ -extern int target_big_endian; - -/* Whether or not, we've set target_big_endian. */ -static int set_target_endian = 0; - -/* Whether to use user friendly register names. */ -#ifndef TARGET_REG_NAMES_P -#ifdef TE_PE -#define TARGET_REG_NAMES_P TRUE -#else -#define TARGET_REG_NAMES_P FALSE -#endif -#endif - -/* Macros for calculating LO, HI, HA, HIGHER, HIGHERA, HIGHEST, - HIGHESTA. */ - -/* #lo(value) denotes the least significant 16 bits of the indicated. */ -#define PPC_LO(v) ((v) & 0xffff) - -/* #hi(value) denotes bits 16 through 31 of the indicated value. */ -#define PPC_HI(v) (((v) >> 16) & 0xffff) - -/* #ha(value) denotes the high adjusted value: bits 16 through 31 of - the indicated value, compensating for #lo() being treated as a - signed number. */ -#define PPC_HA(v) PPC_HI ((v) + 0x8000) - -/* #higher(value) denotes bits 32 through 47 of the indicated value. */ -#define PPC_HIGHER(v) (((v) >> 16 >> 16) & 0xffff) - -/* #highera(value) denotes bits 32 through 47 of the indicated value, - compensating for #lo() being treated as a signed number. */ -#define PPC_HIGHERA(v) PPC_HIGHER ((v) + 0x8000) - -/* #highest(value) denotes bits 48 through 63 of the indicated value. */ -#define PPC_HIGHEST(v) (((v) >> 24 >> 24) & 0xffff) - -/* #highesta(value) denotes bits 48 through 63 of the indicated value, - compensating for #lo being treated as a signed number. */ -#define PPC_HIGHESTA(v) PPC_HIGHEST ((v) + 0x8000) - -#define SEX16(val) (((val) ^ 0x8000) - 0x8000) - -/* For the time being on ppc64, don't report overflow on @h and @ha - applied to constants. */ -#define REPORT_OVERFLOW_HI 0 - -static bfd_boolean reg_names_p = TARGET_REG_NAMES_P; - -static void ppc_macro (char *, const struct powerpc_macro *); -static void ppc_byte (int); - -#if defined (OBJ_XCOFF) || defined (OBJ_ELF) -static void ppc_tc (int); -static void ppc_machine (int); -#endif - -#ifdef OBJ_XCOFF -static void ppc_comm (int); -static void ppc_bb (int); -static void ppc_bc (int); -static void ppc_bf (int); -static void ppc_biei (int); -static void ppc_bs (int); -static void ppc_eb (int); -static void ppc_ec (int); -static void ppc_ef (int); -static void ppc_es (int); -static void ppc_csect (int); -static void ppc_dwsect (int); -static void ppc_change_csect (symbolS *, offsetT); -static void ppc_function (int); -static void ppc_extern (int); -static void ppc_lglobl (int); -static void ppc_ref (int); -static void ppc_section (int); -static void ppc_named_section (int); -static void ppc_stabx (int); -static void ppc_rename (int); -static void ppc_toc (int); -static void ppc_xcoff_cons (int); -static void ppc_vbyte (int); -#endif - -#ifdef OBJ_ELF -static void ppc_elf_cons (int); -static void ppc_elf_rdata (int); -static void ppc_elf_lcomm (int); -static void ppc_elf_localentry (int); -static void ppc_elf_abiversion (int); -#endif - -#ifdef TE_PE -static void ppc_previous (int); -static void ppc_pdata (int); -static void ppc_ydata (int); -static void ppc_reldata (int); -static void ppc_rdata (int); -static void ppc_ualong (int); -static void ppc_znop (int); -static void ppc_pe_comm (int); -static void ppc_pe_section (int); -static void ppc_pe_function (int); -static void ppc_pe_tocd (int); -#endif - -/* Generic assembler global variables which must be defined by all - targets. */ - -#ifdef OBJ_ELF -/* This string holds the chars that always start a comment. If the - pre-processor is disabled, these aren't very useful. The macro - tc_comment_chars points to this. We use this, rather than the - usual comment_chars, so that we can switch for Solaris conventions. */ -static const char ppc_solaris_comment_chars[] = "#!"; -static const char ppc_eabi_comment_chars[] = "#"; - -#ifdef TARGET_SOLARIS_COMMENT -const char *ppc_comment_chars = ppc_solaris_comment_chars; -#else -const char *ppc_comment_chars = ppc_eabi_comment_chars; -#endif -#else -const char comment_chars[] = "#"; -#endif - -/* Characters which start a comment at the beginning of a line. */ -const char line_comment_chars[] = "#"; - -/* Characters which may be used to separate multiple commands on a - single line. */ -const char line_separator_chars[] = ";"; - -/* Characters which are used to indicate an exponent in a floating - point number. */ -const char EXP_CHARS[] = "eE"; - -/* Characters which mean that a number is a floating point constant, - as in 0d1.0. */ -const char FLT_CHARS[] = "dD"; - -/* Anything that can start an operand needs to be mentioned here, - to stop the input scrubber eating whitespace. */ -const char ppc_symbol_chars[] = "%["; - -/* The dwarf2 data alignment, adjusted for 32 or 64 bit. */ -int ppc_cie_data_alignment; - -/* The dwarf2 minimum instruction length. */ -int ppc_dwarf2_line_min_insn_length; - -/* More than this number of nops in an alignment op gets a branch - instead. */ -unsigned long nop_limit = 4; - -/* The type of processor we are assembling for. This is one or more - of the PPC_OPCODE flags defined in opcode/ppc.h. */ -ppc_cpu_t ppc_cpu = 0; -ppc_cpu_t sticky = 0; - -/* Value for ELF e_flags EF_PPC64_ABI. */ -unsigned int ppc_abiversion = 0; - -/* Flags set on encountering toc relocs. */ -enum { - has_large_toc_reloc = 1, - has_small_toc_reloc = 2 -} toc_reloc_types; - -/* The target specific pseudo-ops which we support. */ - -const pseudo_typeS md_pseudo_table[] = -{ - /* Pseudo-ops which must be overridden. */ - { "byte", ppc_byte, 0 }, - -#ifdef OBJ_XCOFF - /* Pseudo-ops specific to the RS/6000 XCOFF format. Some of these - legitimately belong in the obj-*.c file. However, XCOFF is based - on COFF, and is only implemented for the RS/6000. We just use - obj-coff.c, and add what we need here. */ - { "comm", ppc_comm, 0 }, - { "lcomm", ppc_comm, 1 }, - { "bb", ppc_bb, 0 }, - { "bc", ppc_bc, 0 }, - { "bf", ppc_bf, 0 }, - { "bi", ppc_biei, 0 }, - { "bs", ppc_bs, 0 }, - { "csect", ppc_csect, 0 }, - { "dwsect", ppc_dwsect, 0 }, - { "data", ppc_section, 'd' }, - { "eb", ppc_eb, 0 }, - { "ec", ppc_ec, 0 }, - { "ef", ppc_ef, 0 }, - { "ei", ppc_biei, 1 }, - { "es", ppc_es, 0 }, - { "extern", ppc_extern, 0 }, - { "function", ppc_function, 0 }, - { "lglobl", ppc_lglobl, 0 }, - { "ref", ppc_ref, 0 }, - { "rename", ppc_rename, 0 }, - { "section", ppc_named_section, 0 }, - { "stabx", ppc_stabx, 0 }, - { "text", ppc_section, 't' }, - { "toc", ppc_toc, 0 }, - { "long", ppc_xcoff_cons, 2 }, - { "llong", ppc_xcoff_cons, 3 }, - { "word", ppc_xcoff_cons, 1 }, - { "short", ppc_xcoff_cons, 1 }, - { "vbyte", ppc_vbyte, 0 }, -#endif - -#ifdef OBJ_ELF - { "llong", ppc_elf_cons, 8 }, - { "quad", ppc_elf_cons, 8 }, - { "long", ppc_elf_cons, 4 }, - { "word", ppc_elf_cons, 2 }, - { "short", ppc_elf_cons, 2 }, - { "rdata", ppc_elf_rdata, 0 }, - { "rodata", ppc_elf_rdata, 0 }, - { "lcomm", ppc_elf_lcomm, 0 }, - { "localentry", ppc_elf_localentry, 0 }, - { "abiversion", ppc_elf_abiversion, 0 }, -#endif - -#ifdef TE_PE - /* Pseudo-ops specific to the Windows NT PowerPC PE (coff) format. */ - { "previous", ppc_previous, 0 }, - { "pdata", ppc_pdata, 0 }, - { "ydata", ppc_ydata, 0 }, - { "reldata", ppc_reldata, 0 }, - { "rdata", ppc_rdata, 0 }, - { "ualong", ppc_ualong, 0 }, - { "znop", ppc_znop, 0 }, - { "comm", ppc_pe_comm, 0 }, - { "lcomm", ppc_pe_comm, 1 }, - { "section", ppc_pe_section, 0 }, - { "function", ppc_pe_function,0 }, - { "tocd", ppc_pe_tocd, 0 }, -#endif - -#if defined (OBJ_XCOFF) || defined (OBJ_ELF) - { "tc", ppc_tc, 0 }, - { "machine", ppc_machine, 0 }, -#endif - - { NULL, NULL, 0 } -}; - - -/* Predefined register names if -mregnames (or default for Windows NT). - In general, there are lots of them, in an attempt to be compatible - with a number of other Windows NT assemblers. */ - -/* Structure to hold information about predefined registers. */ -struct pd_reg - { - char *name; - int value; - }; - -/* List of registers that are pre-defined: - - Each general register has predefined names of the form: - 1. r<reg_num> which has the value <reg_num>. - 2. r.<reg_num> which has the value <reg_num>. - - Each floating point register has predefined names of the form: - 1. f<reg_num> which has the value <reg_num>. - 2. f.<reg_num> which has the value <reg_num>. - - Each vector unit register has predefined names of the form: - 1. v<reg_num> which has the value <reg_num>. - 2. v.<reg_num> which has the value <reg_num>. - - Each condition register has predefined names of the form: - 1. cr<reg_num> which has the value <reg_num>. - 2. cr.<reg_num> which has the value <reg_num>. - - There are individual registers as well: - sp or r.sp has the value 1 - rtoc or r.toc has the value 2 - fpscr has the value 0 - xer has the value 1 - lr has the value 8 - ctr has the value 9 - pmr has the value 0 - dar has the value 19 - dsisr has the value 18 - dec has the value 22 - sdr1 has the value 25 - srr0 has the value 26 - srr1 has the value 27 - - The table is sorted. Suitable for searching by a binary search. */ - -static const struct pd_reg pre_defined_registers[] = -{ - { "cr.0", 0 }, /* Condition Registers */ - { "cr.1", 1 }, - { "cr.2", 2 }, - { "cr.3", 3 }, - { "cr.4", 4 }, - { "cr.5", 5 }, - { "cr.6", 6 }, - { "cr.7", 7 }, - - { "cr0", 0 }, - { "cr1", 1 }, - { "cr2", 2 }, - { "cr3", 3 }, - { "cr4", 4 }, - { "cr5", 5 }, - { "cr6", 6 }, - { "cr7", 7 }, - - { "ctr", 9 }, - - { "dar", 19 }, /* Data Access Register */ - { "dec", 22 }, /* Decrementer */ - { "dsisr", 18 }, /* Data Storage Interrupt Status Register */ - - { "f.0", 0 }, /* Floating point registers */ - { "f.1", 1 }, - { "f.10", 10 }, - { "f.11", 11 }, - { "f.12", 12 }, - { "f.13", 13 }, - { "f.14", 14 }, - { "f.15", 15 }, - { "f.16", 16 }, - { "f.17", 17 }, - { "f.18", 18 }, - { "f.19", 19 }, - { "f.2", 2 }, - { "f.20", 20 }, - { "f.21", 21 }, - { "f.22", 22 }, - { "f.23", 23 }, - { "f.24", 24 }, - { "f.25", 25 }, - { "f.26", 26 }, - { "f.27", 27 }, - { "f.28", 28 }, - { "f.29", 29 }, - { "f.3", 3 }, - { "f.30", 30 }, - { "f.31", 31 }, - - { "f.32", 32 }, /* Extended floating point scalar registers (ISA 2.06). */ - { "f.33", 33 }, - { "f.34", 34 }, - { "f.35", 35 }, - { "f.36", 36 }, - { "f.37", 37 }, - { "f.38", 38 }, - { "f.39", 39 }, - { "f.4", 4 }, - { "f.40", 40 }, - { "f.41", 41 }, - { "f.42", 42 }, - { "f.43", 43 }, - { "f.44", 44 }, - { "f.45", 45 }, - { "f.46", 46 }, - { "f.47", 47 }, - { "f.48", 48 }, - { "f.49", 49 }, - { "f.5", 5 }, - { "f.50", 50 }, - { "f.51", 51 }, - { "f.52", 52 }, - { "f.53", 53 }, - { "f.54", 54 }, - { "f.55", 55 }, - { "f.56", 56 }, - { "f.57", 57 }, - { "f.58", 58 }, - { "f.59", 59 }, - { "f.6", 6 }, - { "f.60", 60 }, - { "f.61", 61 }, - { "f.62", 62 }, - { "f.63", 63 }, - { "f.7", 7 }, - { "f.8", 8 }, - { "f.9", 9 }, - - { "f0", 0 }, - { "f1", 1 }, - { "f10", 10 }, - { "f11", 11 }, - { "f12", 12 }, - { "f13", 13 }, - { "f14", 14 }, - { "f15", 15 }, - { "f16", 16 }, - { "f17", 17 }, - { "f18", 18 }, - { "f19", 19 }, - { "f2", 2 }, - { "f20", 20 }, - { "f21", 21 }, - { "f22", 22 }, - { "f23", 23 }, - { "f24", 24 }, - { "f25", 25 }, - { "f26", 26 }, - { "f27", 27 }, - { "f28", 28 }, - { "f29", 29 }, - { "f3", 3 }, - { "f30", 30 }, - { "f31", 31 }, - - { "f32", 32 }, /* Extended floating point scalar registers (ISA 2.06). */ - { "f33", 33 }, - { "f34", 34 }, - { "f35", 35 }, - { "f36", 36 }, - { "f37", 37 }, - { "f38", 38 }, - { "f39", 39 }, - { "f4", 4 }, - { "f40", 40 }, - { "f41", 41 }, - { "f42", 42 }, - { "f43", 43 }, - { "f44", 44 }, - { "f45", 45 }, - { "f46", 46 }, - { "f47", 47 }, - { "f48", 48 }, - { "f49", 49 }, - { "f5", 5 }, - { "f50", 50 }, - { "f51", 51 }, - { "f52", 52 }, - { "f53", 53 }, - { "f54", 54 }, - { "f55", 55 }, - { "f56", 56 }, - { "f57", 57 }, - { "f58", 58 }, - { "f59", 59 }, - { "f6", 6 }, - { "f60", 60 }, - { "f61", 61 }, - { "f62", 62 }, - { "f63", 63 }, - { "f7", 7 }, - { "f8", 8 }, - { "f9", 9 }, - - { "fpscr", 0 }, - - /* Quantization registers used with pair single instructions. */ - { "gqr.0", 0 }, - { "gqr.1", 1 }, - { "gqr.2", 2 }, - { "gqr.3", 3 }, - { "gqr.4", 4 }, - { "gqr.5", 5 }, - { "gqr.6", 6 }, - { "gqr.7", 7 }, - { "gqr0", 0 }, - { "gqr1", 1 }, - { "gqr2", 2 }, - { "gqr3", 3 }, - { "gqr4", 4 }, - { "gqr5", 5 }, - { "gqr6", 6 }, - { "gqr7", 7 }, - - { "lr", 8 }, /* Link Register */ - - { "pmr", 0 }, - - { "r.0", 0 }, /* General Purpose Registers */ - { "r.1", 1 }, - { "r.10", 10 }, - { "r.11", 11 }, - { "r.12", 12 }, - { "r.13", 13 }, - { "r.14", 14 }, - { "r.15", 15 }, - { "r.16", 16 }, - { "r.17", 17 }, - { "r.18", 18 }, - { "r.19", 19 }, - { "r.2", 2 }, - { "r.20", 20 }, - { "r.21", 21 }, - { "r.22", 22 }, - { "r.23", 23 }, - { "r.24", 24 }, - { "r.25", 25 }, - { "r.26", 26 }, - { "r.27", 27 }, - { "r.28", 28 }, - { "r.29", 29 }, - { "r.3", 3 }, - { "r.30", 30 }, - { "r.31", 31 }, - { "r.4", 4 }, - { "r.5", 5 }, - { "r.6", 6 }, - { "r.7", 7 }, - { "r.8", 8 }, - { "r.9", 9 }, - - { "r.sp", 1 }, /* Stack Pointer */ - - { "r.toc", 2 }, /* Pointer to the table of contents */ - - { "r0", 0 }, /* More general purpose registers */ - { "r1", 1 }, - { "r10", 10 }, - { "r11", 11 }, - { "r12", 12 }, - { "r13", 13 }, - { "r14", 14 }, - { "r15", 15 }, - { "r16", 16 }, - { "r17", 17 }, - { "r18", 18 }, - { "r19", 19 }, - { "r2", 2 }, - { "r20", 20 }, - { "r21", 21 }, - { "r22", 22 }, - { "r23", 23 }, - { "r24", 24 }, - { "r25", 25 }, - { "r26", 26 }, - { "r27", 27 }, - { "r28", 28 }, - { "r29", 29 }, - { "r3", 3 }, - { "r30", 30 }, - { "r31", 31 }, - { "r4", 4 }, - { "r5", 5 }, - { "r6", 6 }, - { "r7", 7 }, - { "r8", 8 }, - { "r9", 9 }, - - { "rtoc", 2 }, /* Table of contents */ - - { "sdr1", 25 }, /* Storage Description Register 1 */ - - { "sp", 1 }, - - { "srr0", 26 }, /* Machine Status Save/Restore Register 0 */ - { "srr1", 27 }, /* Machine Status Save/Restore Register 1 */ - - { "v.0", 0 }, /* Vector (Altivec/VMX) registers */ - { "v.1", 1 }, - { "v.10", 10 }, - { "v.11", 11 }, - { "v.12", 12 }, - { "v.13", 13 }, - { "v.14", 14 }, - { "v.15", 15 }, - { "v.16", 16 }, - { "v.17", 17 }, - { "v.18", 18 }, - { "v.19", 19 }, - { "v.2", 2 }, - { "v.20", 20 }, - { "v.21", 21 }, - { "v.22", 22 }, - { "v.23", 23 }, - { "v.24", 24 }, - { "v.25", 25 }, - { "v.26", 26 }, - { "v.27", 27 }, - { "v.28", 28 }, - { "v.29", 29 }, - { "v.3", 3 }, - { "v.30", 30 }, - { "v.31", 31 }, - { "v.4", 4 }, - { "v.5", 5 }, - { "v.6", 6 }, - { "v.7", 7 }, - { "v.8", 8 }, - { "v.9", 9 }, - - { "v0", 0 }, - { "v1", 1 }, - { "v10", 10 }, - { "v11", 11 }, - { "v12", 12 }, - { "v13", 13 }, - { "v14", 14 }, - { "v15", 15 }, - { "v16", 16 }, - { "v17", 17 }, - { "v18", 18 }, - { "v19", 19 }, - { "v2", 2 }, - { "v20", 20 }, - { "v21", 21 }, - { "v22", 22 }, - { "v23", 23 }, - { "v24", 24 }, - { "v25", 25 }, - { "v26", 26 }, - { "v27", 27 }, - { "v28", 28 }, - { "v29", 29 }, - { "v3", 3 }, - { "v30", 30 }, - { "v31", 31 }, - { "v4", 4 }, - { "v5", 5 }, - { "v6", 6 }, - { "v7", 7 }, - { "v8", 8 }, - { "v9", 9 }, - - { "vs.0", 0 }, /* Vector Scalar (VSX) registers (ISA 2.06). */ - { "vs.1", 1 }, - { "vs.10", 10 }, - { "vs.11", 11 }, - { "vs.12", 12 }, - { "vs.13", 13 }, - { "vs.14", 14 }, - { "vs.15", 15 }, - { "vs.16", 16 }, - { "vs.17", 17 }, - { "vs.18", 18 }, - { "vs.19", 19 }, - { "vs.2", 2 }, - { "vs.20", 20 }, - { "vs.21", 21 }, - { "vs.22", 22 }, - { "vs.23", 23 }, - { "vs.24", 24 }, - { "vs.25", 25 }, - { "vs.26", 26 }, - { "vs.27", 27 }, - { "vs.28", 28 }, - { "vs.29", 29 }, - { "vs.3", 3 }, - { "vs.30", 30 }, - { "vs.31", 31 }, - { "vs.32", 32 }, - { "vs.33", 33 }, - { "vs.34", 34 }, - { "vs.35", 35 }, - { "vs.36", 36 }, - { "vs.37", 37 }, - { "vs.38", 38 }, - { "vs.39", 39 }, - { "vs.4", 4 }, - { "vs.40", 40 }, - { "vs.41", 41 }, - { "vs.42", 42 }, - { "vs.43", 43 }, - { "vs.44", 44 }, - { "vs.45", 45 }, - { "vs.46", 46 }, - { "vs.47", 47 }, - { "vs.48", 48 }, - { "vs.49", 49 }, - { "vs.5", 5 }, - { "vs.50", 50 }, - { "vs.51", 51 }, - { "vs.52", 52 }, - { "vs.53", 53 }, - { "vs.54", 54 }, - { "vs.55", 55 }, - { "vs.56", 56 }, - { "vs.57", 57 }, - { "vs.58", 58 }, - { "vs.59", 59 }, - { "vs.6", 6 }, - { "vs.60", 60 }, - { "vs.61", 61 }, - { "vs.62", 62 }, - { "vs.63", 63 }, - { "vs.7", 7 }, - { "vs.8", 8 }, - { "vs.9", 9 }, - - { "vs0", 0 }, - { "vs1", 1 }, - { "vs10", 10 }, - { "vs11", 11 }, - { "vs12", 12 }, - { "vs13", 13 }, - { "vs14", 14 }, - { "vs15", 15 }, - { "vs16", 16 }, - { "vs17", 17 }, - { "vs18", 18 }, - { "vs19", 19 }, - { "vs2", 2 }, - { "vs20", 20 }, - { "vs21", 21 }, - { "vs22", 22 }, - { "vs23", 23 }, - { "vs24", 24 }, - { "vs25", 25 }, - { "vs26", 26 }, - { "vs27", 27 }, - { "vs28", 28 }, - { "vs29", 29 }, - { "vs3", 3 }, - { "vs30", 30 }, - { "vs31", 31 }, - { "vs32", 32 }, - { "vs33", 33 }, - { "vs34", 34 }, - { "vs35", 35 }, - { "vs36", 36 }, - { "vs37", 37 }, - { "vs38", 38 }, - { "vs39", 39 }, - { "vs4", 4 }, - { "vs40", 40 }, - { "vs41", 41 }, - { "vs42", 42 }, - { "vs43", 43 }, - { "vs44", 44 }, - { "vs45", 45 }, - { "vs46", 46 }, - { "vs47", 47 }, - { "vs48", 48 }, - { "vs49", 49 }, - { "vs5", 5 }, - { "vs50", 50 }, - { "vs51", 51 }, - { "vs52", 52 }, - { "vs53", 53 }, - { "vs54", 54 }, - { "vs55", 55 }, - { "vs56", 56 }, - { "vs57", 57 }, - { "vs58", 58 }, - { "vs59", 59 }, - { "vs6", 6 }, - { "vs60", 60 }, - { "vs61", 61 }, - { "vs62", 62 }, - { "vs63", 63 }, - { "vs7", 7 }, - { "vs8", 8 }, - { "vs9", 9 }, - - { "xer", 1 }, - -}; - -#define REG_NAME_CNT (sizeof (pre_defined_registers) / sizeof (struct pd_reg)) - -/* Given NAME, find the register number associated with that name, return - the integer value associated with the given name or -1 on failure. */ - -static int -reg_name_search (const struct pd_reg *regs, int regcount, const char *name) -{ - int middle, low, high; - int cmp; - - low = 0; - high = regcount - 1; - - do - { - middle = (low + high) / 2; - cmp = strcasecmp (name, regs[middle].name); - if (cmp < 0) - high = middle - 1; - else if (cmp > 0) - low = middle + 1; - else - return regs[middle].value; - } - while (low <= high); - - return -1; -} - -/* - * Summary of register_name. - * - * in: Input_line_pointer points to 1st char of operand. - * - * out: A expressionS. - * The operand may have been a register: in this case, X_op == O_register, - * X_add_number is set to the register number, and truth is returned. - * Input_line_pointer->(next non-blank) char after operand, or is in its - * original state. - */ - -static bfd_boolean -register_name (expressionS *expressionP) -{ - int reg_number; - char *name; - char *start; - char c; - - /* Find the spelling of the operand. */ - start = name = input_line_pointer; - if (name[0] == '%' && ISALPHA (name[1])) - name = ++input_line_pointer; - - else if (!reg_names_p || !ISALPHA (name[0])) - return FALSE; - - c = get_symbol_end (); - reg_number = reg_name_search (pre_defined_registers, REG_NAME_CNT, name); - - /* Put back the delimiting char. */ - *input_line_pointer = c; - - /* Look to see if it's in the register table. */ - if (reg_number >= 0) - { - expressionP->X_op = O_register; - expressionP->X_add_number = reg_number; - - /* Make the rest nice. */ - expressionP->X_add_symbol = NULL; - expressionP->X_op_symbol = NULL; - return TRUE; - } - - /* Reset the line as if we had not done anything. */ - input_line_pointer = start; - return FALSE; -} - -/* This function is called for each symbol seen in an expression. It - handles the special parsing which PowerPC assemblers are supposed - to use for condition codes. */ - -/* Whether to do the special parsing. */ -static bfd_boolean cr_operand; - -/* Names to recognize in a condition code. This table is sorted. */ -static const struct pd_reg cr_names[] = -{ - { "cr0", 0 }, - { "cr1", 1 }, - { "cr2", 2 }, - { "cr3", 3 }, - { "cr4", 4 }, - { "cr5", 5 }, - { "cr6", 6 }, - { "cr7", 7 }, - { "eq", 2 }, - { "gt", 1 }, - { "lt", 0 }, - { "so", 3 }, - { "un", 3 } -}; - -/* Parsing function. This returns non-zero if it recognized an - expression. */ - -int -ppc_parse_name (const char *name, expressionS *exp) -{ - int val; - - if (! cr_operand) - return 0; - - if (*name == '%') - ++name; - val = reg_name_search (cr_names, sizeof cr_names / sizeof cr_names[0], - name); - if (val < 0) - return 0; - - exp->X_op = O_constant; - exp->X_add_number = val; - - return 1; -} - -/* Local variables. */ - -/* Whether to target xcoff64/elf64. */ -static unsigned int ppc_obj64 = BFD_DEFAULT_TARGET_SIZE == 64; - -/* Opcode hash table. */ -static struct hash_control *ppc_hash; - -/* Macro hash table. */ -static struct hash_control *ppc_macro_hash; - -#ifdef OBJ_ELF -/* What type of shared library support to use. */ -static enum { SHLIB_NONE, SHLIB_PIC, SHLIB_MRELOCATABLE } shlib = SHLIB_NONE; - -/* Flags to set in the elf header. */ -static flagword ppc_flags = 0; - -/* Whether this is Solaris or not. */ -#ifdef TARGET_SOLARIS_COMMENT -#define SOLARIS_P TRUE -#else -#define SOLARIS_P FALSE -#endif - -static bfd_boolean msolaris = SOLARIS_P; -#endif - -#ifdef OBJ_XCOFF - -/* The RS/6000 assembler uses the .csect pseudo-op to generate code - using a bunch of different sections. These assembler sections, - however, are all encompassed within the .text or .data sections of - the final output file. We handle this by using different - subsegments within these main segments. */ - -/* Next subsegment to allocate within the .text segment. */ -static subsegT ppc_text_subsegment = 2; - -/* Linked list of csects in the text section. */ -static symbolS *ppc_text_csects; - -/* Next subsegment to allocate within the .data segment. */ -static subsegT ppc_data_subsegment = 2; - -/* Linked list of csects in the data section. */ -static symbolS *ppc_data_csects; - -/* The current csect. */ -static symbolS *ppc_current_csect; - -/* The RS/6000 assembler uses a TOC which holds addresses of functions - and variables. Symbols are put in the TOC with the .tc pseudo-op. - A special relocation is used when accessing TOC entries. We handle - the TOC as a subsegment within the .data segment. We set it up if - we see a .toc pseudo-op, and save the csect symbol here. */ -static symbolS *ppc_toc_csect; - -/* The first frag in the TOC subsegment. */ -static fragS *ppc_toc_frag; - -/* The first frag in the first subsegment after the TOC in the .data - segment. NULL if there are no subsegments after the TOC. */ -static fragS *ppc_after_toc_frag; - -/* The current static block. */ -static symbolS *ppc_current_block; - -/* The COFF debugging section; set by md_begin. This is not the - .debug section, but is instead the secret BFD section which will - cause BFD to set the section number of a symbol to N_DEBUG. */ -static asection *ppc_coff_debug_section; - -/* Structure to set the length field of the dwarf sections. */ -struct dw_subsection { - /* Subsections are simply linked. */ - struct dw_subsection *link; - - /* The subsection number. */ - subsegT subseg; - - /* Expression to compute the length of the section. */ - expressionS end_exp; -}; - -static struct dw_section { - /* Corresponding section. */ - segT sect; - - /* Simply linked list of subsections with a label. */ - struct dw_subsection *list_subseg; - - /* The anonymous subsection. */ - struct dw_subsection *anon_subseg; -} dw_sections[XCOFF_DWSECT_NBR_NAMES]; -#endif /* OBJ_XCOFF */ - -#ifdef TE_PE - -/* Various sections that we need for PE coff support. */ -static segT ydata_section; -static segT pdata_section; -static segT reldata_section; -static segT rdata_section; -static segT tocdata_section; - -/* The current section and the previous section. See ppc_previous. */ -static segT ppc_previous_section; -static segT ppc_current_section; - -#endif /* TE_PE */ - -#ifdef OBJ_ELF -symbolS *GOT_symbol; /* Pre-defined "_GLOBAL_OFFSET_TABLE" */ -#define PPC_APUINFO_ISEL 0x40 -#define PPC_APUINFO_PMR 0x41 -#define PPC_APUINFO_RFMCI 0x42 -#define PPC_APUINFO_CACHELCK 0x43 -#define PPC_APUINFO_SPE 0x100 -#define PPC_APUINFO_EFS 0x101 -#define PPC_APUINFO_BRLOCK 0x102 -#define PPC_APUINFO_VLE 0x104 - -/* - * We keep a list of APUinfo - */ -unsigned long *ppc_apuinfo_list; -unsigned int ppc_apuinfo_num; -unsigned int ppc_apuinfo_num_alloc; -#endif /* OBJ_ELF */ - -#ifdef OBJ_ELF -const char *const md_shortopts = "b:l:usm:K:VQ:"; -#else -const char *const md_shortopts = "um:"; -#endif -#define OPTION_NOPS (OPTION_MD_BASE + 0) -const struct option md_longopts[] = { - {"nops", required_argument, NULL, OPTION_NOPS}, - {NULL, no_argument, NULL, 0} -}; -const size_t md_longopts_size = sizeof (md_longopts); - -int -md_parse_option (int c, char *arg) -{ - ppc_cpu_t new_cpu; - - switch (c) - { - case 'u': - /* -u means that any undefined symbols should be treated as - external, which is the default for gas anyhow. */ - break; - -#ifdef OBJ_ELF - case 'l': - /* Solaris as takes -le (presumably for little endian). For completeness - sake, recognize -be also. */ - if (strcmp (arg, "e") == 0) - { - target_big_endian = 0; - set_target_endian = 1; - if (ppc_cpu & PPC_OPCODE_VLE) - as_bad (_("the use of -mvle requires big endian.")); - } - else - return 0; - - break; - - case 'b': - if (strcmp (arg, "e") == 0) - { - target_big_endian = 1; - set_target_endian = 1; - } - else - return 0; - - break; - - case 'K': - /* Recognize -K PIC. */ - if (strcmp (arg, "PIC") == 0 || strcmp (arg, "pic") == 0) - { - shlib = SHLIB_PIC; - ppc_flags |= EF_PPC_RELOCATABLE_LIB; - } - else - return 0; - - break; -#endif - - /* a64 and a32 determine whether to use XCOFF64 or XCOFF32. */ - case 'a': - if (strcmp (arg, "64") == 0) - { -#ifdef BFD64 - ppc_obj64 = 1; - if (ppc_cpu & PPC_OPCODE_VLE) - as_bad (_("the use of -mvle requires -a32.")); -#else - as_fatal (_("%s unsupported"), "-a64"); -#endif - } - else if (strcmp (arg, "32") == 0) - ppc_obj64 = 0; - else - return 0; - break; - - case 'm': - new_cpu = ppc_parse_cpu (ppc_cpu, &sticky, arg); - if (new_cpu != 0) - { - ppc_cpu = new_cpu; - if (strcmp (arg, "vle") == 0) - { - if (set_target_endian && target_big_endian == 0) - as_bad (_("the use of -mvle requires big endian.")); - if (ppc_obj64) - as_bad (_("the use of -mvle requires -a32.")); - } - } - - else if (strcmp (arg, "regnames") == 0) - reg_names_p = TRUE; - - else if (strcmp (arg, "no-regnames") == 0) - reg_names_p = FALSE; - -#ifdef OBJ_ELF - /* -mrelocatable/-mrelocatable-lib -- warn about initializations - that require relocation. */ - else if (strcmp (arg, "relocatable") == 0) - { - shlib = SHLIB_MRELOCATABLE; - ppc_flags |= EF_PPC_RELOCATABLE; - } - - else if (strcmp (arg, "relocatable-lib") == 0) - { - shlib = SHLIB_MRELOCATABLE; - ppc_flags |= EF_PPC_RELOCATABLE_LIB; - } - - /* -memb, set embedded bit. */ - else if (strcmp (arg, "emb") == 0) - ppc_flags |= EF_PPC_EMB; - - /* -mlittle/-mbig set the endianness. */ - else if (strcmp (arg, "little") == 0 - || strcmp (arg, "little-endian") == 0) - { - target_big_endian = 0; - set_target_endian = 1; - if (ppc_cpu & PPC_OPCODE_VLE) - as_bad (_("the use of -mvle requires big endian.")); - } - - else if (strcmp (arg, "big") == 0 || strcmp (arg, "big-endian") == 0) - { - target_big_endian = 1; - set_target_endian = 1; - } - - else if (strcmp (arg, "solaris") == 0) - { - msolaris = TRUE; - ppc_comment_chars = ppc_solaris_comment_chars; - } - - else if (strcmp (arg, "no-solaris") == 0) - { - msolaris = FALSE; - ppc_comment_chars = ppc_eabi_comment_chars; - } -#endif - else - { - as_bad (_("invalid switch -m%s"), arg); - return 0; - } - break; - -#ifdef OBJ_ELF - /* -V: SVR4 argument to print version ID. */ - case 'V': - print_version_id (); - break; - - /* -Qy, -Qn: SVR4 arguments controlling whether a .comment section - should be emitted or not. FIXME: Not implemented. */ - case 'Q': - break; - - /* Solaris takes -s to specify that .stabs go in a .stabs section, - rather than .stabs.excl, which is ignored by the linker. - FIXME: Not implemented. */ - case 's': - if (arg) - return 0; - - break; -#endif - - case OPTION_NOPS: - { - char *end; - nop_limit = strtoul (optarg, &end, 0); - if (*end) - as_bad (_("--nops needs a numeric argument")); - } - break; - - default: - return 0; - } - - return 1; -} - -void -md_show_usage (FILE *stream) -{ - fprintf (stream, _("\ -PowerPC options:\n\ --a32 generate ELF32/XCOFF32\n\ --a64 generate ELF64/XCOFF64\n\ --u ignored\n\ --mpwrx, -mpwr2 generate code for POWER/2 (RIOS2)\n\ --mpwr generate code for POWER (RIOS1)\n\ --m601 generate code for PowerPC 601\n\ --mppc, -mppc32, -m603, -m604\n\ - generate code for PowerPC 603/604\n\ --m403 generate code for PowerPC 403\n\ --m405 generate code for PowerPC 405\n\ --m440 generate code for PowerPC 440\n\ --m464 generate code for PowerPC 464\n\ --m476 generate code for PowerPC 476\n\ --m7400, -m7410, -m7450, -m7455\n\ - generate code for PowerPC 7400/7410/7450/7455\n\ --m750cl generate code for PowerPC 750cl\n")); - fprintf (stream, _("\ --mppc64, -m620 generate code for PowerPC 620/625/630\n\ --mppc64bridge generate code for PowerPC 64, including bridge insns\n\ --mbooke generate code for 32-bit PowerPC BookE\n\ --ma2 generate code for A2 architecture\n\ --mpower4, -mpwr4 generate code for Power4 architecture\n\ --mpower5, -mpwr5, -mpwr5x\n\ - generate code for Power5 architecture\n\ --mpower6, -mpwr6 generate code for Power6 architecture\n\ --mpower7, -mpwr7 generate code for Power7 architecture\n\ --mpower8, -mpwr8 generate code for Power8 architecture\n\ --mcell generate code for Cell Broadband Engine architecture\n\ --mcom generate code Power/PowerPC common instructions\n\ --many generate code for any architecture (PWR/PWRX/PPC)\n")); - fprintf (stream, _("\ --maltivec generate code for AltiVec\n\ --mvsx generate code for Vector-Scalar (VSX) instructions\n\ --mhtm generate code for Hardware Transactional Memory\n\ --me300 generate code for PowerPC e300 family\n\ --me500, -me500x2 generate code for Motorola e500 core complex\n\ --me500mc, generate code for Freescale e500mc core complex\n\ --me500mc64, generate code for Freescale e500mc64 core complex\n\ --me5500, generate code for Freescale e5500 core complex\n\ --me6500, generate code for Freescale e6500 core complex\n\ --mspe generate code for Motorola SPE instructions\n\ --mvle generate code for Freescale VLE instructions\n\ --mtitan generate code for AppliedMicro Titan core complex\n\ --mregnames Allow symbolic names for registers\n\ --mno-regnames Do not allow symbolic names for registers\n")); -#ifdef OBJ_ELF - fprintf (stream, _("\ --mrelocatable support for GCC's -mrelocatble option\n\ --mrelocatable-lib support for GCC's -mrelocatble-lib option\n\ --memb set PPC_EMB bit in ELF flags\n\ --mlittle, -mlittle-endian, -le\n\ - generate code for a little endian machine\n\ --mbig, -mbig-endian, -be\n\ - generate code for a big endian machine\n\ --msolaris generate code for Solaris\n\ --mno-solaris do not generate code for Solaris\n\ --K PIC set EF_PPC_RELOCATABLE_LIB in ELF flags\n\ --V print assembler version number\n\ --Qy, -Qn ignored\n")); -#endif - fprintf (stream, _("\ --nops=count when aligning, more than COUNT nops uses a branch\n")); -} - -/* Set ppc_cpu if it is not already set. */ - -static void -ppc_set_cpu (void) -{ - const char *default_os = TARGET_OS; - const char *default_cpu = TARGET_CPU; - - if ((ppc_cpu & ~(ppc_cpu_t) PPC_OPCODE_ANY) == 0) - { - if (ppc_obj64) - ppc_cpu |= PPC_OPCODE_PPC | PPC_OPCODE_64; - else if (strncmp (default_os, "aix", 3) == 0 - && default_os[3] >= '4' && default_os[3] <= '9') - ppc_cpu |= PPC_OPCODE_COMMON; - else if (strncmp (default_os, "aix3", 4) == 0) - ppc_cpu |= PPC_OPCODE_POWER; - else if (strcmp (default_cpu, "rs6000") == 0) - ppc_cpu |= PPC_OPCODE_POWER; - else if (strncmp (default_cpu, "powerpc", 7) == 0) - ppc_cpu |= PPC_OPCODE_PPC; - else - as_fatal (_("unknown default cpu = %s, os = %s"), - default_cpu, default_os); - } -} - -/* Figure out the BFD architecture to use. This function and ppc_mach - are called well before md_begin, when the output file is opened. */ - -enum bfd_architecture -ppc_arch (void) -{ - const char *default_cpu = TARGET_CPU; - ppc_set_cpu (); - - if ((ppc_cpu & PPC_OPCODE_PPC) != 0) - return bfd_arch_powerpc; - if ((ppc_cpu & PPC_OPCODE_VLE) != 0) - return bfd_arch_powerpc; - if ((ppc_cpu & PPC_OPCODE_POWER) != 0) - return bfd_arch_rs6000; - if ((ppc_cpu & (PPC_OPCODE_COMMON | PPC_OPCODE_ANY)) != 0) - { - if (strcmp (default_cpu, "rs6000") == 0) - return bfd_arch_rs6000; - else if (strncmp (default_cpu, "powerpc", 7) == 0) - return bfd_arch_powerpc; - } - - as_fatal (_("neither Power nor PowerPC opcodes were selected.")); - return bfd_arch_unknown; -} - -unsigned long -ppc_mach (void) -{ - if (ppc_obj64) - return bfd_mach_ppc64; - else if (ppc_arch () == bfd_arch_rs6000) - return bfd_mach_rs6k; - else if (ppc_cpu & PPC_OPCODE_TITAN) - return bfd_mach_ppc_titan; - else if (ppc_cpu & PPC_OPCODE_VLE) - return bfd_mach_ppc_vle; - else - return bfd_mach_ppc; -} - -extern char* -ppc_target_format (void) -{ -#ifdef OBJ_COFF -#ifdef TE_PE - return target_big_endian ? "pe-powerpc" : "pe-powerpcle"; -#elif TE_POWERMAC - return "xcoff-powermac"; -#else -# ifdef TE_AIX5 - return (ppc_obj64 ? "aix5coff64-rs6000" : "aixcoff-rs6000"); -# else - return (ppc_obj64 ? "aixcoff64-rs6000" : "aixcoff-rs6000"); -# endif -#endif -#endif -#ifdef OBJ_ELF -# ifdef TE_FreeBSD - return (ppc_obj64 ? "elf64-powerpc-freebsd" : "elf32-powerpc-freebsd"); -# elif defined (TE_VXWORKS) - return "elf32-powerpc-vxworks"; -# else - return (target_big_endian - ? (ppc_obj64 ? "elf64-powerpc" : "elf32-powerpc") - : (ppc_obj64 ? "elf64-powerpcle" : "elf32-powerpcle")); -# endif -#endif -} - -/* Validate one entry in powerpc_opcodes[] or vle_opcodes[]. - Return TRUE if there's a problem, otherwise FALSE. */ - -static bfd_boolean -insn_validate (const struct powerpc_opcode *op) -{ - const unsigned char *o; - unsigned long omask = op->mask; - - /* The mask had better not trim off opcode bits. */ - if ((op->opcode & omask) != op->opcode) - { - as_bad (_("mask trims opcode bits for %s"), op->name); - return TRUE; - } - - /* The operands must not overlap the opcode or each other. */ - for (o = op->operands; *o; ++o) - { - if (*o >= num_powerpc_operands) - { - as_bad (_("operand index error for %s"), op->name); - return TRUE; - } - else - { - const struct powerpc_operand *operand = &powerpc_operands[*o]; - if (operand->shift != PPC_OPSHIFT_INV) - { - unsigned long mask; - - if (operand->shift >= 0) - mask = operand->bitm << operand->shift; - else - mask = operand->bitm >> -operand->shift; - if (omask & mask) - { - as_bad (_("operand %d overlap in %s"), - (int) (o - op->operands), op->name); - return TRUE; - } - omask |= mask; - } - } - } - return FALSE; -} - -/* Insert opcodes and macros into hash tables. Called at startup and - for .machine pseudo. */ - -static void -ppc_setup_opcodes (void) -{ - const struct powerpc_opcode *op; - const struct powerpc_opcode *op_end; - const struct powerpc_macro *macro; - const struct powerpc_macro *macro_end; - bfd_boolean bad_insn = FALSE; - - if (ppc_hash != NULL) - hash_die (ppc_hash); - if (ppc_macro_hash != NULL) - hash_die (ppc_macro_hash); - - /* Insert the opcodes into a hash table. */ - ppc_hash = hash_new (); - - if (ENABLE_CHECKING) - { - unsigned int i; - - /* An index into powerpc_operands is stored in struct fix - fx_pcrel_adjust which is 8 bits wide. */ - gas_assert (num_powerpc_operands < 256); - - /* Check operand masks. Code here and in the disassembler assumes - all the 1's in the mask are contiguous. */ - for (i = 0; i < num_powerpc_operands; ++i) - { - unsigned long mask = powerpc_operands[i].bitm; - unsigned long right_bit; - unsigned int j; - - right_bit = mask & -mask; - mask += right_bit; - right_bit = mask & -mask; - if (mask != right_bit) - { - as_bad (_("powerpc_operands[%d].bitm invalid"), i); - bad_insn = TRUE; - } - for (j = i + 1; j < num_powerpc_operands; ++j) - if (memcmp (&powerpc_operands[i], &powerpc_operands[j], - sizeof (powerpc_operands[0])) == 0) - { - as_bad (_("powerpc_operands[%d] duplicates powerpc_operands[%d]"), - j, i); - bad_insn = TRUE; - } - } - } - - op_end = powerpc_opcodes + powerpc_num_opcodes; - for (op = powerpc_opcodes; op < op_end; op++) - { - if (ENABLE_CHECKING) - { - if (op != powerpc_opcodes) - { - int old_opcode = PPC_OP (op[-1].opcode); - int new_opcode = PPC_OP (op[0].opcode); - -#ifdef PRINT_OPCODE_TABLE - printf ("%-14s\t#%04u\tmajor op: 0x%x\top: 0x%x\tmask: 0x%x\tflags: 0x%llx\n", - op->name, (unsigned int) (op - powerpc_opcodes), - (unsigned int) new_opcode, (unsigned int) op->opcode, - (unsigned int) op->mask, (unsigned long long) op->flags); -#endif - - /* The major opcodes had better be sorted. Code in the - disassembler assumes the insns are sorted according to - major opcode. */ - if (new_opcode < old_opcode) - { - as_bad (_("major opcode is not sorted for %s"), - op->name); - bad_insn = TRUE; - } - } - bad_insn |= insn_validate (op); - } - - if ((ppc_cpu & op->flags) != 0 - && !(ppc_cpu & op->deprecated)) - { - const char *retval; - - retval = hash_insert (ppc_hash, op->name, (void *) op); - if (retval != NULL) - { - as_bad (_("duplicate instruction %s"), - op->name); - bad_insn = TRUE; - } - } - } - - if ((ppc_cpu & PPC_OPCODE_ANY) != 0) - for (op = powerpc_opcodes; op < op_end; op++) - hash_insert (ppc_hash, op->name, (void *) op); - - op_end = vle_opcodes + vle_num_opcodes; - for (op = vle_opcodes; op < op_end; op++) - { - if (ENABLE_CHECKING) - { - if (op != vle_opcodes) - { - unsigned old_seg, new_seg; - - old_seg = VLE_OP (op[-1].opcode, op[-1].mask); - old_seg = VLE_OP_TO_SEG (old_seg); - new_seg = VLE_OP (op[0].opcode, op[0].mask); - new_seg = VLE_OP_TO_SEG (new_seg); - -#ifdef PRINT_OPCODE_TABLE - printf ("%-14s\t#%04u\tmajor op: 0x%x\top: 0x%x\tmask: 0x%x\tflags: 0x%llx\n", - op->name, (unsigned int) (op - powerpc_opcodes), - (unsigned int) new_seg, (unsigned int) op->opcode, - (unsigned int) op->mask, (unsigned long long) op->flags); -#endif - /* The major opcodes had better be sorted. Code in the - disassembler assumes the insns are sorted according to - major opcode. */ - if (new_seg < old_seg) - { - as_bad (_("major opcode is not sorted for %s"), - op->name); - bad_insn = TRUE; - } - } - - bad_insn |= insn_validate (op); - } - - if ((ppc_cpu & op->flags) != 0 - && !(ppc_cpu & op->deprecated)) - { - const char *retval; - - retval = hash_insert (ppc_hash, op->name, (void *) op); - if (retval != NULL) - { - as_bad (_("duplicate instruction %s"), - op->name); - bad_insn = TRUE; - } - } - } - - if ((ppc_cpu & PPC_OPCODE_VLE) != 0) - for (op = vle_opcodes; op < op_end; op++) - hash_insert (ppc_hash, op->name, (void *) op); - - /* Insert the macros into a hash table. */ - ppc_macro_hash = hash_new (); - - macro_end = powerpc_macros + powerpc_num_macros; - for (macro = powerpc_macros; macro < macro_end; macro++) - { - if ((macro->flags & ppc_cpu) != 0 || (ppc_cpu & PPC_OPCODE_ANY) != 0) - { - const char *retval; - - retval = hash_insert (ppc_macro_hash, macro->name, (void *) macro); - if (retval != (const char *) NULL) - { - as_bad (_("duplicate macro %s"), macro->name); - bad_insn = TRUE; - } - } - } - - if (bad_insn) - abort (); -} - -/* This function is called when the assembler starts up. It is called - after the options have been parsed and the output file has been - opened. */ - -void -md_begin (void) -{ - ppc_set_cpu (); - - ppc_cie_data_alignment = ppc_obj64 ? -8 : -4; - ppc_dwarf2_line_min_insn_length = (ppc_cpu & PPC_OPCODE_VLE) ? 2 : 4; - -#ifdef OBJ_ELF - /* Set the ELF flags if desired. */ - if (ppc_flags && !msolaris) - bfd_set_private_flags (stdoutput, ppc_flags); -#endif - - ppc_setup_opcodes (); - - /* Tell the main code what the endianness is if it is not overridden - by the user. */ - if (!set_target_endian) - { - set_target_endian = 1; - target_big_endian = PPC_BIG_ENDIAN; - } - -#ifdef OBJ_XCOFF - ppc_coff_debug_section = coff_section_from_bfd_index (stdoutput, N_DEBUG); - - /* Create dummy symbols to serve as initial csects. This forces the - text csects to precede the data csects. These symbols will not - be output. */ - ppc_text_csects = symbol_make ("dummy\001"); - symbol_get_tc (ppc_text_csects)->within = ppc_text_csects; - ppc_data_csects = symbol_make ("dummy\001"); - symbol_get_tc (ppc_data_csects)->within = ppc_data_csects; -#endif - -#ifdef TE_PE - - ppc_current_section = text_section; - ppc_previous_section = 0; - -#endif -} - -void -ppc_cleanup (void) -{ -#ifdef OBJ_ELF - if (ppc_apuinfo_list == NULL) - return; - - /* Ok, so write the section info out. We have this layout: - - byte data what - ---- ---- ---- - 0 8 length of "APUinfo\0" - 4 (n*4) number of APU's (4 bytes each) - 8 2 note type 2 - 12 "APUinfo\0" name - 20 APU#1 first APU's info - 24 APU#2 second APU's info - ... ... - */ - { - char *p; - asection *seg = now_seg; - subsegT subseg = now_subseg; - asection *apuinfo_secp = (asection *) NULL; - unsigned int i; - - /* Create the .PPC.EMB.apuinfo section. */ - apuinfo_secp = subseg_new (".PPC.EMB.apuinfo", 0); - bfd_set_section_flags (stdoutput, - apuinfo_secp, - SEC_HAS_CONTENTS | SEC_READONLY); - - p = frag_more (4); - md_number_to_chars (p, (valueT) 8, 4); - - p = frag_more (4); - md_number_to_chars (p, (valueT) ppc_apuinfo_num * 4, 4); - - p = frag_more (4); - md_number_to_chars (p, (valueT) 2, 4); - - p = frag_more (8); - strcpy (p, "APUinfo"); - - for (i = 0; i < ppc_apuinfo_num; i++) - { - p = frag_more (4); - md_number_to_chars (p, (valueT) ppc_apuinfo_list[i], 4); - } - - frag_align (2, 0, 0); - - /* We probably can't restore the current segment, for there likely - isn't one yet... */ - if (seg && subseg) - subseg_set (seg, subseg); - } -#endif -} - -/* Insert an operand value into an instruction. */ - -static unsigned long -ppc_insert_operand (unsigned long insn, - const struct powerpc_operand *operand, - offsetT val, - ppc_cpu_t cpu, - char *file, - unsigned int line) -{ - long min, max, right; - - max = operand->bitm; - right = max & -max; - min = 0; - - if ((operand->flags & PPC_OPERAND_SIGNED) != 0) - { - if ((operand->flags & PPC_OPERAND_SIGNOPT) == 0) - max = (max >> 1) & -right; - min = ~max & -right; - } - - if ((operand->flags & PPC_OPERAND_PLUS1) != 0) - max++; - - if ((operand->flags & PPC_OPERAND_NEGATIVE) != 0) - { - long tmp = min; - min = -max; - max = -tmp; - } - - if (min <= max) - { - /* Some people write constants with the sign extension done by - hand but only up to 32 bits. This shouldn't really be valid, - but, to permit this code to assemble on a 64-bit host, we - sign extend the 32-bit value to 64 bits if so doing makes the - value valid. */ - if (val > max - && (offsetT) (val - 0x80000000 - 0x80000000) >= min - && (offsetT) (val - 0x80000000 - 0x80000000) <= max - && ((val - 0x80000000 - 0x80000000) & (right - 1)) == 0) - val = val - 0x80000000 - 0x80000000; - - /* Similarly, people write expressions like ~(1<<15), and expect - this to be OK for a 32-bit unsigned value. */ - else if (val < min - && (offsetT) (val + 0x80000000 + 0x80000000) >= min - && (offsetT) (val + 0x80000000 + 0x80000000) <= max - && ((val + 0x80000000 + 0x80000000) & (right - 1)) == 0) - val = val + 0x80000000 + 0x80000000; - - else if (val < min - || val > max - || (val & (right - 1)) != 0) - as_bad_value_out_of_range (_("operand"), val, min, max, file, line); - } - - if (operand->insert) - { - const char *errmsg; - - errmsg = NULL; - insn = (*operand->insert) (insn, (long) val, cpu, &errmsg); - if (errmsg != (const char *) NULL) - as_bad_where (file, line, "%s", errmsg); - } - else if (operand->shift >= 0) - insn |= ((long) val & operand->bitm) << operand->shift; - else - insn |= ((long) val & operand->bitm) >> -operand->shift; - - return insn; -} - - -#ifdef OBJ_ELF -/* Parse @got, etc. and return the desired relocation. */ -static bfd_reloc_code_real_type -ppc_elf_suffix (char **str_p, expressionS *exp_p) -{ - struct map_bfd { - char *string; - unsigned int length : 8; - unsigned int valid32 : 1; - unsigned int valid64 : 1; - unsigned int reloc; - }; - - char ident[20]; - char *str = *str_p; - char *str2; - int ch; - int len; - const struct map_bfd *ptr; - -#define MAP(str, reloc) { str, sizeof (str) - 1, 1, 1, reloc } -#define MAP32(str, reloc) { str, sizeof (str) - 1, 1, 0, reloc } -#define MAP64(str, reloc) { str, sizeof (str) - 1, 0, 1, reloc } - - static const struct map_bfd mapping[] = { - MAP ("l", BFD_RELOC_LO16), - MAP ("h", BFD_RELOC_HI16), - MAP ("ha", BFD_RELOC_HI16_S), - MAP ("brtaken", BFD_RELOC_PPC_B16_BRTAKEN), - MAP ("brntaken", BFD_RELOC_PPC_B16_BRNTAKEN), - MAP ("got", BFD_RELOC_16_GOTOFF), - MAP ("got@l", BFD_RELOC_LO16_GOTOFF), - MAP ("got@h", BFD_RELOC_HI16_GOTOFF), - MAP ("got@ha", BFD_RELOC_HI16_S_GOTOFF), - MAP ("plt@l", BFD_RELOC_LO16_PLTOFF), - MAP ("plt@h", BFD_RELOC_HI16_PLTOFF), - MAP ("plt@ha", BFD_RELOC_HI16_S_PLTOFF), - MAP ("copy", BFD_RELOC_PPC_COPY), - MAP ("globdat", BFD_RELOC_PPC_GLOB_DAT), - MAP ("sectoff", BFD_RELOC_16_BASEREL), - MAP ("sectoff@l", BFD_RELOC_LO16_BASEREL), - MAP ("sectoff@h", BFD_RELOC_HI16_BASEREL), - MAP ("sectoff@ha", BFD_RELOC_HI16_S_BASEREL), - MAP ("tls", BFD_RELOC_PPC_TLS), - MAP ("dtpmod", BFD_RELOC_PPC_DTPMOD), - MAP ("dtprel", BFD_RELOC_PPC_DTPREL), - MAP ("dtprel@l", BFD_RELOC_PPC_DTPREL16_LO), - MAP ("dtprel@h", BFD_RELOC_PPC_DTPREL16_HI), - MAP ("dtprel@ha", BFD_RELOC_PPC_DTPREL16_HA), - MAP ("tprel", BFD_RELOC_PPC_TPREL), - MAP ("tprel@l", BFD_RELOC_PPC_TPREL16_LO), - MAP ("tprel@h", BFD_RELOC_PPC_TPREL16_HI), - MAP ("tprel@ha", BFD_RELOC_PPC_TPREL16_HA), - MAP ("got@tlsgd", BFD_RELOC_PPC_GOT_TLSGD16), - MAP ("got@tlsgd@l", BFD_RELOC_PPC_GOT_TLSGD16_LO), - MAP ("got@tlsgd@h", BFD_RELOC_PPC_GOT_TLSGD16_HI), - MAP ("got@tlsgd@ha", BFD_RELOC_PPC_GOT_TLSGD16_HA), - MAP ("got@tlsld", BFD_RELOC_PPC_GOT_TLSLD16), - MAP ("got@tlsld@l", BFD_RELOC_PPC_GOT_TLSLD16_LO), - MAP ("got@tlsld@h", BFD_RELOC_PPC_GOT_TLSLD16_HI), - MAP ("got@tlsld@ha", BFD_RELOC_PPC_GOT_TLSLD16_HA), - MAP ("got@dtprel", BFD_RELOC_PPC_GOT_DTPREL16), - MAP ("got@dtprel@l", BFD_RELOC_PPC_GOT_DTPREL16_LO), - MAP ("got@dtprel@h", BFD_RELOC_PPC_GOT_DTPREL16_HI), - MAP ("got@dtprel@ha", BFD_RELOC_PPC_GOT_DTPREL16_HA), - MAP ("got@tprel", BFD_RELOC_PPC_GOT_TPREL16), - MAP ("got@tprel@l", BFD_RELOC_PPC_GOT_TPREL16_LO), - MAP ("got@tprel@h", BFD_RELOC_PPC_GOT_TPREL16_HI), - MAP ("got@tprel@ha", BFD_RELOC_PPC_GOT_TPREL16_HA), - MAP32 ("fixup", BFD_RELOC_CTOR), - MAP32 ("plt", BFD_RELOC_24_PLT_PCREL), - MAP32 ("pltrel24", BFD_RELOC_24_PLT_PCREL), - MAP32 ("local24pc", BFD_RELOC_PPC_LOCAL24PC), - MAP32 ("local", BFD_RELOC_PPC_LOCAL24PC), - MAP32 ("pltrel", BFD_RELOC_32_PLT_PCREL), - MAP32 ("sdarel", BFD_RELOC_GPREL16), - MAP32 ("sdarel@l", BFD_RELOC_PPC_VLE_SDAREL_LO16A), - MAP32 ("sdarel@h", BFD_RELOC_PPC_VLE_SDAREL_HI16A), - MAP32 ("sdarel@ha", BFD_RELOC_PPC_VLE_SDAREL_HA16A), - MAP32 ("naddr", BFD_RELOC_PPC_EMB_NADDR32), - MAP32 ("naddr16", BFD_RELOC_PPC_EMB_NADDR16), - MAP32 ("naddr@l", BFD_RELOC_PPC_EMB_NADDR16_LO), - MAP32 ("naddr@h", BFD_RELOC_PPC_EMB_NADDR16_HI), - MAP32 ("naddr@ha", BFD_RELOC_PPC_EMB_NADDR16_HA), - MAP32 ("sdai16", BFD_RELOC_PPC_EMB_SDAI16), - MAP32 ("sda2rel", BFD_RELOC_PPC_EMB_SDA2REL), - MAP32 ("sda2i16", BFD_RELOC_PPC_EMB_SDA2I16), - MAP32 ("sda21", BFD_RELOC_PPC_EMB_SDA21), - MAP32 ("sda21@l", BFD_RELOC_PPC_VLE_SDA21_LO), - MAP32 ("mrkref", BFD_RELOC_PPC_EMB_MRKREF), - MAP32 ("relsect", BFD_RELOC_PPC_EMB_RELSEC16), - MAP32 ("relsect@l", BFD_RELOC_PPC_EMB_RELST_LO), - MAP32 ("relsect@h", BFD_RELOC_PPC_EMB_RELST_HI), - MAP32 ("relsect@ha", BFD_RELOC_PPC_EMB_RELST_HA), - MAP32 ("bitfld", BFD_RELOC_PPC_EMB_BIT_FLD), - MAP32 ("relsda", BFD_RELOC_PPC_EMB_RELSDA), - MAP32 ("xgot", BFD_RELOC_PPC_TOC16), - MAP64 ("high", BFD_RELOC_PPC64_ADDR16_HIGH), - MAP64 ("higha", BFD_RELOC_PPC64_ADDR16_HIGHA), - MAP64 ("higher", BFD_RELOC_PPC64_HIGHER), - MAP64 ("highera", BFD_RELOC_PPC64_HIGHER_S), - MAP64 ("highest", BFD_RELOC_PPC64_HIGHEST), - MAP64 ("highesta", BFD_RELOC_PPC64_HIGHEST_S), - MAP64 ("tocbase", BFD_RELOC_PPC64_TOC), - MAP64 ("toc", BFD_RELOC_PPC_TOC16), - MAP64 ("toc@l", BFD_RELOC_PPC64_TOC16_LO), - MAP64 ("toc@h", BFD_RELOC_PPC64_TOC16_HI), - MAP64 ("toc@ha", BFD_RELOC_PPC64_TOC16_HA), - MAP64 ("dtprel@high", BFD_RELOC_PPC64_DTPREL16_HIGH), - MAP64 ("dtprel@higha", BFD_RELOC_PPC64_DTPREL16_HIGHA), - MAP64 ("dtprel@higher", BFD_RELOC_PPC64_DTPREL16_HIGHER), - MAP64 ("dtprel@highera", BFD_RELOC_PPC64_DTPREL16_HIGHERA), - MAP64 ("dtprel@highest", BFD_RELOC_PPC64_DTPREL16_HIGHEST), - MAP64 ("dtprel@highesta", BFD_RELOC_PPC64_DTPREL16_HIGHESTA), - MAP64 ("tprel@high", BFD_RELOC_PPC64_TPREL16_HIGH), - MAP64 ("tprel@higha", BFD_RELOC_PPC64_TPREL16_HIGHA), - MAP64 ("tprel@higher", BFD_RELOC_PPC64_TPREL16_HIGHER), - MAP64 ("tprel@highera", BFD_RELOC_PPC64_TPREL16_HIGHERA), - MAP64 ("tprel@highest", BFD_RELOC_PPC64_TPREL16_HIGHEST), - MAP64 ("tprel@highesta", BFD_RELOC_PPC64_TPREL16_HIGHESTA), - { (char *) 0, 0, 0, 0, BFD_RELOC_UNUSED } - }; - - if (*str++ != '@') - return BFD_RELOC_UNUSED; - - for (ch = *str, str2 = ident; - (str2 < ident + sizeof (ident) - 1 - && (ISALNUM (ch) || ch == '@')); - ch = *++str) - { - *str2++ = TOLOWER (ch); - } - - *str2 = '\0'; - len = str2 - ident; - - ch = ident[0]; - for (ptr = &mapping[0]; ptr->length > 0; ptr++) - if (ch == ptr->string[0] - && len == ptr->length - && memcmp (ident, ptr->string, ptr->length) == 0 - && (ppc_obj64 ? ptr->valid64 : ptr->valid32)) - { - int reloc = ptr->reloc; - - if (!ppc_obj64 && exp_p->X_add_number != 0) - { - switch (reloc) - { - case BFD_RELOC_16_GOTOFF: - case BFD_RELOC_LO16_GOTOFF: - case BFD_RELOC_HI16_GOTOFF: - case BFD_RELOC_HI16_S_GOTOFF: - as_warn (_("identifier+constant@got means " - "identifier@got+constant")); - break; - - case BFD_RELOC_PPC_GOT_TLSGD16: - case BFD_RELOC_PPC_GOT_TLSGD16_LO: - case BFD_RELOC_PPC_GOT_TLSGD16_HI: - case BFD_RELOC_PPC_GOT_TLSGD16_HA: - case BFD_RELOC_PPC_GOT_TLSLD16: - case BFD_RELOC_PPC_GOT_TLSLD16_LO: - case BFD_RELOC_PPC_GOT_TLSLD16_HI: - case BFD_RELOC_PPC_GOT_TLSLD16_HA: - case BFD_RELOC_PPC_GOT_DTPREL16: - case BFD_RELOC_PPC_GOT_DTPREL16_LO: - case BFD_RELOC_PPC_GOT_DTPREL16_HI: - case BFD_RELOC_PPC_GOT_DTPREL16_HA: - case BFD_RELOC_PPC_GOT_TPREL16: - case BFD_RELOC_PPC_GOT_TPREL16_LO: - case BFD_RELOC_PPC_GOT_TPREL16_HI: - case BFD_RELOC_PPC_GOT_TPREL16_HA: - as_bad (_("symbol+offset not supported for got tls")); - break; - } - } - - /* Now check for identifier@suffix+constant. */ - if (*str == '-' || *str == '+') - { - char *orig_line = input_line_pointer; - expressionS new_exp; - - input_line_pointer = str; - expression (&new_exp); - if (new_exp.X_op == O_constant) - { - exp_p->X_add_number += new_exp.X_add_number; - str = input_line_pointer; - } - - if (&input_line_pointer != str_p) - input_line_pointer = orig_line; - } - *str_p = str; - - if (reloc == (int) BFD_RELOC_PPC64_TOC - && exp_p->X_op == O_symbol - && strcmp (S_GET_NAME (exp_p->X_add_symbol), ".TOC.") == 0) - { - /* Change the symbol so that the dummy .TOC. symbol can be - omitted from the object file. */ - exp_p->X_add_symbol = &abs_symbol; - } - - return (bfd_reloc_code_real_type) reloc; - } - - return BFD_RELOC_UNUSED; -} - -/* Like normal .long/.short/.word, except support @got, etc. - Clobbers input_line_pointer, checks end-of-line. */ -static void -ppc_elf_cons (int nbytes /* 1=.byte, 2=.word, 4=.long, 8=.llong */) -{ - expressionS exp; - bfd_reloc_code_real_type reloc; - - if (is_it_end_of_statement ()) - { - demand_empty_rest_of_line (); - return; - } - - do - { - expression (&exp); - if (*input_line_pointer == '@' - && (reloc = ppc_elf_suffix (&input_line_pointer, - &exp)) != BFD_RELOC_UNUSED) - { - reloc_howto_type *reloc_howto; - int size; - - reloc_howto = bfd_reloc_type_lookup (stdoutput, reloc); - size = bfd_get_reloc_size (reloc_howto); - - if (size > nbytes) - { - as_bad (_("%s relocations do not fit in %d bytes\n"), - reloc_howto->name, nbytes); - } - else - { - char *p; - int offset; - - p = frag_more (nbytes); - memset (p, 0, nbytes); - offset = 0; - if (target_big_endian) - offset = nbytes - size; - fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size, - &exp, 0, reloc); - } - } - else - emit_expr (&exp, (unsigned int) nbytes); - } - while (*input_line_pointer++ == ','); - - /* Put terminator back into stream. */ - input_line_pointer--; - demand_empty_rest_of_line (); -} - -/* Solaris pseduo op to change to the .rodata section. */ -static void -ppc_elf_rdata (int xxx) -{ - char *save_line = input_line_pointer; - static char section[] = ".rodata\n"; - - /* Just pretend this is .section .rodata */ - input_line_pointer = section; - obj_elf_section (xxx); - - input_line_pointer = save_line; -} - -/* Pseudo op to make file scope bss items. */ -static void -ppc_elf_lcomm (int xxx ATTRIBUTE_UNUSED) -{ - char *name; - char c; - char *p; - offsetT size; - symbolS *symbolP; - offsetT align; - segT old_sec; - int old_subsec; - char *pfrag; - int align2; - - name = input_line_pointer; - c = get_symbol_end (); - - /* just after name is now '\0'. */ - p = input_line_pointer; - *p = c; - SKIP_WHITESPACE (); - if (*input_line_pointer != ',') - { - as_bad (_("expected comma after symbol-name: rest of line ignored.")); - ignore_rest_of_line (); - return; - } - - input_line_pointer++; /* skip ',' */ - if ((size = get_absolute_expression ()) < 0) - { - as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) size); - ignore_rest_of_line (); - return; - } - - /* The third argument to .lcomm is the alignment. */ - if (*input_line_pointer != ',') - align = 8; - else - { - ++input_line_pointer; - align = get_absolute_expression (); - if (align <= 0) - { - as_warn (_("ignoring bad alignment")); - align = 8; - } - } - - *p = 0; - symbolP = symbol_find_or_make (name); - *p = c; - - if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) - { - as_bad (_("ignoring attempt to re-define symbol `%s'."), - S_GET_NAME (symbolP)); - ignore_rest_of_line (); - return; - } - - if (S_GET_VALUE (symbolP) && S_GET_VALUE (symbolP) != (valueT) size) - { - as_bad (_("length of .lcomm \"%s\" is already %ld. Not changed to %ld."), - S_GET_NAME (symbolP), - (long) S_GET_VALUE (symbolP), - (long) size); - - ignore_rest_of_line (); - return; - } - - /* Allocate_bss. */ - old_sec = now_seg; - old_subsec = now_subseg; - if (align) - { - /* Convert to a power of 2 alignment. */ - for (align2 = 0; (align & 1) == 0; align >>= 1, ++align2); - if (align != 1) - { - as_bad (_("common alignment not a power of 2")); - ignore_rest_of_line (); - return; - } - } - else - align2 = 0; - - record_alignment (bss_section, align2); - subseg_set (bss_section, 1); - if (align2) - frag_align (align2, 0, 0); - if (S_GET_SEGMENT (symbolP) == bss_section) - symbol_get_frag (symbolP)->fr_symbol = 0; - symbol_set_frag (symbolP, frag_now); - pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, size, - (char *) 0); - *pfrag = 0; - S_SET_SIZE (symbolP, size); - S_SET_SEGMENT (symbolP, bss_section); - subseg_set (old_sec, old_subsec); - demand_empty_rest_of_line (); -} - -/* Pseudo op to set symbol local entry point. */ -static void -ppc_elf_localentry (int ignore ATTRIBUTE_UNUSED) -{ - char *name = input_line_pointer; - char c = get_symbol_end (); - char *p; - expressionS exp; - symbolS *sym; - asymbol *bfdsym; - elf_symbol_type *elfsym; - - p = input_line_pointer; - *p = c; - SKIP_WHITESPACE (); - if (*input_line_pointer != ',') - { - *p = 0; - as_bad (_("expected comma after name `%s' in .localentry directive"), - name); - *p = c; - ignore_rest_of_line (); - return; - } - input_line_pointer++; - expression (&exp); - if (exp.X_op == O_absent) - { - as_bad (_("missing expression in .localentry directive")); - exp.X_op = O_constant; - exp.X_add_number = 0; - } - *p = 0; - sym = symbol_find_or_make (name); - *p = c; - - if (resolve_expression (&exp) - && exp.X_op == O_constant) - { - unsigned char encoded = PPC64_SET_LOCAL_ENTRY_OFFSET (exp.X_add_number); - - if (exp.X_add_number != (offsetT) PPC64_LOCAL_ENTRY_OFFSET (encoded)) - as_bad (_(".localentry expression for `%s' " - "is not a valid power of 2"), S_GET_NAME (sym)); - else - { - bfdsym = symbol_get_bfdsym (sym); - elfsym = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym); - gas_assert (elfsym); - elfsym->internal_elf_sym.st_other &= ~STO_PPC64_LOCAL_MASK; - elfsym->internal_elf_sym.st_other |= encoded; - if (ppc_abiversion == 0) - ppc_abiversion = 2; - } - } - else - as_bad (_(".localentry expression for `%s' " - "does not evaluate to a constant"), S_GET_NAME (sym)); - - demand_empty_rest_of_line (); -} - -/* Pseudo op to set ABI version. */ -static void -ppc_elf_abiversion (int ignore ATTRIBUTE_UNUSED) -{ - expressionS exp; - - expression (&exp); - if (exp.X_op == O_absent) - { - as_bad (_("missing expression in .abiversion directive")); - exp.X_op = O_constant; - exp.X_add_number = 0; - } - - if (resolve_expression (&exp) - && exp.X_op == O_constant) - ppc_abiversion = exp.X_add_number; - else - as_bad (_(".abiversion expression does not evaluate to a constant")); - demand_empty_rest_of_line (); -} - -/* Set ABI version in output file. */ -void -ppc_elf_end (void) -{ - if (ppc_obj64 && ppc_abiversion != 0) - { - elf_elfheader (stdoutput)->e_flags &= ~EF_PPC64_ABI; - elf_elfheader (stdoutput)->e_flags |= ppc_abiversion & EF_PPC64_ABI; - } -} - -/* Validate any relocations emitted for -mrelocatable, possibly adding - fixups for word relocations in writable segments, so we can adjust - them at runtime. */ -static void -ppc_elf_validate_fix (fixS *fixp, segT seg) -{ - if (fixp->fx_done || fixp->fx_pcrel) - return; - - switch (shlib) - { - case SHLIB_NONE: - case SHLIB_PIC: - return; - - case SHLIB_MRELOCATABLE: - if (fixp->fx_r_type <= BFD_RELOC_UNUSED - && fixp->fx_r_type != BFD_RELOC_16_GOTOFF - && fixp->fx_r_type != BFD_RELOC_HI16_GOTOFF - && fixp->fx_r_type != BFD_RELOC_LO16_GOTOFF - && fixp->fx_r_type != BFD_RELOC_HI16_S_GOTOFF - && fixp->fx_r_type != BFD_RELOC_16_BASEREL - && fixp->fx_r_type != BFD_RELOC_LO16_BASEREL - && fixp->fx_r_type != BFD_RELOC_HI16_BASEREL - && fixp->fx_r_type != BFD_RELOC_HI16_S_BASEREL - && (seg->flags & SEC_LOAD) != 0 - && strcmp (segment_name (seg), ".got2") != 0 - && strcmp (segment_name (seg), ".dtors") != 0 - && strcmp (segment_name (seg), ".ctors") != 0 - && strcmp (segment_name (seg), ".fixup") != 0 - && strcmp (segment_name (seg), ".gcc_except_table") != 0 - && strcmp (segment_name (seg), ".eh_frame") != 0 - && strcmp (segment_name (seg), ".ex_shared") != 0) - { - if ((seg->flags & (SEC_READONLY | SEC_CODE)) != 0 - || fixp->fx_r_type != BFD_RELOC_CTOR) - { - as_bad_where (fixp->fx_file, fixp->fx_line, - _("relocation cannot be done when using -mrelocatable")); - } - } - return; - } -} - -/* Prevent elf_frob_file_before_adjust removing a weak undefined - function descriptor sym if the corresponding code sym is used. */ - -void -ppc_frob_file_before_adjust (void) -{ - symbolS *symp; - asection *toc; - - if (!ppc_obj64) - return; - - for (symp = symbol_rootP; symp; symp = symbol_next (symp)) - { - const char *name; - char *dotname; - symbolS *dotsym; - size_t len; - - name = S_GET_NAME (symp); - if (name[0] == '.') - continue; - - if (! S_IS_WEAK (symp) - || S_IS_DEFINED (symp)) - continue; - - len = strlen (name) + 1; - dotname = xmalloc (len + 1); - dotname[0] = '.'; - memcpy (dotname + 1, name, len); - dotsym = symbol_find_noref (dotname, 1); - free (dotname); - if (dotsym != NULL && (symbol_used_p (dotsym) - || symbol_used_in_reloc_p (dotsym))) - symbol_mark_used (symp); - - } - - toc = bfd_get_section_by_name (stdoutput, ".toc"); - if (toc != NULL - && toc_reloc_types != has_large_toc_reloc - && bfd_section_size (stdoutput, toc) > 0x10000) - as_warn (_("TOC section size exceeds 64k")); -} - -/* .TOC. used in an opd entry as .TOC.@tocbase doesn't need to be - emitted. Other uses of .TOC. will cause the symbol to be marked - with BSF_KEEP in md_apply_fix. */ - -void -ppc_elf_adjust_symtab (void) -{ - if (ppc_obj64) - { - symbolS *symp; - symp = symbol_find (".TOC."); - if (symp != NULL) - { - asymbol *bsym = symbol_get_bfdsym (symp); - if ((bsym->flags & BSF_KEEP) == 0) - symbol_remove (symp, &symbol_rootP, &symbol_lastP); - } - } -} -#endif /* OBJ_ELF */ - -#ifdef TE_PE - -/* - * Summary of parse_toc_entry. - * - * in: Input_line_pointer points to the '[' in one of: - * - * [toc] [tocv] [toc32] [toc64] - * - * Anything else is an error of one kind or another. - * - * out: - * return value: success or failure - * toc_kind: kind of toc reference - * input_line_pointer: - * success: first char after the ']' - * failure: unchanged - * - * settings: - * - * [toc] - rv == success, toc_kind = default_toc - * [tocv] - rv == success, toc_kind = data_in_toc - * [toc32] - rv == success, toc_kind = must_be_32 - * [toc64] - rv == success, toc_kind = must_be_64 - * - */ - -enum toc_size_qualifier -{ - default_toc, /* The toc cell constructed should be the system default size */ - data_in_toc, /* This is a direct reference to a toc cell */ - must_be_32, /* The toc cell constructed must be 32 bits wide */ - must_be_64 /* The toc cell constructed must be 64 bits wide */ -}; - -static int -parse_toc_entry (enum toc_size_qualifier *toc_kind) -{ - char *start; - char *toc_spec; - char c; - enum toc_size_qualifier t; - - /* Save the input_line_pointer. */ - start = input_line_pointer; - - /* Skip over the '[' , and whitespace. */ - ++input_line_pointer; - SKIP_WHITESPACE (); - - /* Find the spelling of the operand. */ - toc_spec = input_line_pointer; - c = get_symbol_end (); - - if (strcmp (toc_spec, "toc") == 0) - { - t = default_toc; - } - else if (strcmp (toc_spec, "tocv") == 0) - { - t = data_in_toc; - } - else if (strcmp (toc_spec, "toc32") == 0) - { - t = must_be_32; - } - else if (strcmp (toc_spec, "toc64") == 0) - { - t = must_be_64; - } - else - { - as_bad (_("syntax error: invalid toc specifier `%s'"), toc_spec); - *input_line_pointer = c; - input_line_pointer = start; - return 0; - } - - /* Now find the ']'. */ - *input_line_pointer = c; - - SKIP_WHITESPACE (); /* leading whitespace could be there. */ - c = *input_line_pointer++; /* input_line_pointer->past char in c. */ - - if (c != ']') - { - as_bad (_("syntax error: expected `]', found `%c'"), c); - input_line_pointer = start; - return 0; - } - - *toc_kind = t; - return 1; -} -#endif - -#if defined (OBJ_XCOFF) || defined (OBJ_ELF) -/* See whether a symbol is in the TOC section. */ - -static int -ppc_is_toc_sym (symbolS *sym) -{ -#ifdef OBJ_XCOFF - return (symbol_get_tc (sym)->symbol_class == XMC_TC - || symbol_get_tc (sym)->symbol_class == XMC_TC0); -#endif -#ifdef OBJ_ELF - const char *sname = segment_name (S_GET_SEGMENT (sym)); - if (ppc_obj64) - return strcmp (sname, ".toc") == 0; - else - return strcmp (sname, ".got") == 0; -#endif -} -#endif /* defined (OBJ_XCOFF) || defined (OBJ_ELF) */ - - -#ifdef OBJ_ELF -#define APUID(a,v) ((((a) & 0xffff) << 16) | ((v) & 0xffff)) -static void -ppc_apuinfo_section_add (unsigned int apu, unsigned int version) -{ - unsigned int i; - - /* Check we don't already exist. */ - for (i = 0; i < ppc_apuinfo_num; i++) - if (ppc_apuinfo_list[i] == APUID (apu, version)) - return; - - if (ppc_apuinfo_num == ppc_apuinfo_num_alloc) - { - if (ppc_apuinfo_num_alloc == 0) - { - ppc_apuinfo_num_alloc = 4; - ppc_apuinfo_list = (unsigned long *) - xmalloc (sizeof (unsigned long) * ppc_apuinfo_num_alloc); - } - else - { - ppc_apuinfo_num_alloc += 4; - ppc_apuinfo_list = (unsigned long *) xrealloc (ppc_apuinfo_list, - sizeof (unsigned long) * ppc_apuinfo_num_alloc); - } - } - ppc_apuinfo_list[ppc_apuinfo_num++] = APUID (apu, version); -} -#undef APUID -#endif - - -/* We need to keep a list of fixups. We can't simply generate them as - we go, because that would require us to first create the frag, and - that would screw up references to ``.''. */ - -struct ppc_fixup -{ - expressionS exp; - int opindex; - bfd_reloc_code_real_type reloc; -}; - -#define MAX_INSN_FIXUPS (5) - -/* Form I16L. */ -#define E_OR2I_INSN 0x7000C000 -#define E_AND2I_DOT_INSN 0x7000C800 -#define E_OR2IS_INSN 0x7000D000 -#define E_LIS_INSN 0x7000E000 -#define E_AND2IS_DOT_INSN 0x7000E800 - -/* Form I16A. */ -#define E_ADD2I_DOT_INSN 0x70008800 -#define E_ADD2IS_INSN 0x70009000 -#define E_CMP16I_INSN 0x70009800 -#define E_MULL2I_INSN 0x7000A000 -#define E_CMPL16I_INSN 0x7000A800 -#define E_CMPH16I_INSN 0x7000B000 -#define E_CMPHL16I_INSN 0x7000B800 - -/* This routine is called for each instruction to be assembled. */ - -void -md_assemble (char *str) -{ - char *s; - const struct powerpc_opcode *opcode; - unsigned long insn; - const unsigned char *opindex_ptr; - int skip_optional; - int need_paren; - int next_opindex; - struct ppc_fixup fixups[MAX_INSN_FIXUPS]; - int fc; - char *f; - int addr_mod; - int i; - unsigned int insn_length; - - /* Get the opcode. */ - for (s = str; *s != '\0' && ! ISSPACE (*s); s++) - ; - if (*s != '\0') - *s++ = '\0'; - - /* Look up the opcode in the hash table. */ - opcode = (const struct powerpc_opcode *) hash_find (ppc_hash, str); - if (opcode == (const struct powerpc_opcode *) NULL) - { - const struct powerpc_macro *macro; - - macro = (const struct powerpc_macro *) hash_find (ppc_macro_hash, str); - if (macro == (const struct powerpc_macro *) NULL) - as_bad (_("unrecognized opcode: `%s'"), str); - else - ppc_macro (s, macro); - - return; - } - - insn = opcode->opcode; - - str = s; - while (ISSPACE (*str)) - ++str; - - /* PowerPC operands are just expressions. The only real issue is - that a few operand types are optional. All cases which might use - an optional operand separate the operands only with commas (in some - cases parentheses are used, as in ``lwz 1,0(1)'' but such cases never - have optional operands). Most instructions with optional operands - have only one. Those that have more than one optional operand can - take either all their operands or none. So, before we start seriously - parsing the operands, we check to see if we have optional operands, - and if we do, we count the number of commas to see which operands - have been omitted. */ - skip_optional = 0; - for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++) - { - const struct powerpc_operand *operand; - - operand = &powerpc_operands[*opindex_ptr]; - if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0) - { - unsigned int opcount; - unsigned int num_operands_expected; - - /* There is an optional operand. Count the number of - commas in the input line. */ - if (*str == '\0') - opcount = 0; - else - { - opcount = 1; - s = str; - while ((s = strchr (s, ',')) != (char *) NULL) - { - ++opcount; - ++s; - } - } - - /* Compute the number of expected operands. - Do not count fake operands. */ - for (num_operands_expected = 0, i = 0; opcode->operands[i]; i ++) - if ((powerpc_operands [opcode->operands[i]].flags & PPC_OPERAND_FAKE) == 0) - ++ num_operands_expected; - - /* If there are fewer operands in the line then are called - for by the instruction, we want to skip the optional - operands. */ - if (opcount < num_operands_expected) - skip_optional = 1; - - break; - } - } - - /* Gather the operands. */ - need_paren = 0; - next_opindex = 0; - fc = 0; - for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++) - { - const struct powerpc_operand *operand; - const char *errmsg; - char *hold; - expressionS ex; - char endc; - - if (next_opindex == 0) - operand = &powerpc_operands[*opindex_ptr]; - else - { - operand = &powerpc_operands[next_opindex]; - next_opindex = 0; - } - errmsg = NULL; - - /* If this is a fake operand, then we do not expect anything - from the input. */ - if ((operand->flags & PPC_OPERAND_FAKE) != 0) - { - insn = (*operand->insert) (insn, 0L, ppc_cpu, &errmsg); - if (errmsg != (const char *) NULL) - as_bad ("%s", errmsg); - continue; - } - - /* If this is an optional operand, and we are skipping it, just - insert a zero. */ - if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0 - && skip_optional) - { - if (operand->insert) - { - insn = (*operand->insert) (insn, 0L, ppc_cpu, &errmsg); - if (errmsg != (const char *) NULL) - as_bad ("%s", errmsg); - } - if ((operand->flags & PPC_OPERAND_NEXT) != 0) - next_opindex = *opindex_ptr + 1; - continue; - } - - /* Gather the operand. */ - hold = input_line_pointer; - input_line_pointer = str; - -#ifdef TE_PE - if (*input_line_pointer == '[') - { - /* We are expecting something like the second argument here: - * - * lwz r4,[toc].GS.0.static_int(rtoc) - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * The argument following the `]' must be a symbol name, and the - * register must be the toc register: 'rtoc' or '2' - * - * The effect is to 0 as the displacement field - * in the instruction, and issue an IMAGE_REL_PPC_TOCREL16 (or - * the appropriate variation) reloc against it based on the symbol. - * The linker will build the toc, and insert the resolved toc offset. - * - * Note: - * o The size of the toc entry is currently assumed to be - * 32 bits. This should not be assumed to be a hard coded - * number. - * o In an effort to cope with a change from 32 to 64 bits, - * there are also toc entries that are specified to be - * either 32 or 64 bits: - * lwz r4,[toc32].GS.0.static_int(rtoc) - * lwz r4,[toc64].GS.0.static_int(rtoc) - * These demand toc entries of the specified size, and the - * instruction probably requires it. - */ - - int valid_toc; - enum toc_size_qualifier toc_kind; - bfd_reloc_code_real_type toc_reloc; - - /* Go parse off the [tocXX] part. */ - valid_toc = parse_toc_entry (&toc_kind); - - if (!valid_toc) - { - ignore_rest_of_line (); - break; - } - - /* Now get the symbol following the ']'. */ - expression (&ex); - - switch (toc_kind) - { - case default_toc: - /* In this case, we may not have seen the symbol yet, - since it is allowed to appear on a .extern or .globl - or just be a label in the .data section. */ - toc_reloc = BFD_RELOC_PPC_TOC16; - break; - case data_in_toc: - /* 1. The symbol must be defined and either in the toc - section, or a global. - 2. The reloc generated must have the TOCDEFN flag set - in upper bit mess of the reloc type. - FIXME: It's a little confusing what the tocv - qualifier can be used for. At the very least, I've - seen three uses, only one of which I'm sure I can - explain. */ - if (ex.X_op == O_symbol) - { - gas_assert (ex.X_add_symbol != NULL); - if (symbol_get_bfdsym (ex.X_add_symbol)->section - != tocdata_section) - { - as_bad (_("[tocv] symbol is not a toc symbol")); - } - } - - toc_reloc = BFD_RELOC_PPC_TOC16; - break; - case must_be_32: - /* FIXME: these next two specifically specify 32/64 bit - toc entries. We don't support them today. Is this - the right way to say that? */ - toc_reloc = BFD_RELOC_UNUSED; - as_bad (_("unimplemented toc32 expression modifier")); - break; - case must_be_64: - /* FIXME: see above. */ - toc_reloc = BFD_RELOC_UNUSED; - as_bad (_("unimplemented toc64 expression modifier")); - break; - default: - fprintf (stderr, - _("Unexpected return value [%d] from parse_toc_entry!\n"), - toc_kind); - abort (); - break; - } - - /* We need to generate a fixup for this expression. */ - if (fc >= MAX_INSN_FIXUPS) - as_fatal (_("too many fixups")); - - fixups[fc].reloc = toc_reloc; - fixups[fc].exp = ex; - fixups[fc].opindex = *opindex_ptr; - ++fc; - - /* Ok. We've set up the fixup for the instruction. Now make it - look like the constant 0 was found here. */ - ex.X_unsigned = 1; - ex.X_op = O_constant; - ex.X_add_number = 0; - ex.X_add_symbol = NULL; - ex.X_op_symbol = NULL; - } - - else -#endif /* TE_PE */ - { - if ((reg_names_p - && (((operand->flags & PPC_OPERAND_CR_BIT) != 0) - || ((operand->flags & PPC_OPERAND_CR_REG) != 0))) - || !register_name (&ex)) - { - char save_lex = lex_type['%']; - - if (((operand->flags & PPC_OPERAND_CR_REG) != 0) - || (operand->flags & PPC_OPERAND_CR_BIT) != 0) - { - cr_operand = TRUE; - lex_type['%'] |= LEX_BEGIN_NAME; - } - expression (&ex); - cr_operand = FALSE; - lex_type['%'] = save_lex; - } - } - - str = input_line_pointer; - input_line_pointer = hold; - - if (ex.X_op == O_illegal) - as_bad (_("illegal operand")); - else if (ex.X_op == O_absent) - as_bad (_("missing operand")); - else if (ex.X_op == O_register) - { - insn = ppc_insert_operand (insn, operand, ex.X_add_number, - ppc_cpu, (char *) NULL, 0); - } - else if (ex.X_op == O_constant) - { -#ifdef OBJ_ELF - /* Allow @HA, @L, @H on constants. */ - bfd_reloc_code_real_type reloc; - char *orig_str = str; - - if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED) - switch (reloc) - { - default: - str = orig_str; - break; - - case BFD_RELOC_LO16: - ex.X_add_number &= 0xffff; - if ((operand->flags & PPC_OPERAND_SIGNED) != 0) - ex.X_add_number = SEX16 (ex.X_add_number); - break; - - case BFD_RELOC_HI16: - if (REPORT_OVERFLOW_HI && ppc_obj64) - { - /* PowerPC64 @h is tested for overflow. */ - ex.X_add_number = (addressT) ex.X_add_number >> 16; - if ((operand->flags & PPC_OPERAND_SIGNED) != 0) - { - addressT sign = (((addressT) -1 >> 16) + 1) >> 1; - ex.X_add_number - = ((addressT) ex.X_add_number ^ sign) - sign; - } - break; - } - /* Fall thru */ - - case BFD_RELOC_PPC64_ADDR16_HIGH: - ex.X_add_number = PPC_HI (ex.X_add_number); - if ((operand->flags & PPC_OPERAND_SIGNED) != 0) - ex.X_add_number = SEX16 (ex.X_add_number); - break; - - case BFD_RELOC_HI16_S: - if (REPORT_OVERFLOW_HI && ppc_obj64) - { - /* PowerPC64 @ha is tested for overflow. */ - ex.X_add_number - = ((addressT) ex.X_add_number + 0x8000) >> 16; - if ((operand->flags & PPC_OPERAND_SIGNED) != 0) - { - addressT sign = (((addressT) -1 >> 16) + 1) >> 1; - ex.X_add_number - = ((addressT) ex.X_add_number ^ sign) - sign; - } - break; - } - /* Fall thru */ - - case BFD_RELOC_PPC64_ADDR16_HIGHA: - ex.X_add_number = PPC_HA (ex.X_add_number); - if ((operand->flags & PPC_OPERAND_SIGNED) != 0) - ex.X_add_number = SEX16 (ex.X_add_number); - break; - - case BFD_RELOC_PPC64_HIGHER: - ex.X_add_number = PPC_HIGHER (ex.X_add_number); - if ((operand->flags & PPC_OPERAND_SIGNED) != 0) - ex.X_add_number = SEX16 (ex.X_add_number); - break; - - case BFD_RELOC_PPC64_HIGHER_S: - ex.X_add_number = PPC_HIGHERA (ex.X_add_number); - if ((operand->flags & PPC_OPERAND_SIGNED) != 0) - ex.X_add_number = SEX16 (ex.X_add_number); - break; - - case BFD_RELOC_PPC64_HIGHEST: - ex.X_add_number = PPC_HIGHEST (ex.X_add_number); - if ((operand->flags & PPC_OPERAND_SIGNED) != 0) - ex.X_add_number = SEX16 (ex.X_add_number); - break; - - case BFD_RELOC_PPC64_HIGHEST_S: - ex.X_add_number = PPC_HIGHESTA (ex.X_add_number); - if ((operand->flags & PPC_OPERAND_SIGNED) != 0) - ex.X_add_number = SEX16 (ex.X_add_number); - break; - } -#endif /* OBJ_ELF */ - insn = ppc_insert_operand (insn, operand, ex.X_add_number, - ppc_cpu, (char *) NULL, 0); - } - else - { - bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED; -#ifdef OBJ_ELF - if (ex.X_op == O_symbol && str[0] == '(') - { - const char *sym_name = S_GET_NAME (ex.X_add_symbol); - if (sym_name[0] == '.') - ++sym_name; - - if (strcasecmp (sym_name, "__tls_get_addr") == 0) - { - expressionS tls_exp; - - hold = input_line_pointer; - input_line_pointer = str + 1; - expression (&tls_exp); - if (tls_exp.X_op == O_symbol) - { - reloc = BFD_RELOC_UNUSED; - if (strncasecmp (input_line_pointer, "@tlsgd)", 7) == 0) - { - reloc = BFD_RELOC_PPC_TLSGD; - input_line_pointer += 7; - } - else if (strncasecmp (input_line_pointer, "@tlsld)", 7) == 0) - { - reloc = BFD_RELOC_PPC_TLSLD; - input_line_pointer += 7; - } - if (reloc != BFD_RELOC_UNUSED) - { - SKIP_WHITESPACE (); - str = input_line_pointer; - - if (fc >= MAX_INSN_FIXUPS) - as_fatal (_("too many fixups")); - fixups[fc].exp = tls_exp; - fixups[fc].opindex = *opindex_ptr; - fixups[fc].reloc = reloc; - ++fc; - } - } - input_line_pointer = hold; - } - } - - if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED) - { - /* Some TLS tweaks. */ - switch (reloc) - { - default: - break; - - case BFD_RELOC_PPC_TLS: - if (!_bfd_elf_ppc_at_tls_transform (opcode->opcode, 0)) - as_bad (_("@tls may not be used with \"%s\" operands"), - opcode->name); - else if (operand->shift != 11) - as_bad (_("@tls may only be used in last operand")); - else - insn = ppc_insert_operand (insn, operand, - ppc_obj64 ? 13 : 2, - ppc_cpu, (char *) NULL, 0); - break; - - /* We'll only use the 32 (or 64) bit form of these relocations - in constants. Instructions get the 16 bit form. */ - case BFD_RELOC_PPC_DTPREL: - reloc = BFD_RELOC_PPC_DTPREL16; - break; - case BFD_RELOC_PPC_TPREL: - reloc = BFD_RELOC_PPC_TPREL16; - break; - } - - /* If VLE-mode convert LO/HI/HA relocations. */ - if (opcode->flags & PPC_OPCODE_VLE) - { - int tmp_insn = insn & opcode->mask; - - int use_d_reloc = (tmp_insn == E_OR2I_INSN - || tmp_insn == E_AND2I_DOT_INSN - || tmp_insn == E_OR2IS_INSN - || tmp_insn == E_LIS_INSN - || tmp_insn == E_AND2IS_DOT_INSN); - - - int use_a_reloc = (tmp_insn == E_ADD2I_DOT_INSN - || tmp_insn == E_ADD2IS_INSN - || tmp_insn == E_CMP16I_INSN - || tmp_insn == E_MULL2I_INSN - || tmp_insn == E_CMPL16I_INSN - || tmp_insn == E_CMPH16I_INSN - || tmp_insn == E_CMPHL16I_INSN); - - switch (reloc) - { - default: - break; - - case BFD_RELOC_PPC_EMB_SDA21: - reloc = BFD_RELOC_PPC_VLE_SDA21; - break; - - case BFD_RELOC_LO16: - if (use_d_reloc) - reloc = BFD_RELOC_PPC_VLE_LO16D; - else if (use_a_reloc) - reloc = BFD_RELOC_PPC_VLE_LO16A; - break; - - case BFD_RELOC_HI16: - if (use_d_reloc) - reloc = BFD_RELOC_PPC_VLE_HI16D; - else if (use_a_reloc) - reloc = BFD_RELOC_PPC_VLE_HI16A; - break; - - case BFD_RELOC_HI16_S: - if (use_d_reloc) - reloc = BFD_RELOC_PPC_VLE_HA16D; - else if (use_a_reloc) - reloc = BFD_RELOC_PPC_VLE_HA16A; - break; - - case BFD_RELOC_PPC_VLE_SDAREL_LO16A: - if (use_d_reloc) - reloc = BFD_RELOC_PPC_VLE_SDAREL_LO16D; - break; - - case BFD_RELOC_PPC_VLE_SDAREL_HI16A: - if (use_d_reloc) - reloc = BFD_RELOC_PPC_VLE_SDAREL_HI16D; - break; - - case BFD_RELOC_PPC_VLE_SDAREL_HA16A: - if (use_d_reloc) - reloc = BFD_RELOC_PPC_VLE_SDAREL_HA16D; - break; - } - } - - /* For the absolute forms of branches, convert the PC - relative form back into the absolute. */ - if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) - { - switch (reloc) - { - case BFD_RELOC_PPC_B26: - reloc = BFD_RELOC_PPC_BA26; - break; - case BFD_RELOC_PPC_B16: - reloc = BFD_RELOC_PPC_BA16; - break; - case BFD_RELOC_PPC_B16_BRTAKEN: - reloc = BFD_RELOC_PPC_BA16_BRTAKEN; - break; - case BFD_RELOC_PPC_B16_BRNTAKEN: - reloc = BFD_RELOC_PPC_BA16_BRNTAKEN; - break; - default: - break; - } - } - - switch (reloc) - { - case BFD_RELOC_PPC_TOC16: - toc_reloc_types |= has_small_toc_reloc; - break; - case BFD_RELOC_PPC64_TOC16_LO: - case BFD_RELOC_PPC64_TOC16_HI: - case BFD_RELOC_PPC64_TOC16_HA: - toc_reloc_types |= has_large_toc_reloc; - break; - default: - break; - } - - if ((operand->flags & (PPC_OPERAND_DS | PPC_OPERAND_DQ)) != 0) - { - switch (reloc) - { - case BFD_RELOC_16: - reloc = BFD_RELOC_PPC64_ADDR16_DS; - break; - case BFD_RELOC_LO16: - reloc = BFD_RELOC_PPC64_ADDR16_LO_DS; - break; - case BFD_RELOC_16_GOTOFF: - reloc = BFD_RELOC_PPC64_GOT16_DS; - break; - case BFD_RELOC_LO16_GOTOFF: - reloc = BFD_RELOC_PPC64_GOT16_LO_DS; - break; - case BFD_RELOC_LO16_PLTOFF: - reloc = BFD_RELOC_PPC64_PLT16_LO_DS; - break; - case BFD_RELOC_16_BASEREL: - reloc = BFD_RELOC_PPC64_SECTOFF_DS; - break; - case BFD_RELOC_LO16_BASEREL: - reloc = BFD_RELOC_PPC64_SECTOFF_LO_DS; - break; - case BFD_RELOC_PPC_TOC16: - reloc = BFD_RELOC_PPC64_TOC16_DS; - break; - case BFD_RELOC_PPC64_TOC16_LO: - reloc = BFD_RELOC_PPC64_TOC16_LO_DS; - break; - case BFD_RELOC_PPC64_PLTGOT16: - reloc = BFD_RELOC_PPC64_PLTGOT16_DS; - break; - case BFD_RELOC_PPC64_PLTGOT16_LO: - reloc = BFD_RELOC_PPC64_PLTGOT16_LO_DS; - break; - case BFD_RELOC_PPC_DTPREL16: - reloc = BFD_RELOC_PPC64_DTPREL16_DS; - break; - case BFD_RELOC_PPC_DTPREL16_LO: - reloc = BFD_RELOC_PPC64_DTPREL16_LO_DS; - break; - case BFD_RELOC_PPC_TPREL16: - reloc = BFD_RELOC_PPC64_TPREL16_DS; - break; - case BFD_RELOC_PPC_TPREL16_LO: - reloc = BFD_RELOC_PPC64_TPREL16_LO_DS; - break; - case BFD_RELOC_PPC_GOT_DTPREL16: - case BFD_RELOC_PPC_GOT_DTPREL16_LO: - case BFD_RELOC_PPC_GOT_TPREL16: - case BFD_RELOC_PPC_GOT_TPREL16_LO: - break; - default: - as_bad (_("unsupported relocation for DS offset field")); - break; - } - } - } -#endif /* OBJ_ELF */ - - if (reloc != BFD_RELOC_UNUSED) - ; - /* Determine a BFD reloc value based on the operand information. - We are only prepared to turn a few of the operands into - relocs. */ - else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 - && operand->bitm == 0x3fffffc - && operand->shift == 0) - reloc = BFD_RELOC_PPC_B26; - else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 - && operand->bitm == 0xfffc - && operand->shift == 0) - reloc = BFD_RELOC_PPC_B16; - else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 - && operand->bitm == 0x1fe - && operand->shift == -1) - reloc = BFD_RELOC_PPC_VLE_REL8; - else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 - && operand->bitm == 0xfffe - && operand->shift == 0) - reloc = BFD_RELOC_PPC_VLE_REL15; - else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 - && operand->bitm == 0x1fffffe - && operand->shift == 0) - reloc = BFD_RELOC_PPC_VLE_REL24; - else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0 - && operand->bitm == 0x3fffffc - && operand->shift == 0) - reloc = BFD_RELOC_PPC_BA26; - else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0 - && operand->bitm == 0xfffc - && operand->shift == 0) - reloc = BFD_RELOC_PPC_BA16; -#if defined (OBJ_XCOFF) || defined (OBJ_ELF) - else if ((operand->flags & PPC_OPERAND_PARENS) != 0 - && (operand->bitm & 0xfff0) == 0xfff0 - && operand->shift == 0) - { - /* Note: the symbol may be not yet defined. */ - if (ppc_is_toc_sym (ex.X_add_symbol)) - { - reloc = BFD_RELOC_PPC_TOC16; -#ifdef OBJ_ELF - if (ppc_obj64 - && (operand->flags & PPC_OPERAND_DS) != 0) - reloc = BFD_RELOC_PPC64_TOC16_DS; -#endif - } - else - { - reloc = BFD_RELOC_16; -#ifdef OBJ_ELF - if (ppc_obj64 - && (operand->flags & PPC_OPERAND_DS) != 0) - reloc = BFD_RELOC_PPC64_ADDR16_DS; -#endif - } - } -#endif /* defined (OBJ_XCOFF) || defined (OBJ_ELF) */ - - /* We need to generate a fixup for this expression. */ - if (fc >= MAX_INSN_FIXUPS) - as_fatal (_("too many fixups")); - fixups[fc].exp = ex; - fixups[fc].opindex = *opindex_ptr; - fixups[fc].reloc = reloc; - ++fc; - } - - if (need_paren) - { - endc = ')'; - need_paren = 0; - /* If expecting more operands, then we want to see "),". */ - if (*str == endc && opindex_ptr[1] != 0) - { - do - ++str; - while (ISSPACE (*str)); - endc = ','; - } - } - else if ((operand->flags & PPC_OPERAND_PARENS) != 0) - { - endc = '('; - need_paren = 1; - } - else - endc = ','; - - /* The call to expression should have advanced str past any - whitespace. */ - if (*str != endc - && (endc != ',' || *str != '\0')) - { - if (*str == '\0') - as_bad (_("syntax error; end of line, expected `%c'"), endc); - else - as_bad (_("syntax error; found `%c', expected `%c'"), *str, endc); - break; - } - - if (*str != '\0') - ++str; - } - - while (ISSPACE (*str)) - ++str; - - if (*str != '\0') - as_bad (_("junk at end of line: `%s'"), str); - -#ifdef OBJ_ELF - /* Do we need/want an APUinfo section? */ - if ((ppc_cpu & (PPC_OPCODE_E500 | PPC_OPCODE_E500MC | PPC_OPCODE_VLE)) != 0 - && !ppc_obj64) - { - /* These are all version "1". */ - if (opcode->flags & PPC_OPCODE_SPE) - ppc_apuinfo_section_add (PPC_APUINFO_SPE, 1); - if (opcode->flags & PPC_OPCODE_ISEL) - ppc_apuinfo_section_add (PPC_APUINFO_ISEL, 1); - if (opcode->flags & PPC_OPCODE_EFS) - ppc_apuinfo_section_add (PPC_APUINFO_EFS, 1); - if (opcode->flags & PPC_OPCODE_BRLOCK) - ppc_apuinfo_section_add (PPC_APUINFO_BRLOCK, 1); - if (opcode->flags & PPC_OPCODE_PMR) - ppc_apuinfo_section_add (PPC_APUINFO_PMR, 1); - if (opcode->flags & PPC_OPCODE_CACHELCK) - ppc_apuinfo_section_add (PPC_APUINFO_CACHELCK, 1); - if (opcode->flags & PPC_OPCODE_RFMCI) - ppc_apuinfo_section_add (PPC_APUINFO_RFMCI, 1); - if (opcode->flags & PPC_OPCODE_VLE) - ppc_apuinfo_section_add (PPC_APUINFO_VLE, 1); - } -#endif - - /* Write out the instruction. */ - /* Differentiate between two and four byte insns. */ - if (ppc_mach () == bfd_mach_ppc_vle) - { - if (PPC_OP_SE_VLE (insn)) - insn_length = 2; - else - insn_length = 4; - addr_mod = frag_now_fix () & 1; - } - else - { - insn_length = 4; - addr_mod = frag_now_fix () & 3; - } - /* All instructions can start on a 2 byte boundary for VLE. */ - f = frag_more (insn_length); - if (frag_now->has_code && frag_now->insn_addr != addr_mod) - { - if (ppc_mach() == bfd_mach_ppc_vle) - as_bad (_("instruction address is not a multiple of 2")); - else - as_bad (_("instruction address is not a multiple of 4")); - } - frag_now->insn_addr = addr_mod; - frag_now->has_code = 1; - md_number_to_chars (f, insn, insn_length); - -#ifdef OBJ_ELF - dwarf2_emit_insn (insn_length); -#endif - - /* Create any fixups. */ - for (i = 0; i < fc; i++) - { - fixS *fixP; - if (fixups[i].reloc != BFD_RELOC_UNUSED) - { - reloc_howto_type *reloc_howto; - int size; - int offset; - - reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc); - if (!reloc_howto) - abort (); - - size = bfd_get_reloc_size (reloc_howto); - offset = target_big_endian ? (insn_length - size) : 0; - - if (size < 1 || size > 4) - abort (); - - fixP = fix_new_exp (frag_now, - f - frag_now->fr_literal + offset, - size, - &fixups[i].exp, - reloc_howto->pc_relative, - fixups[i].reloc); - } - else - { - const struct powerpc_operand *operand; - - operand = &powerpc_operands[fixups[i].opindex]; - fixP = fix_new_exp (frag_now, - f - frag_now->fr_literal, - insn_length, - &fixups[i].exp, - (operand->flags & PPC_OPERAND_RELATIVE) != 0, - BFD_RELOC_UNUSED); - } - fixP->fx_pcrel_adjust = fixups[i].opindex; - } -} - -/* Handle a macro. Gather all the operands, transform them as - described by the macro, and call md_assemble recursively. All the - operands are separated by commas; we don't accept parentheses - around operands here. */ - -static void -ppc_macro (char *str, const struct powerpc_macro *macro) -{ - char *operands[10]; - unsigned int count; - char *s; - unsigned int len; - const char *format; - unsigned int arg; - char *send; - char *complete; - - /* Gather the users operands into the operands array. */ - count = 0; - s = str; - while (1) - { - if (count >= sizeof operands / sizeof operands[0]) - break; - operands[count++] = s; - s = strchr (s, ','); - if (s == (char *) NULL) - break; - *s++ = '\0'; - } - - if (count != macro->operands) - { - as_bad (_("wrong number of operands")); - return; - } - - /* Work out how large the string must be (the size is unbounded - because it includes user input). */ - len = 0; - format = macro->format; - while (*format != '\0') - { - if (*format != '%') - { - ++len; - ++format; - } - else - { - arg = strtol (format + 1, &send, 10); - know (send != format && arg < count); - len += strlen (operands[arg]); - format = send; - } - } - - /* Put the string together. */ - complete = s = (char *) alloca (len + 1); - format = macro->format; - while (*format != '\0') - { - if (*format != '%') - *s++ = *format++; - else - { - arg = strtol (format + 1, &send, 10); - strcpy (s, operands[arg]); - s += strlen (s); - format = send; - } - } - *s = '\0'; - - /* Assemble the constructed instruction. */ - md_assemble (complete); -} - -#ifdef OBJ_ELF -/* For ELF, add support for SHT_ORDERED. */ - -int -ppc_section_type (char *str, size_t len) -{ - if (len == 7 && strncmp (str, "ordered", 7) == 0) - return SHT_ORDERED; - - return -1; -} - -int -ppc_section_flags (flagword flags, bfd_vma attr ATTRIBUTE_UNUSED, int type) -{ - if (type == SHT_ORDERED) - flags |= SEC_ALLOC | SEC_LOAD | SEC_SORT_ENTRIES; - - return flags; -} -#endif /* OBJ_ELF */ - - -/* Pseudo-op handling. */ - -/* The .byte pseudo-op. This is similar to the normal .byte - pseudo-op, but it can also take a single ASCII string. */ - -static void -ppc_byte (int ignore ATTRIBUTE_UNUSED) -{ - if (*input_line_pointer != '\"') - { - cons (1); - return; - } - - /* Gather characters. A real double quote is doubled. Unusual - characters are not permitted. */ - ++input_line_pointer; - while (1) - { - char c; - - c = *input_line_pointer++; - - if (c == '\"') - { - if (*input_line_pointer != '\"') - break; - ++input_line_pointer; - } - - FRAG_APPEND_1_CHAR (c); - } - - demand_empty_rest_of_line (); -} - -#ifdef OBJ_XCOFF - -/* XCOFF specific pseudo-op handling. */ - -/* This is set if we are creating a .stabx symbol, since we don't want - to handle symbol suffixes for such symbols. */ -static bfd_boolean ppc_stab_symbol; - -/* The .comm and .lcomm pseudo-ops for XCOFF. XCOFF puts common - symbols in the .bss segment as though they were local common - symbols, and uses a different smclas. The native Aix 4.3.3 assembler - aligns .comm and .lcomm to 4 bytes. */ - -static void -ppc_comm (int lcomm) -{ - asection *current_seg = now_seg; - subsegT current_subseg = now_subseg; - char *name; - char endc; - char *end_name; - offsetT size; - offsetT align; - symbolS *lcomm_sym = NULL; - symbolS *sym; - char *pfrag; - - name = input_line_pointer; - endc = get_symbol_end (); - end_name = input_line_pointer; - *end_name = endc; - - if (*input_line_pointer != ',') - { - as_bad (_("missing size")); - ignore_rest_of_line (); - return; - } - ++input_line_pointer; - - size = get_absolute_expression (); - if (size < 0) - { - as_bad (_("negative size")); - ignore_rest_of_line (); - return; - } - - if (! lcomm) - { - /* The third argument to .comm is the alignment. */ - if (*input_line_pointer != ',') - align = 2; - else - { - ++input_line_pointer; - align = get_absolute_expression (); - if (align <= 0) - { - as_warn (_("ignoring bad alignment")); - align = 2; - } - } - } - else - { - char *lcomm_name; - char lcomm_endc; - - /* The third argument to .lcomm appears to be the real local - common symbol to create. References to the symbol named in - the first argument are turned into references to the third - argument. */ - if (*input_line_pointer != ',') - { - as_bad (_("missing real symbol name")); - ignore_rest_of_line (); - return; - } - ++input_line_pointer; - - lcomm_name = input_line_pointer; - lcomm_endc = get_symbol_end (); - - lcomm_sym = symbol_find_or_make (lcomm_name); - - *input_line_pointer = lcomm_endc; - - /* The fourth argument to .lcomm is the alignment. */ - if (*input_line_pointer != ',') - { - if (size <= 4) - align = 2; - else - align = 3; - } - else - { - ++input_line_pointer; - align = get_absolute_expression (); - if (align <= 0) - { - as_warn (_("ignoring bad alignment")); - align = 2; - } - } - } - - *end_name = '\0'; - sym = symbol_find_or_make (name); - *end_name = endc; - - if (S_IS_DEFINED (sym) - || S_GET_VALUE (sym) != 0) - { - as_bad (_("attempt to redefine symbol")); - ignore_rest_of_line (); - return; - } - - record_alignment (bss_section, align); - - if (! lcomm - || ! S_IS_DEFINED (lcomm_sym)) - { - symbolS *def_sym; - offsetT def_size; - - if (! lcomm) - { - def_sym = sym; - def_size = size; - S_SET_EXTERNAL (sym); - } - else - { - symbol_get_tc (lcomm_sym)->output = 1; - def_sym = lcomm_sym; - def_size = 0; - } - - subseg_set (bss_section, 1); - frag_align (align, 0, 0); - - symbol_set_frag (def_sym, frag_now); - pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, def_sym, - def_size, (char *) NULL); - *pfrag = 0; - S_SET_SEGMENT (def_sym, bss_section); - symbol_get_tc (def_sym)->align = align; - } - else if (lcomm) - { - /* Align the size of lcomm_sym. */ - symbol_get_frag (lcomm_sym)->fr_offset = - ((symbol_get_frag (lcomm_sym)->fr_offset + (1 << align) - 1) - &~ ((1 << align) - 1)); - if (align > symbol_get_tc (lcomm_sym)->align) - symbol_get_tc (lcomm_sym)->align = align; - } - - if (lcomm) - { - /* Make sym an offset from lcomm_sym. */ - S_SET_SEGMENT (sym, bss_section); - symbol_set_frag (sym, symbol_get_frag (lcomm_sym)); - S_SET_VALUE (sym, symbol_get_frag (lcomm_sym)->fr_offset); - symbol_get_frag (lcomm_sym)->fr_offset += size; - } - - subseg_set (current_seg, current_subseg); - - demand_empty_rest_of_line (); -} - -/* The .csect pseudo-op. This switches us into a different - subsegment. The first argument is a symbol whose value is the - start of the .csect. In COFF, csect symbols get special aux - entries defined by the x_csect field of union internal_auxent. The - optional second argument is the alignment (the default is 2). */ - -static void -ppc_csect (int ignore ATTRIBUTE_UNUSED) -{ - char *name; - char endc; - symbolS *sym; - offsetT align; - - name = input_line_pointer; - endc = get_symbol_end (); - - sym = symbol_find_or_make (name); - - *input_line_pointer = endc; - - if (S_GET_NAME (sym)[0] == '\0') - { - /* An unnamed csect is assumed to be [PR]. */ - symbol_get_tc (sym)->symbol_class = XMC_PR; - } - - align = 2; - if (*input_line_pointer == ',') - { - ++input_line_pointer; - align = get_absolute_expression (); - } - - ppc_change_csect (sym, align); - - demand_empty_rest_of_line (); -} - -/* Change to a different csect. */ - -static void -ppc_change_csect (symbolS *sym, offsetT align) -{ - if (S_IS_DEFINED (sym)) - subseg_set (S_GET_SEGMENT (sym), symbol_get_tc (sym)->subseg); - else - { - symbolS **list_ptr; - int after_toc; - int hold_chunksize; - symbolS *list; - int is_code; - segT sec; - - /* This is a new csect. We need to look at the symbol class to - figure out whether it should go in the text section or the - data section. */ - after_toc = 0; - is_code = 0; - switch (symbol_get_tc (sym)->symbol_class) - { - case XMC_PR: - case XMC_RO: - case XMC_DB: - case XMC_GL: - case XMC_XO: - case XMC_SV: - case XMC_TI: - case XMC_TB: - S_SET_SEGMENT (sym, text_section); - symbol_get_tc (sym)->subseg = ppc_text_subsegment; - ++ppc_text_subsegment; - list_ptr = &ppc_text_csects; - is_code = 1; - break; - case XMC_RW: - case XMC_TC0: - case XMC_TC: - case XMC_DS: - case XMC_UA: - case XMC_BS: - case XMC_UC: - if (ppc_toc_csect != NULL - && (symbol_get_tc (ppc_toc_csect)->subseg + 1 - == ppc_data_subsegment)) - after_toc = 1; - S_SET_SEGMENT (sym, data_section); - symbol_get_tc (sym)->subseg = ppc_data_subsegment; - ++ppc_data_subsegment; - list_ptr = &ppc_data_csects; - break; - default: - abort (); - } - - /* We set the obstack chunk size to a small value before - changing subsegments, so that we don't use a lot of memory - space for what may be a small section. */ - hold_chunksize = chunksize; - chunksize = 64; - - sec = subseg_new (segment_name (S_GET_SEGMENT (sym)), - symbol_get_tc (sym)->subseg); - - chunksize = hold_chunksize; - - if (after_toc) - ppc_after_toc_frag = frag_now; - - record_alignment (sec, align); - if (is_code) - frag_align_code (align, 0); - else - frag_align (align, 0, 0); - - symbol_set_frag (sym, frag_now); - S_SET_VALUE (sym, (valueT) frag_now_fix ()); - - symbol_get_tc (sym)->align = align; - symbol_get_tc (sym)->output = 1; - symbol_get_tc (sym)->within = sym; - - for (list = *list_ptr; - symbol_get_tc (list)->next != (symbolS *) NULL; - list = symbol_get_tc (list)->next) - ; - symbol_get_tc (list)->next = sym; - - symbol_remove (sym, &symbol_rootP, &symbol_lastP); - symbol_append (sym, symbol_get_tc (list)->within, &symbol_rootP, - &symbol_lastP); - } - - ppc_current_csect = sym; -} - -static void -ppc_change_debug_section (unsigned int idx, subsegT subseg) -{ - segT sec; - flagword oldflags; - const struct xcoff_dwsect_name *dw = &xcoff_dwsect_names[idx]; - - sec = subseg_new (dw->name, subseg); - oldflags = bfd_get_section_flags (stdoutput, sec); - if (oldflags == SEC_NO_FLAGS) - { - /* Just created section. */ - gas_assert (dw_sections[idx].sect == NULL); - - bfd_set_section_flags (stdoutput, sec, SEC_DEBUGGING); - bfd_set_section_alignment (stdoutput, sec, 0); - dw_sections[idx].sect = sec; - } - - /* Not anymore in a csect. */ - ppc_current_csect = NULL; -} - -/* The .dwsect pseudo-op. Defines a DWARF section. Syntax is: - .dwsect flag [, opt-label ] -*/ - -static void -ppc_dwsect (int ignore ATTRIBUTE_UNUSED) -{ - offsetT flag; - symbolS *opt_label; - const struct xcoff_dwsect_name *dw; - struct dw_subsection *subseg; - struct dw_section *dws; - int i; - - /* Find section. */ - flag = get_absolute_expression (); - dw = NULL; - for (i = 0; i < XCOFF_DWSECT_NBR_NAMES; i++) - if (xcoff_dwsect_names[i].flag == flag) - { - dw = &xcoff_dwsect_names[i]; - break; - } - - /* Parse opt-label. */ - if (*input_line_pointer == ',') - { - const char *label; - char c; - - ++input_line_pointer; - - label = input_line_pointer; - c = get_symbol_end (); - opt_label = symbol_find_or_make (label); - *input_line_pointer = c; - } - else - opt_label = NULL; - - demand_empty_rest_of_line (); - - /* Return now in case of unknown subsection. */ - if (dw == NULL) - { - as_bad (_("no known dwarf XCOFF section for flag 0x%08x\n"), - (unsigned)flag); - return; - } - - /* Find the subsection. */ - dws = &dw_sections[i]; - subseg = NULL; - if (opt_label != NULL && S_IS_DEFINED (opt_label)) - { - /* Sanity check (note that in theory S_GET_SEGMENT mustn't be null). */ - if (dws->sect == NULL || S_GET_SEGMENT (opt_label) != dws->sect) - { - as_bad (_("label %s was not defined in this dwarf section"), - S_GET_NAME (opt_label)); - subseg = dws->anon_subseg; - opt_label = NULL; - } - else - subseg = symbol_get_tc (opt_label)->u.dw; - } - - if (subseg != NULL) - { - /* Switch to the subsection. */ - ppc_change_debug_section (i, subseg->subseg); - } - else - { - /* Create a new dw subsection. */ - subseg = (struct dw_subsection *) - xmalloc (sizeof (struct dw_subsection)); - - if (opt_label == NULL) - { - /* The anonymous one. */ - subseg->subseg = 0; - subseg->link = NULL; - dws->anon_subseg = subseg; - } - else - { - /* A named one. */ - if (dws->list_subseg != NULL) - subseg->subseg = dws->list_subseg->subseg + 1; - else - subseg->subseg = 1; - - subseg->link = dws->list_subseg; - dws->list_subseg = subseg; - symbol_get_tc (opt_label)->u.dw = subseg; - } - - ppc_change_debug_section (i, subseg->subseg); - - if (dw->def_size) - { - /* Add the length field. */ - expressionS *exp = &subseg->end_exp; - int sz; - - if (opt_label != NULL) - symbol_set_value_now (opt_label); - - /* Add the length field. Note that according to the AIX assembler - manual, the size of the length field is 4 for powerpc32 but - 12 for powerpc64. */ - if (ppc_obj64) - { - /* Write the 64bit marker. */ - md_number_to_chars (frag_more (4), -1, 4); - } - - exp->X_op = O_subtract; - exp->X_op_symbol = symbol_temp_new_now (); - exp->X_add_symbol = symbol_temp_make (); - - sz = ppc_obj64 ? 8 : 4; - exp->X_add_number = -sz; - emit_expr (exp, sz); - } - } -} - -/* This function handles the .text and .data pseudo-ops. These - pseudo-ops aren't really used by XCOFF; we implement them for the - convenience of people who aren't used to XCOFF. */ - -static void -ppc_section (int type) -{ - const char *name; - symbolS *sym; - - if (type == 't') - name = ".text[PR]"; - else if (type == 'd') - name = ".data[RW]"; - else - abort (); - - sym = symbol_find_or_make (name); - - ppc_change_csect (sym, 2); - - demand_empty_rest_of_line (); -} - -/* This function handles the .section pseudo-op. This is mostly to - give an error, since XCOFF only supports .text, .data and .bss, but - we do permit the user to name the text or data section. */ - -static void -ppc_named_section (int ignore ATTRIBUTE_UNUSED) -{ - char *user_name; - const char *real_name; - char c; - symbolS *sym; - - user_name = input_line_pointer; - c = get_symbol_end (); - - if (strcmp (user_name, ".text") == 0) - real_name = ".text[PR]"; - else if (strcmp (user_name, ".data") == 0) - real_name = ".data[RW]"; - else - { - as_bad (_("the XCOFF file format does not support arbitrary sections")); - *input_line_pointer = c; - ignore_rest_of_line (); - return; - } - - *input_line_pointer = c; - - sym = symbol_find_or_make (real_name); - - ppc_change_csect (sym, 2); - - demand_empty_rest_of_line (); -} - -/* The .extern pseudo-op. We create an undefined symbol. */ - -static void -ppc_extern (int ignore ATTRIBUTE_UNUSED) -{ - char *name; - char endc; - - name = input_line_pointer; - endc = get_symbol_end (); - - (void) symbol_find_or_make (name); - - *input_line_pointer = endc; - - demand_empty_rest_of_line (); -} - -/* The .lglobl pseudo-op. Keep the symbol in the symbol table. */ - -static void -ppc_lglobl (int ignore ATTRIBUTE_UNUSED) -{ - char *name; - char endc; - symbolS *sym; - - name = input_line_pointer; - endc = get_symbol_end (); - - sym = symbol_find_or_make (name); - - *input_line_pointer = endc; - - symbol_get_tc (sym)->output = 1; - - demand_empty_rest_of_line (); -} - -/* The .ref pseudo-op. It takes a list of symbol names and inserts R_REF - relocations at the beginning of the current csect. - - (In principle, there's no reason why the relocations _have_ to be at - the beginning. Anywhere in the csect would do. However, inserting - at the beginning is what the native assmebler does, and it helps to - deal with cases where the .ref statements follow the section contents.) - - ??? .refs don't work for empty .csects. However, the native assembler - doesn't report an error in this case, and neither yet do we. */ - -static void -ppc_ref (int ignore ATTRIBUTE_UNUSED) -{ - char *name; - char c; - - if (ppc_current_csect == NULL) - { - as_bad (_(".ref outside .csect")); - ignore_rest_of_line (); - return; - } - - do - { - name = input_line_pointer; - c = get_symbol_end (); - - fix_at_start (symbol_get_frag (ppc_current_csect), 0, - symbol_find_or_make (name), 0, FALSE, BFD_RELOC_NONE); - - *input_line_pointer = c; - SKIP_WHITESPACE (); - c = *input_line_pointer; - if (c == ',') - { - input_line_pointer++; - SKIP_WHITESPACE (); - if (is_end_of_line[(unsigned char) *input_line_pointer]) - { - as_bad (_("missing symbol name")); - ignore_rest_of_line (); - return; - } - } - } - while (c == ','); - - demand_empty_rest_of_line (); -} - -/* The .rename pseudo-op. The RS/6000 assembler can rename symbols, - although I don't know why it bothers. */ - -static void -ppc_rename (int ignore ATTRIBUTE_UNUSED) -{ - char *name; - char endc; - symbolS *sym; - int len; - - name = input_line_pointer; - endc = get_symbol_end (); - - sym = symbol_find_or_make (name); - - *input_line_pointer = endc; - - if (*input_line_pointer != ',') - { - as_bad (_("missing rename string")); - ignore_rest_of_line (); - return; - } - ++input_line_pointer; - - symbol_get_tc (sym)->real_name = demand_copy_C_string (&len); - - demand_empty_rest_of_line (); -} - -/* The .stabx pseudo-op. This is similar to a normal .stabs - pseudo-op, but slightly different. A sample is - .stabx "main:F-1",.main,142,0 - The first argument is the symbol name to create. The second is the - value, and the third is the storage class. The fourth seems to be - always zero, and I am assuming it is the type. */ - -static void -ppc_stabx (int ignore ATTRIBUTE_UNUSED) -{ - char *name; - int len; - symbolS *sym; - expressionS exp; - - name = demand_copy_C_string (&len); - - if (*input_line_pointer != ',') - { - as_bad (_("missing value")); - return; - } - ++input_line_pointer; - - ppc_stab_symbol = TRUE; - sym = symbol_make (name); - ppc_stab_symbol = FALSE; - - symbol_get_tc (sym)->real_name = name; - - (void) expression (&exp); - - switch (exp.X_op) - { - case O_illegal: - case O_absent: - case O_big: - as_bad (_("illegal .stabx expression; zero assumed")); - exp.X_add_number = 0; - /* Fall through. */ - case O_constant: - S_SET_VALUE (sym, (valueT) exp.X_add_number); - symbol_set_frag (sym, &zero_address_frag); - break; - - case O_symbol: - if (S_GET_SEGMENT (exp.X_add_symbol) == undefined_section) - symbol_set_value_expression (sym, &exp); - else - { - S_SET_VALUE (sym, - exp.X_add_number + S_GET_VALUE (exp.X_add_symbol)); - symbol_set_frag (sym, symbol_get_frag (exp.X_add_symbol)); - } - break; - - default: - /* The value is some complex expression. This will probably - fail at some later point, but this is probably the right - thing to do here. */ - symbol_set_value_expression (sym, &exp); - break; - } - - S_SET_SEGMENT (sym, ppc_coff_debug_section); - symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; - - if (*input_line_pointer != ',') - { - as_bad (_("missing class")); - return; - } - ++input_line_pointer; - - S_SET_STORAGE_CLASS (sym, get_absolute_expression ()); - - if (*input_line_pointer != ',') - { - as_bad (_("missing type")); - return; - } - ++input_line_pointer; - - S_SET_DATA_TYPE (sym, get_absolute_expression ()); - - symbol_get_tc (sym)->output = 1; - - if (S_GET_STORAGE_CLASS (sym) == C_STSYM) - { - /* In this case : - - .bs name - .stabx "z",arrays_,133,0 - .es - - .comm arrays_,13768,3 - - resolve_symbol_value will copy the exp's "within" into sym's when the - offset is 0. Since this seems to be corner case problem, - only do the correction for storage class C_STSYM. A better solution - would be to have the tc field updated in ppc_symbol_new_hook. */ - - if (exp.X_op == O_symbol) - { - if (ppc_current_block == NULL) - as_bad (_(".stabx of storage class stsym must be within .bs/.es")); - - symbol_get_tc (sym)->within = ppc_current_block; - symbol_get_tc (exp.X_add_symbol)->within = ppc_current_block; - } - } - - if (exp.X_op != O_symbol - || ! S_IS_EXTERNAL (exp.X_add_symbol) - || S_GET_SEGMENT (exp.X_add_symbol) != bss_section) - ppc_frob_label (sym); - else - { - symbol_remove (sym, &symbol_rootP, &symbol_lastP); - symbol_append (sym, exp.X_add_symbol, &symbol_rootP, &symbol_lastP); - if (symbol_get_tc (ppc_current_csect)->within == exp.X_add_symbol) - symbol_get_tc (ppc_current_csect)->within = sym; - } - - demand_empty_rest_of_line (); -} - -/* The .function pseudo-op. This takes several arguments. The first - argument seems to be the external name of the symbol. The second - argument seems to be the label for the start of the function. gcc - uses the same name for both. I have no idea what the third and - fourth arguments are meant to be. The optional fifth argument is - an expression for the size of the function. In COFF this symbol - gets an aux entry like that used for a csect. */ - -static void -ppc_function (int ignore ATTRIBUTE_UNUSED) -{ - char *name; - char endc; - char *s; - symbolS *ext_sym; - symbolS *lab_sym; - - name = input_line_pointer; - endc = get_symbol_end (); - - /* Ignore any [PR] suffix. */ - name = ppc_canonicalize_symbol_name (name); - s = strchr (name, '['); - if (s != (char *) NULL - && strcmp (s + 1, "PR]") == 0) - *s = '\0'; - - ext_sym = symbol_find_or_make (name); - - *input_line_pointer = endc; - - if (*input_line_pointer != ',') - { - as_bad (_("missing symbol name")); - ignore_rest_of_line (); - return; - } - ++input_line_pointer; - - name = input_line_pointer; - endc = get_symbol_end (); - - lab_sym = symbol_find_or_make (name); - - *input_line_pointer = endc; - - if (ext_sym != lab_sym) - { - expressionS exp; - - exp.X_op = O_symbol; - exp.X_add_symbol = lab_sym; - exp.X_op_symbol = NULL; - exp.X_add_number = 0; - exp.X_unsigned = 0; - symbol_set_value_expression (ext_sym, &exp); - } - - if (symbol_get_tc (ext_sym)->symbol_class == -1) - symbol_get_tc (ext_sym)->symbol_class = XMC_PR; - symbol_get_tc (ext_sym)->output = 1; - - if (*input_line_pointer == ',') - { - expressionS exp; - - /* Ignore the third argument. */ - ++input_line_pointer; - expression (& exp); - if (*input_line_pointer == ',') - { - /* Ignore the fourth argument. */ - ++input_line_pointer; - expression (& exp); - if (*input_line_pointer == ',') - { - /* The fifth argument is the function size. */ - ++input_line_pointer; - symbol_get_tc (ext_sym)->u.size = symbol_new - ("L0\001", absolute_section,(valueT) 0, &zero_address_frag); - pseudo_set (symbol_get_tc (ext_sym)->u.size); - } - } - } - - S_SET_DATA_TYPE (ext_sym, DT_FCN << N_BTSHFT); - SF_SET_FUNCTION (ext_sym); - SF_SET_PROCESS (ext_sym); - coff_add_linesym (ext_sym); - - demand_empty_rest_of_line (); -} - -/* The .bf pseudo-op. This is just like a COFF C_FCN symbol named - ".bf". If the pseudo op .bi was seen before .bf, patch the .bi sym - with the correct line number */ - -static symbolS *saved_bi_sym = 0; - -static void -ppc_bf (int ignore ATTRIBUTE_UNUSED) -{ - symbolS *sym; - - sym = symbol_make (".bf"); - S_SET_SEGMENT (sym, text_section); - symbol_set_frag (sym, frag_now); - S_SET_VALUE (sym, frag_now_fix ()); - S_SET_STORAGE_CLASS (sym, C_FCN); - - coff_line_base = get_absolute_expression (); - - S_SET_NUMBER_AUXILIARY (sym, 1); - SA_SET_SYM_LNNO (sym, coff_line_base); - - /* Line number for bi. */ - if (saved_bi_sym) - { - S_SET_VALUE (saved_bi_sym, coff_n_line_nos); - saved_bi_sym = 0; - } - - - symbol_get_tc (sym)->output = 1; - - ppc_frob_label (sym); - - demand_empty_rest_of_line (); -} - -/* The .ef pseudo-op. This is just like a COFF C_FCN symbol named - ".ef", except that the line number is absolute, not relative to the - most recent ".bf" symbol. */ - -static void -ppc_ef (int ignore ATTRIBUTE_UNUSED) -{ - symbolS *sym; - - sym = symbol_make (".ef"); - S_SET_SEGMENT (sym, text_section); - symbol_set_frag (sym, frag_now); - S_SET_VALUE (sym, frag_now_fix ()); - S_SET_STORAGE_CLASS (sym, C_FCN); - S_SET_NUMBER_AUXILIARY (sym, 1); - SA_SET_SYM_LNNO (sym, get_absolute_expression ()); - symbol_get_tc (sym)->output = 1; - - ppc_frob_label (sym); - - demand_empty_rest_of_line (); -} - -/* The .bi and .ei pseudo-ops. These take a string argument and - generates a C_BINCL or C_EINCL symbol, which goes at the start of - the symbol list. The value of .bi will be know when the next .bf - is encountered. */ - -static void -ppc_biei (int ei) -{ - static symbolS *last_biei; - - char *name; - int len; - symbolS *sym; - symbolS *look; - - name = demand_copy_C_string (&len); - - /* The value of these symbols is actually file offset. Here we set - the value to the index into the line number entries. In - ppc_frob_symbols we set the fix_line field, which will cause BFD - to do the right thing. */ - - sym = symbol_make (name); - /* obj-coff.c currently only handles line numbers correctly in the - .text section. */ - S_SET_SEGMENT (sym, text_section); - S_SET_VALUE (sym, coff_n_line_nos); - symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; - - S_SET_STORAGE_CLASS (sym, ei ? C_EINCL : C_BINCL); - symbol_get_tc (sym)->output = 1; - - /* Save bi. */ - if (ei) - saved_bi_sym = 0; - else - saved_bi_sym = sym; - - for (look = last_biei ? last_biei : symbol_rootP; - (look != (symbolS *) NULL - && (S_GET_STORAGE_CLASS (look) == C_FILE - || S_GET_STORAGE_CLASS (look) == C_BINCL - || S_GET_STORAGE_CLASS (look) == C_EINCL)); - look = symbol_next (look)) - ; - if (look != (symbolS *) NULL) - { - symbol_remove (sym, &symbol_rootP, &symbol_lastP); - symbol_insert (sym, look, &symbol_rootP, &symbol_lastP); - last_biei = sym; - } - - demand_empty_rest_of_line (); -} - -/* The .bs pseudo-op. This generates a C_BSTAT symbol named ".bs". - There is one argument, which is a csect symbol. The value of the - .bs symbol is the index of this csect symbol. */ - -static void -ppc_bs (int ignore ATTRIBUTE_UNUSED) -{ - char *name; - char endc; - symbolS *csect; - symbolS *sym; - - if (ppc_current_block != NULL) - as_bad (_("nested .bs blocks")); - - name = input_line_pointer; - endc = get_symbol_end (); - - csect = symbol_find_or_make (name); - - *input_line_pointer = endc; - - sym = symbol_make (".bs"); - S_SET_SEGMENT (sym, now_seg); - S_SET_STORAGE_CLASS (sym, C_BSTAT); - symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; - symbol_get_tc (sym)->output = 1; - - symbol_get_tc (sym)->within = csect; - - ppc_frob_label (sym); - - ppc_current_block = sym; - - demand_empty_rest_of_line (); -} - -/* The .es pseudo-op. Generate a C_ESTART symbol named .es. */ - -static void -ppc_es (int ignore ATTRIBUTE_UNUSED) -{ - symbolS *sym; - - if (ppc_current_block == NULL) - as_bad (_(".es without preceding .bs")); - - sym = symbol_make (".es"); - S_SET_SEGMENT (sym, now_seg); - S_SET_STORAGE_CLASS (sym, C_ESTAT); - symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; - symbol_get_tc (sym)->output = 1; - - ppc_frob_label (sym); - - ppc_current_block = NULL; - - demand_empty_rest_of_line (); -} - -/* The .bb pseudo-op. Generate a C_BLOCK symbol named .bb, with a - line number. */ - -static void -ppc_bb (int ignore ATTRIBUTE_UNUSED) -{ - symbolS *sym; - - sym = symbol_make (".bb"); - S_SET_SEGMENT (sym, text_section); - symbol_set_frag (sym, frag_now); - S_SET_VALUE (sym, frag_now_fix ()); - S_SET_STORAGE_CLASS (sym, C_BLOCK); - - S_SET_NUMBER_AUXILIARY (sym, 1); - SA_SET_SYM_LNNO (sym, get_absolute_expression ()); - - symbol_get_tc (sym)->output = 1; - - SF_SET_PROCESS (sym); - - ppc_frob_label (sym); - - demand_empty_rest_of_line (); -} - -/* The .eb pseudo-op. Generate a C_BLOCK symbol named .eb, with a - line number. */ - -static void -ppc_eb (int ignore ATTRIBUTE_UNUSED) -{ - symbolS *sym; - - sym = symbol_make (".eb"); - S_SET_SEGMENT (sym, text_section); - symbol_set_frag (sym, frag_now); - S_SET_VALUE (sym, frag_now_fix ()); - S_SET_STORAGE_CLASS (sym, C_BLOCK); - S_SET_NUMBER_AUXILIARY (sym, 1); - SA_SET_SYM_LNNO (sym, get_absolute_expression ()); - symbol_get_tc (sym)->output = 1; - - SF_SET_PROCESS (sym); - - ppc_frob_label (sym); - - demand_empty_rest_of_line (); -} - -/* The .bc pseudo-op. This just creates a C_BCOMM symbol with a - specified name. */ - -static void -ppc_bc (int ignore ATTRIBUTE_UNUSED) -{ - char *name; - int len; - symbolS *sym; - - name = demand_copy_C_string (&len); - sym = symbol_make (name); - S_SET_SEGMENT (sym, ppc_coff_debug_section); - symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; - S_SET_STORAGE_CLASS (sym, C_BCOMM); - S_SET_VALUE (sym, 0); - symbol_get_tc (sym)->output = 1; - - ppc_frob_label (sym); - - demand_empty_rest_of_line (); -} - -/* The .ec pseudo-op. This just creates a C_ECOMM symbol. */ - -static void -ppc_ec (int ignore ATTRIBUTE_UNUSED) -{ - symbolS *sym; - - sym = symbol_make (".ec"); - S_SET_SEGMENT (sym, ppc_coff_debug_section); - symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; - S_SET_STORAGE_CLASS (sym, C_ECOMM); - S_SET_VALUE (sym, 0); - symbol_get_tc (sym)->output = 1; - - ppc_frob_label (sym); - - demand_empty_rest_of_line (); -} - -/* The .toc pseudo-op. Switch to the .toc subsegment. */ - -static void -ppc_toc (int ignore ATTRIBUTE_UNUSED) -{ - if (ppc_toc_csect != (symbolS *) NULL) - subseg_set (data_section, symbol_get_tc (ppc_toc_csect)->subseg); - else - { - subsegT subseg; - symbolS *sym; - symbolS *list; - - subseg = ppc_data_subsegment; - ++ppc_data_subsegment; - - subseg_new (segment_name (data_section), subseg); - ppc_toc_frag = frag_now; - - sym = symbol_find_or_make ("TOC[TC0]"); - symbol_set_frag (sym, frag_now); - S_SET_SEGMENT (sym, data_section); - S_SET_VALUE (sym, (valueT) frag_now_fix ()); - symbol_get_tc (sym)->subseg = subseg; - symbol_get_tc (sym)->output = 1; - symbol_get_tc (sym)->within = sym; - - ppc_toc_csect = sym; - - for (list = ppc_data_csects; - symbol_get_tc (list)->next != (symbolS *) NULL; - list = symbol_get_tc (list)->next) - ; - symbol_get_tc (list)->next = sym; - - symbol_remove (sym, &symbol_rootP, &symbol_lastP); - symbol_append (sym, symbol_get_tc (list)->within, &symbol_rootP, - &symbol_lastP); - } - - ppc_current_csect = ppc_toc_csect; - - demand_empty_rest_of_line (); -} - -/* The AIX assembler automatically aligns the operands of a .long or - .short pseudo-op, and we want to be compatible. */ - -static void -ppc_xcoff_cons (int log_size) -{ - frag_align (log_size, 0, 0); - record_alignment (now_seg, log_size); - cons (1 << log_size); -} - -static void -ppc_vbyte (int dummy ATTRIBUTE_UNUSED) -{ - expressionS exp; - int byte_count; - - (void) expression (&exp); - - if (exp.X_op != O_constant) - { - as_bad (_("non-constant byte count")); - return; - } - - byte_count = exp.X_add_number; - - if (*input_line_pointer != ',') - { - as_bad (_("missing value")); - return; - } - - ++input_line_pointer; - cons (byte_count); -} - -void -ppc_xcoff_end (void) -{ - int i; - - for (i = 0; i < XCOFF_DWSECT_NBR_NAMES; i++) - { - struct dw_section *dws = &dw_sections[i]; - struct dw_subsection *dwss; - - if (dws->anon_subseg) - { - dwss = dws->anon_subseg; - dwss->link = dws->list_subseg; - } - else - dwss = dws->list_subseg; - - for (; dwss != NULL; dwss = dwss->link) - if (dwss->end_exp.X_add_symbol != NULL) - { - subseg_set (dws->sect, dwss->subseg); - symbol_set_value_now (dwss->end_exp.X_add_symbol); - } - } -} - -#endif /* OBJ_XCOFF */ -#if defined (OBJ_XCOFF) || defined (OBJ_ELF) - -/* The .tc pseudo-op. This is used when generating either XCOFF or - ELF. This takes two or more arguments. - - When generating XCOFF output, the first argument is the name to - give to this location in the toc; this will be a symbol with class - TC. The rest of the arguments are N-byte values to actually put at - this location in the TOC; often there is just one more argument, a - relocatable symbol reference. The size of the value to store - depends on target word size. A 32-bit target uses 4-byte values, a - 64-bit target uses 8-byte values. - - When not generating XCOFF output, the arguments are the same, but - the first argument is simply ignored. */ - -static void -ppc_tc (int ignore ATTRIBUTE_UNUSED) -{ -#ifdef OBJ_XCOFF - - /* Define the TOC symbol name. */ - { - char *name; - char endc; - symbolS *sym; - - if (ppc_toc_csect == (symbolS *) NULL - || ppc_toc_csect != ppc_current_csect) - { - as_bad (_(".tc not in .toc section")); - ignore_rest_of_line (); - return; - } - - name = input_line_pointer; - endc = get_symbol_end (); - - sym = symbol_find_or_make (name); - - *input_line_pointer = endc; - - if (S_IS_DEFINED (sym)) - { - symbolS *label; - - label = symbol_get_tc (ppc_current_csect)->within; - if (symbol_get_tc (label)->symbol_class != XMC_TC0) - { - as_bad (_(".tc with no label")); - ignore_rest_of_line (); - return; - } - - S_SET_SEGMENT (label, S_GET_SEGMENT (sym)); - symbol_set_frag (label, symbol_get_frag (sym)); - S_SET_VALUE (label, S_GET_VALUE (sym)); - - while (! is_end_of_line[(unsigned char) *input_line_pointer]) - ++input_line_pointer; - - return; - } - - S_SET_SEGMENT (sym, now_seg); - symbol_set_frag (sym, frag_now); - S_SET_VALUE (sym, (valueT) frag_now_fix ()); - symbol_get_tc (sym)->symbol_class = XMC_TC; - symbol_get_tc (sym)->output = 1; - - ppc_frob_label (sym); - } - -#endif /* OBJ_XCOFF */ -#ifdef OBJ_ELF - int align; - - /* Skip the TOC symbol name. */ - while (is_part_of_name (*input_line_pointer) - || *input_line_pointer == ' ' - || *input_line_pointer == '[' - || *input_line_pointer == ']' - || *input_line_pointer == '{' - || *input_line_pointer == '}') - ++input_line_pointer; - - /* Align to a four/eight byte boundary. */ - align = ppc_obj64 ? 3 : 2; - frag_align (align, 0, 0); - record_alignment (now_seg, align); -#endif /* OBJ_ELF */ - - if (*input_line_pointer != ',') - demand_empty_rest_of_line (); - else - { - ++input_line_pointer; - cons (ppc_obj64 ? 8 : 4); - } -} - -/* Pseudo-op .machine. */ - -static void -ppc_machine (int ignore ATTRIBUTE_UNUSED) -{ - char *cpu_string; -#define MAX_HISTORY 100 - static ppc_cpu_t *cpu_history; - static int curr_hist; - - SKIP_WHITESPACE (); - - if (*input_line_pointer == '"') - { - int len; - cpu_string = demand_copy_C_string (&len); - } - else - { - char c; - cpu_string = input_line_pointer; - c = get_symbol_end (); - cpu_string = xstrdup (cpu_string); - *input_line_pointer = c; - } - - if (cpu_string != NULL) - { - ppc_cpu_t old_cpu = ppc_cpu; - ppc_cpu_t new_cpu; - char *p; - - for (p = cpu_string; *p != 0; p++) - *p = TOLOWER (*p); - - if (strcmp (cpu_string, "push") == 0) - { - if (cpu_history == NULL) - cpu_history = xmalloc (MAX_HISTORY * sizeof (*cpu_history)); - - if (curr_hist >= MAX_HISTORY) - as_bad (_(".machine stack overflow")); - else - cpu_history[curr_hist++] = ppc_cpu; - } - else if (strcmp (cpu_string, "pop") == 0) - { - if (curr_hist <= 0) - as_bad (_(".machine stack underflow")); - else - ppc_cpu = cpu_history[--curr_hist]; - } - else if ((new_cpu = ppc_parse_cpu (ppc_cpu, &sticky, cpu_string)) != 0) - ppc_cpu = new_cpu; - else - as_bad (_("invalid machine `%s'"), cpu_string); - - if (ppc_cpu != old_cpu) - ppc_setup_opcodes (); - } - - demand_empty_rest_of_line (); -} -#endif /* defined (OBJ_XCOFF) || defined (OBJ_ELF) */ - -#ifdef TE_PE - -/* Pseudo-ops specific to the Windows NT PowerPC PE (coff) format. */ - -/* Set the current section. */ -static void -ppc_set_current_section (segT new) -{ - ppc_previous_section = ppc_current_section; - ppc_current_section = new; -} - -/* pseudo-op: .previous - behaviour: toggles the current section with the previous section. - errors: None - warnings: "No previous section" */ - -static void -ppc_previous (int ignore ATTRIBUTE_UNUSED) -{ - if (ppc_previous_section == NULL) - { - as_warn (_("no previous section to return to, ignored.")); - return; - } - - subseg_set (ppc_previous_section, 0); - - ppc_set_current_section (ppc_previous_section); -} - -/* pseudo-op: .pdata - behaviour: predefined read only data section - double word aligned - errors: None - warnings: None - initial: .section .pdata "adr3" - a - don't know -- maybe a misprint - d - initialized data - r - readable - 3 - double word aligned (that would be 4 byte boundary) - - commentary: - Tag index tables (also known as the function table) for exception - handling, debugging, etc. */ - -static void -ppc_pdata (int ignore ATTRIBUTE_UNUSED) -{ - if (pdata_section == 0) - { - pdata_section = subseg_new (".pdata", 0); - - bfd_set_section_flags (stdoutput, pdata_section, - (SEC_ALLOC | SEC_LOAD | SEC_RELOC - | SEC_READONLY | SEC_DATA )); - - bfd_set_section_alignment (stdoutput, pdata_section, 2); - } - else - { - pdata_section = subseg_new (".pdata", 0); - } - ppc_set_current_section (pdata_section); -} - -/* pseudo-op: .ydata - behaviour: predefined read only data section - double word aligned - errors: None - warnings: None - initial: .section .ydata "drw3" - a - don't know -- maybe a misprint - d - initialized data - r - readable - 3 - double word aligned (that would be 4 byte boundary) - commentary: - Tag tables (also known as the scope table) for exception handling, - debugging, etc. */ - -static void -ppc_ydata (int ignore ATTRIBUTE_UNUSED) -{ - if (ydata_section == 0) - { - ydata_section = subseg_new (".ydata", 0); - bfd_set_section_flags (stdoutput, ydata_section, - (SEC_ALLOC | SEC_LOAD | SEC_RELOC - | SEC_READONLY | SEC_DATA )); - - bfd_set_section_alignment (stdoutput, ydata_section, 3); - } - else - { - ydata_section = subseg_new (".ydata", 0); - } - ppc_set_current_section (ydata_section); -} - -/* pseudo-op: .reldata - behaviour: predefined read write data section - double word aligned (4-byte) - FIXME: relocation is applied to it - FIXME: what's the difference between this and .data? - errors: None - warnings: None - initial: .section .reldata "drw3" - d - initialized data - r - readable - w - writeable - 3 - double word aligned (that would be 8 byte boundary) - - commentary: - Like .data, but intended to hold data subject to relocation, such as - function descriptors, etc. */ - -static void -ppc_reldata (int ignore ATTRIBUTE_UNUSED) -{ - if (reldata_section == 0) - { - reldata_section = subseg_new (".reldata", 0); - - bfd_set_section_flags (stdoutput, reldata_section, - (SEC_ALLOC | SEC_LOAD | SEC_RELOC - | SEC_DATA)); - - bfd_set_section_alignment (stdoutput, reldata_section, 2); - } - else - { - reldata_section = subseg_new (".reldata", 0); - } - ppc_set_current_section (reldata_section); -} - -/* pseudo-op: .rdata - behaviour: predefined read only data section - double word aligned - errors: None - warnings: None - initial: .section .rdata "dr3" - d - initialized data - r - readable - 3 - double word aligned (that would be 4 byte boundary) */ - -static void -ppc_rdata (int ignore ATTRIBUTE_UNUSED) -{ - if (rdata_section == 0) - { - rdata_section = subseg_new (".rdata", 0); - bfd_set_section_flags (stdoutput, rdata_section, - (SEC_ALLOC | SEC_LOAD | SEC_RELOC - | SEC_READONLY | SEC_DATA )); - - bfd_set_section_alignment (stdoutput, rdata_section, 2); - } - else - { - rdata_section = subseg_new (".rdata", 0); - } - ppc_set_current_section (rdata_section); -} - -/* pseudo-op: .ualong - behaviour: much like .int, with the exception that no alignment is - performed. - FIXME: test the alignment statement - errors: None - warnings: None */ - -static void -ppc_ualong (int ignore ATTRIBUTE_UNUSED) -{ - /* Try for long. */ - cons (4); -} - -/* pseudo-op: .znop <symbol name> - behaviour: Issue a nop instruction - Issue a IMAGE_REL_PPC_IFGLUE relocation against it, using - the supplied symbol name. - errors: None - warnings: Missing symbol name */ - -static void -ppc_znop (int ignore ATTRIBUTE_UNUSED) -{ - unsigned long insn; - const struct powerpc_opcode *opcode; - char *f; - symbolS *sym; - char *symbol_name; - char c; - char *name; - - /* Strip out the symbol name. */ - symbol_name = input_line_pointer; - c = get_symbol_end (); - - name = xmalloc (input_line_pointer - symbol_name + 1); - strcpy (name, symbol_name); - - sym = symbol_find_or_make (name); - - *input_line_pointer = c; - - SKIP_WHITESPACE (); - - /* Look up the opcode in the hash table. */ - opcode = (const struct powerpc_opcode *) hash_find (ppc_hash, "nop"); - - /* Stick in the nop. */ - insn = opcode->opcode; - - /* Write out the instruction. */ - f = frag_more (4); - md_number_to_chars (f, insn, 4); - fix_new (frag_now, - f - frag_now->fr_literal, - 4, - sym, - 0, - 0, - BFD_RELOC_16_GOT_PCREL); - -} - -/* pseudo-op: - behaviour: - errors: - warnings: */ - -static void -ppc_pe_comm (int lcomm) -{ - char *name; - char c; - char *p; - offsetT temp; - symbolS *symbolP; - offsetT align; - - name = input_line_pointer; - c = get_symbol_end (); - - /* just after name is now '\0'. */ - p = input_line_pointer; - *p = c; - SKIP_WHITESPACE (); - if (*input_line_pointer != ',') - { - as_bad (_("expected comma after symbol-name: rest of line ignored.")); - ignore_rest_of_line (); - return; - } - - input_line_pointer++; /* skip ',' */ - if ((temp = get_absolute_expression ()) < 0) - { - as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) temp); - ignore_rest_of_line (); - return; - } - - if (! lcomm) - { - /* The third argument to .comm is the alignment. */ - if (*input_line_pointer != ',') - align = 3; - else - { - ++input_line_pointer; - align = get_absolute_expression (); - if (align <= 0) - { - as_warn (_("ignoring bad alignment")); - align = 3; - } - } - } - - *p = 0; - symbolP = symbol_find_or_make (name); - - *p = c; - if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) - { - as_bad (_("ignoring attempt to re-define symbol `%s'."), - S_GET_NAME (symbolP)); - ignore_rest_of_line (); - return; - } - - if (S_GET_VALUE (symbolP)) - { - if (S_GET_VALUE (symbolP) != (valueT) temp) - as_bad (_("length of .comm \"%s\" is already %ld. Not changed to %ld."), - S_GET_NAME (symbolP), - (long) S_GET_VALUE (symbolP), - (long) temp); - } - else - { - S_SET_VALUE (symbolP, (valueT) temp); - S_SET_EXTERNAL (symbolP); - S_SET_SEGMENT (symbolP, bfd_com_section_ptr); - } - - demand_empty_rest_of_line (); -} - -/* - * implement the .section pseudo op: - * .section name {, "flags"} - * ^ ^ - * | +--- optional flags: 'b' for bss - * | 'i' for info - * +-- section name 'l' for lib - * 'n' for noload - * 'o' for over - * 'w' for data - * 'd' (apparently m88k for data) - * 'x' for text - * But if the argument is not a quoted string, treat it as a - * subsegment number. - * - * FIXME: this is a copy of the section processing from obj-coff.c, with - * additions/changes for the moto-pas assembler support. There are three - * categories: - * - * FIXME: I just noticed this. This doesn't work at all really. It it - * setting bits that bfd probably neither understands or uses. The - * correct approach (?) will have to incorporate extra fields attached - * to the section to hold the system specific stuff. (krk) - * - * Section Contents: - * 'a' - unknown - referred to in documentation, but no definition supplied - * 'c' - section has code - * 'd' - section has initialized data - * 'u' - section has uninitialized data - * 'i' - section contains directives (info) - * 'n' - section can be discarded - * 'R' - remove section at link time - * - * Section Protection: - * 'r' - section is readable - * 'w' - section is writeable - * 'x' - section is executable - * 's' - section is sharable - * - * Section Alignment: - * '0' - align to byte boundary - * '1' - align to halfword undary - * '2' - align to word boundary - * '3' - align to doubleword boundary - * '4' - align to quadword boundary - * '5' - align to 32 byte boundary - * '6' - align to 64 byte boundary - * - */ - -void -ppc_pe_section (int ignore ATTRIBUTE_UNUSED) -{ - /* Strip out the section name. */ - char *section_name; - char c; - char *name; - unsigned int exp; - flagword flags; - segT sec; - int align; - - section_name = input_line_pointer; - c = get_symbol_end (); - - name = xmalloc (input_line_pointer - section_name + 1); - strcpy (name, section_name); - - *input_line_pointer = c; - - SKIP_WHITESPACE (); - - exp = 0; - flags = SEC_NO_FLAGS; - - if (strcmp (name, ".idata$2") == 0) - { - align = 0; - } - else if (strcmp (name, ".idata$3") == 0) - { - align = 0; - } - else if (strcmp (name, ".idata$4") == 0) - { - align = 2; - } - else if (strcmp (name, ".idata$5") == 0) - { - align = 2; - } - else if (strcmp (name, ".idata$6") == 0) - { - align = 1; - } - else - /* Default alignment to 16 byte boundary. */ - align = 4; - - if (*input_line_pointer == ',') - { - ++input_line_pointer; - SKIP_WHITESPACE (); - if (*input_line_pointer != '"') - exp = get_absolute_expression (); - else - { - ++input_line_pointer; - while (*input_line_pointer != '"' - && ! is_end_of_line[(unsigned char) *input_line_pointer]) - { - switch (*input_line_pointer) - { - /* Section Contents */ - case 'a': /* unknown */ - as_bad (_("unsupported section attribute -- 'a'")); - break; - case 'c': /* code section */ - flags |= SEC_CODE; - break; - case 'd': /* section has initialized data */ - flags |= SEC_DATA; - break; - case 'u': /* section has uninitialized data */ - /* FIXME: This is IMAGE_SCN_CNT_UNINITIALIZED_DATA - in winnt.h */ - flags |= SEC_ROM; - break; - case 'i': /* section contains directives (info) */ - /* FIXME: This is IMAGE_SCN_LNK_INFO - in winnt.h */ - flags |= SEC_HAS_CONTENTS; - break; - case 'n': /* section can be discarded */ - flags &=~ SEC_LOAD; - break; - case 'R': /* Remove section at link time */ - flags |= SEC_NEVER_LOAD; - break; -#if IFLICT_BRAIN_DAMAGE - /* Section Protection */ - case 'r': /* section is readable */ - flags |= IMAGE_SCN_MEM_READ; - break; - case 'w': /* section is writeable */ - flags |= IMAGE_SCN_MEM_WRITE; - break; - case 'x': /* section is executable */ - flags |= IMAGE_SCN_MEM_EXECUTE; - break; - case 's': /* section is sharable */ - flags |= IMAGE_SCN_MEM_SHARED; - break; - - /* Section Alignment */ - case '0': /* align to byte boundary */ - flags |= IMAGE_SCN_ALIGN_1BYTES; - align = 0; - break; - case '1': /* align to halfword boundary */ - flags |= IMAGE_SCN_ALIGN_2BYTES; - align = 1; - break; - case '2': /* align to word boundary */ - flags |= IMAGE_SCN_ALIGN_4BYTES; - align = 2; - break; - case '3': /* align to doubleword boundary */ - flags |= IMAGE_SCN_ALIGN_8BYTES; - align = 3; - break; - case '4': /* align to quadword boundary */ - flags |= IMAGE_SCN_ALIGN_16BYTES; - align = 4; - break; - case '5': /* align to 32 byte boundary */ - flags |= IMAGE_SCN_ALIGN_32BYTES; - align = 5; - break; - case '6': /* align to 64 byte boundary */ - flags |= IMAGE_SCN_ALIGN_64BYTES; - align = 6; - break; -#endif - default: - as_bad (_("unknown section attribute '%c'"), - *input_line_pointer); - break; - } - ++input_line_pointer; - } - if (*input_line_pointer == '"') - ++input_line_pointer; - } - } - - sec = subseg_new (name, (subsegT) exp); - - ppc_set_current_section (sec); - - if (flags != SEC_NO_FLAGS) - { - if (! bfd_set_section_flags (stdoutput, sec, flags)) - as_bad (_("error setting flags for \"%s\": %s"), - bfd_section_name (stdoutput, sec), - bfd_errmsg (bfd_get_error ())); - } - - bfd_set_section_alignment (stdoutput, sec, align); -} - -static void -ppc_pe_function (int ignore ATTRIBUTE_UNUSED) -{ - char *name; - char endc; - symbolS *ext_sym; - - name = input_line_pointer; - endc = get_symbol_end (); - - ext_sym = symbol_find_or_make (name); - - *input_line_pointer = endc; - - S_SET_DATA_TYPE (ext_sym, DT_FCN << N_BTSHFT); - SF_SET_FUNCTION (ext_sym); - SF_SET_PROCESS (ext_sym); - coff_add_linesym (ext_sym); - - demand_empty_rest_of_line (); -} - -static void -ppc_pe_tocd (int ignore ATTRIBUTE_UNUSED) -{ - if (tocdata_section == 0) - { - tocdata_section = subseg_new (".tocd", 0); - /* FIXME: section flags won't work. */ - bfd_set_section_flags (stdoutput, tocdata_section, - (SEC_ALLOC | SEC_LOAD | SEC_RELOC - | SEC_READONLY | SEC_DATA)); - - bfd_set_section_alignment (stdoutput, tocdata_section, 2); - } - else - { - rdata_section = subseg_new (".tocd", 0); - } - - ppc_set_current_section (tocdata_section); - - demand_empty_rest_of_line (); -} - -/* Don't adjust TOC relocs to use the section symbol. */ - -int -ppc_pe_fix_adjustable (fixS *fix) -{ - return fix->fx_r_type != BFD_RELOC_PPC_TOC16; -} - -#endif - -#ifdef OBJ_XCOFF - -/* XCOFF specific symbol and file handling. */ - -/* Canonicalize the symbol name. We use the to force the suffix, if - any, to use square brackets, and to be in upper case. */ - -char * -ppc_canonicalize_symbol_name (char *name) -{ - char *s; - - if (ppc_stab_symbol) - return name; - - for (s = name; *s != '\0' && *s != '{' && *s != '['; s++) - ; - if (*s != '\0') - { - char brac; - - if (*s == '[') - brac = ']'; - else - { - *s = '['; - brac = '}'; - } - - for (s++; *s != '\0' && *s != brac; s++) - *s = TOUPPER (*s); - - if (*s == '\0' || s[1] != '\0') - as_bad (_("bad symbol suffix")); - - *s = ']'; - } - - return name; -} - -/* Set the class of a symbol based on the suffix, if any. This is - called whenever a new symbol is created. */ - -void -ppc_symbol_new_hook (symbolS *sym) -{ - struct ppc_tc_sy *tc; - const char *s; - - tc = symbol_get_tc (sym); - tc->next = NULL; - tc->output = 0; - tc->symbol_class = -1; - tc->real_name = NULL; - tc->subseg = 0; - tc->align = 0; - tc->u.size = NULL; - tc->u.dw = NULL; - tc->within = NULL; - - if (ppc_stab_symbol) - return; - - s = strchr (S_GET_NAME (sym), '['); - if (s == (const char *) NULL) - { - /* There is no suffix. */ - return; - } - - ++s; - - switch (s[0]) - { - case 'B': - if (strcmp (s, "BS]") == 0) - tc->symbol_class = XMC_BS; - break; - case 'D': - if (strcmp (s, "DB]") == 0) - tc->symbol_class = XMC_DB; - else if (strcmp (s, "DS]") == 0) - tc->symbol_class = XMC_DS; - break; - case 'G': - if (strcmp (s, "GL]") == 0) - tc->symbol_class = XMC_GL; - break; - case 'P': - if (strcmp (s, "PR]") == 0) - tc->symbol_class = XMC_PR; - break; - case 'R': - if (strcmp (s, "RO]") == 0) - tc->symbol_class = XMC_RO; - else if (strcmp (s, "RW]") == 0) - tc->symbol_class = XMC_RW; - break; - case 'S': - if (strcmp (s, "SV]") == 0) - tc->symbol_class = XMC_SV; - break; - case 'T': - if (strcmp (s, "TC]") == 0) - tc->symbol_class = XMC_TC; - else if (strcmp (s, "TI]") == 0) - tc->symbol_class = XMC_TI; - else if (strcmp (s, "TB]") == 0) - tc->symbol_class = XMC_TB; - else if (strcmp (s, "TC0]") == 0 || strcmp (s, "T0]") == 0) - tc->symbol_class = XMC_TC0; - break; - case 'U': - if (strcmp (s, "UA]") == 0) - tc->symbol_class = XMC_UA; - else if (strcmp (s, "UC]") == 0) - tc->symbol_class = XMC_UC; - break; - case 'X': - if (strcmp (s, "XO]") == 0) - tc->symbol_class = XMC_XO; - break; - } - - if (tc->symbol_class == -1) - as_bad (_("unrecognized symbol suffix")); -} - -/* Set the class of a label based on where it is defined. This - handles symbols without suffixes. Also, move the symbol so that it - follows the csect symbol. */ - -void -ppc_frob_label (symbolS *sym) -{ - if (ppc_current_csect != (symbolS *) NULL) - { - if (symbol_get_tc (sym)->symbol_class == -1) - symbol_get_tc (sym)->symbol_class = symbol_get_tc (ppc_current_csect)->symbol_class; - - symbol_remove (sym, &symbol_rootP, &symbol_lastP); - symbol_append (sym, symbol_get_tc (ppc_current_csect)->within, - &symbol_rootP, &symbol_lastP); - symbol_get_tc (ppc_current_csect)->within = sym; - symbol_get_tc (sym)->within = ppc_current_csect; - } - -#ifdef OBJ_ELF - dwarf2_emit_label (sym); -#endif -} - -/* This variable is set by ppc_frob_symbol if any absolute symbols are - seen. It tells ppc_adjust_symtab whether it needs to look through - the symbols. */ - -static bfd_boolean ppc_saw_abs; - -/* Change the name of a symbol just before writing it out. Set the - real name if the .rename pseudo-op was used. Otherwise, remove any - class suffix. Return 1 if the symbol should not be included in the - symbol table. */ - -int -ppc_frob_symbol (symbolS *sym) -{ - static symbolS *ppc_last_function; - static symbolS *set_end; - - /* Discard symbols that should not be included in the output symbol - table. */ - if (! symbol_used_in_reloc_p (sym) - && ((symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) != 0 - || (! (S_IS_EXTERNAL (sym) || S_IS_WEAK (sym)) - && ! symbol_get_tc (sym)->output - && S_GET_STORAGE_CLASS (sym) != C_FILE))) - return 1; - - /* This one will disappear anyway. Don't make a csect sym for it. */ - if (sym == abs_section_sym) - return 1; - - if (symbol_get_tc (sym)->real_name != (char *) NULL) - S_SET_NAME (sym, symbol_get_tc (sym)->real_name); - else - { - const char *name; - const char *s; - - name = S_GET_NAME (sym); - s = strchr (name, '['); - if (s != (char *) NULL) - { - unsigned int len; - char *snew; - - len = s - name; - snew = xmalloc (len + 1); - memcpy (snew, name, len); - snew[len] = '\0'; - - S_SET_NAME (sym, snew); - } - } - - if (set_end != (symbolS *) NULL) - { - SA_SET_SYM_ENDNDX (set_end, sym); - set_end = NULL; - } - - if (SF_GET_FUNCTION (sym)) - { - if (ppc_last_function != (symbolS *) NULL) - as_bad (_("two .function pseudo-ops with no intervening .ef")); - ppc_last_function = sym; - if (symbol_get_tc (sym)->u.size != (symbolS *) NULL) - { - resolve_symbol_value (symbol_get_tc (sym)->u.size); - SA_SET_SYM_FSIZE (sym, - (long) S_GET_VALUE (symbol_get_tc (sym)->u.size)); - } - } - else if (S_GET_STORAGE_CLASS (sym) == C_FCN - && strcmp (S_GET_NAME (sym), ".ef") == 0) - { - if (ppc_last_function == (symbolS *) NULL) - as_bad (_(".ef with no preceding .function")); - else - { - set_end = ppc_last_function; - ppc_last_function = NULL; - - /* We don't have a C_EFCN symbol, but we need to force the - COFF backend to believe that it has seen one. */ - coff_last_function = NULL; - } - } - - if (! (S_IS_EXTERNAL (sym) || S_IS_WEAK (sym)) - && (symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) == 0 - && S_GET_STORAGE_CLASS (sym) != C_FILE - && S_GET_STORAGE_CLASS (sym) != C_FCN - && S_GET_STORAGE_CLASS (sym) != C_BLOCK - && S_GET_STORAGE_CLASS (sym) != C_BSTAT - && S_GET_STORAGE_CLASS (sym) != C_ESTAT - && S_GET_STORAGE_CLASS (sym) != C_BINCL - && S_GET_STORAGE_CLASS (sym) != C_EINCL - && S_GET_SEGMENT (sym) != ppc_coff_debug_section) - S_SET_STORAGE_CLASS (sym, C_HIDEXT); - - if (S_GET_STORAGE_CLASS (sym) == C_EXT - || S_GET_STORAGE_CLASS (sym) == C_AIX_WEAKEXT - || S_GET_STORAGE_CLASS (sym) == C_HIDEXT) - { - int i; - union internal_auxent *a; - - /* Create a csect aux. */ - i = S_GET_NUMBER_AUXILIARY (sym); - S_SET_NUMBER_AUXILIARY (sym, i + 1); - a = &coffsymbol (symbol_get_bfdsym (sym))->native[i + 1].u.auxent; - if (symbol_get_tc (sym)->symbol_class == XMC_TC0) - { - /* This is the TOC table. */ - know (strcmp (S_GET_NAME (sym), "TOC") == 0); - a->x_csect.x_scnlen.l = 0; - a->x_csect.x_smtyp = (2 << 3) | XTY_SD; - } - else if (symbol_get_tc (sym)->subseg != 0) - { - /* This is a csect symbol. x_scnlen is the size of the - csect. */ - if (symbol_get_tc (sym)->next == (symbolS *) NULL) - a->x_csect.x_scnlen.l = (bfd_section_size (stdoutput, - S_GET_SEGMENT (sym)) - - S_GET_VALUE (sym)); - else - { - resolve_symbol_value (symbol_get_tc (sym)->next); - a->x_csect.x_scnlen.l = (S_GET_VALUE (symbol_get_tc (sym)->next) - - S_GET_VALUE (sym)); - } - a->x_csect.x_smtyp = (symbol_get_tc (sym)->align << 3) | XTY_SD; - } - else if (S_GET_SEGMENT (sym) == bss_section) - { - /* This is a common symbol. */ - a->x_csect.x_scnlen.l = symbol_get_frag (sym)->fr_offset; - a->x_csect.x_smtyp = (symbol_get_tc (sym)->align << 3) | XTY_CM; - if (S_IS_EXTERNAL (sym)) - symbol_get_tc (sym)->symbol_class = XMC_RW; - else - symbol_get_tc (sym)->symbol_class = XMC_BS; - } - else if (S_GET_SEGMENT (sym) == absolute_section) - { - /* This is an absolute symbol. The csect will be created by - ppc_adjust_symtab. */ - ppc_saw_abs = TRUE; - a->x_csect.x_smtyp = XTY_LD; - if (symbol_get_tc (sym)->symbol_class == -1) - symbol_get_tc (sym)->symbol_class = XMC_XO; - } - else if (! S_IS_DEFINED (sym)) - { - /* This is an external symbol. */ - a->x_csect.x_scnlen.l = 0; - a->x_csect.x_smtyp = XTY_ER; - } - else if (symbol_get_tc (sym)->symbol_class == XMC_TC) - { - symbolS *next; - - /* This is a TOC definition. x_scnlen is the size of the - TOC entry. */ - next = symbol_next (sym); - while (symbol_get_tc (next)->symbol_class == XMC_TC0) - next = symbol_next (next); - if (next == (symbolS *) NULL - || symbol_get_tc (next)->symbol_class != XMC_TC) - { - if (ppc_after_toc_frag == (fragS *) NULL) - a->x_csect.x_scnlen.l = (bfd_section_size (stdoutput, - data_section) - - S_GET_VALUE (sym)); - else - a->x_csect.x_scnlen.l = (ppc_after_toc_frag->fr_address - - S_GET_VALUE (sym)); - } - else - { - resolve_symbol_value (next); - a->x_csect.x_scnlen.l = (S_GET_VALUE (next) - - S_GET_VALUE (sym)); - } - a->x_csect.x_smtyp = (2 << 3) | XTY_SD; - } - else - { - symbolS *csect; - - /* This is a normal symbol definition. x_scnlen is the - symbol index of the containing csect. */ - if (S_GET_SEGMENT (sym) == text_section) - csect = ppc_text_csects; - else if (S_GET_SEGMENT (sym) == data_section) - csect = ppc_data_csects; - else - abort (); - - /* Skip the initial dummy symbol. */ - csect = symbol_get_tc (csect)->next; - - if (csect == (symbolS *) NULL) - { - as_warn (_("warning: symbol %s has no csect"), S_GET_NAME (sym)); - a->x_csect.x_scnlen.l = 0; - } - else - { - while (symbol_get_tc (csect)->next != (symbolS *) NULL) - { - resolve_symbol_value (symbol_get_tc (csect)->next); - if (S_GET_VALUE (symbol_get_tc (csect)->next) - > S_GET_VALUE (sym)) - break; - csect = symbol_get_tc (csect)->next; - } - - a->x_csect.x_scnlen.p = - coffsymbol (symbol_get_bfdsym (csect))->native; - coffsymbol (symbol_get_bfdsym (sym))->native[i + 1].fix_scnlen = - 1; - } - a->x_csect.x_smtyp = XTY_LD; - } - - a->x_csect.x_parmhash = 0; - a->x_csect.x_snhash = 0; - if (symbol_get_tc (sym)->symbol_class == -1) - a->x_csect.x_smclas = XMC_PR; - else - a->x_csect.x_smclas = symbol_get_tc (sym)->symbol_class; - a->x_csect.x_stab = 0; - a->x_csect.x_snstab = 0; - - /* Don't let the COFF backend resort these symbols. */ - symbol_get_bfdsym (sym)->flags |= BSF_NOT_AT_END; - } - else if (S_GET_STORAGE_CLASS (sym) == C_BSTAT) - { - /* We want the value to be the symbol index of the referenced - csect symbol. BFD will do that for us if we set the right - flags. */ - asymbol *bsym = symbol_get_bfdsym (symbol_get_tc (sym)->within); - combined_entry_type *c = coffsymbol (bsym)->native; - - S_SET_VALUE (sym, (valueT) (size_t) c); - coffsymbol (symbol_get_bfdsym (sym))->native->fix_value = 1; - } - else if (S_GET_STORAGE_CLASS (sym) == C_STSYM) - { - symbolS *block; - valueT base; - - block = symbol_get_tc (sym)->within; - if (block) - { - /* The value is the offset from the enclosing csect. */ - symbolS *csect; - - csect = symbol_get_tc (block)->within; - resolve_symbol_value (csect); - base = S_GET_VALUE (csect); - } - else - base = 0; - - S_SET_VALUE (sym, S_GET_VALUE (sym) - base); - } - else if (S_GET_STORAGE_CLASS (sym) == C_BINCL - || S_GET_STORAGE_CLASS (sym) == C_EINCL) - { - /* We want the value to be a file offset into the line numbers. - BFD will do that for us if we set the right flags. We have - already set the value correctly. */ - coffsymbol (symbol_get_bfdsym (sym))->native->fix_line = 1; - } - - return 0; -} - -/* Adjust the symbol table. This creates csect symbols for all - absolute symbols. */ - -void -ppc_adjust_symtab (void) -{ - symbolS *sym; - - if (! ppc_saw_abs) - return; - - for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym)) - { - symbolS *csect; - int i; - union internal_auxent *a; - - if (S_GET_SEGMENT (sym) != absolute_section) - continue; - - csect = symbol_create (".abs[XO]", absolute_section, - S_GET_VALUE (sym), &zero_address_frag); - symbol_get_bfdsym (csect)->value = S_GET_VALUE (sym); - S_SET_STORAGE_CLASS (csect, C_HIDEXT); - i = S_GET_NUMBER_AUXILIARY (csect); - S_SET_NUMBER_AUXILIARY (csect, i + 1); - a = &coffsymbol (symbol_get_bfdsym (csect))->native[i + 1].u.auxent; - a->x_csect.x_scnlen.l = 0; - a->x_csect.x_smtyp = XTY_SD; - a->x_csect.x_parmhash = 0; - a->x_csect.x_snhash = 0; - a->x_csect.x_smclas = XMC_XO; - a->x_csect.x_stab = 0; - a->x_csect.x_snstab = 0; - - symbol_insert (csect, sym, &symbol_rootP, &symbol_lastP); - - i = S_GET_NUMBER_AUXILIARY (sym); - a = &coffsymbol (symbol_get_bfdsym (sym))->native[i].u.auxent; - a->x_csect.x_scnlen.p = coffsymbol (symbol_get_bfdsym (csect))->native; - coffsymbol (symbol_get_bfdsym (sym))->native[i].fix_scnlen = 1; - } - - ppc_saw_abs = FALSE; -} - -/* Set the VMA for a section. This is called on all the sections in - turn. */ - -void -ppc_frob_section (asection *sec) -{ - static bfd_vma vma = 0; - - /* Dwarf sections start at 0. */ - if (bfd_get_section_flags (NULL, sec) & SEC_DEBUGGING) - return; - - vma = md_section_align (sec, vma); - bfd_set_section_vma (stdoutput, sec, vma); - vma += bfd_section_size (stdoutput, sec); -} - -#endif /* OBJ_XCOFF */ - -char * -md_atof (int type, char *litp, int *sizep) -{ - return ieee_md_atof (type, litp, sizep, target_big_endian); -} - -/* Write a value out to the object file, using the appropriate - endianness. */ - -void -md_number_to_chars (char *buf, valueT val, int n) -{ - if (target_big_endian) - number_to_chars_bigendian (buf, val, n); - else - number_to_chars_littleendian (buf, val, n); -} - -/* Align a section (I don't know why this is machine dependent). */ - -valueT -md_section_align (asection *seg ATTRIBUTE_UNUSED, valueT addr) -{ -#ifdef OBJ_ELF - return addr; -#else - int align = bfd_get_section_alignment (stdoutput, seg); - - return ((addr + (1 << align) - 1) & (-1 << align)); -#endif -} - -/* We don't have any form of relaxing. */ - -int -md_estimate_size_before_relax (fragS *fragp ATTRIBUTE_UNUSED, - asection *seg ATTRIBUTE_UNUSED) -{ - abort (); - return 0; -} - -/* Convert a machine dependent frag. We never generate these. */ - -void -md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec ATTRIBUTE_UNUSED, - fragS *fragp ATTRIBUTE_UNUSED) -{ - abort (); -} - -/* We have no need to default values of symbols. */ - -symbolS * -md_undefined_symbol (char *name ATTRIBUTE_UNUSED) -{ - return 0; -} - -/* Functions concerning relocs. */ - -/* The location from which a PC relative jump should be calculated, - given a PC relative reloc. */ - -long -md_pcrel_from_section (fixS *fixp, segT sec ATTRIBUTE_UNUSED) -{ - return fixp->fx_frag->fr_address + fixp->fx_where; -} - -#ifdef OBJ_XCOFF - -/* This is called to see whether a fixup should be adjusted to use a - section symbol. We take the opportunity to change a fixup against - a symbol in the TOC subsegment into a reloc against the - corresponding .tc symbol. */ - -int -ppc_fix_adjustable (fixS *fix) -{ - valueT val = resolve_symbol_value (fix->fx_addsy); - segT symseg = S_GET_SEGMENT (fix->fx_addsy); - TC_SYMFIELD_TYPE *tc; - - if (symseg == absolute_section) - return 0; - - /* Always adjust symbols in debugging sections. */ - if (bfd_get_section_flags (stdoutput, symseg) & SEC_DEBUGGING) - return 1; - - if (ppc_toc_csect != (symbolS *) NULL - && fix->fx_addsy != ppc_toc_csect - && symseg == data_section - && val >= ppc_toc_frag->fr_address - && (ppc_after_toc_frag == (fragS *) NULL - || val < ppc_after_toc_frag->fr_address)) - { - symbolS *sy; - - for (sy = symbol_next (ppc_toc_csect); - sy != (symbolS *) NULL; - sy = symbol_next (sy)) - { - TC_SYMFIELD_TYPE *sy_tc = symbol_get_tc (sy); - - if (sy_tc->symbol_class == XMC_TC0) - continue; - if (sy_tc->symbol_class != XMC_TC) - break; - if (val == resolve_symbol_value (sy)) - { - fix->fx_addsy = sy; - fix->fx_addnumber = val - ppc_toc_frag->fr_address; - return 0; - } - } - - as_bad_where (fix->fx_file, fix->fx_line, - _("symbol in .toc does not match any .tc")); - } - - /* Possibly adjust the reloc to be against the csect. */ - tc = symbol_get_tc (fix->fx_addsy); - if (tc->subseg == 0 - && tc->symbol_class != XMC_TC0 - && tc->symbol_class != XMC_TC - && symseg != bss_section - /* Don't adjust if this is a reloc in the toc section. */ - && (symseg != data_section - || ppc_toc_csect == NULL - || val < ppc_toc_frag->fr_address - || (ppc_after_toc_frag != NULL - && val >= ppc_after_toc_frag->fr_address))) - { - symbolS *csect = tc->within; - - /* If the symbol was not declared by a label (eg: a section symbol), - use the section instead of the csect. This doesn't happen in - normal AIX assembly code. */ - if (csect == NULL) - csect = seg_info (symseg)->sym; - - fix->fx_offset += val - symbol_get_frag (csect)->fr_address; - fix->fx_addsy = csect; - - return 0; - } - - /* Adjust a reloc against a .lcomm symbol to be against the base - .lcomm. */ - if (symseg == bss_section - && ! S_IS_EXTERNAL (fix->fx_addsy)) - { - symbolS *sy = symbol_get_frag (fix->fx_addsy)->fr_symbol; - - fix->fx_offset += val - resolve_symbol_value (sy); - fix->fx_addsy = sy; - } - - return 0; -} - -/* A reloc from one csect to another must be kept. The assembler - will, of course, keep relocs between sections, and it will keep - absolute relocs, but we need to force it to keep PC relative relocs - between two csects in the same section. */ - -int -ppc_force_relocation (fixS *fix) -{ - /* At this point fix->fx_addsy should already have been converted to - a csect symbol. If the csect does not include the fragment, then - we need to force the relocation. */ - if (fix->fx_pcrel - && fix->fx_addsy != NULL - && symbol_get_tc (fix->fx_addsy)->subseg != 0 - && ((symbol_get_frag (fix->fx_addsy)->fr_address - > fix->fx_frag->fr_address) - || (symbol_get_tc (fix->fx_addsy)->next != NULL - && (symbol_get_frag (symbol_get_tc (fix->fx_addsy)->next)->fr_address - <= fix->fx_frag->fr_address)))) - return 1; - - return generic_force_reloc (fix); -} - -void -ppc_new_dot_label (symbolS *sym) -{ - /* Anchor this label to the current csect for relocations. */ - symbol_get_tc (sym)->within = ppc_current_csect; -} - -#endif /* OBJ_XCOFF */ - -#ifdef OBJ_ELF -/* If this function returns non-zero, it guarantees that a relocation - will be emitted for a fixup. */ - -int -ppc_force_relocation (fixS *fix) -{ - /* Branch prediction relocations must force a relocation, as must - the vtable description relocs. */ - switch (fix->fx_r_type) - { - case BFD_RELOC_PPC_B16_BRTAKEN: - case BFD_RELOC_PPC_B16_BRNTAKEN: - case BFD_RELOC_PPC_BA16_BRTAKEN: - case BFD_RELOC_PPC_BA16_BRNTAKEN: - case BFD_RELOC_24_PLT_PCREL: - case BFD_RELOC_PPC64_TOC: - return 1; - case BFD_RELOC_PPC_B26: - case BFD_RELOC_PPC_BA26: - case BFD_RELOC_PPC_B16: - case BFD_RELOC_PPC_BA16: - /* All branch fixups targeting a localentry symbol must - force a relocation. */ - if (fix->fx_addsy) - { - asymbol *bfdsym = symbol_get_bfdsym (fix->fx_addsy); - elf_symbol_type *elfsym - = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym); - gas_assert (elfsym); - if ((STO_PPC64_LOCAL_MASK & elfsym->internal_elf_sym.st_other) != 0) - return 1; - } - break; - default: - break; - } - - if (fix->fx_r_type >= BFD_RELOC_PPC_TLS - && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA) - return 1; - - return generic_force_reloc (fix); -} - -int -ppc_fix_adjustable (fixS *fix) -{ - switch (fix->fx_r_type) - { - /* All branch fixups targeting a localentry symbol must - continue using the symbol. */ - case BFD_RELOC_PPC_B26: - case BFD_RELOC_PPC_BA26: - case BFD_RELOC_PPC_B16: - case BFD_RELOC_PPC_BA16: - case BFD_RELOC_PPC_B16_BRTAKEN: - case BFD_RELOC_PPC_B16_BRNTAKEN: - case BFD_RELOC_PPC_BA16_BRTAKEN: - case BFD_RELOC_PPC_BA16_BRNTAKEN: - if (fix->fx_addsy) - { - asymbol *bfdsym = symbol_get_bfdsym (fix->fx_addsy); - elf_symbol_type *elfsym - = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym); - gas_assert (elfsym); - if ((STO_PPC64_LOCAL_MASK & elfsym->internal_elf_sym.st_other) != 0) - return 0; - } - break; - default: - break; - } - - return (fix->fx_r_type != BFD_RELOC_16_GOTOFF - && fix->fx_r_type != BFD_RELOC_LO16_GOTOFF - && fix->fx_r_type != BFD_RELOC_HI16_GOTOFF - && fix->fx_r_type != BFD_RELOC_HI16_S_GOTOFF - && fix->fx_r_type != BFD_RELOC_PPC64_GOT16_DS - && fix->fx_r_type != BFD_RELOC_PPC64_GOT16_LO_DS - && fix->fx_r_type != BFD_RELOC_GPREL16 - && fix->fx_r_type != BFD_RELOC_VTABLE_INHERIT - && fix->fx_r_type != BFD_RELOC_VTABLE_ENTRY - && !(fix->fx_r_type >= BFD_RELOC_PPC_TLS - && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA)); -} -#endif - -void -ppc_frag_check (struct frag *fragP) -{ - if (!fragP->has_code) - return; - - if (ppc_mach() == bfd_mach_ppc_vle) - { - if (((fragP->fr_address + fragP->insn_addr) & 1) != 0) - as_bad (_("instruction address is not a multiple of 2")); - } - else - { - if (((fragP->fr_address + fragP->insn_addr) & 3) != 0) - as_bad (_("instruction address is not a multiple of 4")); - } -} - -/* Implement HANDLE_ALIGN. This writes the NOP pattern into an - rs_align_code frag. */ - -void -ppc_handle_align (struct frag *fragP) -{ - valueT count = (fragP->fr_next->fr_address - - (fragP->fr_address + fragP->fr_fix)); - - if (ppc_mach() == bfd_mach_ppc_vle && count != 0 && (count & 1) == 0) - { - char *dest = fragP->fr_literal + fragP->fr_fix; - - fragP->fr_var = 2; - md_number_to_chars (dest, 0x4400, 2); - } - else if (count != 0 && (count & 3) == 0) - { - char *dest = fragP->fr_literal + fragP->fr_fix; - - fragP->fr_var = 4; - - if (count > 4 * nop_limit && count < 0x2000000) - { - struct frag *rest; - - /* Make a branch, then follow with nops. Insert another - frag to handle the nops. */ - md_number_to_chars (dest, 0x48000000 + count, 4); - count -= 4; - if (count == 0) - return; - - rest = xmalloc (SIZEOF_STRUCT_FRAG + 4); - memcpy (rest, fragP, SIZEOF_STRUCT_FRAG); - fragP->fr_next = rest; - fragP = rest; - rest->fr_address += rest->fr_fix + 4; - rest->fr_fix = 0; - /* If we leave the next frag as rs_align_code we'll come here - again, resulting in a bunch of branches rather than a - branch followed by nops. */ - rest->fr_type = rs_align; - dest = rest->fr_literal; - } - - md_number_to_chars (dest, 0x60000000, 4); - - if ((ppc_cpu & PPC_OPCODE_POWER6) != 0 - || (ppc_cpu & PPC_OPCODE_POWER7) != 0 - || (ppc_cpu & PPC_OPCODE_POWER8) != 0) - { - /* For power6, power7 and power8, we want the last nop to be a group - terminating one. Do this by inserting an rs_fill frag immediately - after this one, with its address set to the last nop location. - This will automatically reduce the number of nops in the current - frag by one. */ - if (count > 4) - { - struct frag *group_nop = xmalloc (SIZEOF_STRUCT_FRAG + 4); - - memcpy (group_nop, fragP, SIZEOF_STRUCT_FRAG); - group_nop->fr_address = group_nop->fr_next->fr_address - 4; - group_nop->fr_fix = 0; - group_nop->fr_offset = 1; - group_nop->fr_type = rs_fill; - fragP->fr_next = group_nop; - dest = group_nop->fr_literal; - } - - if ((ppc_cpu & PPC_OPCODE_POWER7) != 0 - || (ppc_cpu & PPC_OPCODE_POWER8) != 0) - { - if (ppc_cpu & PPC_OPCODE_E500MC) - /* e500mc group terminating nop: "ori 0,0,0". */ - md_number_to_chars (dest, 0x60000000, 4); - else - /* power7/power8 group terminating nop: "ori 2,2,0". */ - md_number_to_chars (dest, 0x60420000, 4); - } - else - /* power6 group terminating nop: "ori 1,1,0". */ - md_number_to_chars (dest, 0x60210000, 4); - } - } -} - -/* Apply a fixup to the object code. This is called for all the - fixups we generated by the calls to fix_new_exp, above. */ - -void -md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) -{ - valueT value = * valP; - offsetT fieldval; - const struct powerpc_operand *operand; - -#ifdef OBJ_ELF - if (fixP->fx_addsy != NULL) - { - /* Hack around bfd_install_relocation brain damage. */ - if (fixP->fx_pcrel) - value += fixP->fx_frag->fr_address + fixP->fx_where; - } - else - fixP->fx_done = 1; -#else - /* FIXME FIXME FIXME: The value we are passed in *valP includes - the symbol values. If we are doing this relocation the code in - write.c is going to call bfd_install_relocation, which is also - going to use the symbol value. That means that if the reloc is - fully resolved we want to use *valP since bfd_install_relocation is - not being used. - However, if the reloc is not fully resolved we do not want to - use *valP, and must use fx_offset instead. If the relocation - is PC-relative, we then need to re-apply md_pcrel_from_section - to this new relocation value. */ - if (fixP->fx_addsy == (symbolS *) NULL) - fixP->fx_done = 1; - - else - { - value = fixP->fx_offset; - if (fixP->fx_pcrel) - value -= md_pcrel_from_section (fixP, seg); - } -#endif - - if (fixP->fx_subsy != (symbolS *) NULL) - { - /* We can't actually support subtracting a symbol. */ - as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex")); - } - - operand = NULL; - if (fixP->fx_pcrel_adjust != 0) - { - /* This is a fixup on an instruction. */ - int opindex = fixP->fx_pcrel_adjust & 0xff; - - operand = &powerpc_operands[opindex]; -#ifdef OBJ_XCOFF - /* An instruction like `lwz 9,sym(30)' when `sym' is not a TOC symbol - does not generate a reloc. It uses the offset of `sym' within its - csect. Other usages, such as `.long sym', generate relocs. This - is the documented behaviour of non-TOC symbols. */ - if ((operand->flags & PPC_OPERAND_PARENS) != 0 - && (operand->bitm & 0xfff0) == 0xfff0 - && operand->shift == 0 - && (operand->insert == NULL || ppc_obj64) - && fixP->fx_addsy != NULL - && symbol_get_tc (fixP->fx_addsy)->subseg != 0 - && symbol_get_tc (fixP->fx_addsy)->symbol_class != XMC_TC - && symbol_get_tc (fixP->fx_addsy)->symbol_class != XMC_TC0 - && S_GET_SEGMENT (fixP->fx_addsy) != bss_section) - { - value = fixP->fx_offset; - fixP->fx_done = 1; - } - - /* During parsing of instructions, a TOC16 reloc is generated for - instructions such as 'lwz RT,SYM(RB)' if SYM is a symbol defined - in the toc. But at parse time, SYM may be not yet defined, so - check again here. */ - if (fixP->fx_r_type == BFD_RELOC_16 - && fixP->fx_addsy != NULL - && ppc_is_toc_sym (fixP->fx_addsy)) - fixP->fx_r_type = BFD_RELOC_PPC_TOC16; -#endif - } - - /* Calculate value to be stored in field. */ - fieldval = value; - switch (fixP->fx_r_type) - { -#ifdef OBJ_ELF - case BFD_RELOC_PPC64_ADDR16_LO_DS: - case BFD_RELOC_PPC_VLE_LO16A: - case BFD_RELOC_PPC_VLE_LO16D: -#endif - case BFD_RELOC_LO16: - case BFD_RELOC_LO16_PCREL: - fieldval = value & 0xffff; - sign_extend_16: - if (operand != NULL && (operand->flags & PPC_OPERAND_SIGNED) != 0) - fieldval = SEX16 (fieldval); - fixP->fx_no_overflow = 1; - break; - - case BFD_RELOC_HI16: - case BFD_RELOC_HI16_PCREL: -#ifdef OBJ_ELF - if (REPORT_OVERFLOW_HI && ppc_obj64) - { - fieldval = value >> 16; - if (operand != NULL && (operand->flags & PPC_OPERAND_SIGNED) != 0) - { - valueT sign = (((valueT) -1 >> 16) + 1) >> 1; - fieldval = ((valueT) fieldval ^ sign) - sign; - } - break; - } - /* Fall thru */ - - case BFD_RELOC_PPC_VLE_HI16A: - case BFD_RELOC_PPC_VLE_HI16D: - case BFD_RELOC_PPC64_ADDR16_HIGH: -#endif - fieldval = PPC_HI (value); - goto sign_extend_16; - - case BFD_RELOC_HI16_S: - case BFD_RELOC_HI16_S_PCREL: -#ifdef OBJ_ELF - if (REPORT_OVERFLOW_HI && ppc_obj64) - { - fieldval = (value + 0x8000) >> 16; - if (operand != NULL && (operand->flags & PPC_OPERAND_SIGNED) != 0) - { - valueT sign = (((valueT) -1 >> 16) + 1) >> 1; - fieldval = ((valueT) fieldval ^ sign) - sign; - } - break; - } - /* Fall thru */ - - case BFD_RELOC_PPC_VLE_HA16A: - case BFD_RELOC_PPC_VLE_HA16D: - case BFD_RELOC_PPC64_ADDR16_HIGHA: -#endif - fieldval = PPC_HA (value); - goto sign_extend_16; - -#ifdef OBJ_ELF - case BFD_RELOC_PPC64_HIGHER: - fieldval = PPC_HIGHER (value); - goto sign_extend_16; - - case BFD_RELOC_PPC64_HIGHER_S: - fieldval = PPC_HIGHERA (value); - goto sign_extend_16; - - case BFD_RELOC_PPC64_HIGHEST: - fieldval = PPC_HIGHEST (value); - goto sign_extend_16; - - case BFD_RELOC_PPC64_HIGHEST_S: - fieldval = PPC_HIGHESTA (value); - goto sign_extend_16; -#endif - - default: - break; - } - - if (operand != NULL) - { - /* Handle relocs in an insn. */ - char *where; - unsigned long insn; - - switch (fixP->fx_r_type) - { -#ifdef OBJ_ELF - /* The following relocs can't be calculated by the assembler. - Leave the field zero. */ - case BFD_RELOC_PPC_TPREL16: - case BFD_RELOC_PPC_TPREL16_LO: - case BFD_RELOC_PPC_TPREL16_HI: - case BFD_RELOC_PPC_TPREL16_HA: - case BFD_RELOC_PPC_DTPREL16: - case BFD_RELOC_PPC_DTPREL16_LO: - case BFD_RELOC_PPC_DTPREL16_HI: - case BFD_RELOC_PPC_DTPREL16_HA: - case BFD_RELOC_PPC_GOT_TLSGD16: - case BFD_RELOC_PPC_GOT_TLSGD16_LO: - case BFD_RELOC_PPC_GOT_TLSGD16_HI: - case BFD_RELOC_PPC_GOT_TLSGD16_HA: - case BFD_RELOC_PPC_GOT_TLSLD16: - case BFD_RELOC_PPC_GOT_TLSLD16_LO: - case BFD_RELOC_PPC_GOT_TLSLD16_HI: - case BFD_RELOC_PPC_GOT_TLSLD16_HA: - case BFD_RELOC_PPC_GOT_TPREL16: - case BFD_RELOC_PPC_GOT_TPREL16_LO: - case BFD_RELOC_PPC_GOT_TPREL16_HI: - case BFD_RELOC_PPC_GOT_TPREL16_HA: - case BFD_RELOC_PPC_GOT_DTPREL16: - case BFD_RELOC_PPC_GOT_DTPREL16_LO: - case BFD_RELOC_PPC_GOT_DTPREL16_HI: - case BFD_RELOC_PPC_GOT_DTPREL16_HA: - case BFD_RELOC_PPC64_TPREL16_DS: - case BFD_RELOC_PPC64_TPREL16_LO_DS: - case BFD_RELOC_PPC64_TPREL16_HIGH: - case BFD_RELOC_PPC64_TPREL16_HIGHA: - case BFD_RELOC_PPC64_TPREL16_HIGHER: - case BFD_RELOC_PPC64_TPREL16_HIGHERA: - case BFD_RELOC_PPC64_TPREL16_HIGHEST: - case BFD_RELOC_PPC64_TPREL16_HIGHESTA: - case BFD_RELOC_PPC64_DTPREL16_HIGH: - case BFD_RELOC_PPC64_DTPREL16_HIGHA: - case BFD_RELOC_PPC64_DTPREL16_DS: - case BFD_RELOC_PPC64_DTPREL16_LO_DS: - case BFD_RELOC_PPC64_DTPREL16_HIGHER: - case BFD_RELOC_PPC64_DTPREL16_HIGHERA: - case BFD_RELOC_PPC64_DTPREL16_HIGHEST: - case BFD_RELOC_PPC64_DTPREL16_HIGHESTA: - gas_assert (fixP->fx_addsy != NULL); - S_SET_THREAD_LOCAL (fixP->fx_addsy); - fieldval = 0; - break; - - /* These also should leave the field zero for the same - reason. Note that older versions of gas wrote values - here. If we want to go back to the old behaviour, then - all _LO and _LO_DS cases will need to be treated like - BFD_RELOC_LO16_PCREL above. Similarly for _HI etc. */ - case BFD_RELOC_16_GOTOFF: - case BFD_RELOC_LO16_GOTOFF: - case BFD_RELOC_HI16_GOTOFF: - case BFD_RELOC_HI16_S_GOTOFF: - case BFD_RELOC_LO16_PLTOFF: - case BFD_RELOC_HI16_PLTOFF: - case BFD_RELOC_HI16_S_PLTOFF: - case BFD_RELOC_GPREL16: - case BFD_RELOC_16_BASEREL: - case BFD_RELOC_LO16_BASEREL: - case BFD_RELOC_HI16_BASEREL: - case BFD_RELOC_HI16_S_BASEREL: - case BFD_RELOC_PPC_TOC16: - case BFD_RELOC_PPC64_TOC16_LO: - case BFD_RELOC_PPC64_TOC16_HI: - case BFD_RELOC_PPC64_TOC16_HA: - case BFD_RELOC_PPC64_PLTGOT16: - case BFD_RELOC_PPC64_PLTGOT16_LO: - case BFD_RELOC_PPC64_PLTGOT16_HI: - case BFD_RELOC_PPC64_PLTGOT16_HA: - case BFD_RELOC_PPC64_GOT16_DS: - case BFD_RELOC_PPC64_GOT16_LO_DS: - case BFD_RELOC_PPC64_PLT16_LO_DS: - case BFD_RELOC_PPC64_SECTOFF_DS: - case BFD_RELOC_PPC64_SECTOFF_LO_DS: - case BFD_RELOC_PPC64_TOC16_DS: - case BFD_RELOC_PPC64_TOC16_LO_DS: - case BFD_RELOC_PPC64_PLTGOT16_DS: - case BFD_RELOC_PPC64_PLTGOT16_LO_DS: - case BFD_RELOC_PPC_EMB_NADDR16: - case BFD_RELOC_PPC_EMB_NADDR16_LO: - case BFD_RELOC_PPC_EMB_NADDR16_HI: - case BFD_RELOC_PPC_EMB_NADDR16_HA: - case BFD_RELOC_PPC_EMB_SDAI16: - case BFD_RELOC_PPC_EMB_SDA2I16: - case BFD_RELOC_PPC_EMB_SDA2REL: - case BFD_RELOC_PPC_EMB_SDA21: - case BFD_RELOC_PPC_EMB_MRKREF: - case BFD_RELOC_PPC_EMB_RELSEC16: - case BFD_RELOC_PPC_EMB_RELST_LO: - case BFD_RELOC_PPC_EMB_RELST_HI: - case BFD_RELOC_PPC_EMB_RELST_HA: - case BFD_RELOC_PPC_EMB_BIT_FLD: - case BFD_RELOC_PPC_EMB_RELSDA: - case BFD_RELOC_PPC_VLE_SDA21: - case BFD_RELOC_PPC_VLE_SDA21_LO: - case BFD_RELOC_PPC_VLE_SDAREL_LO16A: - case BFD_RELOC_PPC_VLE_SDAREL_LO16D: - case BFD_RELOC_PPC_VLE_SDAREL_HI16A: - case BFD_RELOC_PPC_VLE_SDAREL_HI16D: - case BFD_RELOC_PPC_VLE_SDAREL_HA16A: - case BFD_RELOC_PPC_VLE_SDAREL_HA16D: - gas_assert (fixP->fx_addsy != NULL); - /* Fall thru */ - - case BFD_RELOC_PPC_TLS: - case BFD_RELOC_PPC_TLSGD: - case BFD_RELOC_PPC_TLSLD: - fieldval = 0; - break; -#endif - -#ifdef OBJ_XCOFF - case BFD_RELOC_PPC_B16: - /* Adjust the offset to the instruction boundary. */ - fieldval += 2; - break; -#endif - - default: - break; - } - -#ifdef OBJ_ELF -/* powerpc uses RELA style relocs, so if emitting a reloc the field - contents can stay at zero. */ -#define APPLY_RELOC fixP->fx_done -#else -#define APPLY_RELOC 1 -#endif - if ((fieldval != 0 && APPLY_RELOC) || operand->insert != NULL) - { - /* Fetch the instruction, insert the fully resolved operand - value, and stuff the instruction back again. */ - where = fixP->fx_frag->fr_literal + fixP->fx_where; - if (target_big_endian) - { - if (fixP->fx_size == 4) - insn = bfd_getb32 ((unsigned char *) where); - else - insn = bfd_getb16 ((unsigned char *) where); - } - else - { - if (fixP->fx_size == 4) - insn = bfd_getl32 ((unsigned char *) where); - else - insn = bfd_getl16 ((unsigned char *) where); - } - insn = ppc_insert_operand (insn, operand, fieldval, - fixP->tc_fix_data.ppc_cpu, - fixP->fx_file, fixP->fx_line); - if (target_big_endian) - { - if (fixP->fx_size == 4) - bfd_putb32 ((bfd_vma) insn, (unsigned char *) where); - else - bfd_putb16 ((bfd_vma) insn, (unsigned char *) where); - } - else - { - if (fixP->fx_size == 4) - bfd_putl32 ((bfd_vma) insn, (unsigned char *) where); - else - bfd_putl16 ((bfd_vma) insn, (unsigned char *) where); - } - } - - if (fixP->fx_done) - /* Nothing else to do here. */ - return; - - gas_assert (fixP->fx_addsy != NULL); - if (fixP->fx_r_type == BFD_RELOC_UNUSED) - { - char *sfile; - unsigned int sline; - - /* Use expr_symbol_where to see if this is an expression - symbol. */ - if (expr_symbol_where (fixP->fx_addsy, &sfile, &sline)) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("unresolved expression that must be resolved")); - else - as_bad_where (fixP->fx_file, fixP->fx_line, - _("unsupported relocation against %s"), - S_GET_NAME (fixP->fx_addsy)); - fixP->fx_done = 1; - return; - } - } - else - { - /* Handle relocs in data. */ - switch (fixP->fx_r_type) - { - case BFD_RELOC_VTABLE_INHERIT: - if (fixP->fx_addsy - && !S_IS_DEFINED (fixP->fx_addsy) - && !S_IS_WEAK (fixP->fx_addsy)) - S_SET_WEAK (fixP->fx_addsy); - /* Fall thru */ - - case BFD_RELOC_VTABLE_ENTRY: - fixP->fx_done = 0; - break; - -#ifdef OBJ_ELF - /* These can appear with @l etc. in data. */ - case BFD_RELOC_LO16: - case BFD_RELOC_LO16_PCREL: - case BFD_RELOC_HI16: - case BFD_RELOC_HI16_PCREL: - case BFD_RELOC_HI16_S: - case BFD_RELOC_HI16_S_PCREL: - case BFD_RELOC_PPC64_HIGHER: - case BFD_RELOC_PPC64_HIGHER_S: - case BFD_RELOC_PPC64_HIGHEST: - case BFD_RELOC_PPC64_HIGHEST_S: - case BFD_RELOC_PPC64_ADDR16_HIGH: - case BFD_RELOC_PPC64_ADDR16_HIGHA: - break; - - case BFD_RELOC_PPC_DTPMOD: - case BFD_RELOC_PPC_TPREL: - case BFD_RELOC_PPC_DTPREL: - S_SET_THREAD_LOCAL (fixP->fx_addsy); - break; - - /* Just punt all of these to the linker. */ - case BFD_RELOC_PPC_B16_BRTAKEN: - case BFD_RELOC_PPC_B16_BRNTAKEN: - case BFD_RELOC_16_GOTOFF: - case BFD_RELOC_LO16_GOTOFF: - case BFD_RELOC_HI16_GOTOFF: - case BFD_RELOC_HI16_S_GOTOFF: - case BFD_RELOC_LO16_PLTOFF: - case BFD_RELOC_HI16_PLTOFF: - case BFD_RELOC_HI16_S_PLTOFF: - case BFD_RELOC_PPC_COPY: - case BFD_RELOC_PPC_GLOB_DAT: - case BFD_RELOC_16_BASEREL: - case BFD_RELOC_LO16_BASEREL: - case BFD_RELOC_HI16_BASEREL: - case BFD_RELOC_HI16_S_BASEREL: - case BFD_RELOC_PPC_TLS: - case BFD_RELOC_PPC_DTPREL16_LO: - case BFD_RELOC_PPC_DTPREL16_HI: - case BFD_RELOC_PPC_DTPREL16_HA: - case BFD_RELOC_PPC_TPREL16_LO: - case BFD_RELOC_PPC_TPREL16_HI: - case BFD_RELOC_PPC_TPREL16_HA: - case BFD_RELOC_PPC_GOT_TLSGD16: - case BFD_RELOC_PPC_GOT_TLSGD16_LO: - case BFD_RELOC_PPC_GOT_TLSGD16_HI: - case BFD_RELOC_PPC_GOT_TLSGD16_HA: - case BFD_RELOC_PPC_GOT_TLSLD16: - case BFD_RELOC_PPC_GOT_TLSLD16_LO: - case BFD_RELOC_PPC_GOT_TLSLD16_HI: - case BFD_RELOC_PPC_GOT_TLSLD16_HA: - case BFD_RELOC_PPC_GOT_DTPREL16: - case BFD_RELOC_PPC_GOT_DTPREL16_LO: - case BFD_RELOC_PPC_GOT_DTPREL16_HI: - case BFD_RELOC_PPC_GOT_DTPREL16_HA: - case BFD_RELOC_PPC_GOT_TPREL16: - case BFD_RELOC_PPC_GOT_TPREL16_LO: - case BFD_RELOC_PPC_GOT_TPREL16_HI: - case BFD_RELOC_PPC_GOT_TPREL16_HA: - case BFD_RELOC_24_PLT_PCREL: - case BFD_RELOC_PPC_LOCAL24PC: - case BFD_RELOC_32_PLT_PCREL: - case BFD_RELOC_GPREL16: - case BFD_RELOC_PPC_VLE_SDAREL_LO16A: - case BFD_RELOC_PPC_VLE_SDAREL_HI16A: - case BFD_RELOC_PPC_VLE_SDAREL_HA16A: - case BFD_RELOC_PPC_EMB_NADDR32: - case BFD_RELOC_PPC_EMB_NADDR16: - case BFD_RELOC_PPC_EMB_NADDR16_LO: - case BFD_RELOC_PPC_EMB_NADDR16_HI: - case BFD_RELOC_PPC_EMB_NADDR16_HA: - case BFD_RELOC_PPC_EMB_SDAI16: - case BFD_RELOC_PPC_EMB_SDA2REL: - case BFD_RELOC_PPC_EMB_SDA2I16: - case BFD_RELOC_PPC_EMB_SDA21: - case BFD_RELOC_PPC_VLE_SDA21_LO: - case BFD_RELOC_PPC_EMB_MRKREF: - case BFD_RELOC_PPC_EMB_RELSEC16: - case BFD_RELOC_PPC_EMB_RELST_LO: - case BFD_RELOC_PPC_EMB_RELST_HI: - case BFD_RELOC_PPC_EMB_RELST_HA: - case BFD_RELOC_PPC_EMB_BIT_FLD: - case BFD_RELOC_PPC_EMB_RELSDA: - case BFD_RELOC_PPC64_TOC: - case BFD_RELOC_PPC_TOC16: - case BFD_RELOC_PPC64_TOC16_LO: - case BFD_RELOC_PPC64_TOC16_HI: - case BFD_RELOC_PPC64_TOC16_HA: - case BFD_RELOC_PPC64_DTPREL16_HIGH: - case BFD_RELOC_PPC64_DTPREL16_HIGHA: - case BFD_RELOC_PPC64_DTPREL16_HIGHER: - case BFD_RELOC_PPC64_DTPREL16_HIGHERA: - case BFD_RELOC_PPC64_DTPREL16_HIGHEST: - case BFD_RELOC_PPC64_DTPREL16_HIGHESTA: - case BFD_RELOC_PPC64_TPREL16_HIGH: - case BFD_RELOC_PPC64_TPREL16_HIGHA: - case BFD_RELOC_PPC64_TPREL16_HIGHER: - case BFD_RELOC_PPC64_TPREL16_HIGHERA: - case BFD_RELOC_PPC64_TPREL16_HIGHEST: - case BFD_RELOC_PPC64_TPREL16_HIGHESTA: - fixP->fx_done = 0; - break; -#endif - -#ifdef OBJ_XCOFF - case BFD_RELOC_NONE: -#endif - case BFD_RELOC_CTOR: - case BFD_RELOC_32: - case BFD_RELOC_32_PCREL: - case BFD_RELOC_RVA: - case BFD_RELOC_64: - case BFD_RELOC_64_PCREL: - case BFD_RELOC_16: - case BFD_RELOC_16_PCREL: - case BFD_RELOC_8: - break; - - default: - fprintf (stderr, - _("Gas failure, reloc value %d\n"), fixP->fx_r_type); - fflush (stderr); - abort (); - } - - if (fixP->fx_size && APPLY_RELOC) - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - fieldval, fixP->fx_size); - } - - /* We are only able to convert some relocs to pc-relative. */ - if (!fixP->fx_done && fixP->fx_pcrel) - { - switch (fixP->fx_r_type) - { - case BFD_RELOC_LO16: - fixP->fx_r_type = BFD_RELOC_LO16_PCREL; - break; - - case BFD_RELOC_HI16: - fixP->fx_r_type = BFD_RELOC_HI16_PCREL; - break; - - case BFD_RELOC_HI16_S: - fixP->fx_r_type = BFD_RELOC_HI16_S_PCREL; - break; - - case BFD_RELOC_64: - fixP->fx_r_type = BFD_RELOC_64_PCREL; - break; - - case BFD_RELOC_32: - fixP->fx_r_type = BFD_RELOC_32_PCREL; - break; - - case BFD_RELOC_16: - fixP->fx_r_type = BFD_RELOC_16_PCREL; - break; - - /* Some of course are already pc-relative. */ - case BFD_RELOC_LO16_PCREL: - case BFD_RELOC_HI16_PCREL: - case BFD_RELOC_HI16_S_PCREL: - case BFD_RELOC_64_PCREL: - case BFD_RELOC_32_PCREL: - case BFD_RELOC_16_PCREL: - case BFD_RELOC_PPC_B16: - case BFD_RELOC_PPC_B16_BRTAKEN: - case BFD_RELOC_PPC_B16_BRNTAKEN: - case BFD_RELOC_PPC_B26: - case BFD_RELOC_PPC_LOCAL24PC: - case BFD_RELOC_24_PLT_PCREL: - case BFD_RELOC_32_PLT_PCREL: - case BFD_RELOC_64_PLT_PCREL: - case BFD_RELOC_PPC_VLE_REL8: - case BFD_RELOC_PPC_VLE_REL15: - case BFD_RELOC_PPC_VLE_REL24: - break; - - default: - if (fixP->fx_addsy) - { - char *sfile; - unsigned int sline; - - /* Use expr_symbol_where to see if this is an - expression symbol. */ - if (expr_symbol_where (fixP->fx_addsy, &sfile, &sline)) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("unresolved expression that must" - " be resolved")); - else - as_bad_where (fixP->fx_file, fixP->fx_line, - _("cannot emit PC relative %s relocation" - " against %s"), - bfd_get_reloc_code_name (fixP->fx_r_type), - S_GET_NAME (fixP->fx_addsy)); - } - else - as_bad_where (fixP->fx_file, fixP->fx_line, - _("unable to resolve expression")); - fixP->fx_done = 1; - break; - } - } - -#ifdef OBJ_ELF - ppc_elf_validate_fix (fixP, seg); - fixP->fx_addnumber = value; - - /* PowerPC uses RELA relocs, ie. the reloc addend is stored separately - from the section contents. If we are going to be emitting a reloc - then the section contents are immaterial, so don't warn if they - happen to overflow. Leave such warnings to ld. */ - if (!fixP->fx_done) - { - fixP->fx_no_overflow = 1; - - /* Arrange to emit .TOC. as a normal symbol if used in anything - but .TOC.@tocbase. */ - if (ppc_obj64 - && fixP->fx_r_type != BFD_RELOC_PPC64_TOC - && fixP->fx_addsy != NULL - && strcmp (S_GET_NAME (fixP->fx_addsy), ".TOC.") == 0) - symbol_get_bfdsym (fixP->fx_addsy)->flags |= BSF_KEEP; - } -#else - if (fixP->fx_r_type != BFD_RELOC_PPC_TOC16) - fixP->fx_addnumber = 0; - else - { -#ifdef TE_PE - fixP->fx_addnumber = 0; -#else - /* We want to use the offset within the toc, not the actual VMA - of the symbol. */ - fixP->fx_addnumber = - - bfd_get_section_vma (stdoutput, S_GET_SEGMENT (fixP->fx_addsy)) - - S_GET_VALUE (ppc_toc_csect); - /* Set *valP to avoid errors. */ - *valP = value; -#endif - } -#endif -} - -/* Generate a reloc for a fixup. */ - -arelent * -tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp) -{ - arelent *reloc; - - reloc = (arelent *) xmalloc (sizeof (arelent)); - - reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); - *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); - reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; - reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); - if (reloc->howto == (reloc_howto_type *) NULL) - { - as_bad_where (fixp->fx_file, fixp->fx_line, - _("reloc %d not supported by object file format"), - (int) fixp->fx_r_type); - return NULL; - } - reloc->addend = fixp->fx_addnumber; - - return reloc; -} - -void -ppc_cfi_frame_initial_instructions (void) -{ - cfi_add_CFA_def_cfa (1, 0); -} - -int -tc_ppc_regname_to_dw2regnum (char *regname) -{ - unsigned int regnum = -1; - unsigned int i; - const char *p; - char *q; - static struct { char *name; int dw2regnum; } regnames[] = - { - { "sp", 1 }, { "r.sp", 1 }, { "rtoc", 2 }, { "r.toc", 2 }, - { "mq", 64 }, { "lr", 65 }, { "ctr", 66 }, { "ap", 67 }, - { "cr", 70 }, { "xer", 76 }, { "vrsave", 109 }, { "vscr", 110 }, - { "spe_acc", 111 }, { "spefscr", 112 } - }; - - for (i = 0; i < ARRAY_SIZE (regnames); ++i) - if (strcmp (regnames[i].name, regname) == 0) - return regnames[i].dw2regnum; - - if (regname[0] == 'r' || regname[0] == 'f' || regname[0] == 'v') - { - p = regname + 1 + (regname[1] == '.'); - regnum = strtoul (p, &q, 10); - if (p == q || *q || regnum >= 32) - return -1; - if (regname[0] == 'f') - regnum += 32; - else if (regname[0] == 'v') - regnum += 77; - } - else if (regname[0] == 'c' && regname[1] == 'r') - { - p = regname + 2 + (regname[2] == '.'); - if (p[0] < '0' || p[0] > '7' || p[1]) - return -1; - regnum = p[0] - '0' + 68; - } - return regnum; -} |