160484Sobrien/* tc-ppc.c -- Assemble for the PowerPC or POWER (RS/6000)
2130561Sobrien   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
3218822Sdim   2004, 2005, 2006, 2007 Free Software Foundation, Inc.
460484Sobrien   Written by Ian Lance Taylor, Cygnus Support.
560484Sobrien
660484Sobrien   This file is part of GAS, the GNU Assembler.
760484Sobrien
860484Sobrien   GAS is free software; you can redistribute it and/or modify
960484Sobrien   it under the terms of the GNU General Public License as published by
1060484Sobrien   the Free Software Foundation; either version 2, or (at your option)
1160484Sobrien   any later version.
1260484Sobrien
1360484Sobrien   GAS is distributed in the hope that it will be useful,
1460484Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1560484Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1660484Sobrien   GNU General Public License for more details.
1760484Sobrien
1860484Sobrien   You should have received a copy of the GNU General Public License
1960484Sobrien   along with GAS; see the file COPYING.  If not, write to the Free
20218822Sdim   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
21218822Sdim   02110-1301, USA.  */
2260484Sobrien
2360484Sobrien#include "as.h"
2489857Sobrien#include "safe-ctype.h"
2560484Sobrien#include "subsegs.h"
26130561Sobrien#include "dw2gencfi.h"
2760484Sobrien#include "opcode/ppc.h"
2860484Sobrien
2960484Sobrien#ifdef OBJ_ELF
3060484Sobrien#include "elf/ppc.h"
3177298Sobrien#include "dwarf2dbg.h"
3260484Sobrien#endif
3360484Sobrien
3460484Sobrien#ifdef TE_PE
3560484Sobrien#include "coff/pe.h"
3660484Sobrien#endif
3760484Sobrien
3860484Sobrien/* This is the assembler for the PowerPC or POWER (RS/6000) chips.  */
3960484Sobrien
4060484Sobrien/* Tell the main code what the endianness is.  */
4160484Sobrienextern int target_big_endian;
4260484Sobrien
4360484Sobrien/* Whether or not, we've set target_big_endian.  */
4460484Sobrienstatic int set_target_endian = 0;
4560484Sobrien
4660484Sobrien/* Whether to use user friendly register names.  */
4760484Sobrien#ifndef TARGET_REG_NAMES_P
4860484Sobrien#ifdef TE_PE
49130561Sobrien#define TARGET_REG_NAMES_P TRUE
5060484Sobrien#else
51130561Sobrien#define TARGET_REG_NAMES_P FALSE
5260484Sobrien#endif
5360484Sobrien#endif
5460484Sobrien
5589857Sobrien/* Macros for calculating LO, HI, HA, HIGHER, HIGHERA, HIGHEST,
5689857Sobrien   HIGHESTA.  */
5789857Sobrien
5889857Sobrien/* #lo(value) denotes the least significant 16 bits of the indicated.  */
5989857Sobrien#define PPC_LO(v) ((v) & 0xffff)
6089857Sobrien
6189857Sobrien/* #hi(value) denotes bits 16 through 31 of the indicated value.  */
6289857Sobrien#define PPC_HI(v) (((v) >> 16) & 0xffff)
6389857Sobrien
6489857Sobrien/* #ha(value) denotes the high adjusted value: bits 16 through 31 of
6589857Sobrien  the indicated value, compensating for #lo() being treated as a
6689857Sobrien  signed number.  */
6789857Sobrien#define PPC_HA(v) PPC_HI ((v) + 0x8000)
6889857Sobrien
6989857Sobrien/* #higher(value) denotes bits 32 through 47 of the indicated value.  */
70107492Sobrien#define PPC_HIGHER(v) (((v) >> 16 >> 16) & 0xffff)
7189857Sobrien
7289857Sobrien/* #highera(value) denotes bits 32 through 47 of the indicated value,
7389857Sobrien   compensating for #lo() being treated as a signed number.  */
7489857Sobrien#define PPC_HIGHERA(v) PPC_HIGHER ((v) + 0x8000)
7589857Sobrien
7689857Sobrien/* #highest(value) denotes bits 48 through 63 of the indicated value.  */
77107492Sobrien#define PPC_HIGHEST(v) (((v) >> 24 >> 24) & 0xffff)
7889857Sobrien
7989857Sobrien/* #highesta(value) denotes bits 48 through 63 of the indicated value,
8089857Sobrien   compensating for #lo being treated as a signed number.  */
8189857Sobrien#define PPC_HIGHESTA(v) PPC_HIGHEST ((v) + 0x8000)
8289857Sobrien
8389857Sobrien#define SEX16(val) ((((val) & 0xffff) ^ 0x8000) - 0x8000)
8489857Sobrien
85130561Sobrienstatic bfd_boolean reg_names_p = TARGET_REG_NAMES_P;
8660484Sobrien
87218822Sdimstatic void ppc_macro (char *, const struct powerpc_macro *);
88218822Sdimstatic void ppc_byte (int);
8989857Sobrien
9089857Sobrien#if defined (OBJ_XCOFF) || defined (OBJ_ELF)
91218822Sdimstatic void ppc_tc (int);
92218822Sdimstatic void ppc_machine (int);
9389857Sobrien#endif
9460484Sobrien
9560484Sobrien#ifdef OBJ_XCOFF
96218822Sdimstatic void ppc_comm (int);
97218822Sdimstatic void ppc_bb (int);
98218822Sdimstatic void ppc_bc (int);
99218822Sdimstatic void ppc_bf (int);
100218822Sdimstatic void ppc_biei (int);
101218822Sdimstatic void ppc_bs (int);
102218822Sdimstatic void ppc_eb (int);
103218822Sdimstatic void ppc_ec (int);
104218822Sdimstatic void ppc_ef (int);
105218822Sdimstatic void ppc_es (int);
106218822Sdimstatic void ppc_csect (int);
107218822Sdimstatic void ppc_change_csect (symbolS *, offsetT);
108218822Sdimstatic void ppc_function (int);
109218822Sdimstatic void ppc_extern (int);
110218822Sdimstatic void ppc_lglobl (int);
111218822Sdimstatic void ppc_section (int);
112218822Sdimstatic void ppc_named_section (int);
113218822Sdimstatic void ppc_stabx (int);
114218822Sdimstatic void ppc_rename (int);
115218822Sdimstatic void ppc_toc (int);
116218822Sdimstatic void ppc_xcoff_cons (int);
117218822Sdimstatic void ppc_vbyte (int);
11860484Sobrien#endif
11960484Sobrien
12060484Sobrien#ifdef OBJ_ELF
121218822Sdimstatic void ppc_elf_cons (int);
122218822Sdimstatic void ppc_elf_rdata (int);
123218822Sdimstatic void ppc_elf_lcomm (int);
12460484Sobrien#endif
12560484Sobrien
12660484Sobrien#ifdef TE_PE
127218822Sdimstatic void ppc_previous (int);
128218822Sdimstatic void ppc_pdata (int);
129218822Sdimstatic void ppc_ydata (int);
130218822Sdimstatic void ppc_reldata (int);
131218822Sdimstatic void ppc_rdata (int);
132218822Sdimstatic void ppc_ualong (int);
133218822Sdimstatic void ppc_znop (int);
134218822Sdimstatic void ppc_pe_comm (int);
135218822Sdimstatic void ppc_pe_section (int);
136218822Sdimstatic void ppc_pe_function (int);
137218822Sdimstatic void ppc_pe_tocd (int);
13860484Sobrien#endif
13960484Sobrien
14060484Sobrien/* Generic assembler global variables which must be defined by all
14160484Sobrien   targets.  */
14260484Sobrien
14360484Sobrien#ifdef OBJ_ELF
14460484Sobrien/* This string holds the chars that always start a comment.  If the
14560484Sobrien   pre-processor is disabled, these aren't very useful.  The macro
14660484Sobrien   tc_comment_chars points to this.  We use this, rather than the
14760484Sobrien   usual comment_chars, so that we can switch for Solaris conventions.  */
14860484Sobrienstatic const char ppc_solaris_comment_chars[] = "#!";
14960484Sobrienstatic const char ppc_eabi_comment_chars[] = "#";
15060484Sobrien
15160484Sobrien#ifdef TARGET_SOLARIS_COMMENT
15260484Sobrienconst char *ppc_comment_chars = ppc_solaris_comment_chars;
15360484Sobrien#else
15460484Sobrienconst char *ppc_comment_chars = ppc_eabi_comment_chars;
15560484Sobrien#endif
15660484Sobrien#else
15760484Sobrienconst char comment_chars[] = "#";
15860484Sobrien#endif
15960484Sobrien
16060484Sobrien/* Characters which start a comment at the beginning of a line.  */
16160484Sobrienconst char line_comment_chars[] = "#";
16260484Sobrien
16360484Sobrien/* Characters which may be used to separate multiple commands on a
16460484Sobrien   single line.  */
16560484Sobrienconst char line_separator_chars[] = ";";
16660484Sobrien
16760484Sobrien/* Characters which are used to indicate an exponent in a floating
16860484Sobrien   point number.  */
16960484Sobrienconst char EXP_CHARS[] = "eE";
17060484Sobrien
17160484Sobrien/* Characters which mean that a number is a floating point constant,
17260484Sobrien   as in 0d1.0.  */
17360484Sobrienconst char FLT_CHARS[] = "dD";
174130561Sobrien
175218822Sdim/* Anything that can start an operand needs to be mentioned here,
176218822Sdim   to stop the input scrubber eating whitespace.  */
177218822Sdimconst char ppc_symbol_chars[] = "%[";
178130561Sobrien
179130561Sobrien/* The dwarf2 data alignment, adjusted for 32 or 64 bit.  */
180130561Sobrienint ppc_cie_data_alignment;
18160484Sobrien
18260484Sobrien/* The target specific pseudo-ops which we support.  */
18360484Sobrien
18460484Sobrienconst pseudo_typeS md_pseudo_table[] =
18560484Sobrien{
18660484Sobrien  /* Pseudo-ops which must be overridden.  */
18760484Sobrien  { "byte",	ppc_byte,	0 },
18860484Sobrien
18960484Sobrien#ifdef OBJ_XCOFF
19060484Sobrien  /* Pseudo-ops specific to the RS/6000 XCOFF format.  Some of these
19160484Sobrien     legitimately belong in the obj-*.c file.  However, XCOFF is based
19260484Sobrien     on COFF, and is only implemented for the RS/6000.  We just use
19360484Sobrien     obj-coff.c, and add what we need here.  */
19460484Sobrien  { "comm",	ppc_comm,	0 },
19560484Sobrien  { "lcomm",	ppc_comm,	1 },
19660484Sobrien  { "bb",	ppc_bb,		0 },
19760484Sobrien  { "bc",	ppc_bc,		0 },
19860484Sobrien  { "bf",	ppc_bf,		0 },
19960484Sobrien  { "bi",	ppc_biei,	0 },
20060484Sobrien  { "bs",	ppc_bs,		0 },
20160484Sobrien  { "csect",	ppc_csect,	0 },
20260484Sobrien  { "data",	ppc_section,	'd' },
20360484Sobrien  { "eb",	ppc_eb,		0 },
20460484Sobrien  { "ec",	ppc_ec,		0 },
20560484Sobrien  { "ef",	ppc_ef,		0 },
20660484Sobrien  { "ei",	ppc_biei,	1 },
20760484Sobrien  { "es",	ppc_es,		0 },
20860484Sobrien  { "extern",	ppc_extern,	0 },
20960484Sobrien  { "function",	ppc_function,	0 },
21060484Sobrien  { "lglobl",	ppc_lglobl,	0 },
21160484Sobrien  { "rename",	ppc_rename,	0 },
21260484Sobrien  { "section",	ppc_named_section, 0 },
21360484Sobrien  { "stabx",	ppc_stabx,	0 },
21460484Sobrien  { "text",	ppc_section,	't' },
21560484Sobrien  { "toc",	ppc_toc,	0 },
21660484Sobrien  { "long",	ppc_xcoff_cons,	2 },
21777298Sobrien  { "llong",	ppc_xcoff_cons,	3 },
21860484Sobrien  { "word",	ppc_xcoff_cons,	1 },
21960484Sobrien  { "short",	ppc_xcoff_cons,	1 },
22060484Sobrien  { "vbyte",    ppc_vbyte,	0 },
22160484Sobrien#endif
22260484Sobrien
22360484Sobrien#ifdef OBJ_ELF
22489857Sobrien  { "llong",	ppc_elf_cons,	8 },
22589857Sobrien  { "quad",	ppc_elf_cons,	8 },
22660484Sobrien  { "long",	ppc_elf_cons,	4 },
22760484Sobrien  { "word",	ppc_elf_cons,	2 },
22860484Sobrien  { "short",	ppc_elf_cons,	2 },
22960484Sobrien  { "rdata",	ppc_elf_rdata,	0 },
23060484Sobrien  { "rodata",	ppc_elf_rdata,	0 },
23160484Sobrien  { "lcomm",	ppc_elf_lcomm,	0 },
23260484Sobrien#endif
23360484Sobrien
23460484Sobrien#ifdef TE_PE
23589857Sobrien  /* Pseudo-ops specific to the Windows NT PowerPC PE (coff) format.  */
23660484Sobrien  { "previous", ppc_previous,   0 },
23760484Sobrien  { "pdata",    ppc_pdata,      0 },
23860484Sobrien  { "ydata",    ppc_ydata,      0 },
23960484Sobrien  { "reldata",  ppc_reldata,    0 },
24060484Sobrien  { "rdata",    ppc_rdata,      0 },
24160484Sobrien  { "ualong",   ppc_ualong,     0 },
24260484Sobrien  { "znop",     ppc_znop,       0 },
24360484Sobrien  { "comm",	ppc_pe_comm,	0 },
24460484Sobrien  { "lcomm",	ppc_pe_comm,	1 },
24560484Sobrien  { "section",  ppc_pe_section, 0 },
24660484Sobrien  { "function",	ppc_pe_function,0 },
24760484Sobrien  { "tocd",     ppc_pe_tocd,    0 },
24860484Sobrien#endif
24960484Sobrien
25089857Sobrien#if defined (OBJ_XCOFF) || defined (OBJ_ELF)
25160484Sobrien  { "tc",	ppc_tc,		0 },
25289857Sobrien  { "machine",  ppc_machine,    0 },
25389857Sobrien#endif
25460484Sobrien
25560484Sobrien  { NULL,	NULL,		0 }
25660484Sobrien};
25760484Sobrien
25860484Sobrien
25989857Sobrien/* Predefined register names if -mregnames (or default for Windows NT).
26089857Sobrien   In general, there are lots of them, in an attempt to be compatible
26189857Sobrien   with a number of other Windows NT assemblers.  */
26260484Sobrien
26360484Sobrien/* Structure to hold information about predefined registers.  */
26460484Sobrienstruct pd_reg
26560484Sobrien  {
26660484Sobrien    char *name;
26760484Sobrien    int value;
26860484Sobrien  };
26960484Sobrien
27060484Sobrien/* List of registers that are pre-defined:
27160484Sobrien
27260484Sobrien   Each general register has predefined names of the form:
27360484Sobrien   1. r<reg_num> which has the value <reg_num>.
27460484Sobrien   2. r.<reg_num> which has the value <reg_num>.
27560484Sobrien
27660484Sobrien   Each floating point register has predefined names of the form:
27760484Sobrien   1. f<reg_num> which has the value <reg_num>.
27860484Sobrien   2. f.<reg_num> which has the value <reg_num>.
27960484Sobrien
28077298Sobrien   Each vector unit register has predefined names of the form:
28177298Sobrien   1. v<reg_num> which has the value <reg_num>.
28277298Sobrien   2. v.<reg_num> which has the value <reg_num>.
28377298Sobrien
28460484Sobrien   Each condition register has predefined names of the form:
28560484Sobrien   1. cr<reg_num> which has the value <reg_num>.
28660484Sobrien   2. cr.<reg_num> which has the value <reg_num>.
28760484Sobrien
28860484Sobrien   There are individual registers as well:
28960484Sobrien   sp or r.sp     has the value 1
29060484Sobrien   rtoc or r.toc  has the value 2
29160484Sobrien   fpscr          has the value 0
29260484Sobrien   xer            has the value 1
29360484Sobrien   lr             has the value 8
29460484Sobrien   ctr            has the value 9
29560484Sobrien   pmr            has the value 0
29660484Sobrien   dar            has the value 19
29760484Sobrien   dsisr          has the value 18
29860484Sobrien   dec            has the value 22
29960484Sobrien   sdr1           has the value 25
30060484Sobrien   srr0           has the value 26
30160484Sobrien   srr1           has the value 27
30260484Sobrien
30377298Sobrien   The table is sorted. Suitable for searching by a binary search.  */
30460484Sobrien
30560484Sobrienstatic const struct pd_reg pre_defined_registers[] =
30660484Sobrien{
30760484Sobrien  { "cr.0", 0 },    /* Condition Registers */
30860484Sobrien  { "cr.1", 1 },
30960484Sobrien  { "cr.2", 2 },
31060484Sobrien  { "cr.3", 3 },
31160484Sobrien  { "cr.4", 4 },
31260484Sobrien  { "cr.5", 5 },
31360484Sobrien  { "cr.6", 6 },
31460484Sobrien  { "cr.7", 7 },
31560484Sobrien
31660484Sobrien  { "cr0", 0 },
31760484Sobrien  { "cr1", 1 },
31860484Sobrien  { "cr2", 2 },
31960484Sobrien  { "cr3", 3 },
32060484Sobrien  { "cr4", 4 },
32160484Sobrien  { "cr5", 5 },
32260484Sobrien  { "cr6", 6 },
32360484Sobrien  { "cr7", 7 },
32460484Sobrien
32560484Sobrien  { "ctr", 9 },
32660484Sobrien
32760484Sobrien  { "dar", 19 },    /* Data Access Register */
32860484Sobrien  { "dec", 22 },    /* Decrementer */
32960484Sobrien  { "dsisr", 18 },  /* Data Storage Interrupt Status Register */
33060484Sobrien
33160484Sobrien  { "f.0", 0 },     /* Floating point registers */
33277298Sobrien  { "f.1", 1 },
33377298Sobrien  { "f.10", 10 },
33477298Sobrien  { "f.11", 11 },
33577298Sobrien  { "f.12", 12 },
33677298Sobrien  { "f.13", 13 },
33777298Sobrien  { "f.14", 14 },
33877298Sobrien  { "f.15", 15 },
33977298Sobrien  { "f.16", 16 },
34077298Sobrien  { "f.17", 17 },
34177298Sobrien  { "f.18", 18 },
34277298Sobrien  { "f.19", 19 },
34377298Sobrien  { "f.2", 2 },
34477298Sobrien  { "f.20", 20 },
34577298Sobrien  { "f.21", 21 },
34677298Sobrien  { "f.22", 22 },
34777298Sobrien  { "f.23", 23 },
34877298Sobrien  { "f.24", 24 },
34977298Sobrien  { "f.25", 25 },
35077298Sobrien  { "f.26", 26 },
35177298Sobrien  { "f.27", 27 },
35277298Sobrien  { "f.28", 28 },
35377298Sobrien  { "f.29", 29 },
35477298Sobrien  { "f.3", 3 },
35560484Sobrien  { "f.30", 30 },
35660484Sobrien  { "f.31", 31 },
35777298Sobrien  { "f.4", 4 },
35877298Sobrien  { "f.5", 5 },
35977298Sobrien  { "f.6", 6 },
36077298Sobrien  { "f.7", 7 },
36177298Sobrien  { "f.8", 8 },
36277298Sobrien  { "f.9", 9 },
36360484Sobrien
36477298Sobrien  { "f0", 0 },
36577298Sobrien  { "f1", 1 },
36677298Sobrien  { "f10", 10 },
36777298Sobrien  { "f11", 11 },
36877298Sobrien  { "f12", 12 },
36977298Sobrien  { "f13", 13 },
37077298Sobrien  { "f14", 14 },
37177298Sobrien  { "f15", 15 },
37277298Sobrien  { "f16", 16 },
37377298Sobrien  { "f17", 17 },
37477298Sobrien  { "f18", 18 },
37577298Sobrien  { "f19", 19 },
37677298Sobrien  { "f2", 2 },
37777298Sobrien  { "f20", 20 },
37877298Sobrien  { "f21", 21 },
37977298Sobrien  { "f22", 22 },
38077298Sobrien  { "f23", 23 },
38177298Sobrien  { "f24", 24 },
38277298Sobrien  { "f25", 25 },
38377298Sobrien  { "f26", 26 },
38477298Sobrien  { "f27", 27 },
38577298Sobrien  { "f28", 28 },
38677298Sobrien  { "f29", 29 },
38777298Sobrien  { "f3", 3 },
38860484Sobrien  { "f30", 30 },
38960484Sobrien  { "f31", 31 },
39077298Sobrien  { "f4", 4 },
39177298Sobrien  { "f5", 5 },
39277298Sobrien  { "f6", 6 },
39377298Sobrien  { "f7", 7 },
39477298Sobrien  { "f8", 8 },
39577298Sobrien  { "f9", 9 },
39660484Sobrien
39760484Sobrien  { "fpscr", 0 },
39860484Sobrien
39960484Sobrien  { "lr", 8 },     /* Link Register */
40060484Sobrien
40160484Sobrien  { "pmr", 0 },
40260484Sobrien
40360484Sobrien  { "r.0", 0 },    /* General Purpose Registers */
40460484Sobrien  { "r.1", 1 },
40560484Sobrien  { "r.10", 10 },
40660484Sobrien  { "r.11", 11 },
40760484Sobrien  { "r.12", 12 },
40860484Sobrien  { "r.13", 13 },
40960484Sobrien  { "r.14", 14 },
41060484Sobrien  { "r.15", 15 },
41160484Sobrien  { "r.16", 16 },
41260484Sobrien  { "r.17", 17 },
41360484Sobrien  { "r.18", 18 },
41460484Sobrien  { "r.19", 19 },
41560484Sobrien  { "r.2", 2 },
41660484Sobrien  { "r.20", 20 },
41760484Sobrien  { "r.21", 21 },
41860484Sobrien  { "r.22", 22 },
41960484Sobrien  { "r.23", 23 },
42060484Sobrien  { "r.24", 24 },
42160484Sobrien  { "r.25", 25 },
42260484Sobrien  { "r.26", 26 },
42360484Sobrien  { "r.27", 27 },
42460484Sobrien  { "r.28", 28 },
42560484Sobrien  { "r.29", 29 },
42660484Sobrien  { "r.3", 3 },
42760484Sobrien  { "r.30", 30 },
42860484Sobrien  { "r.31", 31 },
42960484Sobrien  { "r.4", 4 },
43060484Sobrien  { "r.5", 5 },
43160484Sobrien  { "r.6", 6 },
43260484Sobrien  { "r.7", 7 },
43360484Sobrien  { "r.8", 8 },
43460484Sobrien  { "r.9", 9 },
43560484Sobrien
43660484Sobrien  { "r.sp", 1 },   /* Stack Pointer */
43760484Sobrien
43860484Sobrien  { "r.toc", 2 },  /* Pointer to the table of contents */
43960484Sobrien
44060484Sobrien  { "r0", 0 },     /* More general purpose registers */
44160484Sobrien  { "r1", 1 },
44260484Sobrien  { "r10", 10 },
44360484Sobrien  { "r11", 11 },
44460484Sobrien  { "r12", 12 },
44560484Sobrien  { "r13", 13 },
44660484Sobrien  { "r14", 14 },
44760484Sobrien  { "r15", 15 },
44860484Sobrien  { "r16", 16 },
44960484Sobrien  { "r17", 17 },
45060484Sobrien  { "r18", 18 },
45160484Sobrien  { "r19", 19 },
45260484Sobrien  { "r2", 2 },
45360484Sobrien  { "r20", 20 },
45460484Sobrien  { "r21", 21 },
45560484Sobrien  { "r22", 22 },
45660484Sobrien  { "r23", 23 },
45760484Sobrien  { "r24", 24 },
45860484Sobrien  { "r25", 25 },
45960484Sobrien  { "r26", 26 },
46060484Sobrien  { "r27", 27 },
46160484Sobrien  { "r28", 28 },
46260484Sobrien  { "r29", 29 },
46360484Sobrien  { "r3", 3 },
46460484Sobrien  { "r30", 30 },
46560484Sobrien  { "r31", 31 },
46660484Sobrien  { "r4", 4 },
46760484Sobrien  { "r5", 5 },
46860484Sobrien  { "r6", 6 },
46960484Sobrien  { "r7", 7 },
47060484Sobrien  { "r8", 8 },
47160484Sobrien  { "r9", 9 },
47260484Sobrien
47360484Sobrien  { "rtoc", 2 },  /* Table of contents */
47460484Sobrien
47560484Sobrien  { "sdr1", 25 }, /* Storage Description Register 1 */
47660484Sobrien
47760484Sobrien  { "sp", 1 },
47860484Sobrien
47960484Sobrien  { "srr0", 26 }, /* Machine Status Save/Restore Register 0 */
48060484Sobrien  { "srr1", 27 }, /* Machine Status Save/Restore Register 1 */
48160484Sobrien
48277298Sobrien  { "v.0", 0 },     /* Vector registers */
48377298Sobrien  { "v.1", 1 },
48477298Sobrien  { "v.10", 10 },
48577298Sobrien  { "v.11", 11 },
48677298Sobrien  { "v.12", 12 },
48777298Sobrien  { "v.13", 13 },
48877298Sobrien  { "v.14", 14 },
48977298Sobrien  { "v.15", 15 },
49077298Sobrien  { "v.16", 16 },
49177298Sobrien  { "v.17", 17 },
49277298Sobrien  { "v.18", 18 },
49377298Sobrien  { "v.19", 19 },
49477298Sobrien  { "v.2", 2 },
49577298Sobrien  { "v.20", 20 },
49677298Sobrien  { "v.21", 21 },
49777298Sobrien  { "v.22", 22 },
49877298Sobrien  { "v.23", 23 },
49977298Sobrien  { "v.24", 24 },
50077298Sobrien  { "v.25", 25 },
50177298Sobrien  { "v.26", 26 },
50277298Sobrien  { "v.27", 27 },
50377298Sobrien  { "v.28", 28 },
50477298Sobrien  { "v.29", 29 },
50577298Sobrien  { "v.3", 3 },
50677298Sobrien  { "v.30", 30 },
50777298Sobrien  { "v.31", 31 },
50877298Sobrien  { "v.4", 4 },
50977298Sobrien  { "v.5", 5 },
51077298Sobrien  { "v.6", 6 },
51177298Sobrien  { "v.7", 7 },
51277298Sobrien  { "v.8", 8 },
51377298Sobrien  { "v.9", 9 },
51477298Sobrien
51577298Sobrien  { "v0", 0 },
51677298Sobrien  { "v1", 1 },
51777298Sobrien  { "v10", 10 },
51877298Sobrien  { "v11", 11 },
51977298Sobrien  { "v12", 12 },
52077298Sobrien  { "v13", 13 },
52177298Sobrien  { "v14", 14 },
52277298Sobrien  { "v15", 15 },
52377298Sobrien  { "v16", 16 },
52477298Sobrien  { "v17", 17 },
52577298Sobrien  { "v18", 18 },
52677298Sobrien  { "v19", 19 },
52777298Sobrien  { "v2", 2 },
52877298Sobrien  { "v20", 20 },
52977298Sobrien  { "v21", 21 },
53077298Sobrien  { "v22", 22 },
53177298Sobrien  { "v23", 23 },
53277298Sobrien  { "v24", 24 },
53377298Sobrien  { "v25", 25 },
53477298Sobrien  { "v26", 26 },
53577298Sobrien  { "v27", 27 },
53677298Sobrien  { "v28", 28 },
53777298Sobrien  { "v29", 29 },
53877298Sobrien  { "v3", 3 },
53977298Sobrien  { "v30", 30 },
54077298Sobrien  { "v31", 31 },
54177298Sobrien  { "v4", 4 },
54277298Sobrien  { "v5", 5 },
54377298Sobrien  { "v6", 6 },
54477298Sobrien  { "v7", 7 },
54577298Sobrien  { "v8", 8 },
54677298Sobrien  { "v9", 9 },
54777298Sobrien
54860484Sobrien  { "xer", 1 },
54960484Sobrien
55060484Sobrien};
55160484Sobrien
55277298Sobrien#define REG_NAME_CNT	(sizeof (pre_defined_registers) / sizeof (struct pd_reg))
55360484Sobrien
55460484Sobrien/* Given NAME, find the register number associated with that name, return
55560484Sobrien   the integer value associated with the given name or -1 on failure.  */
55660484Sobrien
55760484Sobrienstatic int
558218822Sdimreg_name_search (const struct pd_reg *regs, int regcount, const char *name)
55960484Sobrien{
56060484Sobrien  int middle, low, high;
56160484Sobrien  int cmp;
56260484Sobrien
56360484Sobrien  low = 0;
56460484Sobrien  high = regcount - 1;
56560484Sobrien
56660484Sobrien  do
56760484Sobrien    {
56860484Sobrien      middle = (low + high) / 2;
56960484Sobrien      cmp = strcasecmp (name, regs[middle].name);
57060484Sobrien      if (cmp < 0)
57160484Sobrien	high = middle - 1;
57260484Sobrien      else if (cmp > 0)
57360484Sobrien	low = middle + 1;
57460484Sobrien      else
57560484Sobrien	return regs[middle].value;
57660484Sobrien    }
57760484Sobrien  while (low <= high);
57860484Sobrien
57960484Sobrien  return -1;
58060484Sobrien}
58160484Sobrien
58260484Sobrien/*
58389857Sobrien * Summary of register_name.
58460484Sobrien *
58560484Sobrien * in:	Input_line_pointer points to 1st char of operand.
58660484Sobrien *
58760484Sobrien * out:	A expressionS.
58860484Sobrien *      The operand may have been a register: in this case, X_op == O_register,
58960484Sobrien *      X_add_number is set to the register number, and truth is returned.
59060484Sobrien *	Input_line_pointer->(next non-blank) char after operand, or is in its
59160484Sobrien *      original state.
59260484Sobrien */
59360484Sobrien
594130561Sobrienstatic bfd_boolean
595218822Sdimregister_name (expressionS *expressionP)
59660484Sobrien{
59760484Sobrien  int reg_number;
59860484Sobrien  char *name;
59960484Sobrien  char *start;
60060484Sobrien  char c;
60160484Sobrien
60289857Sobrien  /* Find the spelling of the operand.  */
60360484Sobrien  start = name = input_line_pointer;
60489857Sobrien  if (name[0] == '%' && ISALPHA (name[1]))
60560484Sobrien    name = ++input_line_pointer;
60660484Sobrien
60789857Sobrien  else if (!reg_names_p || !ISALPHA (name[0]))
608130561Sobrien    return FALSE;
60960484Sobrien
61060484Sobrien  c = get_symbol_end ();
61160484Sobrien  reg_number = reg_name_search (pre_defined_registers, REG_NAME_CNT, name);
61260484Sobrien
61389857Sobrien  /* Put back the delimiting char.  */
61489857Sobrien  *input_line_pointer = c;
61589857Sobrien
61689857Sobrien  /* Look to see if it's in the register table.  */
61777298Sobrien  if (reg_number >= 0)
61860484Sobrien    {
61960484Sobrien      expressionP->X_op = O_register;
62060484Sobrien      expressionP->X_add_number = reg_number;
62177298Sobrien
62289857Sobrien      /* Make the rest nice.  */
62360484Sobrien      expressionP->X_add_symbol = NULL;
62460484Sobrien      expressionP->X_op_symbol = NULL;
625130561Sobrien      return TRUE;
62660484Sobrien    }
62789857Sobrien
62889857Sobrien  /* Reset the line as if we had not done anything.  */
62989857Sobrien  input_line_pointer = start;
630130561Sobrien  return FALSE;
63160484Sobrien}
63260484Sobrien
63360484Sobrien/* This function is called for each symbol seen in an expression.  It
63460484Sobrien   handles the special parsing which PowerPC assemblers are supposed
63560484Sobrien   to use for condition codes.  */
63660484Sobrien
63760484Sobrien/* Whether to do the special parsing.  */
638130561Sobrienstatic bfd_boolean cr_operand;
63960484Sobrien
64060484Sobrien/* Names to recognize in a condition code.  This table is sorted.  */
64160484Sobrienstatic const struct pd_reg cr_names[] =
64260484Sobrien{
64360484Sobrien  { "cr0", 0 },
64460484Sobrien  { "cr1", 1 },
64560484Sobrien  { "cr2", 2 },
64660484Sobrien  { "cr3", 3 },
64760484Sobrien  { "cr4", 4 },
64860484Sobrien  { "cr5", 5 },
64960484Sobrien  { "cr6", 6 },
65060484Sobrien  { "cr7", 7 },
65160484Sobrien  { "eq", 2 },
65260484Sobrien  { "gt", 1 },
65360484Sobrien  { "lt", 0 },
65460484Sobrien  { "so", 3 },
65560484Sobrien  { "un", 3 }
65660484Sobrien};
65760484Sobrien
65860484Sobrien/* Parsing function.  This returns non-zero if it recognized an
65960484Sobrien   expression.  */
66060484Sobrien
66160484Sobrienint
662218822Sdimppc_parse_name (const char *name, expressionS *expr)
66360484Sobrien{
66460484Sobrien  int val;
66560484Sobrien
66660484Sobrien  if (! cr_operand)
66760484Sobrien    return 0;
66860484Sobrien
66960484Sobrien  val = reg_name_search (cr_names, sizeof cr_names / sizeof cr_names[0],
67060484Sobrien			 name);
67160484Sobrien  if (val < 0)
67260484Sobrien    return 0;
67360484Sobrien
67460484Sobrien  expr->X_op = O_constant;
67560484Sobrien  expr->X_add_number = val;
67660484Sobrien
67760484Sobrien  return 1;
67860484Sobrien}
67960484Sobrien
68060484Sobrien/* Local variables.  */
68160484Sobrien
68260484Sobrien/* The type of processor we are assembling for.  This is one or more
68360484Sobrien   of the PPC_OPCODE flags defined in opcode/ppc.h.  */
684261422Sjhibbitsstatic unsigned long ppc_cpu = PPC_OPCODE_ANY;
68560484Sobrien
686104834Sobrien/* Whether to target xcoff64/elf64.  */
687104834Sobrienstatic unsigned int ppc_obj64 = BFD_DEFAULT_TARGET_SIZE == 64;
68860484Sobrien
68960484Sobrien/* Opcode hash table.  */
69060484Sobrienstatic struct hash_control *ppc_hash;
69160484Sobrien
69260484Sobrien/* Macro hash table.  */
69360484Sobrienstatic struct hash_control *ppc_macro_hash;
69460484Sobrien
69560484Sobrien#ifdef OBJ_ELF
69689857Sobrien/* What type of shared library support to use.  */
69777298Sobrienstatic enum { SHLIB_NONE, SHLIB_PIC, SHLIB_MRELOCATABLE } shlib = SHLIB_NONE;
69860484Sobrien
69989857Sobrien/* Flags to set in the elf header.  */
70060484Sobrienstatic flagword ppc_flags = 0;
70160484Sobrien
70260484Sobrien/* Whether this is Solaris or not.  */
70360484Sobrien#ifdef TARGET_SOLARIS_COMMENT
704130561Sobrien#define SOLARIS_P TRUE
70560484Sobrien#else
706130561Sobrien#define SOLARIS_P FALSE
70760484Sobrien#endif
70860484Sobrien
709130561Sobrienstatic bfd_boolean msolaris = SOLARIS_P;
71060484Sobrien#endif
71160484Sobrien
71260484Sobrien#ifdef OBJ_XCOFF
71360484Sobrien
71460484Sobrien/* The RS/6000 assembler uses the .csect pseudo-op to generate code
71560484Sobrien   using a bunch of different sections.  These assembler sections,
71660484Sobrien   however, are all encompassed within the .text or .data sections of
71760484Sobrien   the final output file.  We handle this by using different
71860484Sobrien   subsegments within these main segments.  */
71960484Sobrien
72060484Sobrien/* Next subsegment to allocate within the .text segment.  */
72160484Sobrienstatic subsegT ppc_text_subsegment = 2;
72260484Sobrien
72360484Sobrien/* Linked list of csects in the text section.  */
72460484Sobrienstatic symbolS *ppc_text_csects;
72560484Sobrien
72660484Sobrien/* Next subsegment to allocate within the .data segment.  */
72760484Sobrienstatic subsegT ppc_data_subsegment = 2;
72860484Sobrien
72960484Sobrien/* Linked list of csects in the data section.  */
73060484Sobrienstatic symbolS *ppc_data_csects;
73160484Sobrien
73260484Sobrien/* The current csect.  */
73360484Sobrienstatic symbolS *ppc_current_csect;
73460484Sobrien
73560484Sobrien/* The RS/6000 assembler uses a TOC which holds addresses of functions
73660484Sobrien   and variables.  Symbols are put in the TOC with the .tc pseudo-op.
73760484Sobrien   A special relocation is used when accessing TOC entries.  We handle
73860484Sobrien   the TOC as a subsegment within the .data segment.  We set it up if
73960484Sobrien   we see a .toc pseudo-op, and save the csect symbol here.  */
74060484Sobrienstatic symbolS *ppc_toc_csect;
74160484Sobrien
74260484Sobrien/* The first frag in the TOC subsegment.  */
74360484Sobrienstatic fragS *ppc_toc_frag;
74460484Sobrien
74560484Sobrien/* The first frag in the first subsegment after the TOC in the .data
74660484Sobrien   segment.  NULL if there are no subsegments after the TOC.  */
74760484Sobrienstatic fragS *ppc_after_toc_frag;
74860484Sobrien
74960484Sobrien/* The current static block.  */
75060484Sobrienstatic symbolS *ppc_current_block;
75160484Sobrien
75260484Sobrien/* The COFF debugging section; set by md_begin.  This is not the
75360484Sobrien   .debug section, but is instead the secret BFD section which will
75460484Sobrien   cause BFD to set the section number of a symbol to N_DEBUG.  */
75560484Sobrienstatic asection *ppc_coff_debug_section;
75660484Sobrien
75760484Sobrien#endif /* OBJ_XCOFF */
75860484Sobrien
75960484Sobrien#ifdef TE_PE
76060484Sobrien
76160484Sobrien/* Various sections that we need for PE coff support.  */
76260484Sobrienstatic segT ydata_section;
76360484Sobrienstatic segT pdata_section;
76460484Sobrienstatic segT reldata_section;
76560484Sobrienstatic segT rdata_section;
76660484Sobrienstatic segT tocdata_section;
76760484Sobrien
76877298Sobrien/* The current section and the previous section. See ppc_previous.  */
76960484Sobrienstatic segT ppc_previous_section;
77060484Sobrienstatic segT ppc_current_section;
77160484Sobrien
77260484Sobrien#endif /* TE_PE */
77360484Sobrien
77460484Sobrien#ifdef OBJ_ELF
77560484SobriensymbolS *GOT_symbol;		/* Pre-defined "_GLOBAL_OFFSET_TABLE" */
776130561Sobrien#define PPC_APUINFO_ISEL	0x40
777130561Sobrien#define PPC_APUINFO_PMR		0x41
778130561Sobrien#define PPC_APUINFO_RFMCI	0x42
779130561Sobrien#define PPC_APUINFO_CACHELCK	0x43
780130561Sobrien#define PPC_APUINFO_SPE		0x100
781130561Sobrien#define PPC_APUINFO_EFS		0x101
782130561Sobrien#define PPC_APUINFO_BRLOCK	0x102
783130561Sobrien
784130561Sobrien/*
785130561Sobrien * We keep a list of APUinfo
786130561Sobrien */
787130561Sobrienunsigned long *ppc_apuinfo_list;
788130561Sobrienunsigned int ppc_apuinfo_num;
789130561Sobrienunsigned int ppc_apuinfo_num_alloc;
79060484Sobrien#endif /* OBJ_ELF */
79160484Sobrien
79260484Sobrien#ifdef OBJ_ELF
79389857Sobrienconst char *const md_shortopts = "b:l:usm:K:VQ:";
79460484Sobrien#else
79589857Sobrienconst char *const md_shortopts = "um:";
79660484Sobrien#endif
79789857Sobrienconst struct option md_longopts[] = {
79860484Sobrien  {NULL, no_argument, NULL, 0}
79960484Sobrien};
80089857Sobrienconst size_t md_longopts_size = sizeof (md_longopts);
80160484Sobrien
802130561Sobrien
803130561Sobrien/* Handle -m options that set cpu type, and .machine arg.  */
804130561Sobrien
805130561Sobrienstatic int
806130561Sobrienparse_cpu (const char *arg)
807130561Sobrien{
808130561Sobrien  /* -mpwrx and -mpwr2 mean to assemble for the IBM POWER/2
809130561Sobrien     (RIOS2).  */
810130561Sobrien  if (strcmp (arg, "pwrx") == 0 || strcmp (arg, "pwr2") == 0)
811130561Sobrien    ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_POWER2 | PPC_OPCODE_32;
812130561Sobrien  /* -mpwr means to assemble for the IBM POWER (RIOS1).  */
813130561Sobrien  else if (strcmp (arg, "pwr") == 0)
814130561Sobrien    ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_32;
815130561Sobrien  /* -m601 means to assemble for the PowerPC 601, which includes
816130561Sobrien     instructions that are holdovers from the Power.  */
817130561Sobrien  else if (strcmp (arg, "601") == 0)
818130561Sobrien    ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
819130561Sobrien	       | PPC_OPCODE_601 | PPC_OPCODE_32);
820130561Sobrien  /* -mppc, -mppc32, -m603, and -m604 mean to assemble for the
821130561Sobrien     PowerPC 603/604.  */
822130561Sobrien  else if (strcmp (arg, "ppc") == 0
823130561Sobrien	   || strcmp (arg, "ppc32") == 0
824130561Sobrien	   || strcmp (arg, "603") == 0
825130561Sobrien	   || strcmp (arg, "604") == 0)
826130561Sobrien    ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32;
827130561Sobrien  /* -m403 and -m405 mean to assemble for the PowerPC 403/405.  */
828130561Sobrien  else if (strcmp (arg, "403") == 0
829130561Sobrien	   || strcmp (arg, "405") == 0)
830130561Sobrien    ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
831130561Sobrien	       | PPC_OPCODE_403 | PPC_OPCODE_32);
832130561Sobrien  else if (strcmp (arg, "440") == 0)
833130561Sobrien    ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_32
834130561Sobrien	       | PPC_OPCODE_440 | PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI);
835130561Sobrien  else if (strcmp (arg, "7400") == 0
836130561Sobrien	   || strcmp (arg, "7410") == 0
837130561Sobrien	   || strcmp (arg, "7450") == 0
838130561Sobrien	   || strcmp (arg, "7455") == 0)
839130561Sobrien    ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
840130561Sobrien	       | PPC_OPCODE_ALTIVEC | PPC_OPCODE_32);
841218822Sdim  else if (strcmp (arg, "e300") == 0)
842218822Sdim    ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32
843218822Sdim	       | PPC_OPCODE_E300);
844130561Sobrien  else if (strcmp (arg, "altivec") == 0)
845130561Sobrien    {
846130561Sobrien      if (ppc_cpu == 0)
847130561Sobrien	ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_ALTIVEC;
848130561Sobrien      else
849130561Sobrien	ppc_cpu |= PPC_OPCODE_ALTIVEC;
850130561Sobrien    }
851130561Sobrien  else if (strcmp (arg, "e500") == 0 || strcmp (arg, "e500x2") == 0)
852130561Sobrien    {
853130561Sobrien      ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_SPE
854130561Sobrien		 | PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
855130561Sobrien		 | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK
856130561Sobrien		 | PPC_OPCODE_RFMCI);
857130561Sobrien    }
858130561Sobrien  else if (strcmp (arg, "spe") == 0)
859130561Sobrien    {
860130561Sobrien      if (ppc_cpu == 0)
861130561Sobrien	ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_SPE | PPC_OPCODE_EFS;
862130561Sobrien      else
863130561Sobrien	ppc_cpu |= PPC_OPCODE_SPE;
864130561Sobrien    }
865130561Sobrien  /* -mppc64 and -m620 mean to assemble for the 64-bit PowerPC
866130561Sobrien     620.  */
867130561Sobrien  else if (strcmp (arg, "ppc64") == 0 || strcmp (arg, "620") == 0)
868130561Sobrien    {
869130561Sobrien      ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64;
870130561Sobrien    }
871130561Sobrien  else if (strcmp (arg, "ppc64bridge") == 0)
872130561Sobrien    {
873130561Sobrien      ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
874130561Sobrien		 | PPC_OPCODE_64_BRIDGE | PPC_OPCODE_64);
875130561Sobrien    }
876130561Sobrien  /* -mbooke/-mbooke32 mean enable 32-bit BookE support.  */
877130561Sobrien  else if (strcmp (arg, "booke") == 0 || strcmp (arg, "booke32") == 0)
878130561Sobrien    {
879130561Sobrien      ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_32;
880130561Sobrien    }
881130561Sobrien  /* -mbooke64 means enable 64-bit BookE support.  */
882130561Sobrien  else if (strcmp (arg, "booke64") == 0)
883130561Sobrien    {
884130561Sobrien      ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE
885130561Sobrien		 | PPC_OPCODE_BOOKE64 | PPC_OPCODE_64);
886130561Sobrien    }
887130561Sobrien  else if (strcmp (arg, "power4") == 0)
888130561Sobrien    {
889130561Sobrien      ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
890130561Sobrien		 | PPC_OPCODE_64 | PPC_OPCODE_POWER4);
891130561Sobrien    }
892218822Sdim  else if (strcmp (arg, "power5") == 0)
893218822Sdim    {
894218822Sdim      ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
895218822Sdim		 | PPC_OPCODE_64 | PPC_OPCODE_POWER4
896218822Sdim		 | PPC_OPCODE_POWER5);
897218822Sdim    }
898218822Sdim  else if (strcmp (arg, "power6") == 0)
899218822Sdim    {
900218822Sdim      ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
901218822Sdim		 | PPC_OPCODE_64 | PPC_OPCODE_POWER4
902218822Sdim		 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6);
903218822Sdim    }
904218822Sdim  else if (strcmp (arg, "cell") == 0)
905218822Sdim    {
906218822Sdim      ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
907218822Sdim		 | PPC_OPCODE_64 | PPC_OPCODE_POWER4
908218822Sdim		 | PPC_OPCODE_CELL);
909218822Sdim    }
910130561Sobrien  /* -mcom means assemble for the common intersection between Power
911130561Sobrien     and PowerPC.  At present, we just allow the union, rather
912130561Sobrien     than the intersection.  */
913130561Sobrien  else if (strcmp (arg, "com") == 0)
914130561Sobrien    ppc_cpu = PPC_OPCODE_COMMON | PPC_OPCODE_32;
915130561Sobrien  /* -many means to assemble for any architecture (PWR/PWRX/PPC).  */
916130561Sobrien  else if (strcmp (arg, "any") == 0)
917130561Sobrien    ppc_cpu |= PPC_OPCODE_ANY;
918130561Sobrien  else
919130561Sobrien    return 0;
920130561Sobrien
921130561Sobrien  return 1;
922130561Sobrien}
923130561Sobrien
92460484Sobrienint
925218822Sdimmd_parse_option (int c, char *arg)
92660484Sobrien{
92760484Sobrien  switch (c)
92860484Sobrien    {
92960484Sobrien    case 'u':
93060484Sobrien      /* -u means that any undefined symbols should be treated as
93160484Sobrien	 external, which is the default for gas anyhow.  */
93260484Sobrien      break;
93360484Sobrien
93460484Sobrien#ifdef OBJ_ELF
93560484Sobrien    case 'l':
93660484Sobrien      /* Solaris as takes -le (presumably for little endian).  For completeness
93789857Sobrien	 sake, recognize -be also.  */
93860484Sobrien      if (strcmp (arg, "e") == 0)
93960484Sobrien	{
94060484Sobrien	  target_big_endian = 0;
94160484Sobrien	  set_target_endian = 1;
94260484Sobrien	}
94360484Sobrien      else
94460484Sobrien	return 0;
94560484Sobrien
94660484Sobrien      break;
94760484Sobrien
94860484Sobrien    case 'b':
94960484Sobrien      if (strcmp (arg, "e") == 0)
95060484Sobrien	{
95160484Sobrien	  target_big_endian = 1;
95260484Sobrien	  set_target_endian = 1;
95360484Sobrien	}
95460484Sobrien      else
95560484Sobrien	return 0;
95660484Sobrien
95760484Sobrien      break;
95860484Sobrien
95960484Sobrien    case 'K':
96089857Sobrien      /* Recognize -K PIC.  */
96160484Sobrien      if (strcmp (arg, "PIC") == 0 || strcmp (arg, "pic") == 0)
96260484Sobrien	{
96360484Sobrien	  shlib = SHLIB_PIC;
96460484Sobrien	  ppc_flags |= EF_PPC_RELOCATABLE_LIB;
96560484Sobrien	}
96660484Sobrien      else
96760484Sobrien	return 0;
96860484Sobrien
96960484Sobrien      break;
97060484Sobrien#endif
97160484Sobrien
97277298Sobrien      /* a64 and a32 determine whether to use XCOFF64 or XCOFF32.  */
97377298Sobrien    case 'a':
97477298Sobrien      if (strcmp (arg, "64") == 0)
975107492Sobrien	{
976107492Sobrien#ifdef BFD64
977107492Sobrien	  ppc_obj64 = 1;
978107492Sobrien#else
979107492Sobrien	  as_fatal (_("%s unsupported"), "-a64");
980107492Sobrien#endif
981107492Sobrien	}
98277298Sobrien      else if (strcmp (arg, "32") == 0)
983104834Sobrien	ppc_obj64 = 0;
98477298Sobrien      else
98577298Sobrien	return 0;
98677298Sobrien      break;
98777298Sobrien
98860484Sobrien    case 'm':
989130561Sobrien      if (parse_cpu (arg))
990130561Sobrien	;
99160484Sobrien
99260484Sobrien      else if (strcmp (arg, "regnames") == 0)
993130561Sobrien	reg_names_p = TRUE;
99460484Sobrien
99560484Sobrien      else if (strcmp (arg, "no-regnames") == 0)
996130561Sobrien	reg_names_p = FALSE;
99760484Sobrien
99860484Sobrien#ifdef OBJ_ELF
99989857Sobrien      /* -mrelocatable/-mrelocatable-lib -- warn about initializations
100089857Sobrien	 that require relocation.  */
100160484Sobrien      else if (strcmp (arg, "relocatable") == 0)
100260484Sobrien	{
100377298Sobrien	  shlib = SHLIB_MRELOCATABLE;
100460484Sobrien	  ppc_flags |= EF_PPC_RELOCATABLE;
100560484Sobrien	}
100660484Sobrien
100760484Sobrien      else if (strcmp (arg, "relocatable-lib") == 0)
100860484Sobrien	{
100977298Sobrien	  shlib = SHLIB_MRELOCATABLE;
101060484Sobrien	  ppc_flags |= EF_PPC_RELOCATABLE_LIB;
101160484Sobrien	}
101260484Sobrien
101389857Sobrien      /* -memb, set embedded bit.  */
101460484Sobrien      else if (strcmp (arg, "emb") == 0)
101560484Sobrien	ppc_flags |= EF_PPC_EMB;
101660484Sobrien
101789857Sobrien      /* -mlittle/-mbig set the endianess.  */
101889857Sobrien      else if (strcmp (arg, "little") == 0
101989857Sobrien	       || strcmp (arg, "little-endian") == 0)
102060484Sobrien	{
102160484Sobrien	  target_big_endian = 0;
102260484Sobrien	  set_target_endian = 1;
102360484Sobrien	}
102460484Sobrien
102560484Sobrien      else if (strcmp (arg, "big") == 0 || strcmp (arg, "big-endian") == 0)
102660484Sobrien	{
102760484Sobrien	  target_big_endian = 1;
102860484Sobrien	  set_target_endian = 1;
102960484Sobrien	}
103060484Sobrien
103160484Sobrien      else if (strcmp (arg, "solaris") == 0)
103260484Sobrien	{
1033130561Sobrien	  msolaris = TRUE;
103460484Sobrien	  ppc_comment_chars = ppc_solaris_comment_chars;
103560484Sobrien	}
103660484Sobrien
103760484Sobrien      else if (strcmp (arg, "no-solaris") == 0)
103860484Sobrien	{
1039130561Sobrien	  msolaris = FALSE;
104060484Sobrien	  ppc_comment_chars = ppc_eabi_comment_chars;
104160484Sobrien	}
104260484Sobrien#endif
104360484Sobrien      else
104460484Sobrien	{
104560484Sobrien	  as_bad (_("invalid switch -m%s"), arg);
104660484Sobrien	  return 0;
104760484Sobrien	}
104860484Sobrien      break;
104960484Sobrien
105060484Sobrien#ifdef OBJ_ELF
105160484Sobrien      /* -V: SVR4 argument to print version ID.  */
105260484Sobrien    case 'V':
105360484Sobrien      print_version_id ();
105460484Sobrien      break;
105560484Sobrien
105660484Sobrien      /* -Qy, -Qn: SVR4 arguments controlling whether a .comment section
105760484Sobrien	 should be emitted or not.  FIXME: Not implemented.  */
105860484Sobrien    case 'Q':
105960484Sobrien      break;
106060484Sobrien
106160484Sobrien      /* Solaris takes -s to specify that .stabs go in a .stabs section,
106260484Sobrien	 rather than .stabs.excl, which is ignored by the linker.
106360484Sobrien	 FIXME: Not implemented.  */
106460484Sobrien    case 's':
106560484Sobrien      if (arg)
106660484Sobrien	return 0;
106760484Sobrien
106860484Sobrien      break;
106960484Sobrien#endif
107060484Sobrien
107160484Sobrien    default:
107260484Sobrien      return 0;
107360484Sobrien    }
107460484Sobrien
107560484Sobrien  return 1;
107660484Sobrien}
107760484Sobrien
107860484Sobrienvoid
1079218822Sdimmd_show_usage (FILE *stream)
108060484Sobrien{
108177298Sobrien  fprintf (stream, _("\
108260484SobrienPowerPC options:\n\
1083130561Sobrien-a32			generate ELF32/XCOFF32\n\
1084130561Sobrien-a64			generate ELF64/XCOFF64\n\
108560484Sobrien-u			ignored\n\
108692828Sobrien-mpwrx, -mpwr2		generate code for POWER/2 (RIOS2)\n\
108792828Sobrien-mpwr			generate code for POWER (RIOS1)\n\
108892828Sobrien-m601			generate code for PowerPC 601\n\
108989857Sobrien-mppc, -mppc32, -m603, -m604\n\
109092828Sobrien			generate code for PowerPC 603/604\n\
1091130561Sobrien-m403, -m405		generate code for PowerPC 403/405\n\
1092130561Sobrien-m440			generate code for PowerPC 440\n\
109389857Sobrien-m7400, -m7410, -m7450, -m7455\n\
1094130561Sobrien			generate code For PowerPC 7400/7410/7450/7455\n"));
1095130561Sobrien  fprintf (stream, _("\
109692828Sobrien-mppc64, -m620		generate code for PowerPC 620/625/630\n\
109760484Sobrien-mppc64bridge		generate code for PowerPC 64, including bridge insns\n\
109889857Sobrien-mbooke64		generate code for 64-bit PowerPC BookE\n\
109989857Sobrien-mbooke, mbooke32	generate code for 32-bit PowerPC BookE\n\
110092828Sobrien-mpower4		generate code for Power4 architecture\n\
1101218822Sdim-mpower5		generate code for Power5 architecture\n\
1102218822Sdim-mpower6		generate code for Power6 architecture\n\
1103218822Sdim-mcell			generate code for Cell Broadband Engine architecture\n\
1104130561Sobrien-mcom			generate code Power/PowerPC common instructions\n\
1105130561Sobrien-many			generate code for any architecture (PWR/PWRX/PPC)\n"));
1106130561Sobrien  fprintf (stream, _("\
110789857Sobrien-maltivec		generate code for AltiVec\n\
1108218822Sdim-me300			generate code for PowerPC e300 family\n\
1109130561Sobrien-me500, -me500x2	generate code for Motorola e500 core complex\n\
1110130561Sobrien-mspe			generate code for Motorola SPE instructions\n\
111160484Sobrien-mregnames		Allow symbolic names for registers\n\
111260484Sobrien-mno-regnames		Do not allow symbolic names for registers\n"));
111360484Sobrien#ifdef OBJ_ELF
111477298Sobrien  fprintf (stream, _("\
111560484Sobrien-mrelocatable		support for GCC's -mrelocatble option\n\
111660484Sobrien-mrelocatable-lib	support for GCC's -mrelocatble-lib option\n\
111760484Sobrien-memb			set PPC_EMB bit in ELF flags\n\
1118130561Sobrien-mlittle, -mlittle-endian, -l, -le\n\
111960484Sobrien			generate code for a little endian machine\n\
1120130561Sobrien-mbig, -mbig-endian, -b, -be\n\
1121130561Sobrien			generate code for a big endian machine\n\
112260484Sobrien-msolaris		generate code for Solaris\n\
112360484Sobrien-mno-solaris		do not generate code for Solaris\n\
112460484Sobrien-V			print assembler version number\n\
112560484Sobrien-Qy, -Qn		ignored\n"));
112660484Sobrien#endif
112760484Sobrien}
112860484Sobrien
112960484Sobrien/* Set ppc_cpu if it is not already set.  */
113060484Sobrien
113160484Sobrienstatic void
1132218822Sdimppc_set_cpu (void)
113360484Sobrien{
113460484Sobrien  const char *default_os  = TARGET_OS;
113560484Sobrien  const char *default_cpu = TARGET_CPU;
113660484Sobrien
1137130561Sobrien  if ((ppc_cpu & ~PPC_OPCODE_ANY) == 0)
113860484Sobrien    {
1139107492Sobrien      if (ppc_obj64)
1140130561Sobrien	ppc_cpu |= PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64;
1141107492Sobrien      else if (strncmp (default_os, "aix", 3) == 0
1142107492Sobrien	       && default_os[3] >= '4' && default_os[3] <= '9')
1143130561Sobrien	ppc_cpu |= PPC_OPCODE_COMMON | PPC_OPCODE_32;
114460484Sobrien      else if (strncmp (default_os, "aix3", 4) == 0)
1145130561Sobrien	ppc_cpu |= PPC_OPCODE_POWER | PPC_OPCODE_32;
114660484Sobrien      else if (strcmp (default_cpu, "rs6000") == 0)
1147130561Sobrien	ppc_cpu |= PPC_OPCODE_POWER | PPC_OPCODE_32;
114889857Sobrien      else if (strncmp (default_cpu, "powerpc", 7) == 0)
1149218822Sdim	ppc_cpu |= PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32;
115060484Sobrien      else
115189857Sobrien	as_fatal (_("Unknown default cpu = %s, os = %s"),
115289857Sobrien		  default_cpu, default_os);
115360484Sobrien    }
115460484Sobrien}
115560484Sobrien
1156218822Sdim/* Figure out the BFD architecture to use.  This function and ppc_mach
1157218822Sdim   are called well before md_begin, when the output file is opened.  */
115860484Sobrien
115960484Sobrienenum bfd_architecture
1160218822Sdimppc_arch (void)
116160484Sobrien{
116260484Sobrien  const char *default_cpu = TARGET_CPU;
116360484Sobrien  ppc_set_cpu ();
116460484Sobrien
116560484Sobrien  if ((ppc_cpu & PPC_OPCODE_PPC) != 0)
116660484Sobrien    return bfd_arch_powerpc;
116760484Sobrien  else if ((ppc_cpu & PPC_OPCODE_POWER) != 0)
116860484Sobrien    return bfd_arch_rs6000;
116960484Sobrien  else if ((ppc_cpu & (PPC_OPCODE_COMMON | PPC_OPCODE_ANY)) != 0)
117060484Sobrien    {
117160484Sobrien      if (strcmp (default_cpu, "rs6000") == 0)
117260484Sobrien	return bfd_arch_rs6000;
117389857Sobrien      else if (strncmp (default_cpu, "powerpc", 7) == 0)
117460484Sobrien	return bfd_arch_powerpc;
117560484Sobrien    }
117660484Sobrien
117760484Sobrien  as_fatal (_("Neither Power nor PowerPC opcodes were selected."));
117860484Sobrien  return bfd_arch_unknown;
117960484Sobrien}
118060484Sobrien
118177298Sobrienunsigned long
1182218822Sdimppc_mach (void)
118377298Sobrien{
1184107492Sobrien  if (ppc_obj64)
1185107492Sobrien    return bfd_mach_ppc64;
1186107492Sobrien  else if (ppc_arch () == bfd_arch_rs6000)
1187107492Sobrien    return bfd_mach_rs6k;
1188107492Sobrien  else
1189107492Sobrien    return bfd_mach_ppc;
119077298Sobrien}
119177298Sobrien
119277298Sobrienextern char*
1193218822Sdimppc_target_format (void)
119477298Sobrien{
119577298Sobrien#ifdef OBJ_COFF
119677298Sobrien#ifdef TE_PE
119789857Sobrien  return target_big_endian ? "pe-powerpc" : "pe-powerpcle";
119877298Sobrien#elif TE_POWERMAC
119989857Sobrien  return "xcoff-powermac";
120077298Sobrien#else
1201104834Sobrien#  ifdef TE_AIX5
1202104834Sobrien    return (ppc_obj64 ? "aix5coff64-rs6000" : "aixcoff-rs6000");
1203104834Sobrien#  else
1204104834Sobrien    return (ppc_obj64 ? "aixcoff64-rs6000" : "aixcoff-rs6000");
1205104834Sobrien#  endif
120677298Sobrien#endif
120777298Sobrien#endif
120877298Sobrien#ifdef OBJ_ELF
1209218822Sdim# ifdef TE_VXWORKS
1210218822Sdim  return "elf32-powerpc-vxworks";
1211218822Sdim# else
121289857Sobrien  return (target_big_endian
1213272888Sbapt	  ? (ppc_obj64 ? "elf64-powerpc-freebsd" : "elf32-powerpc-freebsd")
1214104834Sobrien	  : (ppc_obj64 ? "elf64-powerpcle" : "elf32-powerpcle"));
1215218822Sdim# endif
121677298Sobrien#endif
121777298Sobrien}
121877298Sobrien
1219130561Sobrien/* Insert opcodes and macros into hash tables.  Called at startup and
1220130561Sobrien   for .cpu pseudo.  */
122160484Sobrien
1222130561Sobrienstatic void
1223130561Sobrienppc_setup_opcodes (void)
122460484Sobrien{
1225218822Sdim  const struct powerpc_opcode *op;
122660484Sobrien  const struct powerpc_opcode *op_end;
122760484Sobrien  const struct powerpc_macro *macro;
122860484Sobrien  const struct powerpc_macro *macro_end;
1229218822Sdim  bfd_boolean bad_insn = FALSE;
123060484Sobrien
1231130561Sobrien  if (ppc_hash != NULL)
1232130561Sobrien    hash_die (ppc_hash);
1233130561Sobrien  if (ppc_macro_hash != NULL)
1234130561Sobrien    hash_die (ppc_macro_hash);
123560484Sobrien
123660484Sobrien  /* Insert the opcodes into a hash table.  */
123760484Sobrien  ppc_hash = hash_new ();
123860484Sobrien
1239218822Sdim  if (ENABLE_CHECKING)
1240218822Sdim    {
1241218822Sdim      unsigned int i;
1242218822Sdim
1243218822Sdim      /* Check operand masks.  Code here and in the disassembler assumes
1244218822Sdim	 all the 1's in the mask are contiguous.  */
1245218822Sdim      for (i = 0; i < num_powerpc_operands; ++i)
1246218822Sdim	{
1247218822Sdim	  unsigned long mask = powerpc_operands[i].bitm;
1248218822Sdim	  unsigned long right_bit;
1249218822Sdim	  unsigned int j;
1250218822Sdim
1251218822Sdim	  right_bit = mask & -mask;
1252218822Sdim	  mask += right_bit;
1253218822Sdim	  right_bit = mask & -mask;
1254218822Sdim	  if (mask != right_bit)
1255218822Sdim	    {
1256218822Sdim	      as_bad (_("powerpc_operands[%d].bitm invalid"), i);
1257218822Sdim	      bad_insn = TRUE;
1258218822Sdim	    }
1259218822Sdim	  for (j = i + 1; j < num_powerpc_operands; ++j)
1260218822Sdim	    if (memcmp (&powerpc_operands[i], &powerpc_operands[j],
1261218822Sdim			sizeof (powerpc_operands[0])) == 0)
1262218822Sdim	      {
1263218822Sdim		as_bad (_("powerpc_operands[%d] duplicates powerpc_operands[%d]"),
1264218822Sdim			j, i);
1265218822Sdim		bad_insn = TRUE;
1266218822Sdim	      }
1267218822Sdim	}
1268218822Sdim    }
1269218822Sdim
127060484Sobrien  op_end = powerpc_opcodes + powerpc_num_opcodes;
127160484Sobrien  for (op = powerpc_opcodes; op < op_end; op++)
127260484Sobrien    {
1273218822Sdim      if (ENABLE_CHECKING)
1274218822Sdim	{
1275218822Sdim	  const unsigned char *o;
1276218822Sdim	  unsigned long omask = op->mask;
127760484Sobrien
1278218822Sdim	  /* The mask had better not trim off opcode bits.  */
1279218822Sdim	  if ((op->opcode & omask) != op->opcode)
1280218822Sdim	    {
1281218822Sdim	      as_bad (_("mask trims opcode bits for %s"),
1282218822Sdim		      op->name);
1283218822Sdim	      bad_insn = TRUE;
1284218822Sdim	    }
1285218822Sdim
1286218822Sdim	  /* The operands must not overlap the opcode or each other.  */
1287218822Sdim	  for (o = op->operands; *o; ++o)
1288218822Sdim	    if (*o >= num_powerpc_operands)
1289218822Sdim	      {
1290218822Sdim		as_bad (_("operand index error for %s"),
1291218822Sdim			op->name);
1292218822Sdim		bad_insn = TRUE;
1293218822Sdim	      }
1294218822Sdim	    else
1295218822Sdim	      {
1296218822Sdim		const struct powerpc_operand *operand = &powerpc_operands[*o];
1297218822Sdim		if (operand->shift >= 0)
1298218822Sdim		  {
1299218822Sdim		    unsigned long mask = operand->bitm << operand->shift;
1300218822Sdim		    if (omask & mask)
1301218822Sdim		      {
1302218822Sdim			as_bad (_("operand %d overlap in %s"),
1303218822Sdim				(int) (o - op->operands), op->name);
1304218822Sdim			bad_insn = TRUE;
1305218822Sdim		      }
1306218822Sdim		    omask |= mask;
1307218822Sdim		  }
1308218822Sdim	      }
1309218822Sdim	}
1310218822Sdim
1311104834Sobrien      if ((op->flags & ppc_cpu & ~(PPC_OPCODE_32 | PPC_OPCODE_64)) != 0
131260484Sobrien	  && ((op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64)) == 0
1313104834Sobrien	      || ((op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64))
1314104834Sobrien		  == (ppc_cpu & (PPC_OPCODE_32 | PPC_OPCODE_64)))
131592828Sobrien	      || (ppc_cpu & PPC_OPCODE_64_BRIDGE) != 0)
1316104834Sobrien	  /* Certain instructions (eg: extsw) do not exist in the
1317104834Sobrien	     32-bit BookE instruction set, but they do exist in the
1318104834Sobrien	     64-bit BookE instruction set, and other PPC instruction
1319104834Sobrien	     sets.  Check to see if the opcode has the BOOKE64 flag set.
1320104834Sobrien	     If it does make sure that the target CPU is not the BookE32.  */
1321104834Sobrien	  && ((op->flags & PPC_OPCODE_BOOKE64) == 0
1322104834Sobrien	      || (ppc_cpu & PPC_OPCODE_BOOKE64) == PPC_OPCODE_BOOKE64
1323104834Sobrien	      || (ppc_cpu & PPC_OPCODE_BOOKE) == 0)
132492828Sobrien	  && ((op->flags & (PPC_OPCODE_POWER4 | PPC_OPCODE_NOPOWER4)) == 0
132592828Sobrien	      || ((op->flags & PPC_OPCODE_POWER4)
1326218822Sdim		  == (ppc_cpu & PPC_OPCODE_POWER4)))
1327218822Sdim	  && ((op->flags & PPC_OPCODE_POWER5) == 0
1328218822Sdim	      || ((op->flags & PPC_OPCODE_POWER5)
1329218822Sdim		  == (ppc_cpu & PPC_OPCODE_POWER5)))
1330218822Sdim	  && ((op->flags & PPC_OPCODE_POWER6) == 0
1331218822Sdim	      || ((op->flags & PPC_OPCODE_POWER6)
1332218822Sdim		  == (ppc_cpu & PPC_OPCODE_POWER6))))
133360484Sobrien	{
133460484Sobrien	  const char *retval;
133560484Sobrien
1336218822Sdim	  retval = hash_insert (ppc_hash, op->name, (void *) op);
1337130561Sobrien	  if (retval != NULL)
133860484Sobrien	    {
133989857Sobrien	      /* Ignore Power duplicates for -m601.  */
134060484Sobrien	      if ((ppc_cpu & PPC_OPCODE_601) != 0
134160484Sobrien		  && (op->flags & PPC_OPCODE_POWER) != 0)
134260484Sobrien		continue;
134360484Sobrien
1344218822Sdim	      as_bad (_("duplicate instruction %s"),
134589857Sobrien		      op->name);
1346218822Sdim	      bad_insn = TRUE;
134760484Sobrien	    }
134860484Sobrien	}
134960484Sobrien    }
135060484Sobrien
1351130561Sobrien  if ((ppc_cpu & PPC_OPCODE_ANY) != 0)
1352130561Sobrien    for (op = powerpc_opcodes; op < op_end; op++)
1353218822Sdim      hash_insert (ppc_hash, op->name, (void *) op);
1354130561Sobrien
135560484Sobrien  /* Insert the macros into a hash table.  */
135660484Sobrien  ppc_macro_hash = hash_new ();
135760484Sobrien
135860484Sobrien  macro_end = powerpc_macros + powerpc_num_macros;
135960484Sobrien  for (macro = powerpc_macros; macro < macro_end; macro++)
136060484Sobrien    {
136160484Sobrien      if ((macro->flags & ppc_cpu) != 0)
136260484Sobrien	{
136360484Sobrien	  const char *retval;
136460484Sobrien
1365218822Sdim	  retval = hash_insert (ppc_macro_hash, macro->name, (void *) macro);
136660484Sobrien	  if (retval != (const char *) NULL)
136760484Sobrien	    {
1368218822Sdim	      as_bad (_("duplicate macro %s"), macro->name);
1369218822Sdim	      bad_insn = TRUE;
137060484Sobrien	    }
137160484Sobrien	}
137260484Sobrien    }
137360484Sobrien
1374218822Sdim  if (bad_insn)
137560484Sobrien    abort ();
1376130561Sobrien}
137760484Sobrien
1378130561Sobrien/* This function is called when the assembler starts up.  It is called
1379130561Sobrien   after the options have been parsed and the output file has been
1380130561Sobrien   opened.  */
1381130561Sobrien
1382130561Sobrienvoid
1383218822Sdimmd_begin (void)
1384130561Sobrien{
1385130561Sobrien  ppc_set_cpu ();
1386130561Sobrien
1387130561Sobrien  ppc_cie_data_alignment = ppc_obj64 ? -8 : -4;
1388130561Sobrien
1389130561Sobrien#ifdef OBJ_ELF
1390130561Sobrien  /* Set the ELF flags if desired.  */
1391130561Sobrien  if (ppc_flags && !msolaris)
1392130561Sobrien    bfd_set_private_flags (stdoutput, ppc_flags);
1393130561Sobrien#endif
1394130561Sobrien
1395130561Sobrien  ppc_setup_opcodes ();
1396130561Sobrien
1397130561Sobrien  /* Tell the main code what the endianness is if it is not overridden
139889857Sobrien     by the user.  */
139960484Sobrien  if (!set_target_endian)
140060484Sobrien    {
140160484Sobrien      set_target_endian = 1;
140260484Sobrien      target_big_endian = PPC_BIG_ENDIAN;
140360484Sobrien    }
140460484Sobrien
140560484Sobrien#ifdef OBJ_XCOFF
140660484Sobrien  ppc_coff_debug_section = coff_section_from_bfd_index (stdoutput, N_DEBUG);
140760484Sobrien
140860484Sobrien  /* Create dummy symbols to serve as initial csects.  This forces the
140960484Sobrien     text csects to precede the data csects.  These symbols will not
141060484Sobrien     be output.  */
141160484Sobrien  ppc_text_csects = symbol_make ("dummy\001");
141260484Sobrien  symbol_get_tc (ppc_text_csects)->within = ppc_text_csects;
141360484Sobrien  ppc_data_csects = symbol_make ("dummy\001");
141460484Sobrien  symbol_get_tc (ppc_data_csects)->within = ppc_data_csects;
141560484Sobrien#endif
141660484Sobrien
141760484Sobrien#ifdef TE_PE
141860484Sobrien
141960484Sobrien  ppc_current_section = text_section;
142077298Sobrien  ppc_previous_section = 0;
142160484Sobrien
142260484Sobrien#endif
142360484Sobrien}
142460484Sobrien
1425130561Sobrienvoid
1426218822Sdimppc_cleanup (void)
1427130561Sobrien{
1428130561Sobrien#ifdef OBJ_ELF
1429130561Sobrien  if (ppc_apuinfo_list == NULL)
1430130561Sobrien    return;
1431130561Sobrien
1432130561Sobrien  /* Ok, so write the section info out.  We have this layout:
1433130561Sobrien
1434130561Sobrien  byte	data		what
1435130561Sobrien  ----	----		----
1436130561Sobrien  0	8		length of "APUinfo\0"
1437130561Sobrien  4	(n*4)		number of APU's (4 bytes each)
1438130561Sobrien  8	2		note type 2
1439130561Sobrien  12	"APUinfo\0"	name
1440130561Sobrien  20	APU#1		first APU's info
1441130561Sobrien  24	APU#2		second APU's info
1442130561Sobrien  ...	...
1443130561Sobrien  */
1444130561Sobrien  {
1445130561Sobrien    char *p;
1446130561Sobrien    asection *seg = now_seg;
1447130561Sobrien    subsegT subseg = now_subseg;
1448130561Sobrien    asection *apuinfo_secp = (asection *) NULL;
1449130561Sobrien    unsigned int i;
1450130561Sobrien
1451130561Sobrien    /* Create the .PPC.EMB.apuinfo section.  */
1452130561Sobrien    apuinfo_secp = subseg_new (".PPC.EMB.apuinfo", 0);
1453130561Sobrien    bfd_set_section_flags (stdoutput,
1454130561Sobrien			   apuinfo_secp,
1455130561Sobrien			   SEC_HAS_CONTENTS | SEC_READONLY);
1456130561Sobrien
1457130561Sobrien    p = frag_more (4);
1458130561Sobrien    md_number_to_chars (p, (valueT) 8, 4);
1459130561Sobrien
1460130561Sobrien    p = frag_more (4);
1461130561Sobrien    md_number_to_chars (p, (valueT) ppc_apuinfo_num * 4, 4);
1462130561Sobrien
1463130561Sobrien    p = frag_more (4);
1464130561Sobrien    md_number_to_chars (p, (valueT) 2, 4);
1465130561Sobrien
1466130561Sobrien    p = frag_more (8);
1467130561Sobrien    strcpy (p, "APUinfo");
1468130561Sobrien
1469130561Sobrien    for (i = 0; i < ppc_apuinfo_num; i++)
1470130561Sobrien      {
1471130561Sobrien	p = frag_more (4);
1472130561Sobrien	md_number_to_chars (p, (valueT) ppc_apuinfo_list[i], 4);
1473130561Sobrien      }
1474130561Sobrien
1475130561Sobrien    frag_align (2, 0, 0);
1476130561Sobrien
1477130561Sobrien    /* We probably can't restore the current segment, for there likely
1478130561Sobrien       isn't one yet...  */
1479130561Sobrien    if (seg && subseg)
1480130561Sobrien      subseg_set (seg, subseg);
1481130561Sobrien  }
1482130561Sobrien#endif
1483130561Sobrien}
1484130561Sobrien
148560484Sobrien/* Insert an operand value into an instruction.  */
148660484Sobrien
148760484Sobrienstatic unsigned long
1488218822Sdimppc_insert_operand (unsigned long insn,
1489218822Sdim		    const struct powerpc_operand *operand,
1490218822Sdim		    offsetT val,
1491218822Sdim		    char *file,
1492218822Sdim		    unsigned int line)
149360484Sobrien{
1494218822Sdim  long min, max, right;
1495218822Sdim
1496218822Sdim  max = operand->bitm;
1497218822Sdim  right = max & -max;
1498218822Sdim  min = 0;
1499218822Sdim
1500218822Sdim  if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
150160484Sobrien    {
1502218822Sdim      if ((operand->flags & PPC_OPERAND_SIGNOPT) == 0)
1503218822Sdim	max = (max >> 1) & -right;
1504218822Sdim      min = ~max & -right;
1505218822Sdim    }
150660484Sobrien
1507218822Sdim  if ((operand->flags & PPC_OPERAND_PLUS1) != 0)
1508218822Sdim    max++;
150960484Sobrien
1510218822Sdim  if ((operand->flags & PPC_OPERAND_NEGATIVE) != 0)
1511218822Sdim    {
1512218822Sdim      long tmp = min;
1513218822Sdim      min = -max;
1514218822Sdim      max = -tmp;
1515218822Sdim    }
151660484Sobrien
1517218822Sdim  if (min <= max)
1518218822Sdim    {
1519218822Sdim      /* Some people write constants with the sign extension done by
1520218822Sdim	 hand but only up to 32 bits.  This shouldn't really be valid,
1521218822Sdim	 but, to permit this code to assemble on a 64-bit host, we
1522218822Sdim	 sign extend the 32-bit value to 64 bits if so doing makes the
1523218822Sdim	 value valid.  */
1524218822Sdim      if (val > max
1525218822Sdim	  && (offsetT) (val - 0x80000000 - 0x80000000) >= min
1526218822Sdim	  && (offsetT) (val - 0x80000000 - 0x80000000) <= max
1527218822Sdim	  && ((val - 0x80000000 - 0x80000000) & (right - 1)) == 0)
1528218822Sdim	val = val - 0x80000000 - 0x80000000;
152960484Sobrien
1530218822Sdim      /* Similarly, people write expressions like ~(1<<15), and expect
1531218822Sdim	 this to be OK for a 32-bit unsigned value.  */
1532218822Sdim      else if (val < min
1533218822Sdim	       && (offsetT) (val + 0x80000000 + 0x80000000) >= min
1534218822Sdim	       && (offsetT) (val + 0x80000000 + 0x80000000) <= max
1535218822Sdim	       && ((val + 0x80000000 + 0x80000000) & (right - 1)) == 0)
1536218822Sdim	val = val + 0x80000000 + 0x80000000;
153760484Sobrien
1538218822Sdim      else if (val < min
1539218822Sdim	       || val > max
1540218822Sdim	       || (val & (right - 1)) != 0)
1541218822Sdim	as_bad_value_out_of_range (_("operand"), val, min, max, file, line);
154260484Sobrien    }
154360484Sobrien
154460484Sobrien  if (operand->insert)
154560484Sobrien    {
154660484Sobrien      const char *errmsg;
154760484Sobrien
154860484Sobrien      errmsg = NULL;
1549104834Sobrien      insn = (*operand->insert) (insn, (long) val, ppc_cpu, &errmsg);
155060484Sobrien      if (errmsg != (const char *) NULL)
1551276346Sdim	as_bad_where (file, line, "%s", errmsg);
155260484Sobrien    }
155360484Sobrien  else
1554218822Sdim    insn |= ((long) val & operand->bitm) << operand->shift;
155560484Sobrien
155660484Sobrien  return insn;
155760484Sobrien}
155860484Sobrien
155960484Sobrien
156060484Sobrien#ifdef OBJ_ELF
156160484Sobrien/* Parse @got, etc. and return the desired relocation.  */
156260484Sobrienstatic bfd_reloc_code_real_type
1563218822Sdimppc_elf_suffix (char **str_p, expressionS *exp_p)
156460484Sobrien{
156560484Sobrien  struct map_bfd {
156660484Sobrien    char *string;
1567130561Sobrien    unsigned int length : 8;
1568130561Sobrien    unsigned int valid32 : 1;
1569130561Sobrien    unsigned int valid64 : 1;
1570130561Sobrien    unsigned int reloc;
157160484Sobrien  };
157260484Sobrien
157360484Sobrien  char ident[20];
157460484Sobrien  char *str = *str_p;
157560484Sobrien  char *str2;
157660484Sobrien  int ch;
157760484Sobrien  int len;
157889857Sobrien  const struct map_bfd *ptr;
157960484Sobrien
1580130561Sobrien#define MAP(str, reloc)   { str, sizeof (str) - 1, 1, 1, reloc }
1581130561Sobrien#define MAP32(str, reloc) { str, sizeof (str) - 1, 1, 0, reloc }
1582130561Sobrien#define MAP64(str, reloc) { str, sizeof (str) - 1, 0, 1, reloc }
158360484Sobrien
158489857Sobrien  static const struct map_bfd mapping[] = {
1585130561Sobrien    MAP ("l",			BFD_RELOC_LO16),
1586130561Sobrien    MAP ("h",			BFD_RELOC_HI16),
1587130561Sobrien    MAP ("ha",			BFD_RELOC_HI16_S),
1588130561Sobrien    MAP ("brtaken",		BFD_RELOC_PPC_B16_BRTAKEN),
1589130561Sobrien    MAP ("brntaken",		BFD_RELOC_PPC_B16_BRNTAKEN),
1590130561Sobrien    MAP ("got",			BFD_RELOC_16_GOTOFF),
1591130561Sobrien    MAP ("got@l",		BFD_RELOC_LO16_GOTOFF),
1592130561Sobrien    MAP ("got@h",		BFD_RELOC_HI16_GOTOFF),
1593130561Sobrien    MAP ("got@ha",		BFD_RELOC_HI16_S_GOTOFF),
1594130561Sobrien    MAP ("plt@l",		BFD_RELOC_LO16_PLTOFF),
1595130561Sobrien    MAP ("plt@h",		BFD_RELOC_HI16_PLTOFF),
1596130561Sobrien    MAP ("plt@ha",		BFD_RELOC_HI16_S_PLTOFF),
1597130561Sobrien    MAP ("copy",		BFD_RELOC_PPC_COPY),
1598130561Sobrien    MAP ("globdat",		BFD_RELOC_PPC_GLOB_DAT),
1599130561Sobrien    MAP ("sectoff",		BFD_RELOC_16_BASEREL),
1600130561Sobrien    MAP ("sectoff@l",		BFD_RELOC_LO16_BASEREL),
1601130561Sobrien    MAP ("sectoff@h",		BFD_RELOC_HI16_BASEREL),
1602130561Sobrien    MAP ("sectoff@ha",		BFD_RELOC_HI16_S_BASEREL),
1603130561Sobrien    MAP ("tls",			BFD_RELOC_PPC_TLS),
1604130561Sobrien    MAP ("dtpmod",		BFD_RELOC_PPC_DTPMOD),
1605130561Sobrien    MAP ("dtprel",		BFD_RELOC_PPC_DTPREL),
1606130561Sobrien    MAP ("dtprel@l",		BFD_RELOC_PPC_DTPREL16_LO),
1607130561Sobrien    MAP ("dtprel@h",		BFD_RELOC_PPC_DTPREL16_HI),
1608130561Sobrien    MAP ("dtprel@ha",		BFD_RELOC_PPC_DTPREL16_HA),
1609130561Sobrien    MAP ("tprel",		BFD_RELOC_PPC_TPREL),
1610130561Sobrien    MAP ("tprel@l",		BFD_RELOC_PPC_TPREL16_LO),
1611130561Sobrien    MAP ("tprel@h",		BFD_RELOC_PPC_TPREL16_HI),
1612130561Sobrien    MAP ("tprel@ha",		BFD_RELOC_PPC_TPREL16_HA),
1613130561Sobrien    MAP ("got@tlsgd",		BFD_RELOC_PPC_GOT_TLSGD16),
1614130561Sobrien    MAP ("got@tlsgd@l",		BFD_RELOC_PPC_GOT_TLSGD16_LO),
1615130561Sobrien    MAP ("got@tlsgd@h",		BFD_RELOC_PPC_GOT_TLSGD16_HI),
1616130561Sobrien    MAP ("got@tlsgd@ha",	BFD_RELOC_PPC_GOT_TLSGD16_HA),
1617130561Sobrien    MAP ("got@tlsld",		BFD_RELOC_PPC_GOT_TLSLD16),
1618130561Sobrien    MAP ("got@tlsld@l",		BFD_RELOC_PPC_GOT_TLSLD16_LO),
1619130561Sobrien    MAP ("got@tlsld@h",		BFD_RELOC_PPC_GOT_TLSLD16_HI),
1620130561Sobrien    MAP ("got@tlsld@ha",	BFD_RELOC_PPC_GOT_TLSLD16_HA),
1621130561Sobrien    MAP ("got@dtprel",		BFD_RELOC_PPC_GOT_DTPREL16),
1622130561Sobrien    MAP ("got@dtprel@l",	BFD_RELOC_PPC_GOT_DTPREL16_LO),
1623130561Sobrien    MAP ("got@dtprel@h",	BFD_RELOC_PPC_GOT_DTPREL16_HI),
1624130561Sobrien    MAP ("got@dtprel@ha",	BFD_RELOC_PPC_GOT_DTPREL16_HA),
1625130561Sobrien    MAP ("got@tprel",		BFD_RELOC_PPC_GOT_TPREL16),
1626130561Sobrien    MAP ("got@tprel@l",		BFD_RELOC_PPC_GOT_TPREL16_LO),
1627130561Sobrien    MAP ("got@tprel@h",		BFD_RELOC_PPC_GOT_TPREL16_HI),
1628130561Sobrien    MAP ("got@tprel@ha",	BFD_RELOC_PPC_GOT_TPREL16_HA),
1629130561Sobrien    MAP32 ("fixup",		BFD_RELOC_CTOR),
1630130561Sobrien    MAP32 ("plt",		BFD_RELOC_24_PLT_PCREL),
1631130561Sobrien    MAP32 ("pltrel24",		BFD_RELOC_24_PLT_PCREL),
1632130561Sobrien    MAP32 ("local24pc",		BFD_RELOC_PPC_LOCAL24PC),
1633130561Sobrien    MAP32 ("local",		BFD_RELOC_PPC_LOCAL24PC),
1634130561Sobrien    MAP32 ("pltrel",		BFD_RELOC_32_PLT_PCREL),
1635130561Sobrien    MAP32 ("sdarel",		BFD_RELOC_GPREL16),
1636130561Sobrien    MAP32 ("naddr",		BFD_RELOC_PPC_EMB_NADDR32),
1637130561Sobrien    MAP32 ("naddr16",		BFD_RELOC_PPC_EMB_NADDR16),
1638130561Sobrien    MAP32 ("naddr@l",		BFD_RELOC_PPC_EMB_NADDR16_LO),
1639130561Sobrien    MAP32 ("naddr@h",		BFD_RELOC_PPC_EMB_NADDR16_HI),
1640130561Sobrien    MAP32 ("naddr@ha",		BFD_RELOC_PPC_EMB_NADDR16_HA),
1641130561Sobrien    MAP32 ("sdai16",		BFD_RELOC_PPC_EMB_SDAI16),
1642130561Sobrien    MAP32 ("sda2rel",		BFD_RELOC_PPC_EMB_SDA2REL),
1643130561Sobrien    MAP32 ("sda2i16",		BFD_RELOC_PPC_EMB_SDA2I16),
1644130561Sobrien    MAP32 ("sda21",		BFD_RELOC_PPC_EMB_SDA21),
1645130561Sobrien    MAP32 ("mrkref",		BFD_RELOC_PPC_EMB_MRKREF),
1646130561Sobrien    MAP32 ("relsect",		BFD_RELOC_PPC_EMB_RELSEC16),
1647130561Sobrien    MAP32 ("relsect@l",		BFD_RELOC_PPC_EMB_RELST_LO),
1648130561Sobrien    MAP32 ("relsect@h",		BFD_RELOC_PPC_EMB_RELST_HI),
1649130561Sobrien    MAP32 ("relsect@ha",	BFD_RELOC_PPC_EMB_RELST_HA),
1650130561Sobrien    MAP32 ("bitfld",		BFD_RELOC_PPC_EMB_BIT_FLD),
1651130561Sobrien    MAP32 ("relsda",		BFD_RELOC_PPC_EMB_RELSDA),
1652130561Sobrien    MAP32 ("xgot",		BFD_RELOC_PPC_TOC16),
1653130561Sobrien    MAP64 ("higher",		BFD_RELOC_PPC64_HIGHER),
1654130561Sobrien    MAP64 ("highera",		BFD_RELOC_PPC64_HIGHER_S),
1655130561Sobrien    MAP64 ("highest",		BFD_RELOC_PPC64_HIGHEST),
1656130561Sobrien    MAP64 ("highesta",		BFD_RELOC_PPC64_HIGHEST_S),
1657130561Sobrien    MAP64 ("tocbase",		BFD_RELOC_PPC64_TOC),
1658130561Sobrien    MAP64 ("toc",		BFD_RELOC_PPC_TOC16),
1659130561Sobrien    MAP64 ("toc@l",		BFD_RELOC_PPC64_TOC16_LO),
1660130561Sobrien    MAP64 ("toc@h",		BFD_RELOC_PPC64_TOC16_HI),
1661130561Sobrien    MAP64 ("toc@ha",		BFD_RELOC_PPC64_TOC16_HA),
1662130561Sobrien    MAP64 ("dtprel@higher",	BFD_RELOC_PPC64_DTPREL16_HIGHER),
1663130561Sobrien    MAP64 ("dtprel@highera",	BFD_RELOC_PPC64_DTPREL16_HIGHERA),
1664130561Sobrien    MAP64 ("dtprel@highest",	BFD_RELOC_PPC64_DTPREL16_HIGHEST),
1665130561Sobrien    MAP64 ("dtprel@highesta",	BFD_RELOC_PPC64_DTPREL16_HIGHESTA),
1666130561Sobrien    MAP64 ("tprel@higher",	BFD_RELOC_PPC64_TPREL16_HIGHER),
1667130561Sobrien    MAP64 ("tprel@highera",	BFD_RELOC_PPC64_TPREL16_HIGHERA),
1668130561Sobrien    MAP64 ("tprel@highest",	BFD_RELOC_PPC64_TPREL16_HIGHEST),
1669130561Sobrien    MAP64 ("tprel@highesta",	BFD_RELOC_PPC64_TPREL16_HIGHESTA),
1670130561Sobrien    { (char *) 0, 0, 0, 0,	BFD_RELOC_UNUSED }
167160484Sobrien  };
167260484Sobrien
167360484Sobrien  if (*str++ != '@')
167460484Sobrien    return BFD_RELOC_UNUSED;
167560484Sobrien
167660484Sobrien  for (ch = *str, str2 = ident;
167760484Sobrien       (str2 < ident + sizeof (ident) - 1
167889857Sobrien	&& (ISALNUM (ch) || ch == '@'));
167960484Sobrien       ch = *++str)
168060484Sobrien    {
168189857Sobrien      *str2++ = TOLOWER (ch);
168260484Sobrien    }
168360484Sobrien
168460484Sobrien  *str2 = '\0';
168560484Sobrien  len = str2 - ident;
168660484Sobrien
168760484Sobrien  ch = ident[0];
168860484Sobrien  for (ptr = &mapping[0]; ptr->length > 0; ptr++)
168960484Sobrien    if (ch == ptr->string[0]
169060484Sobrien	&& len == ptr->length
1691130561Sobrien	&& memcmp (ident, ptr->string, ptr->length) == 0
1692130561Sobrien	&& (ppc_obj64 ? ptr->valid64 : ptr->valid32))
169360484Sobrien      {
169489857Sobrien	int reloc = ptr->reloc;
169589857Sobrien
1696130561Sobrien	if (!ppc_obj64)
1697130561Sobrien	  if (exp_p->X_add_number != 0
1698130561Sobrien	      && (reloc == (int) BFD_RELOC_16_GOTOFF
1699130561Sobrien		  || reloc == (int) BFD_RELOC_LO16_GOTOFF
1700130561Sobrien		  || reloc == (int) BFD_RELOC_HI16_GOTOFF
1701130561Sobrien		  || reloc == (int) BFD_RELOC_HI16_S_GOTOFF))
1702130561Sobrien	    as_warn (_("identifier+constant@got means identifier@got+constant"));
170389857Sobrien
170489857Sobrien	/* Now check for identifier@suffix+constant.  */
170560484Sobrien	if (*str == '-' || *str == '+')
170660484Sobrien	  {
170760484Sobrien	    char *orig_line = input_line_pointer;
170860484Sobrien	    expressionS new_exp;
170960484Sobrien
171060484Sobrien	    input_line_pointer = str;
171160484Sobrien	    expression (&new_exp);
171260484Sobrien	    if (new_exp.X_op == O_constant)
171360484Sobrien	      {
171460484Sobrien		exp_p->X_add_number += new_exp.X_add_number;
171560484Sobrien		str = input_line_pointer;
171660484Sobrien	      }
171760484Sobrien
171860484Sobrien	    if (&input_line_pointer != str_p)
171960484Sobrien	      input_line_pointer = orig_line;
172060484Sobrien	  }
172189857Sobrien	*str_p = str;
172260484Sobrien
1723104834Sobrien	if (reloc == (int) BFD_RELOC_PPC64_TOC
1724130561Sobrien	    && exp_p->X_op == O_symbol
1725130561Sobrien	    && strcmp (S_GET_NAME (exp_p->X_add_symbol), ".TOC.") == 0)
172689857Sobrien	  {
1727130561Sobrien	    /* Change the symbol so that the dummy .TOC. symbol can be
1728130561Sobrien	       omitted from the object file.  */
172989857Sobrien	    exp_p->X_add_symbol = &abs_symbol;
173089857Sobrien	  }
173189857Sobrien
173289857Sobrien	return (bfd_reloc_code_real_type) reloc;
173360484Sobrien      }
173460484Sobrien
173560484Sobrien  return BFD_RELOC_UNUSED;
173660484Sobrien}
173760484Sobrien
173889857Sobrien/* Like normal .long/.short/.word, except support @got, etc.
173989857Sobrien   Clobbers input_line_pointer, checks end-of-line.  */
174060484Sobrienstatic void
1741218822Sdimppc_elf_cons (int nbytes /* 1=.byte, 2=.word, 4=.long, 8=.llong */)
174260484Sobrien{
174360484Sobrien  expressionS exp;
174460484Sobrien  bfd_reloc_code_real_type reloc;
174560484Sobrien
174660484Sobrien  if (is_it_end_of_statement ())
174760484Sobrien    {
174860484Sobrien      demand_empty_rest_of_line ();
174960484Sobrien      return;
175060484Sobrien    }
175160484Sobrien
175260484Sobrien  do
175360484Sobrien    {
175460484Sobrien      expression (&exp);
175560484Sobrien      if (exp.X_op == O_symbol
175660484Sobrien	  && *input_line_pointer == '@'
175789857Sobrien	  && (reloc = ppc_elf_suffix (&input_line_pointer,
175889857Sobrien				      &exp)) != BFD_RELOC_UNUSED)
175960484Sobrien	{
176089857Sobrien	  reloc_howto_type *reloc_howto;
176189857Sobrien	  int size;
176260484Sobrien
176389857Sobrien	  reloc_howto = bfd_reloc_type_lookup (stdoutput, reloc);
176489857Sobrien	  size = bfd_get_reloc_size (reloc_howto);
176589857Sobrien
176660484Sobrien	  if (size > nbytes)
176789857Sobrien	    {
176889857Sobrien	      as_bad (_("%s relocations do not fit in %d bytes\n"),
176989857Sobrien		      reloc_howto->name, nbytes);
177089857Sobrien	    }
177160484Sobrien	  else
177260484Sobrien	    {
177389857Sobrien	      char *p;
177489857Sobrien	      int offset;
177560484Sobrien
177689857Sobrien	      p = frag_more (nbytes);
177789857Sobrien	      offset = 0;
177889857Sobrien	      if (target_big_endian)
177989857Sobrien		offset = nbytes - size;
178089857Sobrien	      fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size,
178189857Sobrien			   &exp, 0, reloc);
178260484Sobrien	    }
178360484Sobrien	}
178460484Sobrien      else
178560484Sobrien	emit_expr (&exp, (unsigned int) nbytes);
178660484Sobrien    }
178760484Sobrien  while (*input_line_pointer++ == ',');
178860484Sobrien
178989857Sobrien  /* Put terminator back into stream.  */
179089857Sobrien  input_line_pointer--;
179160484Sobrien  demand_empty_rest_of_line ();
179260484Sobrien}
179360484Sobrien
179460484Sobrien/* Solaris pseduo op to change to the .rodata section.  */
179560484Sobrienstatic void
1796218822Sdimppc_elf_rdata (int xxx)
179760484Sobrien{
179860484Sobrien  char *save_line = input_line_pointer;
179960484Sobrien  static char section[] = ".rodata\n";
180060484Sobrien
180189857Sobrien  /* Just pretend this is .section .rodata  */
180260484Sobrien  input_line_pointer = section;
180360484Sobrien  obj_elf_section (xxx);
180460484Sobrien
180560484Sobrien  input_line_pointer = save_line;
180660484Sobrien}
180760484Sobrien
180889857Sobrien/* Pseudo op to make file scope bss items.  */
180960484Sobrienstatic void
1810218822Sdimppc_elf_lcomm (int xxx ATTRIBUTE_UNUSED)
181160484Sobrien{
1812218822Sdim  char *name;
1813218822Sdim  char c;
1814218822Sdim  char *p;
181560484Sobrien  offsetT size;
1816218822Sdim  symbolS *symbolP;
181760484Sobrien  offsetT align;
181860484Sobrien  segT old_sec;
181960484Sobrien  int old_subsec;
182060484Sobrien  char *pfrag;
182160484Sobrien  int align2;
182260484Sobrien
182360484Sobrien  name = input_line_pointer;
182460484Sobrien  c = get_symbol_end ();
182560484Sobrien
182689857Sobrien  /* just after name is now '\0'.  */
182760484Sobrien  p = input_line_pointer;
182860484Sobrien  *p = c;
182960484Sobrien  SKIP_WHITESPACE ();
183060484Sobrien  if (*input_line_pointer != ',')
183160484Sobrien    {
183260484Sobrien      as_bad (_("Expected comma after symbol-name: rest of line ignored."));
183360484Sobrien      ignore_rest_of_line ();
183460484Sobrien      return;
183560484Sobrien    }
183660484Sobrien
183760484Sobrien  input_line_pointer++;		/* skip ',' */
183860484Sobrien  if ((size = get_absolute_expression ()) < 0)
183960484Sobrien    {
184060484Sobrien      as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) size);
184160484Sobrien      ignore_rest_of_line ();
184260484Sobrien      return;
184360484Sobrien    }
184460484Sobrien
184560484Sobrien  /* The third argument to .lcomm is the alignment.  */
184660484Sobrien  if (*input_line_pointer != ',')
184760484Sobrien    align = 8;
184860484Sobrien  else
184960484Sobrien    {
185060484Sobrien      ++input_line_pointer;
185160484Sobrien      align = get_absolute_expression ();
185260484Sobrien      if (align <= 0)
185360484Sobrien	{
185460484Sobrien	  as_warn (_("ignoring bad alignment"));
185560484Sobrien	  align = 8;
185660484Sobrien	}
185760484Sobrien    }
185860484Sobrien
185960484Sobrien  *p = 0;
186060484Sobrien  symbolP = symbol_find_or_make (name);
186160484Sobrien  *p = c;
186260484Sobrien
186360484Sobrien  if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP))
186460484Sobrien    {
186560484Sobrien      as_bad (_("Ignoring attempt to re-define symbol `%s'."),
186660484Sobrien	      S_GET_NAME (symbolP));
186760484Sobrien      ignore_rest_of_line ();
186860484Sobrien      return;
186960484Sobrien    }
187060484Sobrien
187160484Sobrien  if (S_GET_VALUE (symbolP) && S_GET_VALUE (symbolP) != (valueT) size)
187260484Sobrien    {
187360484Sobrien      as_bad (_("Length of .lcomm \"%s\" is already %ld. Not changed to %ld."),
187460484Sobrien	      S_GET_NAME (symbolP),
187560484Sobrien	      (long) S_GET_VALUE (symbolP),
187660484Sobrien	      (long) size);
187760484Sobrien
187860484Sobrien      ignore_rest_of_line ();
187960484Sobrien      return;
188060484Sobrien    }
188160484Sobrien
188289857Sobrien  /* Allocate_bss.  */
188360484Sobrien  old_sec = now_seg;
188460484Sobrien  old_subsec = now_subseg;
188560484Sobrien  if (align)
188660484Sobrien    {
188789857Sobrien      /* Convert to a power of 2 alignment.  */
188860484Sobrien      for (align2 = 0; (align & 1) == 0; align >>= 1, ++align2);
188960484Sobrien      if (align != 1)
189060484Sobrien	{
189160484Sobrien	  as_bad (_("Common alignment not a power of 2"));
189260484Sobrien	  ignore_rest_of_line ();
189360484Sobrien	  return;
189460484Sobrien	}
189560484Sobrien    }
189660484Sobrien  else
189760484Sobrien    align2 = 0;
189860484Sobrien
189960484Sobrien  record_alignment (bss_section, align2);
190060484Sobrien  subseg_set (bss_section, 0);
190160484Sobrien  if (align2)
190260484Sobrien    frag_align (align2, 0, 0);
190360484Sobrien  if (S_GET_SEGMENT (symbolP) == bss_section)
190460484Sobrien    symbol_get_frag (symbolP)->fr_symbol = 0;
190560484Sobrien  symbol_set_frag (symbolP, frag_now);
190660484Sobrien  pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, size,
190760484Sobrien		    (char *) 0);
190860484Sobrien  *pfrag = 0;
190960484Sobrien  S_SET_SIZE (symbolP, size);
191060484Sobrien  S_SET_SEGMENT (symbolP, bss_section);
191160484Sobrien  subseg_set (old_sec, old_subsec);
191260484Sobrien  demand_empty_rest_of_line ();
191360484Sobrien}
191460484Sobrien
191560484Sobrien/* Validate any relocations emitted for -mrelocatable, possibly adding
191660484Sobrien   fixups for word relocations in writable segments, so we can adjust
191760484Sobrien   them at runtime.  */
191860484Sobrienstatic void
1919218822Sdimppc_elf_validate_fix (fixS *fixp, segT seg)
192060484Sobrien{
192160484Sobrien  if (fixp->fx_done || fixp->fx_pcrel)
192260484Sobrien    return;
192360484Sobrien
192460484Sobrien  switch (shlib)
192560484Sobrien    {
192660484Sobrien    case SHLIB_NONE:
192760484Sobrien    case SHLIB_PIC:
192860484Sobrien      return;
192960484Sobrien
193077298Sobrien    case SHLIB_MRELOCATABLE:
193160484Sobrien      if (fixp->fx_r_type <= BFD_RELOC_UNUSED
193260484Sobrien	  && fixp->fx_r_type != BFD_RELOC_16_GOTOFF
193360484Sobrien	  && fixp->fx_r_type != BFD_RELOC_HI16_GOTOFF
193460484Sobrien	  && fixp->fx_r_type != BFD_RELOC_LO16_GOTOFF
193560484Sobrien	  && fixp->fx_r_type != BFD_RELOC_HI16_S_GOTOFF
193699461Sobrien	  && fixp->fx_r_type != BFD_RELOC_16_BASEREL
193760484Sobrien	  && fixp->fx_r_type != BFD_RELOC_LO16_BASEREL
193860484Sobrien	  && fixp->fx_r_type != BFD_RELOC_HI16_BASEREL
193960484Sobrien	  && fixp->fx_r_type != BFD_RELOC_HI16_S_BASEREL
194089857Sobrien	  && (seg->flags & SEC_LOAD) != 0
194160484Sobrien	  && strcmp (segment_name (seg), ".got2") != 0
194260484Sobrien	  && strcmp (segment_name (seg), ".dtors") != 0
194360484Sobrien	  && strcmp (segment_name (seg), ".ctors") != 0
194460484Sobrien	  && strcmp (segment_name (seg), ".fixup") != 0
194560484Sobrien	  && strcmp (segment_name (seg), ".gcc_except_table") != 0
194660484Sobrien	  && strcmp (segment_name (seg), ".eh_frame") != 0
194760484Sobrien	  && strcmp (segment_name (seg), ".ex_shared") != 0)
194860484Sobrien	{
194960484Sobrien	  if ((seg->flags & (SEC_READONLY | SEC_CODE)) != 0
195060484Sobrien	      || fixp->fx_r_type != BFD_RELOC_CTOR)
195160484Sobrien	    {
195260484Sobrien	      as_bad_where (fixp->fx_file, fixp->fx_line,
195360484Sobrien			    _("Relocation cannot be done when using -mrelocatable"));
195460484Sobrien	    }
195560484Sobrien	}
195660484Sobrien      return;
195760484Sobrien    }
195860484Sobrien}
195989857Sobrien
1960104834Sobrien/* Prevent elf_frob_file_before_adjust removing a weak undefined
1961104834Sobrien   function descriptor sym if the corresponding code sym is used.  */
1962104834Sobrien
1963104834Sobrienvoid
1964218822Sdimppc_frob_file_before_adjust (void)
196589857Sobrien{
1966104834Sobrien  symbolS *symp;
1967218822Sdim  asection *toc;
196889857Sobrien
1969104834Sobrien  if (!ppc_obj64)
1970104834Sobrien    return;
1971104834Sobrien
1972104834Sobrien  for (symp = symbol_rootP; symp; symp = symbol_next (symp))
197389857Sobrien    {
1974104834Sobrien      const char *name;
1975104834Sobrien      char *dotname;
1976104834Sobrien      symbolS *dotsym;
1977104834Sobrien      size_t len;
1978104834Sobrien
1979104834Sobrien      name = S_GET_NAME (symp);
1980104834Sobrien      if (name[0] == '.')
1981104834Sobrien	continue;
1982104834Sobrien
1983104834Sobrien      if (! S_IS_WEAK (symp)
1984104834Sobrien	  || S_IS_DEFINED (symp))
1985104834Sobrien	continue;
1986104834Sobrien
1987104834Sobrien      len = strlen (name) + 1;
1988104834Sobrien      dotname = xmalloc (len + 1);
1989104834Sobrien      dotname[0] = '.';
1990104834Sobrien      memcpy (dotname + 1, name, len);
1991218822Sdim      dotsym = symbol_find_noref (dotname, 1);
1992104834Sobrien      free (dotname);
1993104834Sobrien      if (dotsym != NULL && (symbol_used_p (dotsym)
1994104834Sobrien			     || symbol_used_in_reloc_p (dotsym)))
1995218822Sdim	symbol_mark_used (symp);
1996218822Sdim
199789857Sobrien    }
199889857Sobrien
1999218822Sdim  toc = bfd_get_section_by_name (stdoutput, ".toc");
2000218822Sdim  if (toc != NULL
2001218822Sdim      && bfd_section_size (stdoutput, toc) > 0x10000)
2002218822Sdim    as_warn (_("TOC section size exceeds 64k"));
2003218822Sdim
2004104834Sobrien  /* Don't emit .TOC. symbol.  */
2005104834Sobrien  symp = symbol_find (".TOC.");
2006104834Sobrien  if (symp != NULL)
2007104834Sobrien    symbol_remove (symp, &symbol_rootP, &symbol_lastP);
200889857Sobrien}
200960484Sobrien#endif /* OBJ_ELF */
201060484Sobrien
201160484Sobrien#ifdef TE_PE
201260484Sobrien
201360484Sobrien/*
201489857Sobrien * Summary of parse_toc_entry.
201560484Sobrien *
201660484Sobrien * in:	Input_line_pointer points to the '[' in one of:
201760484Sobrien *
201860484Sobrien *        [toc] [tocv] [toc32] [toc64]
201960484Sobrien *
202060484Sobrien *      Anything else is an error of one kind or another.
202160484Sobrien *
202277298Sobrien * out:
202360484Sobrien *   return value: success or failure
202460484Sobrien *   toc_kind:     kind of toc reference
202560484Sobrien *   input_line_pointer:
202660484Sobrien *     success: first char after the ']'
202760484Sobrien *     failure: unchanged
202860484Sobrien *
202960484Sobrien * settings:
203060484Sobrien *
203160484Sobrien *     [toc]   - rv == success, toc_kind = default_toc
203260484Sobrien *     [tocv]  - rv == success, toc_kind = data_in_toc
203360484Sobrien *     [toc32] - rv == success, toc_kind = must_be_32
203460484Sobrien *     [toc64] - rv == success, toc_kind = must_be_64
203560484Sobrien *
203660484Sobrien */
203760484Sobrien
203877298Sobrienenum toc_size_qualifier
203977298Sobrien{
204060484Sobrien  default_toc, /* The toc cell constructed should be the system default size */
204160484Sobrien  data_in_toc, /* This is a direct reference to a toc cell                   */
204260484Sobrien  must_be_32,  /* The toc cell constructed must be 32 bits wide              */
204360484Sobrien  must_be_64   /* The toc cell constructed must be 64 bits wide              */
204460484Sobrien};
204560484Sobrien
204660484Sobrienstatic int
2047218822Sdimparse_toc_entry (enum toc_size_qualifier *toc_kind)
204860484Sobrien{
204960484Sobrien  char *start;
205060484Sobrien  char *toc_spec;
205160484Sobrien  char c;
205260484Sobrien  enum toc_size_qualifier t;
205360484Sobrien
205489857Sobrien  /* Save the input_line_pointer.  */
205560484Sobrien  start = input_line_pointer;
205660484Sobrien
205789857Sobrien  /* Skip over the '[' , and whitespace.  */
205860484Sobrien  ++input_line_pointer;
205960484Sobrien  SKIP_WHITESPACE ();
206077298Sobrien
206189857Sobrien  /* Find the spelling of the operand.  */
206260484Sobrien  toc_spec = input_line_pointer;
206360484Sobrien  c = get_symbol_end ();
206460484Sobrien
206589857Sobrien  if (strcmp (toc_spec, "toc") == 0)
206660484Sobrien    {
206760484Sobrien      t = default_toc;
206860484Sobrien    }
206989857Sobrien  else if (strcmp (toc_spec, "tocv") == 0)
207060484Sobrien    {
207160484Sobrien      t = data_in_toc;
207260484Sobrien    }
207389857Sobrien  else if (strcmp (toc_spec, "toc32") == 0)
207460484Sobrien    {
207560484Sobrien      t = must_be_32;
207660484Sobrien    }
207789857Sobrien  else if (strcmp (toc_spec, "toc64") == 0)
207860484Sobrien    {
207960484Sobrien      t = must_be_64;
208060484Sobrien    }
208160484Sobrien  else
208260484Sobrien    {
208360484Sobrien      as_bad (_("syntax error: invalid toc specifier `%s'"), toc_spec);
208489857Sobrien      *input_line_pointer = c;
208589857Sobrien      input_line_pointer = start;
208660484Sobrien      return 0;
208760484Sobrien    }
208860484Sobrien
208989857Sobrien  /* Now find the ']'.  */
209089857Sobrien  *input_line_pointer = c;
209160484Sobrien
209277298Sobrien  SKIP_WHITESPACE ();	     /* leading whitespace could be there.  */
209377298Sobrien  c = *input_line_pointer++; /* input_line_pointer->past char in c.  */
209460484Sobrien
209560484Sobrien  if (c != ']')
209660484Sobrien    {
209760484Sobrien      as_bad (_("syntax error: expected `]', found  `%c'"), c);
209889857Sobrien      input_line_pointer = start;
209960484Sobrien      return 0;
210060484Sobrien    }
210160484Sobrien
210289857Sobrien  *toc_kind = t;
210360484Sobrien  return 1;
210460484Sobrien}
210560484Sobrien#endif
210660484Sobrien
210760484Sobrien
2108130561Sobrien#ifdef OBJ_ELF
2109130561Sobrien#define APUID(a,v)	((((a) & 0xffff) << 16) | ((v) & 0xffff))
2110130561Sobrienstatic void
2111218822Sdimppc_apuinfo_section_add (unsigned int apu, unsigned int version)
2112130561Sobrien{
2113130561Sobrien  unsigned int i;
2114130561Sobrien
2115130561Sobrien  /* Check we don't already exist.  */
2116130561Sobrien  for (i = 0; i < ppc_apuinfo_num; i++)
2117130561Sobrien    if (ppc_apuinfo_list[i] == APUID (apu, version))
2118130561Sobrien      return;
2119130561Sobrien
2120130561Sobrien  if (ppc_apuinfo_num == ppc_apuinfo_num_alloc)
2121130561Sobrien    {
2122130561Sobrien      if (ppc_apuinfo_num_alloc == 0)
2123130561Sobrien	{
2124130561Sobrien	  ppc_apuinfo_num_alloc = 4;
2125130561Sobrien	  ppc_apuinfo_list = (unsigned long *)
2126130561Sobrien	      xmalloc (sizeof (unsigned long) * ppc_apuinfo_num_alloc);
2127130561Sobrien	}
2128130561Sobrien      else
2129130561Sobrien	{
2130130561Sobrien	  ppc_apuinfo_num_alloc += 4;
2131130561Sobrien	  ppc_apuinfo_list = (unsigned long *) xrealloc (ppc_apuinfo_list,
2132130561Sobrien	      sizeof (unsigned long) * ppc_apuinfo_num_alloc);
2133130561Sobrien	}
2134130561Sobrien    }
2135130561Sobrien  ppc_apuinfo_list[ppc_apuinfo_num++] = APUID (apu, version);
2136130561Sobrien}
2137130561Sobrien#undef APUID
2138130561Sobrien#endif
2139130561Sobrien
2140130561Sobrien
214160484Sobrien/* We need to keep a list of fixups.  We can't simply generate them as
214260484Sobrien   we go, because that would require us to first create the frag, and
214360484Sobrien   that would screw up references to ``.''.  */
214460484Sobrien
214560484Sobrienstruct ppc_fixup
214660484Sobrien{
214760484Sobrien  expressionS exp;
214860484Sobrien  int opindex;
214960484Sobrien  bfd_reloc_code_real_type reloc;
215060484Sobrien};
215160484Sobrien
215260484Sobrien#define MAX_INSN_FIXUPS (5)
215360484Sobrien
215460484Sobrien/* This routine is called for each instruction to be assembled.  */
215560484Sobrien
215660484Sobrienvoid
2157218822Sdimmd_assemble (char *str)
215860484Sobrien{
215960484Sobrien  char *s;
216060484Sobrien  const struct powerpc_opcode *opcode;
216160484Sobrien  unsigned long insn;
216260484Sobrien  const unsigned char *opindex_ptr;
216360484Sobrien  int skip_optional;
216460484Sobrien  int need_paren;
216560484Sobrien  int next_opindex;
216660484Sobrien  struct ppc_fixup fixups[MAX_INSN_FIXUPS];
216760484Sobrien  int fc;
216860484Sobrien  char *f;
2169218822Sdim  int addr_mod;
217060484Sobrien  int i;
217160484Sobrien#ifdef OBJ_ELF
217260484Sobrien  bfd_reloc_code_real_type reloc;
217360484Sobrien#endif
217460484Sobrien
217560484Sobrien  /* Get the opcode.  */
217689857Sobrien  for (s = str; *s != '\0' && ! ISSPACE (*s); s++)
217760484Sobrien    ;
217860484Sobrien  if (*s != '\0')
217960484Sobrien    *s++ = '\0';
218060484Sobrien
218160484Sobrien  /* Look up the opcode in the hash table.  */
218260484Sobrien  opcode = (const struct powerpc_opcode *) hash_find (ppc_hash, str);
218360484Sobrien  if (opcode == (const struct powerpc_opcode *) NULL)
218460484Sobrien    {
218560484Sobrien      const struct powerpc_macro *macro;
218660484Sobrien
218760484Sobrien      macro = (const struct powerpc_macro *) hash_find (ppc_macro_hash, str);
218860484Sobrien      if (macro == (const struct powerpc_macro *) NULL)
218960484Sobrien	as_bad (_("Unrecognized opcode: `%s'"), str);
219060484Sobrien      else
219160484Sobrien	ppc_macro (s, macro);
219260484Sobrien
219360484Sobrien      return;
219460484Sobrien    }
219560484Sobrien
219660484Sobrien  insn = opcode->opcode;
219760484Sobrien
219860484Sobrien  str = s;
219989857Sobrien  while (ISSPACE (*str))
220060484Sobrien    ++str;
220160484Sobrien
220260484Sobrien  /* PowerPC operands are just expressions.  The only real issue is
220360484Sobrien     that a few operand types are optional.  All cases which might use
2204130561Sobrien     an optional operand separate the operands only with commas (in some
2205130561Sobrien     cases parentheses are used, as in ``lwz 1,0(1)'' but such cases never
2206130561Sobrien     have optional operands).  Most instructions with optional operands
2207130561Sobrien     have only one.  Those that have more than one optional operand can
2208130561Sobrien     take either all their operands or none.  So, before we start seriously
2209130561Sobrien     parsing the operands, we check to see if we have optional operands,
2210130561Sobrien     and if we do, we count the number of commas to see which operands
2211130561Sobrien     have been omitted.  */
221260484Sobrien  skip_optional = 0;
221360484Sobrien  for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++)
221460484Sobrien    {
221560484Sobrien      const struct powerpc_operand *operand;
221660484Sobrien
221760484Sobrien      operand = &powerpc_operands[*opindex_ptr];
221860484Sobrien      if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0)
221960484Sobrien	{
222060484Sobrien	  unsigned int opcount;
2221104834Sobrien	  unsigned int num_operands_expected;
2222104834Sobrien	  unsigned int i;
222360484Sobrien
222460484Sobrien	  /* There is an optional operand.  Count the number of
222560484Sobrien	     commas in the input line.  */
222660484Sobrien	  if (*str == '\0')
222760484Sobrien	    opcount = 0;
222860484Sobrien	  else
222960484Sobrien	    {
223060484Sobrien	      opcount = 1;
223160484Sobrien	      s = str;
223260484Sobrien	      while ((s = strchr (s, ',')) != (char *) NULL)
223360484Sobrien		{
223460484Sobrien		  ++opcount;
223560484Sobrien		  ++s;
223660484Sobrien		}
223760484Sobrien	    }
223860484Sobrien
2239104834Sobrien	  /* Compute the number of expected operands.
2240104834Sobrien	     Do not count fake operands.  */
2241104834Sobrien	  for (num_operands_expected = 0, i = 0; opcode->operands[i]; i ++)
2242104834Sobrien	    if ((powerpc_operands [opcode->operands[i]].flags & PPC_OPERAND_FAKE) == 0)
2243104834Sobrien	      ++ num_operands_expected;
2244104834Sobrien
224560484Sobrien	  /* If there are fewer operands in the line then are called
224660484Sobrien	     for by the instruction, we want to skip the optional
2247130561Sobrien	     operands.  */
2248104834Sobrien	  if (opcount < num_operands_expected)
224960484Sobrien	    skip_optional = 1;
225060484Sobrien
225160484Sobrien	  break;
225260484Sobrien	}
225360484Sobrien    }
225460484Sobrien
225560484Sobrien  /* Gather the operands.  */
225660484Sobrien  need_paren = 0;
225760484Sobrien  next_opindex = 0;
225860484Sobrien  fc = 0;
225960484Sobrien  for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++)
226060484Sobrien    {
226160484Sobrien      const struct powerpc_operand *operand;
226260484Sobrien      const char *errmsg;
226360484Sobrien      char *hold;
226460484Sobrien      expressionS ex;
226560484Sobrien      char endc;
226660484Sobrien
226760484Sobrien      if (next_opindex == 0)
226860484Sobrien	operand = &powerpc_operands[*opindex_ptr];
226960484Sobrien      else
227060484Sobrien	{
227160484Sobrien	  operand = &powerpc_operands[next_opindex];
227260484Sobrien	  next_opindex = 0;
227360484Sobrien	}
227460484Sobrien      errmsg = NULL;
227560484Sobrien
227660484Sobrien      /* If this is a fake operand, then we do not expect anything
227760484Sobrien	 from the input.  */
227860484Sobrien      if ((operand->flags & PPC_OPERAND_FAKE) != 0)
227960484Sobrien	{
2280104834Sobrien	  insn = (*operand->insert) (insn, 0L, ppc_cpu, &errmsg);
228160484Sobrien	  if (errmsg != (const char *) NULL)
2282276346Sdim	    as_bad ("%s", errmsg);
228360484Sobrien	  continue;
228460484Sobrien	}
228560484Sobrien
228660484Sobrien      /* If this is an optional operand, and we are skipping it, just
228760484Sobrien	 insert a zero.  */
228860484Sobrien      if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
228960484Sobrien	  && skip_optional)
229060484Sobrien	{
229160484Sobrien	  if (operand->insert)
229260484Sobrien	    {
2293104834Sobrien	      insn = (*operand->insert) (insn, 0L, ppc_cpu, &errmsg);
229460484Sobrien	      if (errmsg != (const char *) NULL)
2295276346Sdim		as_bad ("%s", errmsg);
229660484Sobrien	    }
229760484Sobrien	  if ((operand->flags & PPC_OPERAND_NEXT) != 0)
229860484Sobrien	    next_opindex = *opindex_ptr + 1;
229960484Sobrien	  continue;
230060484Sobrien	}
230160484Sobrien
230260484Sobrien      /* Gather the operand.  */
230360484Sobrien      hold = input_line_pointer;
230460484Sobrien      input_line_pointer = str;
230560484Sobrien
230660484Sobrien#ifdef TE_PE
230777298Sobrien      if (*input_line_pointer == '[')
230860484Sobrien	{
230960484Sobrien	  /* We are expecting something like the second argument here:
231089857Sobrien	   *
231189857Sobrien	   *    lwz r4,[toc].GS.0.static_int(rtoc)
231289857Sobrien	   *           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
231389857Sobrien	   * The argument following the `]' must be a symbol name, and the
231489857Sobrien	   * register must be the toc register: 'rtoc' or '2'
231589857Sobrien	   *
231689857Sobrien	   * The effect is to 0 as the displacement field
231789857Sobrien	   * in the instruction, and issue an IMAGE_REL_PPC_TOCREL16 (or
231889857Sobrien	   * the appropriate variation) reloc against it based on the symbol.
231989857Sobrien	   * The linker will build the toc, and insert the resolved toc offset.
232089857Sobrien	   *
232189857Sobrien	   * Note:
232289857Sobrien	   * o The size of the toc entry is currently assumed to be
232389857Sobrien	   *   32 bits. This should not be assumed to be a hard coded
232489857Sobrien	   *   number.
232589857Sobrien	   * o In an effort to cope with a change from 32 to 64 bits,
232689857Sobrien	   *   there are also toc entries that are specified to be
232789857Sobrien	   *   either 32 or 64 bits:
232889857Sobrien	   *     lwz r4,[toc32].GS.0.static_int(rtoc)
232989857Sobrien	   *     lwz r4,[toc64].GS.0.static_int(rtoc)
233089857Sobrien	   *   These demand toc entries of the specified size, and the
233189857Sobrien	   *   instruction probably requires it.
233289857Sobrien	   */
233360484Sobrien
233460484Sobrien	  int valid_toc;
233560484Sobrien	  enum toc_size_qualifier toc_kind;
233660484Sobrien	  bfd_reloc_code_real_type toc_reloc;
233760484Sobrien
233889857Sobrien	  /* Go parse off the [tocXX] part.  */
233989857Sobrien	  valid_toc = parse_toc_entry (&toc_kind);
234060484Sobrien
234177298Sobrien	  if (!valid_toc)
234260484Sobrien	    {
234389857Sobrien	      /* Note: message has already been issued.
234489857Sobrien		 FIXME: what sort of recovery should we do?
234589857Sobrien		 demand_rest_of_line (); return; ?  */
234660484Sobrien	    }
234760484Sobrien
234889857Sobrien	  /* Now get the symbol following the ']'.  */
234989857Sobrien	  expression (&ex);
235060484Sobrien
235160484Sobrien	  switch (toc_kind)
235260484Sobrien	    {
235360484Sobrien	    case default_toc:
235489857Sobrien	      /* In this case, we may not have seen the symbol yet,
235589857Sobrien		 since  it is allowed to appear on a .extern or .globl
235689857Sobrien		 or just be a label in the .data section.  */
235760484Sobrien	      toc_reloc = BFD_RELOC_PPC_TOC16;
235860484Sobrien	      break;
235960484Sobrien	    case data_in_toc:
236089857Sobrien	      /* 1. The symbol must be defined and either in the toc
236189857Sobrien		 section, or a global.
236289857Sobrien		 2. The reloc generated must have the TOCDEFN flag set
236389857Sobrien		 in upper bit mess of the reloc type.
236489857Sobrien		 FIXME: It's a little confusing what the tocv
236589857Sobrien		 qualifier can be used for.  At the very least, I've
236689857Sobrien		 seen three uses, only one of which I'm sure I can
236789857Sobrien		 explain.  */
236877298Sobrien	      if (ex.X_op == O_symbol)
236977298Sobrien		{
237060484Sobrien		  assert (ex.X_add_symbol != NULL);
237160484Sobrien		  if (symbol_get_bfdsym (ex.X_add_symbol)->section
237260484Sobrien		      != tocdata_section)
237360484Sobrien		    {
237489857Sobrien		      as_bad (_("[tocv] symbol is not a toc symbol"));
237560484Sobrien		    }
237660484Sobrien		}
237760484Sobrien
237860484Sobrien	      toc_reloc = BFD_RELOC_PPC_TOC16;
237960484Sobrien	      break;
238060484Sobrien	    case must_be_32:
238189857Sobrien	      /* FIXME: these next two specifically specify 32/64 bit
238289857Sobrien		 toc entries.  We don't support them today.  Is this
238389857Sobrien		 the right way to say that?  */
238460484Sobrien	      toc_reloc = BFD_RELOC_UNUSED;
238560484Sobrien	      as_bad (_("Unimplemented toc32 expression modifier"));
238660484Sobrien	      break;
238760484Sobrien	    case must_be_64:
238889857Sobrien	      /* FIXME: see above.  */
238960484Sobrien	      toc_reloc = BFD_RELOC_UNUSED;
239060484Sobrien	      as_bad (_("Unimplemented toc64 expression modifier"));
239160484Sobrien	      break;
239260484Sobrien	    default:
239377298Sobrien	      fprintf (stderr,
239489857Sobrien		       _("Unexpected return value [%d] from parse_toc_entry!\n"),
239589857Sobrien		       toc_kind);
239677298Sobrien	      abort ();
239760484Sobrien	      break;
239860484Sobrien	    }
239960484Sobrien
240060484Sobrien	  /* We need to generate a fixup for this expression.  */
240160484Sobrien	  if (fc >= MAX_INSN_FIXUPS)
240260484Sobrien	    as_fatal (_("too many fixups"));
240360484Sobrien
240460484Sobrien	  fixups[fc].reloc = toc_reloc;
240560484Sobrien	  fixups[fc].exp = ex;
240660484Sobrien	  fixups[fc].opindex = *opindex_ptr;
240760484Sobrien	  ++fc;
240860484Sobrien
240989857Sobrien	  /* Ok. We've set up the fixup for the instruction. Now make it
241089857Sobrien	     look like the constant 0 was found here.  */
241160484Sobrien	  ex.X_unsigned = 1;
241260484Sobrien	  ex.X_op = O_constant;
241360484Sobrien	  ex.X_add_number = 0;
241460484Sobrien	  ex.X_add_symbol = NULL;
241560484Sobrien	  ex.X_op_symbol = NULL;
241660484Sobrien	}
241760484Sobrien
241860484Sobrien      else
241960484Sobrien#endif		/* TE_PE */
242060484Sobrien	{
242160484Sobrien	  if (! register_name (&ex))
242260484Sobrien	    {
242360484Sobrien	      if ((operand->flags & PPC_OPERAND_CR) != 0)
2424130561Sobrien		cr_operand = TRUE;
242560484Sobrien	      expression (&ex);
2426130561Sobrien	      cr_operand = FALSE;
242760484Sobrien	    }
242860484Sobrien	}
242960484Sobrien
243060484Sobrien      str = input_line_pointer;
243160484Sobrien      input_line_pointer = hold;
243260484Sobrien
243360484Sobrien      if (ex.X_op == O_illegal)
243460484Sobrien	as_bad (_("illegal operand"));
243560484Sobrien      else if (ex.X_op == O_absent)
243660484Sobrien	as_bad (_("missing operand"));
243760484Sobrien      else if (ex.X_op == O_register)
243860484Sobrien	{
243960484Sobrien	  insn = ppc_insert_operand (insn, operand, ex.X_add_number,
244060484Sobrien				     (char *) NULL, 0);
244160484Sobrien	}
244260484Sobrien      else if (ex.X_op == O_constant)
244360484Sobrien	{
244460484Sobrien#ifdef OBJ_ELF
244577298Sobrien	  /* Allow @HA, @L, @H on constants.  */
244660484Sobrien	  char *orig_str = str;
244760484Sobrien
244860484Sobrien	  if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)
244960484Sobrien	    switch (reloc)
245060484Sobrien	      {
245160484Sobrien	      default:
245260484Sobrien		str = orig_str;
245360484Sobrien		break;
245460484Sobrien
245560484Sobrien	      case BFD_RELOC_LO16:
245660484Sobrien		/* X_unsigned is the default, so if the user has done
245789857Sobrien		   something which cleared it, we always produce a
245889857Sobrien		   signed value.  */
245989857Sobrien		if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
246060484Sobrien		  ex.X_add_number &= 0xffff;
246160484Sobrien		else
246289857Sobrien		  ex.X_add_number = SEX16 (ex.X_add_number);
246360484Sobrien		break;
246460484Sobrien
246560484Sobrien	      case BFD_RELOC_HI16:
246689857Sobrien		if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
246789857Sobrien		  ex.X_add_number = PPC_HI (ex.X_add_number);
246889857Sobrien		else
246989857Sobrien		  ex.X_add_number = SEX16 (PPC_HI (ex.X_add_number));
247060484Sobrien		break;
247160484Sobrien
247260484Sobrien	      case BFD_RELOC_HI16_S:
247389857Sobrien		if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
247489857Sobrien		  ex.X_add_number = PPC_HA (ex.X_add_number);
247589857Sobrien		else
247689857Sobrien		  ex.X_add_number = SEX16 (PPC_HA (ex.X_add_number));
247760484Sobrien		break;
247889857Sobrien
247989857Sobrien	      case BFD_RELOC_PPC64_HIGHER:
248089857Sobrien		if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
248189857Sobrien		  ex.X_add_number = PPC_HIGHER (ex.X_add_number);
248289857Sobrien		else
248389857Sobrien		  ex.X_add_number = SEX16 (PPC_HIGHER (ex.X_add_number));
248489857Sobrien		break;
248589857Sobrien
248689857Sobrien	      case BFD_RELOC_PPC64_HIGHER_S:
248789857Sobrien		if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
248889857Sobrien		  ex.X_add_number = PPC_HIGHERA (ex.X_add_number);
248989857Sobrien		else
249089857Sobrien		  ex.X_add_number = SEX16 (PPC_HIGHERA (ex.X_add_number));
249189857Sobrien		break;
249289857Sobrien
249389857Sobrien	      case BFD_RELOC_PPC64_HIGHEST:
249489857Sobrien		if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
249589857Sobrien		  ex.X_add_number = PPC_HIGHEST (ex.X_add_number);
249689857Sobrien		else
249789857Sobrien		  ex.X_add_number = SEX16 (PPC_HIGHEST (ex.X_add_number));
249889857Sobrien		break;
249989857Sobrien
250089857Sobrien	      case BFD_RELOC_PPC64_HIGHEST_S:
250189857Sobrien		if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
250289857Sobrien		  ex.X_add_number = PPC_HIGHESTA (ex.X_add_number);
250389857Sobrien		else
250489857Sobrien		  ex.X_add_number = SEX16 (PPC_HIGHESTA (ex.X_add_number));
250589857Sobrien		break;
250660484Sobrien	      }
250789857Sobrien#endif /* OBJ_ELF */
250860484Sobrien	  insn = ppc_insert_operand (insn, operand, ex.X_add_number,
250960484Sobrien				     (char *) NULL, 0);
251060484Sobrien	}
251160484Sobrien#ifdef OBJ_ELF
2512275873Sjhibbits      else
251360484Sobrien	{
2514275873Sjhibbits	  if (ex.X_op == O_symbol && str[0] == '(')
2515130561Sobrien	    {
2516275873Sjhibbits	      const char *sym_name = S_GET_NAME (ex.X_add_symbol);
2517275873Sjhibbits	      if (sym_name[0] == '.')
2518275873Sjhibbits		++sym_name;
2519130561Sobrien
2520275873Sjhibbits	      if (strcasecmp (sym_name, "__tls_get_addr") == 0)
252160484Sobrien		{
2522275873Sjhibbits		  expressionS tls_exp;
2523275873Sjhibbits
2524275873Sjhibbits		  hold = input_line_pointer;
2525275873Sjhibbits		  input_line_pointer = str + 1;
2526275873Sjhibbits		  expression (&tls_exp);
2527275873Sjhibbits		  if (tls_exp.X_op == O_symbol)
2528275873Sjhibbits		    {
2529275873Sjhibbits		      reloc = BFD_RELOC_UNUSED;
2530275873Sjhibbits		      if (strncasecmp (input_line_pointer, "@tlsgd)", 7) == 0)
2531275873Sjhibbits			{
2532275873Sjhibbits			  reloc = BFD_RELOC_PPC_TLSGD;
2533275873Sjhibbits			  input_line_pointer += 7;
2534275873Sjhibbits			}
2535275873Sjhibbits		      else if (strncasecmp (input_line_pointer, "@tlsld)", 7) == 0)
2536275873Sjhibbits			{
2537275873Sjhibbits			  reloc = BFD_RELOC_PPC_TLSLD;
2538275873Sjhibbits			  input_line_pointer += 7;
2539275873Sjhibbits			}
2540275873Sjhibbits		      if (reloc != BFD_RELOC_UNUSED)
2541275873Sjhibbits			{
2542275873Sjhibbits			  SKIP_WHITESPACE ();
2543275873Sjhibbits			  str = input_line_pointer;
2544275873Sjhibbits
2545275873Sjhibbits			  if (fc >= MAX_INSN_FIXUPS)
2546275873Sjhibbits			    as_fatal (_("too many fixups"));
2547275873Sjhibbits			  fixups[fc].exp = tls_exp;
2548275873Sjhibbits			  fixups[fc].opindex = *opindex_ptr;
2549275873Sjhibbits			  fixups[fc].reloc = reloc;
2550275873Sjhibbits			  ++fc;
2551275873Sjhibbits			}
2552275873Sjhibbits		    }
2553275873Sjhibbits		  input_line_pointer = hold;
255460484Sobrien		}
255560484Sobrien	    }
255660484Sobrien
2557275873Sjhibbits	  if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)
255889857Sobrien	    {
2559275873Sjhibbits	      /* Some TLS tweaks.  */
256089857Sobrien	      switch (reloc)
256189857Sobrien		{
2562275873Sjhibbits		default:
256389857Sobrien		  break;
2564275873Sjhibbits
2565275873Sjhibbits		case BFD_RELOC_PPC_TLS:
2566275873Sjhibbits		  insn = ppc_insert_operand (insn, operand, ppc_obj64 ? 13 : 2,
2567275873Sjhibbits					     (char *) NULL, 0);
256889857Sobrien		  break;
2569275873Sjhibbits
2570275873Sjhibbits		  /* We'll only use the 32 (or 64) bit form of these relocations
2571275873Sjhibbits		     in constants.  Instructions get the 16 bit form.  */
2572275873Sjhibbits		case BFD_RELOC_PPC_DTPREL:
2573275873Sjhibbits		  reloc = BFD_RELOC_PPC_DTPREL16;
257489857Sobrien		  break;
2575275873Sjhibbits		case BFD_RELOC_PPC_TPREL:
2576275873Sjhibbits		  reloc = BFD_RELOC_PPC_TPREL16;
257789857Sobrien		  break;
257889857Sobrien		}
2579275873Sjhibbits
2580275873Sjhibbits	      /* For the absolute forms of branches, convert the PC
2581275873Sjhibbits		 relative form back into the absolute.  */
2582275873Sjhibbits	      if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
2583275873Sjhibbits		{
2584275873Sjhibbits		  switch (reloc)
2585275873Sjhibbits		    {
2586275873Sjhibbits		    case BFD_RELOC_PPC_B26:
2587275873Sjhibbits		      reloc = BFD_RELOC_PPC_BA26;
2588275873Sjhibbits		      break;
2589275873Sjhibbits		    case BFD_RELOC_PPC_B16:
2590275873Sjhibbits		      reloc = BFD_RELOC_PPC_BA16;
2591275873Sjhibbits		      break;
2592275873Sjhibbits		    case BFD_RELOC_PPC_B16_BRTAKEN:
2593275873Sjhibbits		      reloc = BFD_RELOC_PPC_BA16_BRTAKEN;
2594275873Sjhibbits		      break;
2595275873Sjhibbits		    case BFD_RELOC_PPC_B16_BRNTAKEN:
2596275873Sjhibbits		      reloc = BFD_RELOC_PPC_BA16_BRNTAKEN;
2597275873Sjhibbits		      break;
2598275873Sjhibbits		    default:
2599275873Sjhibbits		      break;
2600275873Sjhibbits		    }
2601275873Sjhibbits		}
2602275873Sjhibbits
2603275873Sjhibbits	      if (ppc_obj64
2604275873Sjhibbits		  && (operand->flags & (PPC_OPERAND_DS | PPC_OPERAND_DQ)) != 0)
2605275873Sjhibbits		{
2606275873Sjhibbits		  switch (reloc)
2607275873Sjhibbits		    {
2608275873Sjhibbits		    case BFD_RELOC_16:
2609275873Sjhibbits		      reloc = BFD_RELOC_PPC64_ADDR16_DS;
2610275873Sjhibbits		      break;
2611275873Sjhibbits		    case BFD_RELOC_LO16:
2612275873Sjhibbits		      reloc = BFD_RELOC_PPC64_ADDR16_LO_DS;
2613275873Sjhibbits		      break;
2614275873Sjhibbits		    case BFD_RELOC_16_GOTOFF:
2615275873Sjhibbits		      reloc = BFD_RELOC_PPC64_GOT16_DS;
2616275873Sjhibbits		      break;
2617275873Sjhibbits		    case BFD_RELOC_LO16_GOTOFF:
2618275873Sjhibbits		      reloc = BFD_RELOC_PPC64_GOT16_LO_DS;
2619275873Sjhibbits		      break;
2620275873Sjhibbits		    case BFD_RELOC_LO16_PLTOFF:
2621275873Sjhibbits		      reloc = BFD_RELOC_PPC64_PLT16_LO_DS;
2622275873Sjhibbits		      break;
2623275873Sjhibbits		    case BFD_RELOC_16_BASEREL:
2624275873Sjhibbits		      reloc = BFD_RELOC_PPC64_SECTOFF_DS;
2625275873Sjhibbits		      break;
2626275873Sjhibbits		    case BFD_RELOC_LO16_BASEREL:
2627275873Sjhibbits		      reloc = BFD_RELOC_PPC64_SECTOFF_LO_DS;
2628275873Sjhibbits		      break;
2629275873Sjhibbits		    case BFD_RELOC_PPC_TOC16:
2630275873Sjhibbits		      reloc = BFD_RELOC_PPC64_TOC16_DS;
2631275873Sjhibbits		      break;
2632275873Sjhibbits		    case BFD_RELOC_PPC64_TOC16_LO:
2633275873Sjhibbits		      reloc = BFD_RELOC_PPC64_TOC16_LO_DS;
2634275873Sjhibbits		      break;
2635275873Sjhibbits		    case BFD_RELOC_PPC64_PLTGOT16:
2636275873Sjhibbits		      reloc = BFD_RELOC_PPC64_PLTGOT16_DS;
2637275873Sjhibbits		      break;
2638275873Sjhibbits		    case BFD_RELOC_PPC64_PLTGOT16_LO:
2639275873Sjhibbits		      reloc = BFD_RELOC_PPC64_PLTGOT16_LO_DS;
2640275873Sjhibbits		      break;
2641275873Sjhibbits		    case BFD_RELOC_PPC_DTPREL16:
2642275873Sjhibbits		      reloc = BFD_RELOC_PPC64_DTPREL16_DS;
2643275873Sjhibbits		      break;
2644275873Sjhibbits		    case BFD_RELOC_PPC_DTPREL16_LO:
2645275873Sjhibbits		      reloc = BFD_RELOC_PPC64_DTPREL16_LO_DS;
2646275873Sjhibbits		      break;
2647275873Sjhibbits		    case BFD_RELOC_PPC_TPREL16:
2648275873Sjhibbits		      reloc = BFD_RELOC_PPC64_TPREL16_DS;
2649275873Sjhibbits		      break;
2650275873Sjhibbits		    case BFD_RELOC_PPC_TPREL16_LO:
2651275873Sjhibbits		      reloc = BFD_RELOC_PPC64_TPREL16_LO_DS;
2652275873Sjhibbits		      break;
2653275873Sjhibbits		    case BFD_RELOC_PPC_GOT_DTPREL16:
2654275873Sjhibbits		    case BFD_RELOC_PPC_GOT_DTPREL16_LO:
2655275873Sjhibbits		    case BFD_RELOC_PPC_GOT_TPREL16:
2656275873Sjhibbits		    case BFD_RELOC_PPC_GOT_TPREL16_LO:
2657275873Sjhibbits		      break;
2658275873Sjhibbits		    default:
2659275873Sjhibbits		      as_bad (_("unsupported relocation for DS offset field"));
2660275873Sjhibbits		      break;
2661275873Sjhibbits		    }
2662275873Sjhibbits		}
266389857Sobrien	    }
266489857Sobrien
266560484Sobrien	  /* We need to generate a fixup for this expression.  */
266660484Sobrien	  if (fc >= MAX_INSN_FIXUPS)
266760484Sobrien	    as_fatal (_("too many fixups"));
266860484Sobrien	  fixups[fc].exp = ex;
2669275873Sjhibbits	  fixups[fc].opindex = *opindex_ptr;
267060484Sobrien	  fixups[fc].reloc = reloc;
267160484Sobrien	  ++fc;
267260484Sobrien	}
2673275873Sjhibbits#else /* OBJ_ELF */
267460484Sobrien      else
267560484Sobrien	{
267660484Sobrien	  /* We need to generate a fixup for this expression.  */
267760484Sobrien	  if (fc >= MAX_INSN_FIXUPS)
267860484Sobrien	    as_fatal (_("too many fixups"));
267960484Sobrien	  fixups[fc].exp = ex;
268060484Sobrien	  fixups[fc].opindex = *opindex_ptr;
268160484Sobrien	  fixups[fc].reloc = BFD_RELOC_UNUSED;
268260484Sobrien	  ++fc;
268360484Sobrien	}
2684275873Sjhibbits#endif /* OBJ_ELF */
268560484Sobrien
268660484Sobrien      if (need_paren)
268760484Sobrien	{
268860484Sobrien	  endc = ')';
268960484Sobrien	  need_paren = 0;
269060484Sobrien	}
269160484Sobrien      else if ((operand->flags & PPC_OPERAND_PARENS) != 0)
269260484Sobrien	{
269360484Sobrien	  endc = '(';
269460484Sobrien	  need_paren = 1;
269560484Sobrien	}
269660484Sobrien      else
269760484Sobrien	endc = ',';
269860484Sobrien
269960484Sobrien      /* The call to expression should have advanced str past any
270060484Sobrien	 whitespace.  */
270160484Sobrien      if (*str != endc
270260484Sobrien	  && (endc != ',' || *str != '\0'))
270360484Sobrien	{
270460484Sobrien	  as_bad (_("syntax error; found `%c' but expected `%c'"), *str, endc);
270560484Sobrien	  break;
270660484Sobrien	}
270760484Sobrien
270860484Sobrien      if (*str != '\0')
270960484Sobrien	++str;
271060484Sobrien    }
271160484Sobrien
271289857Sobrien  while (ISSPACE (*str))
271360484Sobrien    ++str;
271460484Sobrien
271560484Sobrien  if (*str != '\0')
271660484Sobrien    as_bad (_("junk at end of line: `%s'"), str);
271760484Sobrien
2718130561Sobrien#ifdef OBJ_ELF
2719130561Sobrien  /* Do we need/want a APUinfo section? */
2720130561Sobrien  if (ppc_cpu & (PPC_OPCODE_SPE
2721130561Sobrien   	       | PPC_OPCODE_ISEL | PPC_OPCODE_EFS
2722130561Sobrien	       | PPC_OPCODE_BRLOCK | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK
2723130561Sobrien	       | PPC_OPCODE_RFMCI))
2724130561Sobrien    {
2725130561Sobrien      /* These are all version "1".  */
2726130561Sobrien      if (opcode->flags & PPC_OPCODE_SPE)
2727130561Sobrien	ppc_apuinfo_section_add (PPC_APUINFO_SPE, 1);
2728130561Sobrien      if (opcode->flags & PPC_OPCODE_ISEL)
2729130561Sobrien	ppc_apuinfo_section_add (PPC_APUINFO_ISEL, 1);
2730130561Sobrien      if (opcode->flags & PPC_OPCODE_EFS)
2731130561Sobrien	ppc_apuinfo_section_add (PPC_APUINFO_EFS, 1);
2732130561Sobrien      if (opcode->flags & PPC_OPCODE_BRLOCK)
2733130561Sobrien	ppc_apuinfo_section_add (PPC_APUINFO_BRLOCK, 1);
2734130561Sobrien      if (opcode->flags & PPC_OPCODE_PMR)
2735130561Sobrien	ppc_apuinfo_section_add (PPC_APUINFO_PMR, 1);
2736130561Sobrien      if (opcode->flags & PPC_OPCODE_CACHELCK)
2737130561Sobrien	ppc_apuinfo_section_add (PPC_APUINFO_CACHELCK, 1);
2738130561Sobrien      if (opcode->flags & PPC_OPCODE_RFMCI)
2739130561Sobrien	ppc_apuinfo_section_add (PPC_APUINFO_RFMCI, 1);
2740130561Sobrien    }
2741130561Sobrien#endif
2742130561Sobrien
274360484Sobrien  /* Write out the instruction.  */
274460484Sobrien  f = frag_more (4);
2745218822Sdim  addr_mod = frag_now_fix () & 3;
2746218822Sdim  if (frag_now->has_code && frag_now->insn_addr != addr_mod)
2747218822Sdim    as_bad (_("instruction address is not a multiple of 4"));
2748218822Sdim  frag_now->insn_addr = addr_mod;
2749218822Sdim  frag_now->has_code = 1;
275060484Sobrien  md_number_to_chars (f, insn, 4);
275160484Sobrien
275277298Sobrien#ifdef OBJ_ELF
275377298Sobrien  dwarf2_emit_insn (4);
275477298Sobrien#endif
275577298Sobrien
275660484Sobrien  /* Create any fixups.  At this point we do not use a
275760484Sobrien     bfd_reloc_code_real_type, but instead just use the
275860484Sobrien     BFD_RELOC_UNUSED plus the operand index.  This lets us easily
275960484Sobrien     handle fixups for any operand type, although that is admittedly
276060484Sobrien     not a very exciting feature.  We pick a BFD reloc type in
2761218822Sdim     md_apply_fix.  */
276260484Sobrien  for (i = 0; i < fc; i++)
276360484Sobrien    {
276460484Sobrien      const struct powerpc_operand *operand;
276560484Sobrien
276660484Sobrien      operand = &powerpc_operands[fixups[i].opindex];
276760484Sobrien      if (fixups[i].reloc != BFD_RELOC_UNUSED)
276860484Sobrien	{
276989857Sobrien	  reloc_howto_type *reloc_howto;
277060484Sobrien	  int size;
277160484Sobrien	  int offset;
277260484Sobrien	  fixS *fixP;
277360484Sobrien
277489857Sobrien	  reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc);
277560484Sobrien	  if (!reloc_howto)
277660484Sobrien	    abort ();
277760484Sobrien
277860484Sobrien	  size = bfd_get_reloc_size (reloc_howto);
277960484Sobrien	  offset = target_big_endian ? (4 - size) : 0;
278060484Sobrien
278160484Sobrien	  if (size < 1 || size > 4)
278277298Sobrien	    abort ();
278360484Sobrien
278489857Sobrien	  fixP = fix_new_exp (frag_now,
278589857Sobrien			      f - frag_now->fr_literal + offset,
278689857Sobrien			      size,
278789857Sobrien			      &fixups[i].exp,
278889857Sobrien			      reloc_howto->pc_relative,
278960484Sobrien			      fixups[i].reloc);
279060484Sobrien
279160484Sobrien	  /* Turn off complaints that the addend is too large for things like
279260484Sobrien	     foo+100000@ha.  */
279360484Sobrien	  switch (fixups[i].reloc)
279460484Sobrien	    {
279560484Sobrien	    case BFD_RELOC_16_GOTOFF:
279660484Sobrien	    case BFD_RELOC_PPC_TOC16:
279760484Sobrien	    case BFD_RELOC_LO16:
279860484Sobrien	    case BFD_RELOC_HI16:
279960484Sobrien	    case BFD_RELOC_HI16_S:
280089857Sobrien#ifdef OBJ_ELF
280189857Sobrien	    case BFD_RELOC_PPC64_HIGHER:
280289857Sobrien	    case BFD_RELOC_PPC64_HIGHER_S:
280389857Sobrien	    case BFD_RELOC_PPC64_HIGHEST:
280489857Sobrien	    case BFD_RELOC_PPC64_HIGHEST_S:
280589857Sobrien#endif
280660484Sobrien	      fixP->fx_no_overflow = 1;
280760484Sobrien	      break;
280860484Sobrien	    default:
280960484Sobrien	      break;
281060484Sobrien	    }
281160484Sobrien	}
281260484Sobrien      else
281389857Sobrien	fix_new_exp (frag_now,
281489857Sobrien		     f - frag_now->fr_literal,
281589857Sobrien		     4,
281660484Sobrien		     &fixups[i].exp,
281760484Sobrien		     (operand->flags & PPC_OPERAND_RELATIVE) != 0,
281860484Sobrien		     ((bfd_reloc_code_real_type)
281989857Sobrien		      (fixups[i].opindex + (int) BFD_RELOC_UNUSED)));
282060484Sobrien    }
282160484Sobrien}
282260484Sobrien
282360484Sobrien/* Handle a macro.  Gather all the operands, transform them as
282460484Sobrien   described by the macro, and call md_assemble recursively.  All the
282560484Sobrien   operands are separated by commas; we don't accept parentheses
282660484Sobrien   around operands here.  */
282760484Sobrien
282860484Sobrienstatic void
2829218822Sdimppc_macro (char *str, const struct powerpc_macro *macro)
283060484Sobrien{
283160484Sobrien  char *operands[10];
283260484Sobrien  unsigned int count;
283360484Sobrien  char *s;
283460484Sobrien  unsigned int len;
283560484Sobrien  const char *format;
2836218822Sdim  unsigned int arg;
283760484Sobrien  char *send;
283860484Sobrien  char *complete;
283960484Sobrien
284060484Sobrien  /* Gather the users operands into the operands array.  */
284160484Sobrien  count = 0;
284260484Sobrien  s = str;
284360484Sobrien  while (1)
284460484Sobrien    {
284560484Sobrien      if (count >= sizeof operands / sizeof operands[0])
284660484Sobrien	break;
284760484Sobrien      operands[count++] = s;
284860484Sobrien      s = strchr (s, ',');
284960484Sobrien      if (s == (char *) NULL)
285060484Sobrien	break;
285160484Sobrien      *s++ = '\0';
285277298Sobrien    }
285360484Sobrien
285460484Sobrien  if (count != macro->operands)
285560484Sobrien    {
285660484Sobrien      as_bad (_("wrong number of operands"));
285760484Sobrien      return;
285860484Sobrien    }
285960484Sobrien
286060484Sobrien  /* Work out how large the string must be (the size is unbounded
286160484Sobrien     because it includes user input).  */
286260484Sobrien  len = 0;
286360484Sobrien  format = macro->format;
286460484Sobrien  while (*format != '\0')
286560484Sobrien    {
286660484Sobrien      if (*format != '%')
286760484Sobrien	{
286860484Sobrien	  ++len;
286960484Sobrien	  ++format;
287060484Sobrien	}
287160484Sobrien      else
287260484Sobrien	{
287360484Sobrien	  arg = strtol (format + 1, &send, 10);
2874218822Sdim	  know (send != format && arg < count);
287560484Sobrien	  len += strlen (operands[arg]);
287660484Sobrien	  format = send;
287760484Sobrien	}
287860484Sobrien    }
287960484Sobrien
288060484Sobrien  /* Put the string together.  */
288160484Sobrien  complete = s = (char *) alloca (len + 1);
288260484Sobrien  format = macro->format;
288360484Sobrien  while (*format != '\0')
288460484Sobrien    {
288560484Sobrien      if (*format != '%')
288660484Sobrien	*s++ = *format++;
288760484Sobrien      else
288860484Sobrien	{
288960484Sobrien	  arg = strtol (format + 1, &send, 10);
289060484Sobrien	  strcpy (s, operands[arg]);
289160484Sobrien	  s += strlen (s);
289260484Sobrien	  format = send;
289360484Sobrien	}
289460484Sobrien    }
289560484Sobrien  *s = '\0';
289660484Sobrien
289760484Sobrien  /* Assemble the constructed instruction.  */
289860484Sobrien  md_assemble (complete);
289977298Sobrien}
290060484Sobrien
290160484Sobrien#ifdef OBJ_ELF
290289857Sobrien/* For ELF, add support for SHF_EXCLUDE and SHT_ORDERED.  */
290360484Sobrien
290460484Sobrienint
2905218822Sdimppc_section_letter (int letter, char **ptr_msg)
290660484Sobrien{
290760484Sobrien  if (letter == 'e')
290860484Sobrien    return SHF_EXCLUDE;
290960484Sobrien
2910104834Sobrien  *ptr_msg = _("Bad .section directive: want a,e,w,x,M,S,G,T in string");
2911130561Sobrien  return -1;
291260484Sobrien}
291360484Sobrien
291460484Sobrienint
2915218822Sdimppc_section_word (char *str, size_t len)
291660484Sobrien{
291760484Sobrien  if (len == 7 && strncmp (str, "exclude", 7) == 0)
291860484Sobrien    return SHF_EXCLUDE;
291960484Sobrien
292060484Sobrien  return -1;
292160484Sobrien}
292260484Sobrien
292360484Sobrienint
2924218822Sdimppc_section_type (char *str, size_t len)
292560484Sobrien{
292660484Sobrien  if (len == 7 && strncmp (str, "ordered", 7) == 0)
292760484Sobrien    return SHT_ORDERED;
292860484Sobrien
292960484Sobrien  return -1;
293060484Sobrien}
293160484Sobrien
293260484Sobrienint
2933218822Sdimppc_section_flags (int flags, int attr, int type)
293460484Sobrien{
293560484Sobrien  if (type == SHT_ORDERED)
293660484Sobrien    flags |= SEC_ALLOC | SEC_LOAD | SEC_SORT_ENTRIES;
293760484Sobrien
293860484Sobrien  if (attr & SHF_EXCLUDE)
293960484Sobrien    flags |= SEC_EXCLUDE;
294060484Sobrien
294160484Sobrien  return flags;
294260484Sobrien}
294360484Sobrien#endif /* OBJ_ELF */
294460484Sobrien
294560484Sobrien
294660484Sobrien/* Pseudo-op handling.  */
294760484Sobrien
294860484Sobrien/* The .byte pseudo-op.  This is similar to the normal .byte
294960484Sobrien   pseudo-op, but it can also take a single ASCII string.  */
295060484Sobrien
295160484Sobrienstatic void
2952218822Sdimppc_byte (int ignore ATTRIBUTE_UNUSED)
295360484Sobrien{
295460484Sobrien  if (*input_line_pointer != '\"')
295560484Sobrien    {
295660484Sobrien      cons (1);
295760484Sobrien      return;
295860484Sobrien    }
295960484Sobrien
296060484Sobrien  /* Gather characters.  A real double quote is doubled.  Unusual
296160484Sobrien     characters are not permitted.  */
296260484Sobrien  ++input_line_pointer;
296360484Sobrien  while (1)
296460484Sobrien    {
296560484Sobrien      char c;
296660484Sobrien
296760484Sobrien      c = *input_line_pointer++;
296860484Sobrien
296960484Sobrien      if (c == '\"')
297060484Sobrien	{
297160484Sobrien	  if (*input_line_pointer != '\"')
297260484Sobrien	    break;
297360484Sobrien	  ++input_line_pointer;
297460484Sobrien	}
297560484Sobrien
297660484Sobrien      FRAG_APPEND_1_CHAR (c);
297760484Sobrien    }
297860484Sobrien
297960484Sobrien  demand_empty_rest_of_line ();
298060484Sobrien}
298160484Sobrien
298260484Sobrien#ifdef OBJ_XCOFF
298360484Sobrien
298460484Sobrien/* XCOFF specific pseudo-op handling.  */
298560484Sobrien
298660484Sobrien/* This is set if we are creating a .stabx symbol, since we don't want
298760484Sobrien   to handle symbol suffixes for such symbols.  */
2988130561Sobrienstatic bfd_boolean ppc_stab_symbol;
298960484Sobrien
299060484Sobrien/* The .comm and .lcomm pseudo-ops for XCOFF.  XCOFF puts common
299160484Sobrien   symbols in the .bss segment as though they were local common
2992130561Sobrien   symbols, and uses a different smclas.  The native Aix 4.3.3 assembler
299380016Sobrien   aligns .comm and .lcomm to 4 bytes.  */
299460484Sobrien
299560484Sobrienstatic void
2996218822Sdimppc_comm (int lcomm)
299760484Sobrien{
299860484Sobrien  asection *current_seg = now_seg;
299960484Sobrien  subsegT current_subseg = now_subseg;
300060484Sobrien  char *name;
300160484Sobrien  char endc;
300260484Sobrien  char *end_name;
300360484Sobrien  offsetT size;
300460484Sobrien  offsetT align;
300560484Sobrien  symbolS *lcomm_sym = NULL;
300660484Sobrien  symbolS *sym;
300760484Sobrien  char *pfrag;
300860484Sobrien
300960484Sobrien  name = input_line_pointer;
301060484Sobrien  endc = get_symbol_end ();
301160484Sobrien  end_name = input_line_pointer;
301260484Sobrien  *end_name = endc;
301360484Sobrien
301460484Sobrien  if (*input_line_pointer != ',')
301560484Sobrien    {
301660484Sobrien      as_bad (_("missing size"));
301760484Sobrien      ignore_rest_of_line ();
301860484Sobrien      return;
301960484Sobrien    }
302060484Sobrien  ++input_line_pointer;
302160484Sobrien
302260484Sobrien  size = get_absolute_expression ();
302360484Sobrien  if (size < 0)
302460484Sobrien    {
302560484Sobrien      as_bad (_("negative size"));
302660484Sobrien      ignore_rest_of_line ();
302760484Sobrien      return;
302860484Sobrien    }
302960484Sobrien
303060484Sobrien  if (! lcomm)
303160484Sobrien    {
303260484Sobrien      /* The third argument to .comm is the alignment.  */
303360484Sobrien      if (*input_line_pointer != ',')
303480016Sobrien	align = 2;
303560484Sobrien      else
303660484Sobrien	{
303760484Sobrien	  ++input_line_pointer;
303860484Sobrien	  align = get_absolute_expression ();
303960484Sobrien	  if (align <= 0)
304060484Sobrien	    {
304160484Sobrien	      as_warn (_("ignoring bad alignment"));
304280016Sobrien	      align = 2;
304360484Sobrien	    }
304460484Sobrien	}
304560484Sobrien    }
304660484Sobrien  else
304760484Sobrien    {
304860484Sobrien      char *lcomm_name;
304960484Sobrien      char lcomm_endc;
305060484Sobrien
305180016Sobrien      if (size <= 4)
305260484Sobrien	align = 2;
305360484Sobrien      else
305460484Sobrien	align = 3;
305560484Sobrien
305660484Sobrien      /* The third argument to .lcomm appears to be the real local
305760484Sobrien	 common symbol to create.  References to the symbol named in
305860484Sobrien	 the first argument are turned into references to the third
305960484Sobrien	 argument.  */
306060484Sobrien      if (*input_line_pointer != ',')
306160484Sobrien	{
306260484Sobrien	  as_bad (_("missing real symbol name"));
306360484Sobrien	  ignore_rest_of_line ();
306460484Sobrien	  return;
306560484Sobrien	}
306660484Sobrien      ++input_line_pointer;
306760484Sobrien
306860484Sobrien      lcomm_name = input_line_pointer;
306960484Sobrien      lcomm_endc = get_symbol_end ();
307077298Sobrien
307160484Sobrien      lcomm_sym = symbol_find_or_make (lcomm_name);
307260484Sobrien
307360484Sobrien      *input_line_pointer = lcomm_endc;
307460484Sobrien    }
307560484Sobrien
307660484Sobrien  *end_name = '\0';
307760484Sobrien  sym = symbol_find_or_make (name);
307860484Sobrien  *end_name = endc;
307960484Sobrien
308060484Sobrien  if (S_IS_DEFINED (sym)
308160484Sobrien      || S_GET_VALUE (sym) != 0)
308260484Sobrien    {
308360484Sobrien      as_bad (_("attempt to redefine symbol"));
308460484Sobrien      ignore_rest_of_line ();
308560484Sobrien      return;
308660484Sobrien    }
308777298Sobrien
308860484Sobrien  record_alignment (bss_section, align);
308977298Sobrien
309060484Sobrien  if (! lcomm
309160484Sobrien      || ! S_IS_DEFINED (lcomm_sym))
309260484Sobrien    {
309360484Sobrien      symbolS *def_sym;
309460484Sobrien      offsetT def_size;
309560484Sobrien
309660484Sobrien      if (! lcomm)
309760484Sobrien	{
309860484Sobrien	  def_sym = sym;
309960484Sobrien	  def_size = size;
310060484Sobrien	  S_SET_EXTERNAL (sym);
310160484Sobrien	}
310260484Sobrien      else
310360484Sobrien	{
310460484Sobrien	  symbol_get_tc (lcomm_sym)->output = 1;
310560484Sobrien	  def_sym = lcomm_sym;
310660484Sobrien	  def_size = 0;
310760484Sobrien	}
310860484Sobrien
310960484Sobrien      subseg_set (bss_section, 1);
311060484Sobrien      frag_align (align, 0, 0);
311177298Sobrien
311260484Sobrien      symbol_set_frag (def_sym, frag_now);
311360484Sobrien      pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, def_sym,
311460484Sobrien			def_size, (char *) NULL);
311560484Sobrien      *pfrag = 0;
311660484Sobrien      S_SET_SEGMENT (def_sym, bss_section);
311760484Sobrien      symbol_get_tc (def_sym)->align = align;
311860484Sobrien    }
311960484Sobrien  else if (lcomm)
312060484Sobrien    {
312160484Sobrien      /* Align the size of lcomm_sym.  */
312260484Sobrien      symbol_get_frag (lcomm_sym)->fr_offset =
312360484Sobrien	((symbol_get_frag (lcomm_sym)->fr_offset + (1 << align) - 1)
312460484Sobrien	 &~ ((1 << align) - 1));
312560484Sobrien      if (align > symbol_get_tc (lcomm_sym)->align)
312660484Sobrien	symbol_get_tc (lcomm_sym)->align = align;
312760484Sobrien    }
312860484Sobrien
312960484Sobrien  if (lcomm)
313060484Sobrien    {
313160484Sobrien      /* Make sym an offset from lcomm_sym.  */
313260484Sobrien      S_SET_SEGMENT (sym, bss_section);
313360484Sobrien      symbol_set_frag (sym, symbol_get_frag (lcomm_sym));
313460484Sobrien      S_SET_VALUE (sym, symbol_get_frag (lcomm_sym)->fr_offset);
313560484Sobrien      symbol_get_frag (lcomm_sym)->fr_offset += size;
313660484Sobrien    }
313760484Sobrien
313860484Sobrien  subseg_set (current_seg, current_subseg);
313960484Sobrien
314060484Sobrien  demand_empty_rest_of_line ();
314160484Sobrien}
314260484Sobrien
314360484Sobrien/* The .csect pseudo-op.  This switches us into a different
314460484Sobrien   subsegment.  The first argument is a symbol whose value is the
314560484Sobrien   start of the .csect.  In COFF, csect symbols get special aux
314660484Sobrien   entries defined by the x_csect field of union internal_auxent.  The
314760484Sobrien   optional second argument is the alignment (the default is 2).  */
314860484Sobrien
314960484Sobrienstatic void
3150218822Sdimppc_csect (int ignore ATTRIBUTE_UNUSED)
315160484Sobrien{
315260484Sobrien  char *name;
315360484Sobrien  char endc;
315460484Sobrien  symbolS *sym;
3155130561Sobrien  offsetT align;
315660484Sobrien
315760484Sobrien  name = input_line_pointer;
315860484Sobrien  endc = get_symbol_end ();
315977298Sobrien
316060484Sobrien  sym = symbol_find_or_make (name);
316160484Sobrien
316260484Sobrien  *input_line_pointer = endc;
316360484Sobrien
316460484Sobrien  if (S_GET_NAME (sym)[0] == '\0')
316560484Sobrien    {
316660484Sobrien      /* An unnamed csect is assumed to be [PR].  */
316760484Sobrien      symbol_get_tc (sym)->class = XMC_PR;
316860484Sobrien    }
316960484Sobrien
3170130561Sobrien  align = 2;
317160484Sobrien  if (*input_line_pointer == ',')
317260484Sobrien    {
317360484Sobrien      ++input_line_pointer;
3174130561Sobrien      align = get_absolute_expression ();
317560484Sobrien    }
317660484Sobrien
3177130561Sobrien  ppc_change_csect (sym, align);
3178130561Sobrien
317960484Sobrien  demand_empty_rest_of_line ();
318060484Sobrien}
318160484Sobrien
318260484Sobrien/* Change to a different csect.  */
318360484Sobrien
318460484Sobrienstatic void
3185218822Sdimppc_change_csect (symbolS *sym, offsetT align)
318660484Sobrien{
318760484Sobrien  if (S_IS_DEFINED (sym))
318860484Sobrien    subseg_set (S_GET_SEGMENT (sym), symbol_get_tc (sym)->subseg);
318960484Sobrien  else
319060484Sobrien    {
319160484Sobrien      symbolS **list_ptr;
319260484Sobrien      int after_toc;
319360484Sobrien      int hold_chunksize;
319460484Sobrien      symbolS *list;
3195130561Sobrien      int is_code;
3196130561Sobrien      segT sec;
319760484Sobrien
319860484Sobrien      /* This is a new csect.  We need to look at the symbol class to
319960484Sobrien	 figure out whether it should go in the text section or the
320060484Sobrien	 data section.  */
320160484Sobrien      after_toc = 0;
3202130561Sobrien      is_code = 0;
320360484Sobrien      switch (symbol_get_tc (sym)->class)
320460484Sobrien	{
320560484Sobrien	case XMC_PR:
320660484Sobrien	case XMC_RO:
320760484Sobrien	case XMC_DB:
320860484Sobrien	case XMC_GL:
320960484Sobrien	case XMC_XO:
321060484Sobrien	case XMC_SV:
321160484Sobrien	case XMC_TI:
321260484Sobrien	case XMC_TB:
321360484Sobrien	  S_SET_SEGMENT (sym, text_section);
321460484Sobrien	  symbol_get_tc (sym)->subseg = ppc_text_subsegment;
321560484Sobrien	  ++ppc_text_subsegment;
321660484Sobrien	  list_ptr = &ppc_text_csects;
3217130561Sobrien	  is_code = 1;
321860484Sobrien	  break;
321960484Sobrien	case XMC_RW:
322060484Sobrien	case XMC_TC0:
322160484Sobrien	case XMC_TC:
322260484Sobrien	case XMC_DS:
322360484Sobrien	case XMC_UA:
322460484Sobrien	case XMC_BS:
322560484Sobrien	case XMC_UC:
322660484Sobrien	  if (ppc_toc_csect != NULL
322760484Sobrien	      && (symbol_get_tc (ppc_toc_csect)->subseg + 1
322860484Sobrien		  == ppc_data_subsegment))
322960484Sobrien	    after_toc = 1;
323060484Sobrien	  S_SET_SEGMENT (sym, data_section);
323160484Sobrien	  symbol_get_tc (sym)->subseg = ppc_data_subsegment;
323260484Sobrien	  ++ppc_data_subsegment;
323360484Sobrien	  list_ptr = &ppc_data_csects;
323460484Sobrien	  break;
323560484Sobrien	default:
323660484Sobrien	  abort ();
323760484Sobrien	}
323860484Sobrien
323960484Sobrien      /* We set the obstack chunk size to a small value before
324089857Sobrien	 changing subsegments, so that we don't use a lot of memory
324189857Sobrien	 space for what may be a small section.  */
324260484Sobrien      hold_chunksize = chunksize;
324360484Sobrien      chunksize = 64;
324460484Sobrien
3245130561Sobrien      sec = subseg_new (segment_name (S_GET_SEGMENT (sym)),
3246130561Sobrien			symbol_get_tc (sym)->subseg);
324760484Sobrien
324860484Sobrien      chunksize = hold_chunksize;
324960484Sobrien
325060484Sobrien      if (after_toc)
325160484Sobrien	ppc_after_toc_frag = frag_now;
325260484Sobrien
3253130561Sobrien      record_alignment (sec, align);
3254130561Sobrien      if (is_code)
3255130561Sobrien	frag_align_code (align, 0);
3256130561Sobrien      else
3257130561Sobrien	frag_align (align, 0, 0);
3258130561Sobrien
325960484Sobrien      symbol_set_frag (sym, frag_now);
326060484Sobrien      S_SET_VALUE (sym, (valueT) frag_now_fix ());
326160484Sobrien
3262130561Sobrien      symbol_get_tc (sym)->align = align;
326360484Sobrien      symbol_get_tc (sym)->output = 1;
326460484Sobrien      symbol_get_tc (sym)->within = sym;
326577298Sobrien
326660484Sobrien      for (list = *list_ptr;
326760484Sobrien	   symbol_get_tc (list)->next != (symbolS *) NULL;
326860484Sobrien	   list = symbol_get_tc (list)->next)
326960484Sobrien	;
327060484Sobrien      symbol_get_tc (list)->next = sym;
327177298Sobrien
327260484Sobrien      symbol_remove (sym, &symbol_rootP, &symbol_lastP);
327360484Sobrien      symbol_append (sym, symbol_get_tc (list)->within, &symbol_rootP,
327460484Sobrien		     &symbol_lastP);
327560484Sobrien    }
327660484Sobrien
327760484Sobrien  ppc_current_csect = sym;
327860484Sobrien}
327960484Sobrien
328060484Sobrien/* This function handles the .text and .data pseudo-ops.  These
328160484Sobrien   pseudo-ops aren't really used by XCOFF; we implement them for the
328260484Sobrien   convenience of people who aren't used to XCOFF.  */
328360484Sobrien
328460484Sobrienstatic void
3285218822Sdimppc_section (int type)
328660484Sobrien{
328760484Sobrien  const char *name;
328860484Sobrien  symbolS *sym;
328960484Sobrien
329060484Sobrien  if (type == 't')
329160484Sobrien    name = ".text[PR]";
329260484Sobrien  else if (type == 'd')
329360484Sobrien    name = ".data[RW]";
329460484Sobrien  else
329560484Sobrien    abort ();
329660484Sobrien
329760484Sobrien  sym = symbol_find_or_make (name);
329860484Sobrien
3299130561Sobrien  ppc_change_csect (sym, 2);
330060484Sobrien
330160484Sobrien  demand_empty_rest_of_line ();
330260484Sobrien}
330360484Sobrien
330460484Sobrien/* This function handles the .section pseudo-op.  This is mostly to
330560484Sobrien   give an error, since XCOFF only supports .text, .data and .bss, but
330660484Sobrien   we do permit the user to name the text or data section.  */
330760484Sobrien
330860484Sobrienstatic void
3309218822Sdimppc_named_section (int ignore ATTRIBUTE_UNUSED)
331060484Sobrien{
331160484Sobrien  char *user_name;
331260484Sobrien  const char *real_name;
331360484Sobrien  char c;
331460484Sobrien  symbolS *sym;
331560484Sobrien
331660484Sobrien  user_name = input_line_pointer;
331760484Sobrien  c = get_symbol_end ();
331860484Sobrien
331960484Sobrien  if (strcmp (user_name, ".text") == 0)
332060484Sobrien    real_name = ".text[PR]";
332160484Sobrien  else if (strcmp (user_name, ".data") == 0)
332260484Sobrien    real_name = ".data[RW]";
332360484Sobrien  else
332460484Sobrien    {
332560484Sobrien      as_bad (_("The XCOFF file format does not support arbitrary sections"));
332660484Sobrien      *input_line_pointer = c;
332760484Sobrien      ignore_rest_of_line ();
332860484Sobrien      return;
332960484Sobrien    }
333060484Sobrien
333160484Sobrien  *input_line_pointer = c;
333260484Sobrien
333360484Sobrien  sym = symbol_find_or_make (real_name);
333460484Sobrien
3335130561Sobrien  ppc_change_csect (sym, 2);
333660484Sobrien
333760484Sobrien  demand_empty_rest_of_line ();
333860484Sobrien}
333960484Sobrien
334060484Sobrien/* The .extern pseudo-op.  We create an undefined symbol.  */
334160484Sobrien
334260484Sobrienstatic void
3343218822Sdimppc_extern (int ignore ATTRIBUTE_UNUSED)
334460484Sobrien{
334560484Sobrien  char *name;
334660484Sobrien  char endc;
334760484Sobrien
334860484Sobrien  name = input_line_pointer;
334960484Sobrien  endc = get_symbol_end ();
335060484Sobrien
335160484Sobrien  (void) symbol_find_or_make (name);
335260484Sobrien
335360484Sobrien  *input_line_pointer = endc;
335460484Sobrien
335560484Sobrien  demand_empty_rest_of_line ();
335660484Sobrien}
335760484Sobrien
335860484Sobrien/* The .lglobl pseudo-op.  Keep the symbol in the symbol table.  */
335960484Sobrien
336060484Sobrienstatic void
3361218822Sdimppc_lglobl (int ignore ATTRIBUTE_UNUSED)
336260484Sobrien{
336360484Sobrien  char *name;
336460484Sobrien  char endc;
336560484Sobrien  symbolS *sym;
336660484Sobrien
336760484Sobrien  name = input_line_pointer;
336860484Sobrien  endc = get_symbol_end ();
336960484Sobrien
337060484Sobrien  sym = symbol_find_or_make (name);
337160484Sobrien
337260484Sobrien  *input_line_pointer = endc;
337360484Sobrien
337460484Sobrien  symbol_get_tc (sym)->output = 1;
337560484Sobrien
337660484Sobrien  demand_empty_rest_of_line ();
337760484Sobrien}
337860484Sobrien
337960484Sobrien/* The .rename pseudo-op.  The RS/6000 assembler can rename symbols,
338060484Sobrien   although I don't know why it bothers.  */
338160484Sobrien
338260484Sobrienstatic void
3383218822Sdimppc_rename (int ignore ATTRIBUTE_UNUSED)
338460484Sobrien{
338560484Sobrien  char *name;
338660484Sobrien  char endc;
338760484Sobrien  symbolS *sym;
338860484Sobrien  int len;
338960484Sobrien
339060484Sobrien  name = input_line_pointer;
339160484Sobrien  endc = get_symbol_end ();
339260484Sobrien
339360484Sobrien  sym = symbol_find_or_make (name);
339460484Sobrien
339560484Sobrien  *input_line_pointer = endc;
339660484Sobrien
339760484Sobrien  if (*input_line_pointer != ',')
339860484Sobrien    {
339960484Sobrien      as_bad (_("missing rename string"));
340060484Sobrien      ignore_rest_of_line ();
340160484Sobrien      return;
340260484Sobrien    }
340360484Sobrien  ++input_line_pointer;
340460484Sobrien
340560484Sobrien  symbol_get_tc (sym)->real_name = demand_copy_C_string (&len);
340660484Sobrien
340760484Sobrien  demand_empty_rest_of_line ();
340860484Sobrien}
340960484Sobrien
341060484Sobrien/* The .stabx pseudo-op.  This is similar to a normal .stabs
341160484Sobrien   pseudo-op, but slightly different.  A sample is
341260484Sobrien       .stabx "main:F-1",.main,142,0
341360484Sobrien   The first argument is the symbol name to create.  The second is the
341460484Sobrien   value, and the third is the storage class.  The fourth seems to be
341560484Sobrien   always zero, and I am assuming it is the type.  */
341660484Sobrien
341760484Sobrienstatic void
3418218822Sdimppc_stabx (int ignore ATTRIBUTE_UNUSED)
341960484Sobrien{
342060484Sobrien  char *name;
342160484Sobrien  int len;
342260484Sobrien  symbolS *sym;
342360484Sobrien  expressionS exp;
342460484Sobrien
342560484Sobrien  name = demand_copy_C_string (&len);
342660484Sobrien
342760484Sobrien  if (*input_line_pointer != ',')
342860484Sobrien    {
342960484Sobrien      as_bad (_("missing value"));
343060484Sobrien      return;
343160484Sobrien    }
343260484Sobrien  ++input_line_pointer;
343360484Sobrien
3434130561Sobrien  ppc_stab_symbol = TRUE;
343560484Sobrien  sym = symbol_make (name);
3436130561Sobrien  ppc_stab_symbol = FALSE;
343760484Sobrien
343860484Sobrien  symbol_get_tc (sym)->real_name = name;
343960484Sobrien
344060484Sobrien  (void) expression (&exp);
344160484Sobrien
344260484Sobrien  switch (exp.X_op)
344360484Sobrien    {
344460484Sobrien    case O_illegal:
344560484Sobrien    case O_absent:
344660484Sobrien    case O_big:
344760484Sobrien      as_bad (_("illegal .stabx expression; zero assumed"));
344860484Sobrien      exp.X_add_number = 0;
344960484Sobrien      /* Fall through.  */
345060484Sobrien    case O_constant:
345160484Sobrien      S_SET_VALUE (sym, (valueT) exp.X_add_number);
345260484Sobrien      symbol_set_frag (sym, &zero_address_frag);
345360484Sobrien      break;
345460484Sobrien
345560484Sobrien    case O_symbol:
345660484Sobrien      if (S_GET_SEGMENT (exp.X_add_symbol) == undefined_section)
345760484Sobrien	symbol_set_value_expression (sym, &exp);
345860484Sobrien      else
345960484Sobrien	{
346060484Sobrien	  S_SET_VALUE (sym,
346160484Sobrien		       exp.X_add_number + S_GET_VALUE (exp.X_add_symbol));
346260484Sobrien	  symbol_set_frag (sym, symbol_get_frag (exp.X_add_symbol));
346360484Sobrien	}
346460484Sobrien      break;
346560484Sobrien
346660484Sobrien    default:
346760484Sobrien      /* The value is some complex expression.  This will probably
346889857Sobrien	 fail at some later point, but this is probably the right
346989857Sobrien	 thing to do here.  */
347060484Sobrien      symbol_set_value_expression (sym, &exp);
347160484Sobrien      break;
347260484Sobrien    }
347360484Sobrien
347460484Sobrien  S_SET_SEGMENT (sym, ppc_coff_debug_section);
347560484Sobrien  symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING;
347660484Sobrien
347760484Sobrien  if (*input_line_pointer != ',')
347860484Sobrien    {
347960484Sobrien      as_bad (_("missing class"));
348060484Sobrien      return;
348160484Sobrien    }
348260484Sobrien  ++input_line_pointer;
348360484Sobrien
348460484Sobrien  S_SET_STORAGE_CLASS (sym, get_absolute_expression ());
348560484Sobrien
348660484Sobrien  if (*input_line_pointer != ',')
348760484Sobrien    {
348860484Sobrien      as_bad (_("missing type"));
348960484Sobrien      return;
349060484Sobrien    }
349160484Sobrien  ++input_line_pointer;
349260484Sobrien
349360484Sobrien  S_SET_DATA_TYPE (sym, get_absolute_expression ());
349460484Sobrien
349560484Sobrien  symbol_get_tc (sym)->output = 1;
349660484Sobrien
349778828Sobrien  if (S_GET_STORAGE_CLASS (sym) == C_STSYM) {
349889857Sobrien
349960484Sobrien    symbol_get_tc (sym)->within = ppc_current_block;
350060484Sobrien
350178828Sobrien    /* In this case :
350289857Sobrien
350378828Sobrien       .bs name
350478828Sobrien       .stabx	"z",arrays_,133,0
350578828Sobrien       .es
350689857Sobrien
350778828Sobrien       .comm arrays_,13768,3
350889857Sobrien
350978828Sobrien       resolve_symbol_value will copy the exp's "within" into sym's when the
351078828Sobrien       offset is 0.  Since this seems to be corner case problem,
351178828Sobrien       only do the correction for storage class C_STSYM.  A better solution
351289857Sobrien       would be to have the tc field updated in ppc_symbol_new_hook.  */
351389857Sobrien
351489857Sobrien    if (exp.X_op == O_symbol)
351578828Sobrien      {
351678828Sobrien	symbol_get_tc (exp.X_add_symbol)->within = ppc_current_block;
351778828Sobrien      }
351878828Sobrien  }
351978828Sobrien
352060484Sobrien  if (exp.X_op != O_symbol
352160484Sobrien      || ! S_IS_EXTERNAL (exp.X_add_symbol)
352260484Sobrien      || S_GET_SEGMENT (exp.X_add_symbol) != bss_section)
352360484Sobrien    ppc_frob_label (sym);
352460484Sobrien  else
352560484Sobrien    {
352660484Sobrien      symbol_remove (sym, &symbol_rootP, &symbol_lastP);
352760484Sobrien      symbol_append (sym, exp.X_add_symbol, &symbol_rootP, &symbol_lastP);
352860484Sobrien      if (symbol_get_tc (ppc_current_csect)->within == exp.X_add_symbol)
352960484Sobrien	symbol_get_tc (ppc_current_csect)->within = sym;
353060484Sobrien    }
353160484Sobrien
353260484Sobrien  demand_empty_rest_of_line ();
353360484Sobrien}
353460484Sobrien
353560484Sobrien/* The .function pseudo-op.  This takes several arguments.  The first
353660484Sobrien   argument seems to be the external name of the symbol.  The second
3537130561Sobrien   argument seems to be the label for the start of the function.  gcc
353860484Sobrien   uses the same name for both.  I have no idea what the third and
353960484Sobrien   fourth arguments are meant to be.  The optional fifth argument is
354060484Sobrien   an expression for the size of the function.  In COFF this symbol
354160484Sobrien   gets an aux entry like that used for a csect.  */
354260484Sobrien
354360484Sobrienstatic void
3544218822Sdimppc_function (int ignore ATTRIBUTE_UNUSED)
354560484Sobrien{
354660484Sobrien  char *name;
354760484Sobrien  char endc;
354860484Sobrien  char *s;
354960484Sobrien  symbolS *ext_sym;
355060484Sobrien  symbolS *lab_sym;
355160484Sobrien
355260484Sobrien  name = input_line_pointer;
355360484Sobrien  endc = get_symbol_end ();
355460484Sobrien
355560484Sobrien  /* Ignore any [PR] suffix.  */
355660484Sobrien  name = ppc_canonicalize_symbol_name (name);
355760484Sobrien  s = strchr (name, '[');
355860484Sobrien  if (s != (char *) NULL
355960484Sobrien      && strcmp (s + 1, "PR]") == 0)
356060484Sobrien    *s = '\0';
356160484Sobrien
356260484Sobrien  ext_sym = symbol_find_or_make (name);
356360484Sobrien
356460484Sobrien  *input_line_pointer = endc;
356560484Sobrien
356660484Sobrien  if (*input_line_pointer != ',')
356760484Sobrien    {
356860484Sobrien      as_bad (_("missing symbol name"));
356960484Sobrien      ignore_rest_of_line ();
357060484Sobrien      return;
357160484Sobrien    }
357260484Sobrien  ++input_line_pointer;
357360484Sobrien
357460484Sobrien  name = input_line_pointer;
357560484Sobrien  endc = get_symbol_end ();
357660484Sobrien
357760484Sobrien  lab_sym = symbol_find_or_make (name);
357860484Sobrien
357960484Sobrien  *input_line_pointer = endc;
358060484Sobrien
358160484Sobrien  if (ext_sym != lab_sym)
358260484Sobrien    {
358360484Sobrien      expressionS exp;
358460484Sobrien
358560484Sobrien      exp.X_op = O_symbol;
358660484Sobrien      exp.X_add_symbol = lab_sym;
358760484Sobrien      exp.X_op_symbol = NULL;
358860484Sobrien      exp.X_add_number = 0;
358960484Sobrien      exp.X_unsigned = 0;
359060484Sobrien      symbol_set_value_expression (ext_sym, &exp);
359160484Sobrien    }
359260484Sobrien
359360484Sobrien  if (symbol_get_tc (ext_sym)->class == -1)
359460484Sobrien    symbol_get_tc (ext_sym)->class = XMC_PR;
359560484Sobrien  symbol_get_tc (ext_sym)->output = 1;
359660484Sobrien
359760484Sobrien  if (*input_line_pointer == ',')
359860484Sobrien    {
359960484Sobrien      expressionS ignore;
360060484Sobrien
360160484Sobrien      /* Ignore the third argument.  */
360260484Sobrien      ++input_line_pointer;
360360484Sobrien      expression (&ignore);
360460484Sobrien      if (*input_line_pointer == ',')
360560484Sobrien	{
360660484Sobrien	  /* Ignore the fourth argument.  */
360760484Sobrien	  ++input_line_pointer;
360860484Sobrien	  expression (&ignore);
360960484Sobrien	  if (*input_line_pointer == ',')
361060484Sobrien	    {
361160484Sobrien	      /* The fifth argument is the function size.  */
361260484Sobrien	      ++input_line_pointer;
361360484Sobrien	      symbol_get_tc (ext_sym)->size = symbol_new ("L0\001",
361460484Sobrien							  absolute_section,
361560484Sobrien							  (valueT) 0,
361660484Sobrien							  &zero_address_frag);
361760484Sobrien	      pseudo_set (symbol_get_tc (ext_sym)->size);
361860484Sobrien	    }
361960484Sobrien	}
362060484Sobrien    }
362160484Sobrien
362260484Sobrien  S_SET_DATA_TYPE (ext_sym, DT_FCN << N_BTSHFT);
362360484Sobrien  SF_SET_FUNCTION (ext_sym);
362460484Sobrien  SF_SET_PROCESS (ext_sym);
362560484Sobrien  coff_add_linesym (ext_sym);
362660484Sobrien
362760484Sobrien  demand_empty_rest_of_line ();
362860484Sobrien}
362960484Sobrien
363060484Sobrien/* The .bf pseudo-op.  This is just like a COFF C_FCN symbol named
363189857Sobrien   ".bf".  If the pseudo op .bi was seen before .bf, patch the .bi sym
363289857Sobrien   with the correct line number */
3633104834Sobrien
363489857Sobrienstatic symbolS *saved_bi_sym = 0;
363560484Sobrien
363660484Sobrienstatic void
3637218822Sdimppc_bf (int ignore ATTRIBUTE_UNUSED)
363860484Sobrien{
363960484Sobrien  symbolS *sym;
364060484Sobrien
364160484Sobrien  sym = symbol_make (".bf");
364260484Sobrien  S_SET_SEGMENT (sym, text_section);
364360484Sobrien  symbol_set_frag (sym, frag_now);
364460484Sobrien  S_SET_VALUE (sym, frag_now_fix ());
364560484Sobrien  S_SET_STORAGE_CLASS (sym, C_FCN);
364660484Sobrien
364760484Sobrien  coff_line_base = get_absolute_expression ();
364860484Sobrien
364960484Sobrien  S_SET_NUMBER_AUXILIARY (sym, 1);
365060484Sobrien  SA_SET_SYM_LNNO (sym, coff_line_base);
365160484Sobrien
365289857Sobrien  /* Line number for bi.  */
3653104834Sobrien  if (saved_bi_sym)
365489857Sobrien    {
365589857Sobrien      S_SET_VALUE (saved_bi_sym, coff_n_line_nos);
365689857Sobrien      saved_bi_sym = 0;
365789857Sobrien    }
365889857Sobrien
3659104834Sobrien
366060484Sobrien  symbol_get_tc (sym)->output = 1;
366160484Sobrien
366260484Sobrien  ppc_frob_label (sym);
366360484Sobrien
366460484Sobrien  demand_empty_rest_of_line ();
366560484Sobrien}
366660484Sobrien
366760484Sobrien/* The .ef pseudo-op.  This is just like a COFF C_FCN symbol named
366860484Sobrien   ".ef", except that the line number is absolute, not relative to the
366960484Sobrien   most recent ".bf" symbol.  */
367060484Sobrien
367160484Sobrienstatic void
3672218822Sdimppc_ef (int ignore ATTRIBUTE_UNUSED)
367360484Sobrien{
367460484Sobrien  symbolS *sym;
367560484Sobrien
367660484Sobrien  sym = symbol_make (".ef");
367760484Sobrien  S_SET_SEGMENT (sym, text_section);
367860484Sobrien  symbol_set_frag (sym, frag_now);
367960484Sobrien  S_SET_VALUE (sym, frag_now_fix ());
368060484Sobrien  S_SET_STORAGE_CLASS (sym, C_FCN);
368160484Sobrien  S_SET_NUMBER_AUXILIARY (sym, 1);
368260484Sobrien  SA_SET_SYM_LNNO (sym, get_absolute_expression ());
368360484Sobrien  symbol_get_tc (sym)->output = 1;
368460484Sobrien
368560484Sobrien  ppc_frob_label (sym);
368660484Sobrien
368760484Sobrien  demand_empty_rest_of_line ();
368860484Sobrien}
368960484Sobrien
369060484Sobrien/* The .bi and .ei pseudo-ops.  These take a string argument and
369160484Sobrien   generates a C_BINCL or C_EINCL symbol, which goes at the start of
369289857Sobrien   the symbol list.  The value of .bi will be know when the next .bf
369389857Sobrien   is encountered.  */
369460484Sobrien
369560484Sobrienstatic void
3696218822Sdimppc_biei (int ei)
369760484Sobrien{
369860484Sobrien  static symbolS *last_biei;
369960484Sobrien
370060484Sobrien  char *name;
370160484Sobrien  int len;
370260484Sobrien  symbolS *sym;
370360484Sobrien  symbolS *look;
370460484Sobrien
370560484Sobrien  name = demand_copy_C_string (&len);
370660484Sobrien
370760484Sobrien  /* The value of these symbols is actually file offset.  Here we set
370860484Sobrien     the value to the index into the line number entries.  In
370960484Sobrien     ppc_frob_symbols we set the fix_line field, which will cause BFD
371060484Sobrien     to do the right thing.  */
371160484Sobrien
371260484Sobrien  sym = symbol_make (name);
371360484Sobrien  /* obj-coff.c currently only handles line numbers correctly in the
371460484Sobrien     .text section.  */
371560484Sobrien  S_SET_SEGMENT (sym, text_section);
371660484Sobrien  S_SET_VALUE (sym, coff_n_line_nos);
371760484Sobrien  symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING;
371860484Sobrien
371960484Sobrien  S_SET_STORAGE_CLASS (sym, ei ? C_EINCL : C_BINCL);
372060484Sobrien  symbol_get_tc (sym)->output = 1;
372177298Sobrien
372289857Sobrien  /* Save bi.  */
3723104834Sobrien  if (ei)
372489857Sobrien    saved_bi_sym = 0;
372589857Sobrien  else
372689857Sobrien    saved_bi_sym = sym;
372789857Sobrien
372860484Sobrien  for (look = last_biei ? last_biei : symbol_rootP;
372960484Sobrien       (look != (symbolS *) NULL
373060484Sobrien	&& (S_GET_STORAGE_CLASS (look) == C_FILE
373160484Sobrien	    || S_GET_STORAGE_CLASS (look) == C_BINCL
373260484Sobrien	    || S_GET_STORAGE_CLASS (look) == C_EINCL));
373360484Sobrien       look = symbol_next (look))
373460484Sobrien    ;
373560484Sobrien  if (look != (symbolS *) NULL)
373660484Sobrien    {
373760484Sobrien      symbol_remove (sym, &symbol_rootP, &symbol_lastP);
373860484Sobrien      symbol_insert (sym, look, &symbol_rootP, &symbol_lastP);
373960484Sobrien      last_biei = sym;
374060484Sobrien    }
374160484Sobrien
374260484Sobrien  demand_empty_rest_of_line ();
374360484Sobrien}
374460484Sobrien
374560484Sobrien/* The .bs pseudo-op.  This generates a C_BSTAT symbol named ".bs".
374660484Sobrien   There is one argument, which is a csect symbol.  The value of the
374760484Sobrien   .bs symbol is the index of this csect symbol.  */
374860484Sobrien
374960484Sobrienstatic void
3750218822Sdimppc_bs (int ignore ATTRIBUTE_UNUSED)
375160484Sobrien{
375260484Sobrien  char *name;
375360484Sobrien  char endc;
375460484Sobrien  symbolS *csect;
375560484Sobrien  symbolS *sym;
375660484Sobrien
375760484Sobrien  if (ppc_current_block != NULL)
375860484Sobrien    as_bad (_("nested .bs blocks"));
375960484Sobrien
376060484Sobrien  name = input_line_pointer;
376160484Sobrien  endc = get_symbol_end ();
376260484Sobrien
376360484Sobrien  csect = symbol_find_or_make (name);
376460484Sobrien
376560484Sobrien  *input_line_pointer = endc;
376660484Sobrien
376760484Sobrien  sym = symbol_make (".bs");
376860484Sobrien  S_SET_SEGMENT (sym, now_seg);
376960484Sobrien  S_SET_STORAGE_CLASS (sym, C_BSTAT);
377060484Sobrien  symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING;
377160484Sobrien  symbol_get_tc (sym)->output = 1;
377260484Sobrien
377360484Sobrien  symbol_get_tc (sym)->within = csect;
377460484Sobrien
377560484Sobrien  ppc_frob_label (sym);
377660484Sobrien
377760484Sobrien  ppc_current_block = sym;
377860484Sobrien
377960484Sobrien  demand_empty_rest_of_line ();
378060484Sobrien}
378160484Sobrien
378260484Sobrien/* The .es pseudo-op.  Generate a C_ESTART symbol named .es.  */
378360484Sobrien
378460484Sobrienstatic void
3785218822Sdimppc_es (int ignore ATTRIBUTE_UNUSED)
378660484Sobrien{
378760484Sobrien  symbolS *sym;
378860484Sobrien
378960484Sobrien  if (ppc_current_block == NULL)
379060484Sobrien    as_bad (_(".es without preceding .bs"));
379160484Sobrien
379260484Sobrien  sym = symbol_make (".es");
379360484Sobrien  S_SET_SEGMENT (sym, now_seg);
379460484Sobrien  S_SET_STORAGE_CLASS (sym, C_ESTAT);
379560484Sobrien  symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING;
379660484Sobrien  symbol_get_tc (sym)->output = 1;
379760484Sobrien
379860484Sobrien  ppc_frob_label (sym);
379960484Sobrien
380060484Sobrien  ppc_current_block = NULL;
380160484Sobrien
380260484Sobrien  demand_empty_rest_of_line ();
380360484Sobrien}
380460484Sobrien
380560484Sobrien/* The .bb pseudo-op.  Generate a C_BLOCK symbol named .bb, with a
380660484Sobrien   line number.  */
380760484Sobrien
380860484Sobrienstatic void
3809218822Sdimppc_bb (int ignore ATTRIBUTE_UNUSED)
381060484Sobrien{
381160484Sobrien  symbolS *sym;
381260484Sobrien
381360484Sobrien  sym = symbol_make (".bb");
381460484Sobrien  S_SET_SEGMENT (sym, text_section);
381560484Sobrien  symbol_set_frag (sym, frag_now);
381660484Sobrien  S_SET_VALUE (sym, frag_now_fix ());
381760484Sobrien  S_SET_STORAGE_CLASS (sym, C_BLOCK);
381860484Sobrien
381960484Sobrien  S_SET_NUMBER_AUXILIARY (sym, 1);
382060484Sobrien  SA_SET_SYM_LNNO (sym, get_absolute_expression ());
382160484Sobrien
382260484Sobrien  symbol_get_tc (sym)->output = 1;
382360484Sobrien
382460484Sobrien  SF_SET_PROCESS (sym);
382560484Sobrien
382660484Sobrien  ppc_frob_label (sym);
382760484Sobrien
382860484Sobrien  demand_empty_rest_of_line ();
382960484Sobrien}
383060484Sobrien
383160484Sobrien/* The .eb pseudo-op.  Generate a C_BLOCK symbol named .eb, with a
383260484Sobrien   line number.  */
383360484Sobrien
383460484Sobrienstatic void
3835218822Sdimppc_eb (int ignore ATTRIBUTE_UNUSED)
383660484Sobrien{
383760484Sobrien  symbolS *sym;
383860484Sobrien
383960484Sobrien  sym = symbol_make (".eb");
384060484Sobrien  S_SET_SEGMENT (sym, text_section);
384160484Sobrien  symbol_set_frag (sym, frag_now);
384260484Sobrien  S_SET_VALUE (sym, frag_now_fix ());
384360484Sobrien  S_SET_STORAGE_CLASS (sym, C_BLOCK);
384460484Sobrien  S_SET_NUMBER_AUXILIARY (sym, 1);
384560484Sobrien  SA_SET_SYM_LNNO (sym, get_absolute_expression ());
384660484Sobrien  symbol_get_tc (sym)->output = 1;
384760484Sobrien
384860484Sobrien  SF_SET_PROCESS (sym);
384960484Sobrien
385060484Sobrien  ppc_frob_label (sym);
385160484Sobrien
385260484Sobrien  demand_empty_rest_of_line ();
385360484Sobrien}
385460484Sobrien
385560484Sobrien/* The .bc pseudo-op.  This just creates a C_BCOMM symbol with a
385660484Sobrien   specified name.  */
385760484Sobrien
385860484Sobrienstatic void
3859218822Sdimppc_bc (int ignore ATTRIBUTE_UNUSED)
386060484Sobrien{
386160484Sobrien  char *name;
386260484Sobrien  int len;
386360484Sobrien  symbolS *sym;
386460484Sobrien
386560484Sobrien  name = demand_copy_C_string (&len);
386660484Sobrien  sym = symbol_make (name);
386760484Sobrien  S_SET_SEGMENT (sym, ppc_coff_debug_section);
386860484Sobrien  symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING;
386960484Sobrien  S_SET_STORAGE_CLASS (sym, C_BCOMM);
387060484Sobrien  S_SET_VALUE (sym, 0);
387160484Sobrien  symbol_get_tc (sym)->output = 1;
387260484Sobrien
387360484Sobrien  ppc_frob_label (sym);
387460484Sobrien
387560484Sobrien  demand_empty_rest_of_line ();
387660484Sobrien}
387760484Sobrien
387860484Sobrien/* The .ec pseudo-op.  This just creates a C_ECOMM symbol.  */
387960484Sobrien
388060484Sobrienstatic void
3881218822Sdimppc_ec (int ignore ATTRIBUTE_UNUSED)
388260484Sobrien{
388360484Sobrien  symbolS *sym;
388460484Sobrien
388560484Sobrien  sym = symbol_make (".ec");
388660484Sobrien  S_SET_SEGMENT (sym, ppc_coff_debug_section);
388760484Sobrien  symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING;
388860484Sobrien  S_SET_STORAGE_CLASS (sym, C_ECOMM);
388960484Sobrien  S_SET_VALUE (sym, 0);
389060484Sobrien  symbol_get_tc (sym)->output = 1;
389160484Sobrien
389260484Sobrien  ppc_frob_label (sym);
389360484Sobrien
389460484Sobrien  demand_empty_rest_of_line ();
389560484Sobrien}
389660484Sobrien
389760484Sobrien/* The .toc pseudo-op.  Switch to the .toc subsegment.  */
389860484Sobrien
389960484Sobrienstatic void
3900218822Sdimppc_toc (int ignore ATTRIBUTE_UNUSED)
390160484Sobrien{
390260484Sobrien  if (ppc_toc_csect != (symbolS *) NULL)
390360484Sobrien    subseg_set (data_section, symbol_get_tc (ppc_toc_csect)->subseg);
390460484Sobrien  else
390560484Sobrien    {
390660484Sobrien      subsegT subseg;
390760484Sobrien      symbolS *sym;
390860484Sobrien      symbolS *list;
390977298Sobrien
391060484Sobrien      subseg = ppc_data_subsegment;
391160484Sobrien      ++ppc_data_subsegment;
391260484Sobrien
391360484Sobrien      subseg_new (segment_name (data_section), subseg);
391460484Sobrien      ppc_toc_frag = frag_now;
391560484Sobrien
391660484Sobrien      sym = symbol_find_or_make ("TOC[TC0]");
391760484Sobrien      symbol_set_frag (sym, frag_now);
391860484Sobrien      S_SET_SEGMENT (sym, data_section);
391960484Sobrien      S_SET_VALUE (sym, (valueT) frag_now_fix ());
392060484Sobrien      symbol_get_tc (sym)->subseg = subseg;
392160484Sobrien      symbol_get_tc (sym)->output = 1;
392260484Sobrien      symbol_get_tc (sym)->within = sym;
392360484Sobrien
392460484Sobrien      ppc_toc_csect = sym;
392577298Sobrien
392660484Sobrien      for (list = ppc_data_csects;
392760484Sobrien	   symbol_get_tc (list)->next != (symbolS *) NULL;
392860484Sobrien	   list = symbol_get_tc (list)->next)
392960484Sobrien	;
393060484Sobrien      symbol_get_tc (list)->next = sym;
393160484Sobrien
393260484Sobrien      symbol_remove (sym, &symbol_rootP, &symbol_lastP);
393360484Sobrien      symbol_append (sym, symbol_get_tc (list)->within, &symbol_rootP,
393460484Sobrien		     &symbol_lastP);
393560484Sobrien    }
393660484Sobrien
393760484Sobrien  ppc_current_csect = ppc_toc_csect;
393860484Sobrien
393960484Sobrien  demand_empty_rest_of_line ();
394060484Sobrien}
394160484Sobrien
394260484Sobrien/* The AIX assembler automatically aligns the operands of a .long or
394360484Sobrien   .short pseudo-op, and we want to be compatible.  */
394460484Sobrien
394560484Sobrienstatic void
3946218822Sdimppc_xcoff_cons (int log_size)
394760484Sobrien{
394860484Sobrien  frag_align (log_size, 0, 0);
394960484Sobrien  record_alignment (now_seg, log_size);
395060484Sobrien  cons (1 << log_size);
395160484Sobrien}
395260484Sobrien
395360484Sobrienstatic void
3954218822Sdimppc_vbyte (int dummy ATTRIBUTE_UNUSED)
395560484Sobrien{
395660484Sobrien  expressionS exp;
395760484Sobrien  int byte_count;
395860484Sobrien
395960484Sobrien  (void) expression (&exp);
396060484Sobrien
396160484Sobrien  if (exp.X_op != O_constant)
396260484Sobrien    {
396360484Sobrien      as_bad (_("non-constant byte count"));
396460484Sobrien      return;
396560484Sobrien    }
396660484Sobrien
396760484Sobrien  byte_count = exp.X_add_number;
396860484Sobrien
396960484Sobrien  if (*input_line_pointer != ',')
397060484Sobrien    {
397160484Sobrien      as_bad (_("missing value"));
397260484Sobrien      return;
397360484Sobrien    }
397460484Sobrien
397560484Sobrien  ++input_line_pointer;
397660484Sobrien  cons (byte_count);
397760484Sobrien}
397860484Sobrien
397960484Sobrien#endif /* OBJ_XCOFF */
398089857Sobrien#if defined (OBJ_XCOFF) || defined (OBJ_ELF)
398160484Sobrien
398260484Sobrien/* The .tc pseudo-op.  This is used when generating either XCOFF or
398360484Sobrien   ELF.  This takes two or more arguments.
398460484Sobrien
398560484Sobrien   When generating XCOFF output, the first argument is the name to
398660484Sobrien   give to this location in the toc; this will be a symbol with class
398789857Sobrien   TC.  The rest of the arguments are N-byte values to actually put at
398860484Sobrien   this location in the TOC; often there is just one more argument, a
3989130561Sobrien   relocatable symbol reference.  The size of the value to store
399089857Sobrien   depends on target word size.  A 32-bit target uses 4-byte values, a
399189857Sobrien   64-bit target uses 8-byte values.
399260484Sobrien
399360484Sobrien   When not generating XCOFF output, the arguments are the same, but
399460484Sobrien   the first argument is simply ignored.  */
399560484Sobrien
399660484Sobrienstatic void
3997218822Sdimppc_tc (int ignore ATTRIBUTE_UNUSED)
399860484Sobrien{
399960484Sobrien#ifdef OBJ_XCOFF
400060484Sobrien
400160484Sobrien  /* Define the TOC symbol name.  */
400260484Sobrien  {
400360484Sobrien    char *name;
400460484Sobrien    char endc;
400560484Sobrien    symbolS *sym;
400660484Sobrien
400760484Sobrien    if (ppc_toc_csect == (symbolS *) NULL
400860484Sobrien	|| ppc_toc_csect != ppc_current_csect)
400960484Sobrien      {
401060484Sobrien	as_bad (_(".tc not in .toc section"));
401160484Sobrien	ignore_rest_of_line ();
401260484Sobrien	return;
401360484Sobrien      }
401460484Sobrien
401560484Sobrien    name = input_line_pointer;
401660484Sobrien    endc = get_symbol_end ();
401760484Sobrien
401860484Sobrien    sym = symbol_find_or_make (name);
401960484Sobrien
402060484Sobrien    *input_line_pointer = endc;
402160484Sobrien
402260484Sobrien    if (S_IS_DEFINED (sym))
402360484Sobrien      {
402460484Sobrien	symbolS *label;
402560484Sobrien
402660484Sobrien	label = symbol_get_tc (ppc_current_csect)->within;
402760484Sobrien	if (symbol_get_tc (label)->class != XMC_TC0)
402860484Sobrien	  {
402960484Sobrien	    as_bad (_(".tc with no label"));
403060484Sobrien	    ignore_rest_of_line ();
403160484Sobrien	    return;
403260484Sobrien	  }
403360484Sobrien
403460484Sobrien	S_SET_SEGMENT (label, S_GET_SEGMENT (sym));
403560484Sobrien	symbol_set_frag (label, symbol_get_frag (sym));
403660484Sobrien	S_SET_VALUE (label, S_GET_VALUE (sym));
403760484Sobrien
403860484Sobrien	while (! is_end_of_line[(unsigned char) *input_line_pointer])
403960484Sobrien	  ++input_line_pointer;
404060484Sobrien
404160484Sobrien	return;
404260484Sobrien      }
404360484Sobrien
404460484Sobrien    S_SET_SEGMENT (sym, now_seg);
404560484Sobrien    symbol_set_frag (sym, frag_now);
404660484Sobrien    S_SET_VALUE (sym, (valueT) frag_now_fix ());
404760484Sobrien    symbol_get_tc (sym)->class = XMC_TC;
404860484Sobrien    symbol_get_tc (sym)->output = 1;
404960484Sobrien
405060484Sobrien    ppc_frob_label (sym);
405160484Sobrien  }
405260484Sobrien
405389857Sobrien#endif /* OBJ_XCOFF */
405489857Sobrien#ifdef OBJ_ELF
405589857Sobrien  int align;
405660484Sobrien
405760484Sobrien  /* Skip the TOC symbol name.  */
405860484Sobrien  while (is_part_of_name (*input_line_pointer)
405960484Sobrien	 || *input_line_pointer == '['
406060484Sobrien	 || *input_line_pointer == ']'
406160484Sobrien	 || *input_line_pointer == '{'
406260484Sobrien	 || *input_line_pointer == '}')
406360484Sobrien    ++input_line_pointer;
406460484Sobrien
406589857Sobrien  /* Align to a four/eight byte boundary.  */
4066104834Sobrien  align = ppc_obj64 ? 3 : 2;
406789857Sobrien  frag_align (align, 0, 0);
406889857Sobrien  record_alignment (now_seg, align);
406989857Sobrien#endif /* OBJ_ELF */
407060484Sobrien
407160484Sobrien  if (*input_line_pointer != ',')
407260484Sobrien    demand_empty_rest_of_line ();
407360484Sobrien  else
407460484Sobrien    {
407560484Sobrien      ++input_line_pointer;
4076104834Sobrien      cons (ppc_obj64 ? 8 : 4);
407760484Sobrien    }
407860484Sobrien}
407989857Sobrien
408089857Sobrien/* Pseudo-op .machine.  */
408189857Sobrien
408289857Sobrienstatic void
4083218822Sdimppc_machine (int ignore ATTRIBUTE_UNUSED)
408489857Sobrien{
4085130561Sobrien  char *cpu_string;
4086130561Sobrien#define MAX_HISTORY 100
4087130561Sobrien  static unsigned long *cpu_history;
4088130561Sobrien  static int curr_hist;
4089130561Sobrien
4090130561Sobrien  SKIP_WHITESPACE ();
4091130561Sobrien
4092130561Sobrien  if (*input_line_pointer == '"')
4093130561Sobrien    {
4094130561Sobrien      int len;
4095130561Sobrien      cpu_string = demand_copy_C_string (&len);
4096130561Sobrien    }
4097130561Sobrien  else
4098130561Sobrien    {
4099130561Sobrien      char c;
4100130561Sobrien      cpu_string = input_line_pointer;
4101130561Sobrien      c = get_symbol_end ();
4102130561Sobrien      cpu_string = xstrdup (cpu_string);
4103130561Sobrien      *input_line_pointer = c;
4104130561Sobrien    }
4105130561Sobrien
4106130561Sobrien  if (cpu_string != NULL)
4107130561Sobrien    {
4108130561Sobrien      unsigned long old_cpu = ppc_cpu;
4109130561Sobrien      char *p;
4110130561Sobrien
4111130561Sobrien      for (p = cpu_string; *p != 0; p++)
4112130561Sobrien	*p = TOLOWER (*p);
4113130561Sobrien
4114130561Sobrien      if (strcmp (cpu_string, "push") == 0)
4115130561Sobrien	{
4116130561Sobrien	  if (cpu_history == NULL)
4117130561Sobrien	    cpu_history = xmalloc (MAX_HISTORY * sizeof (*cpu_history));
4118130561Sobrien
4119130561Sobrien	  if (curr_hist >= MAX_HISTORY)
4120130561Sobrien	    as_bad (_(".machine stack overflow"));
4121130561Sobrien	  else
4122130561Sobrien	    cpu_history[curr_hist++] = ppc_cpu;
4123130561Sobrien	}
4124130561Sobrien      else if (strcmp (cpu_string, "pop") == 0)
4125130561Sobrien	{
4126130561Sobrien	  if (curr_hist <= 0)
4127130561Sobrien	    as_bad (_(".machine stack underflow"));
4128130561Sobrien	  else
4129130561Sobrien	    ppc_cpu = cpu_history[--curr_hist];
4130130561Sobrien	}
4131130561Sobrien      else if (parse_cpu (cpu_string))
4132130561Sobrien	;
4133130561Sobrien      else
4134130561Sobrien	as_bad (_("invalid machine `%s'"), cpu_string);
4135130561Sobrien
4136130561Sobrien      if (ppc_cpu != old_cpu)
4137130561Sobrien	ppc_setup_opcodes ();
4138130561Sobrien    }
4139130561Sobrien
4140130561Sobrien  demand_empty_rest_of_line ();
414189857Sobrien}
414289857Sobrien
414389857Sobrien/* See whether a symbol is in the TOC section.  */
414489857Sobrien
414589857Sobrienstatic int
4146218822Sdimppc_is_toc_sym (symbolS *sym)
414789857Sobrien{
414889857Sobrien#ifdef OBJ_XCOFF
414989857Sobrien  return symbol_get_tc (sym)->class == XMC_TC;
415089857Sobrien#endif
415189857Sobrien#ifdef OBJ_ELF
415289857Sobrien  const char *sname = segment_name (S_GET_SEGMENT (sym));
4153104834Sobrien  if (ppc_obj64)
415489857Sobrien    return strcmp (sname, ".toc") == 0;
415589857Sobrien  else
415689857Sobrien    return strcmp (sname, ".got") == 0;
415789857Sobrien#endif
415889857Sobrien}
415989857Sobrien#endif /* defined (OBJ_XCOFF) || defined (OBJ_ELF) */
416060484Sobrien
416160484Sobrien#ifdef TE_PE
416260484Sobrien
416389857Sobrien/* Pseudo-ops specific to the Windows NT PowerPC PE (coff) format.  */
416460484Sobrien
416560484Sobrien/* Set the current section.  */
416660484Sobrienstatic void
4167218822Sdimppc_set_current_section (segT new)
416860484Sobrien{
416960484Sobrien  ppc_previous_section = ppc_current_section;
417060484Sobrien  ppc_current_section = new;
417160484Sobrien}
417260484Sobrien
417360484Sobrien/* pseudo-op: .previous
417460484Sobrien   behaviour: toggles the current section with the previous section.
417560484Sobrien   errors:    None
417689857Sobrien   warnings:  "No previous section"  */
417789857Sobrien
417860484Sobrienstatic void
4179218822Sdimppc_previous (int ignore ATTRIBUTE_UNUSED)
418060484Sobrien{
418160484Sobrien  symbolS *tmp;
418260484Sobrien
418377298Sobrien  if (ppc_previous_section == NULL)
418460484Sobrien    {
418589857Sobrien      as_warn (_("No previous section to return to. Directive ignored."));
418660484Sobrien      return;
418760484Sobrien    }
418860484Sobrien
418989857Sobrien  subseg_set (ppc_previous_section, 0);
419060484Sobrien
419189857Sobrien  ppc_set_current_section (ppc_previous_section);
419260484Sobrien}
419360484Sobrien
419460484Sobrien/* pseudo-op: .pdata
419560484Sobrien   behaviour: predefined read only data section
4196130561Sobrien	      double word aligned
419760484Sobrien   errors:    None
419860484Sobrien   warnings:  None
419960484Sobrien   initial:   .section .pdata "adr3"
4200130561Sobrien	      a - don't know -- maybe a misprint
420160484Sobrien	      d - initialized data
420260484Sobrien	      r - readable
420360484Sobrien	      3 - double word aligned (that would be 4 byte boundary)
420460484Sobrien
420560484Sobrien   commentary:
420660484Sobrien   Tag index tables (also known as the function table) for exception
420789857Sobrien   handling, debugging, etc.  */
420860484Sobrien
420960484Sobrienstatic void
4210218822Sdimppc_pdata (int ignore ATTRIBUTE_UNUSED)
421160484Sobrien{
421277298Sobrien  if (pdata_section == 0)
421360484Sobrien    {
421460484Sobrien      pdata_section = subseg_new (".pdata", 0);
421577298Sobrien
421660484Sobrien      bfd_set_section_flags (stdoutput, pdata_section,
421760484Sobrien			     (SEC_ALLOC | SEC_LOAD | SEC_RELOC
421860484Sobrien			      | SEC_READONLY | SEC_DATA ));
421977298Sobrien
422060484Sobrien      bfd_set_section_alignment (stdoutput, pdata_section, 2);
422160484Sobrien    }
422260484Sobrien  else
422360484Sobrien    {
422489857Sobrien      pdata_section = subseg_new (".pdata", 0);
422560484Sobrien    }
422689857Sobrien  ppc_set_current_section (pdata_section);
422760484Sobrien}
422860484Sobrien
422960484Sobrien/* pseudo-op: .ydata
423060484Sobrien   behaviour: predefined read only data section
4231130561Sobrien	      double word aligned
423260484Sobrien   errors:    None
423360484Sobrien   warnings:  None
423460484Sobrien   initial:   .section .ydata "drw3"
4235130561Sobrien	      a - don't know -- maybe a misprint
423660484Sobrien	      d - initialized data
423760484Sobrien	      r - readable
423860484Sobrien	      3 - double word aligned (that would be 4 byte boundary)
423960484Sobrien   commentary:
424060484Sobrien   Tag tables (also known as the scope table) for exception handling,
424189857Sobrien   debugging, etc.  */
424289857Sobrien
424360484Sobrienstatic void
4244218822Sdimppc_ydata (int ignore ATTRIBUTE_UNUSED)
424560484Sobrien{
424677298Sobrien  if (ydata_section == 0)
424760484Sobrien    {
424860484Sobrien      ydata_section = subseg_new (".ydata", 0);
424960484Sobrien      bfd_set_section_flags (stdoutput, ydata_section,
425089857Sobrien			     (SEC_ALLOC | SEC_LOAD | SEC_RELOC
425189857Sobrien			      | SEC_READONLY | SEC_DATA ));
425260484Sobrien
425360484Sobrien      bfd_set_section_alignment (stdoutput, ydata_section, 3);
425460484Sobrien    }
425560484Sobrien  else
425660484Sobrien    {
425760484Sobrien      ydata_section = subseg_new (".ydata", 0);
425860484Sobrien    }
425989857Sobrien  ppc_set_current_section (ydata_section);
426060484Sobrien}
426160484Sobrien
426260484Sobrien/* pseudo-op: .reldata
426360484Sobrien   behaviour: predefined read write data section
4264130561Sobrien	      double word aligned (4-byte)
426560484Sobrien	      FIXME: relocation is applied to it
426660484Sobrien	      FIXME: what's the difference between this and .data?
426760484Sobrien   errors:    None
426860484Sobrien   warnings:  None
426960484Sobrien   initial:   .section .reldata "drw3"
427060484Sobrien	      d - initialized data
427160484Sobrien	      r - readable
427260484Sobrien	      w - writeable
427360484Sobrien	      3 - double word aligned (that would be 8 byte boundary)
427460484Sobrien
427560484Sobrien   commentary:
427660484Sobrien   Like .data, but intended to hold data subject to relocation, such as
427789857Sobrien   function descriptors, etc.  */
427889857Sobrien
427960484Sobrienstatic void
4280218822Sdimppc_reldata (int ignore ATTRIBUTE_UNUSED)
428160484Sobrien{
428260484Sobrien  if (reldata_section == 0)
428360484Sobrien    {
428460484Sobrien      reldata_section = subseg_new (".reldata", 0);
428560484Sobrien
428660484Sobrien      bfd_set_section_flags (stdoutput, reldata_section,
428789857Sobrien			     (SEC_ALLOC | SEC_LOAD | SEC_RELOC
428889857Sobrien			      | SEC_DATA));
428960484Sobrien
429060484Sobrien      bfd_set_section_alignment (stdoutput, reldata_section, 2);
429160484Sobrien    }
429260484Sobrien  else
429360484Sobrien    {
429460484Sobrien      reldata_section = subseg_new (".reldata", 0);
429560484Sobrien    }
429689857Sobrien  ppc_set_current_section (reldata_section);
429760484Sobrien}
429860484Sobrien
429960484Sobrien/* pseudo-op: .rdata
430060484Sobrien   behaviour: predefined read only data section
4301130561Sobrien	      double word aligned
430260484Sobrien   errors:    None
430360484Sobrien   warnings:  None
430460484Sobrien   initial:   .section .rdata "dr3"
430560484Sobrien	      d - initialized data
430660484Sobrien	      r - readable
430789857Sobrien	      3 - double word aligned (that would be 4 byte boundary)  */
430889857Sobrien
430960484Sobrienstatic void
4310218822Sdimppc_rdata (int ignore ATTRIBUTE_UNUSED)
431160484Sobrien{
431260484Sobrien  if (rdata_section == 0)
431360484Sobrien    {
431460484Sobrien      rdata_section = subseg_new (".rdata", 0);
431560484Sobrien      bfd_set_section_flags (stdoutput, rdata_section,
431660484Sobrien			     (SEC_ALLOC | SEC_LOAD | SEC_RELOC
431760484Sobrien			      | SEC_READONLY | SEC_DATA ));
431860484Sobrien
431960484Sobrien      bfd_set_section_alignment (stdoutput, rdata_section, 2);
432060484Sobrien    }
432160484Sobrien  else
432260484Sobrien    {
432360484Sobrien      rdata_section = subseg_new (".rdata", 0);
432460484Sobrien    }
432589857Sobrien  ppc_set_current_section (rdata_section);
432660484Sobrien}
432760484Sobrien
432860484Sobrien/* pseudo-op: .ualong
432977298Sobrien   behaviour: much like .int, with the exception that no alignment is
4330130561Sobrien	      performed.
433160484Sobrien	      FIXME: test the alignment statement
433260484Sobrien   errors:    None
433389857Sobrien   warnings:  None  */
433489857Sobrien
433560484Sobrienstatic void
4336218822Sdimppc_ualong (int ignore ATTRIBUTE_UNUSED)
433760484Sobrien{
433889857Sobrien  /* Try for long.  */
433989857Sobrien  cons (4);
434060484Sobrien}
434160484Sobrien
434260484Sobrien/* pseudo-op: .znop  <symbol name>
434360484Sobrien   behaviour: Issue a nop instruction
4344130561Sobrien	      Issue a IMAGE_REL_PPC_IFGLUE relocation against it, using
434560484Sobrien	      the supplied symbol name.
434660484Sobrien   errors:    None
434789857Sobrien   warnings:  Missing symbol name  */
434889857Sobrien
434960484Sobrienstatic void
4350218822Sdimppc_znop (int ignore ATTRIBUTE_UNUSED)
435160484Sobrien{
435260484Sobrien  unsigned long insn;
435360484Sobrien  const struct powerpc_opcode *opcode;
435460484Sobrien  expressionS ex;
435560484Sobrien  char *f;
435660484Sobrien  symbolS *sym;
435760484Sobrien  char *symbol_name;
435860484Sobrien  char c;
435960484Sobrien  char *name;
436060484Sobrien  unsigned int exp;
436160484Sobrien  flagword flags;
436260484Sobrien  asection *sec;
436360484Sobrien
436489857Sobrien  /* Strip out the symbol name.  */
436560484Sobrien  symbol_name = input_line_pointer;
436660484Sobrien  c = get_symbol_end ();
436760484Sobrien
436860484Sobrien  name = xmalloc (input_line_pointer - symbol_name + 1);
436960484Sobrien  strcpy (name, symbol_name);
437060484Sobrien
437160484Sobrien  sym = symbol_find_or_make (name);
437260484Sobrien
437360484Sobrien  *input_line_pointer = c;
437460484Sobrien
437560484Sobrien  SKIP_WHITESPACE ();
437660484Sobrien
437760484Sobrien  /* Look up the opcode in the hash table.  */
437860484Sobrien  opcode = (const struct powerpc_opcode *) hash_find (ppc_hash, "nop");
437960484Sobrien
438089857Sobrien  /* Stick in the nop.  */
438160484Sobrien  insn = opcode->opcode;
438260484Sobrien
438360484Sobrien  /* Write out the instruction.  */
438460484Sobrien  f = frag_more (4);
438560484Sobrien  md_number_to_chars (f, insn, 4);
438660484Sobrien  fix_new (frag_now,
438760484Sobrien	   f - frag_now->fr_literal,
438860484Sobrien	   4,
438960484Sobrien	   sym,
439060484Sobrien	   0,
439160484Sobrien	   0,
439260484Sobrien	   BFD_RELOC_16_GOT_PCREL);
439360484Sobrien
439460484Sobrien}
439560484Sobrien
439677298Sobrien/* pseudo-op:
439777298Sobrien   behaviour:
439877298Sobrien   errors:
439989857Sobrien   warnings:  */
440089857Sobrien
440160484Sobrienstatic void
4402218822Sdimppc_pe_comm (int lcomm)
440360484Sobrien{
4404218822Sdim  char *name;
4405218822Sdim  char c;
4406218822Sdim  char *p;
440760484Sobrien  offsetT temp;
4408218822Sdim  symbolS *symbolP;
440960484Sobrien  offsetT align;
441060484Sobrien
441160484Sobrien  name = input_line_pointer;
441260484Sobrien  c = get_symbol_end ();
441360484Sobrien
441489857Sobrien  /* just after name is now '\0'.  */
441560484Sobrien  p = input_line_pointer;
441660484Sobrien  *p = c;
441760484Sobrien  SKIP_WHITESPACE ();
441860484Sobrien  if (*input_line_pointer != ',')
441960484Sobrien    {
442060484Sobrien      as_bad (_("Expected comma after symbol-name: rest of line ignored."));
442160484Sobrien      ignore_rest_of_line ();
442260484Sobrien      return;
442360484Sobrien    }
442460484Sobrien
442560484Sobrien  input_line_pointer++;		/* skip ',' */
442660484Sobrien  if ((temp = get_absolute_expression ()) < 0)
442760484Sobrien    {
442860484Sobrien      as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) temp);
442960484Sobrien      ignore_rest_of_line ();
443060484Sobrien      return;
443160484Sobrien    }
443260484Sobrien
443360484Sobrien  if (! lcomm)
443460484Sobrien    {
443560484Sobrien      /* The third argument to .comm is the alignment.  */
443660484Sobrien      if (*input_line_pointer != ',')
443760484Sobrien	align = 3;
443860484Sobrien      else
443960484Sobrien	{
444060484Sobrien	  ++input_line_pointer;
444160484Sobrien	  align = get_absolute_expression ();
444260484Sobrien	  if (align <= 0)
444360484Sobrien	    {
444460484Sobrien	      as_warn (_("ignoring bad alignment"));
444560484Sobrien	      align = 3;
444660484Sobrien	    }
444760484Sobrien	}
444860484Sobrien    }
444960484Sobrien
445060484Sobrien  *p = 0;
445160484Sobrien  symbolP = symbol_find_or_make (name);
445260484Sobrien
445360484Sobrien  *p = c;
445460484Sobrien  if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP))
445560484Sobrien    {
445660484Sobrien      as_bad (_("Ignoring attempt to re-define symbol `%s'."),
445760484Sobrien	      S_GET_NAME (symbolP));
445860484Sobrien      ignore_rest_of_line ();
445960484Sobrien      return;
446060484Sobrien    }
446160484Sobrien
446260484Sobrien  if (S_GET_VALUE (symbolP))
446360484Sobrien    {
446460484Sobrien      if (S_GET_VALUE (symbolP) != (valueT) temp)
446560484Sobrien	as_bad (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."),
446660484Sobrien		S_GET_NAME (symbolP),
446760484Sobrien		(long) S_GET_VALUE (symbolP),
446860484Sobrien		(long) temp);
446960484Sobrien    }
447060484Sobrien  else
447160484Sobrien    {
447260484Sobrien      S_SET_VALUE (symbolP, (valueT) temp);
447360484Sobrien      S_SET_EXTERNAL (symbolP);
4474218822Sdim      S_SET_SEGMENT (symbolP, bfd_com_section_ptr);
447560484Sobrien    }
447660484Sobrien
447760484Sobrien  demand_empty_rest_of_line ();
447860484Sobrien}
447960484Sobrien
448060484Sobrien/*
448160484Sobrien * implement the .section pseudo op:
448260484Sobrien *	.section name {, "flags"}
448360484Sobrien *                ^         ^
448460484Sobrien *                |         +--- optional flags: 'b' for bss
448560484Sobrien *                |                              'i' for info
448660484Sobrien *                +-- section name               'l' for lib
448760484Sobrien *                                               'n' for noload
448860484Sobrien *                                               'o' for over
448960484Sobrien *                                               'w' for data
449060484Sobrien *						 'd' (apparently m88k for data)
449160484Sobrien *                                               'x' for text
449260484Sobrien * But if the argument is not a quoted string, treat it as a
449360484Sobrien * subsegment number.
449460484Sobrien *
449560484Sobrien * FIXME: this is a copy of the section processing from obj-coff.c, with
449660484Sobrien * additions/changes for the moto-pas assembler support. There are three
449760484Sobrien * categories:
449860484Sobrien *
449977298Sobrien * FIXME: I just noticed this. This doesn't work at all really. It it
450060484Sobrien *        setting bits that bfd probably neither understands or uses. The
450160484Sobrien *        correct approach (?) will have to incorporate extra fields attached
450260484Sobrien *        to the section to hold the system specific stuff. (krk)
450360484Sobrien *
450460484Sobrien * Section Contents:
450560484Sobrien * 'a' - unknown - referred to in documentation, but no definition supplied
450660484Sobrien * 'c' - section has code
450760484Sobrien * 'd' - section has initialized data
450860484Sobrien * 'u' - section has uninitialized data
450960484Sobrien * 'i' - section contains directives (info)
451060484Sobrien * 'n' - section can be discarded
451160484Sobrien * 'R' - remove section at link time
451260484Sobrien *
451360484Sobrien * Section Protection:
451460484Sobrien * 'r' - section is readable
451560484Sobrien * 'w' - section is writeable
451660484Sobrien * 'x' - section is executable
451760484Sobrien * 's' - section is sharable
451860484Sobrien *
451960484Sobrien * Section Alignment:
452060484Sobrien * '0' - align to byte boundary
452160484Sobrien * '1' - align to halfword undary
452260484Sobrien * '2' - align to word boundary
452360484Sobrien * '3' - align to doubleword boundary
452460484Sobrien * '4' - align to quadword boundary
452560484Sobrien * '5' - align to 32 byte boundary
452660484Sobrien * '6' - align to 64 byte boundary
452760484Sobrien *
452860484Sobrien */
452960484Sobrien
453060484Sobrienvoid
4531218822Sdimppc_pe_section (int ignore ATTRIBUTE_UNUSED)
453260484Sobrien{
453389857Sobrien  /* Strip out the section name.  */
453460484Sobrien  char *section_name;
453560484Sobrien  char c;
453660484Sobrien  char *name;
453760484Sobrien  unsigned int exp;
453860484Sobrien  flagword flags;
453960484Sobrien  segT sec;
454060484Sobrien  int align;
454160484Sobrien
454260484Sobrien  section_name = input_line_pointer;
454360484Sobrien  c = get_symbol_end ();
454460484Sobrien
454560484Sobrien  name = xmalloc (input_line_pointer - section_name + 1);
454660484Sobrien  strcpy (name, section_name);
454760484Sobrien
454860484Sobrien  *input_line_pointer = c;
454960484Sobrien
455060484Sobrien  SKIP_WHITESPACE ();
455160484Sobrien
455260484Sobrien  exp = 0;
455360484Sobrien  flags = SEC_NO_FLAGS;
455460484Sobrien
455560484Sobrien  if (strcmp (name, ".idata$2") == 0)
455660484Sobrien    {
455760484Sobrien      align = 0;
455860484Sobrien    }
455960484Sobrien  else if (strcmp (name, ".idata$3") == 0)
456060484Sobrien    {
456160484Sobrien      align = 0;
456260484Sobrien    }
456360484Sobrien  else if (strcmp (name, ".idata$4") == 0)
456460484Sobrien    {
456560484Sobrien      align = 2;
456660484Sobrien    }
456760484Sobrien  else if (strcmp (name, ".idata$5") == 0)
456860484Sobrien    {
456960484Sobrien      align = 2;
457060484Sobrien    }
457160484Sobrien  else if (strcmp (name, ".idata$6") == 0)
457260484Sobrien    {
457360484Sobrien      align = 1;
457460484Sobrien    }
457560484Sobrien  else
457689857Sobrien    /* Default alignment to 16 byte boundary.  */
457789857Sobrien    align = 4;
457860484Sobrien
457960484Sobrien  if (*input_line_pointer == ',')
458060484Sobrien    {
458160484Sobrien      ++input_line_pointer;
458260484Sobrien      SKIP_WHITESPACE ();
458360484Sobrien      if (*input_line_pointer != '"')
458460484Sobrien	exp = get_absolute_expression ();
458560484Sobrien      else
458660484Sobrien	{
458760484Sobrien	  ++input_line_pointer;
458860484Sobrien	  while (*input_line_pointer != '"'
458960484Sobrien		 && ! is_end_of_line[(unsigned char) *input_line_pointer])
459060484Sobrien	    {
459160484Sobrien	      switch (*input_line_pointer)
459260484Sobrien		{
459360484Sobrien		  /* Section Contents */
459460484Sobrien		case 'a': /* unknown */
459560484Sobrien		  as_bad (_("Unsupported section attribute -- 'a'"));
459660484Sobrien		  break;
459760484Sobrien		case 'c': /* code section */
459877298Sobrien		  flags |= SEC_CODE;
459960484Sobrien		  break;
460060484Sobrien		case 'd': /* section has initialized data */
460160484Sobrien		  flags |= SEC_DATA;
460260484Sobrien		  break;
460360484Sobrien		case 'u': /* section has uninitialized data */
460460484Sobrien		  /* FIXME: This is IMAGE_SCN_CNT_UNINITIALIZED_DATA
460560484Sobrien		     in winnt.h */
460660484Sobrien		  flags |= SEC_ROM;
460760484Sobrien		  break;
460860484Sobrien		case 'i': /* section contains directives (info) */
460960484Sobrien		  /* FIXME: This is IMAGE_SCN_LNK_INFO
461060484Sobrien		     in winnt.h */
461160484Sobrien		  flags |= SEC_HAS_CONTENTS;
461260484Sobrien		  break;
461360484Sobrien		case 'n': /* section can be discarded */
461477298Sobrien		  flags &=~ SEC_LOAD;
461560484Sobrien		  break;
461660484Sobrien		case 'R': /* Remove section at link time */
461760484Sobrien		  flags |= SEC_NEVER_LOAD;
461860484Sobrien		  break;
4619218822Sdim#if IFLICT_BRAIN_DAMAGE
462060484Sobrien		  /* Section Protection */
462160484Sobrien		case 'r': /* section is readable */
462260484Sobrien		  flags |= IMAGE_SCN_MEM_READ;
462360484Sobrien		  break;
462460484Sobrien		case 'w': /* section is writeable */
462560484Sobrien		  flags |= IMAGE_SCN_MEM_WRITE;
462660484Sobrien		  break;
462760484Sobrien		case 'x': /* section is executable */
462860484Sobrien		  flags |= IMAGE_SCN_MEM_EXECUTE;
462960484Sobrien		  break;
463060484Sobrien		case 's': /* section is sharable */
463160484Sobrien		  flags |= IMAGE_SCN_MEM_SHARED;
463260484Sobrien		  break;
463360484Sobrien
463460484Sobrien		  /* Section Alignment */
463560484Sobrien		case '0': /* align to byte boundary */
463660484Sobrien		  flags |= IMAGE_SCN_ALIGN_1BYTES;
463760484Sobrien		  align = 0;
463860484Sobrien		  break;
463960484Sobrien		case '1':  /* align to halfword boundary */
464060484Sobrien		  flags |= IMAGE_SCN_ALIGN_2BYTES;
464160484Sobrien		  align = 1;
464260484Sobrien		  break;
464360484Sobrien		case '2':  /* align to word boundary */
464460484Sobrien		  flags |= IMAGE_SCN_ALIGN_4BYTES;
464560484Sobrien		  align = 2;
464660484Sobrien		  break;
464760484Sobrien		case '3':  /* align to doubleword boundary */
464860484Sobrien		  flags |= IMAGE_SCN_ALIGN_8BYTES;
464960484Sobrien		  align = 3;
465060484Sobrien		  break;
465160484Sobrien		case '4':  /* align to quadword boundary */
465260484Sobrien		  flags |= IMAGE_SCN_ALIGN_16BYTES;
465360484Sobrien		  align = 4;
465460484Sobrien		  break;
465560484Sobrien		case '5':  /* align to 32 byte boundary */
465660484Sobrien		  flags |= IMAGE_SCN_ALIGN_32BYTES;
465760484Sobrien		  align = 5;
465860484Sobrien		  break;
465960484Sobrien		case '6':  /* align to 64 byte boundary */
466060484Sobrien		  flags |= IMAGE_SCN_ALIGN_64BYTES;
466160484Sobrien		  align = 6;
466260484Sobrien		  break;
4663218822Sdim#endif
466460484Sobrien		default:
466589857Sobrien		  as_bad (_("unknown section attribute '%c'"),
466689857Sobrien			  *input_line_pointer);
466760484Sobrien		  break;
466860484Sobrien		}
466960484Sobrien	      ++input_line_pointer;
467060484Sobrien	    }
467160484Sobrien	  if (*input_line_pointer == '"')
467260484Sobrien	    ++input_line_pointer;
467360484Sobrien	}
467460484Sobrien    }
467560484Sobrien
467660484Sobrien  sec = subseg_new (name, (subsegT) exp);
467760484Sobrien
467889857Sobrien  ppc_set_current_section (sec);
467960484Sobrien
468060484Sobrien  if (flags != SEC_NO_FLAGS)
468160484Sobrien    {
468260484Sobrien      if (! bfd_set_section_flags (stdoutput, sec, flags))
468360484Sobrien	as_bad (_("error setting flags for \"%s\": %s"),
468460484Sobrien		bfd_section_name (stdoutput, sec),
468560484Sobrien		bfd_errmsg (bfd_get_error ()));
468660484Sobrien    }
468760484Sobrien
468889857Sobrien  bfd_set_section_alignment (stdoutput, sec, align);
468960484Sobrien}
469060484Sobrien
469160484Sobrienstatic void
4692218822Sdimppc_pe_function (int ignore ATTRIBUTE_UNUSED)
469360484Sobrien{
469460484Sobrien  char *name;
469560484Sobrien  char endc;
469660484Sobrien  symbolS *ext_sym;
469760484Sobrien
469860484Sobrien  name = input_line_pointer;
469960484Sobrien  endc = get_symbol_end ();
470060484Sobrien
470160484Sobrien  ext_sym = symbol_find_or_make (name);
470260484Sobrien
470360484Sobrien  *input_line_pointer = endc;
470460484Sobrien
470560484Sobrien  S_SET_DATA_TYPE (ext_sym, DT_FCN << N_BTSHFT);
470660484Sobrien  SF_SET_FUNCTION (ext_sym);
470760484Sobrien  SF_SET_PROCESS (ext_sym);
470860484Sobrien  coff_add_linesym (ext_sym);
470960484Sobrien
471060484Sobrien  demand_empty_rest_of_line ();
471160484Sobrien}
471260484Sobrien
471360484Sobrienstatic void
4714218822Sdimppc_pe_tocd (int ignore ATTRIBUTE_UNUSED)
471560484Sobrien{
471660484Sobrien  if (tocdata_section == 0)
471760484Sobrien    {
471860484Sobrien      tocdata_section = subseg_new (".tocd", 0);
471989857Sobrien      /* FIXME: section flags won't work.  */
472060484Sobrien      bfd_set_section_flags (stdoutput, tocdata_section,
472160484Sobrien			     (SEC_ALLOC | SEC_LOAD | SEC_RELOC
472289857Sobrien			      | SEC_READONLY | SEC_DATA));
472360484Sobrien
472460484Sobrien      bfd_set_section_alignment (stdoutput, tocdata_section, 2);
472560484Sobrien    }
472660484Sobrien  else
472760484Sobrien    {
472860484Sobrien      rdata_section = subseg_new (".tocd", 0);
472960484Sobrien    }
473060484Sobrien
473189857Sobrien  ppc_set_current_section (tocdata_section);
473260484Sobrien
473360484Sobrien  demand_empty_rest_of_line ();
473460484Sobrien}
473560484Sobrien
473660484Sobrien/* Don't adjust TOC relocs to use the section symbol.  */
473760484Sobrien
473860484Sobrienint
4739218822Sdimppc_pe_fix_adjustable (fixS *fix)
474060484Sobrien{
474160484Sobrien  return fix->fx_r_type != BFD_RELOC_PPC_TOC16;
474260484Sobrien}
474360484Sobrien
474460484Sobrien#endif
474560484Sobrien
474660484Sobrien#ifdef OBJ_XCOFF
474760484Sobrien
474860484Sobrien/* XCOFF specific symbol and file handling.  */
474960484Sobrien
475060484Sobrien/* Canonicalize the symbol name.  We use the to force the suffix, if
475160484Sobrien   any, to use square brackets, and to be in upper case.  */
475260484Sobrien
475360484Sobrienchar *
4754218822Sdimppc_canonicalize_symbol_name (char *name)
475560484Sobrien{
475660484Sobrien  char *s;
475760484Sobrien
475860484Sobrien  if (ppc_stab_symbol)
475960484Sobrien    return name;
476060484Sobrien
476160484Sobrien  for (s = name; *s != '\0' && *s != '{' && *s != '['; s++)
476260484Sobrien    ;
476360484Sobrien  if (*s != '\0')
476460484Sobrien    {
476560484Sobrien      char brac;
476660484Sobrien
476760484Sobrien      if (*s == '[')
476860484Sobrien	brac = ']';
476960484Sobrien      else
477060484Sobrien	{
477160484Sobrien	  *s = '[';
477260484Sobrien	  brac = '}';
477360484Sobrien	}
477460484Sobrien
477560484Sobrien      for (s++; *s != '\0' && *s != brac; s++)
477689857Sobrien	*s = TOUPPER (*s);
477760484Sobrien
477860484Sobrien      if (*s == '\0' || s[1] != '\0')
477960484Sobrien	as_bad (_("bad symbol suffix"));
478060484Sobrien
478160484Sobrien      *s = ']';
478260484Sobrien    }
478360484Sobrien
478460484Sobrien  return name;
478560484Sobrien}
478660484Sobrien
478760484Sobrien/* Set the class of a symbol based on the suffix, if any.  This is
478860484Sobrien   called whenever a new symbol is created.  */
478960484Sobrien
479060484Sobrienvoid
4791218822Sdimppc_symbol_new_hook (symbolS *sym)
479260484Sobrien{
479360484Sobrien  struct ppc_tc_sy *tc;
479460484Sobrien  const char *s;
479560484Sobrien
479660484Sobrien  tc = symbol_get_tc (sym);
479760484Sobrien  tc->next = NULL;
479860484Sobrien  tc->output = 0;
479960484Sobrien  tc->class = -1;
480060484Sobrien  tc->real_name = NULL;
480160484Sobrien  tc->subseg = 0;
480260484Sobrien  tc->align = 0;
480360484Sobrien  tc->size = NULL;
480460484Sobrien  tc->within = NULL;
480560484Sobrien
480660484Sobrien  if (ppc_stab_symbol)
480760484Sobrien    return;
480860484Sobrien
480960484Sobrien  s = strchr (S_GET_NAME (sym), '[');
481060484Sobrien  if (s == (const char *) NULL)
481160484Sobrien    {
481260484Sobrien      /* There is no suffix.  */
481360484Sobrien      return;
481460484Sobrien    }
481560484Sobrien
481660484Sobrien  ++s;
481760484Sobrien
481860484Sobrien  switch (s[0])
481960484Sobrien    {
482060484Sobrien    case 'B':
482160484Sobrien      if (strcmp (s, "BS]") == 0)
482260484Sobrien	tc->class = XMC_BS;
482360484Sobrien      break;
482460484Sobrien    case 'D':
482560484Sobrien      if (strcmp (s, "DB]") == 0)
482660484Sobrien	tc->class = XMC_DB;
482760484Sobrien      else if (strcmp (s, "DS]") == 0)
482860484Sobrien	tc->class = XMC_DS;
482960484Sobrien      break;
483060484Sobrien    case 'G':
483160484Sobrien      if (strcmp (s, "GL]") == 0)
483260484Sobrien	tc->class = XMC_GL;
483360484Sobrien      break;
483460484Sobrien    case 'P':
483560484Sobrien      if (strcmp (s, "PR]") == 0)
483660484Sobrien	tc->class = XMC_PR;
483760484Sobrien      break;
483860484Sobrien    case 'R':
483960484Sobrien      if (strcmp (s, "RO]") == 0)
484060484Sobrien	tc->class = XMC_RO;
484160484Sobrien      else if (strcmp (s, "RW]") == 0)
484260484Sobrien	tc->class = XMC_RW;
484360484Sobrien      break;
484460484Sobrien    case 'S':
484560484Sobrien      if (strcmp (s, "SV]") == 0)
484660484Sobrien	tc->class = XMC_SV;
484760484Sobrien      break;
484860484Sobrien    case 'T':
484960484Sobrien      if (strcmp (s, "TC]") == 0)
485060484Sobrien	tc->class = XMC_TC;
485160484Sobrien      else if (strcmp (s, "TI]") == 0)
485260484Sobrien	tc->class = XMC_TI;
485360484Sobrien      else if (strcmp (s, "TB]") == 0)
485460484Sobrien	tc->class = XMC_TB;
485560484Sobrien      else if (strcmp (s, "TC0]") == 0 || strcmp (s, "T0]") == 0)
485660484Sobrien	tc->class = XMC_TC0;
485760484Sobrien      break;
485860484Sobrien    case 'U':
485960484Sobrien      if (strcmp (s, "UA]") == 0)
486060484Sobrien	tc->class = XMC_UA;
486160484Sobrien      else if (strcmp (s, "UC]") == 0)
486260484Sobrien	tc->class = XMC_UC;
486360484Sobrien      break;
486460484Sobrien    case 'X':
486560484Sobrien      if (strcmp (s, "XO]") == 0)
486660484Sobrien	tc->class = XMC_XO;
486760484Sobrien      break;
486860484Sobrien    }
486960484Sobrien
487060484Sobrien  if (tc->class == -1)
487160484Sobrien    as_bad (_("Unrecognized symbol suffix"));
487260484Sobrien}
487360484Sobrien
487460484Sobrien/* Set the class of a label based on where it is defined.  This
487560484Sobrien   handles symbols without suffixes.  Also, move the symbol so that it
487660484Sobrien   follows the csect symbol.  */
487760484Sobrien
487860484Sobrienvoid
4879218822Sdimppc_frob_label (symbolS *sym)
488060484Sobrien{
488160484Sobrien  if (ppc_current_csect != (symbolS *) NULL)
488260484Sobrien    {
488360484Sobrien      if (symbol_get_tc (sym)->class == -1)
488460484Sobrien	symbol_get_tc (sym)->class = symbol_get_tc (ppc_current_csect)->class;
488560484Sobrien
488660484Sobrien      symbol_remove (sym, &symbol_rootP, &symbol_lastP);
488760484Sobrien      symbol_append (sym, symbol_get_tc (ppc_current_csect)->within,
488860484Sobrien		     &symbol_rootP, &symbol_lastP);
488960484Sobrien      symbol_get_tc (ppc_current_csect)->within = sym;
489060484Sobrien    }
4891218822Sdim
4892218822Sdim#ifdef OBJ_ELF
4893218822Sdim  dwarf2_emit_label (sym);
4894218822Sdim#endif
489560484Sobrien}
489660484Sobrien
489760484Sobrien/* This variable is set by ppc_frob_symbol if any absolute symbols are
489860484Sobrien   seen.  It tells ppc_adjust_symtab whether it needs to look through
489960484Sobrien   the symbols.  */
490060484Sobrien
4901130561Sobrienstatic bfd_boolean ppc_saw_abs;
490260484Sobrien
490360484Sobrien/* Change the name of a symbol just before writing it out.  Set the
490460484Sobrien   real name if the .rename pseudo-op was used.  Otherwise, remove any
490560484Sobrien   class suffix.  Return 1 if the symbol should not be included in the
490660484Sobrien   symbol table.  */
490760484Sobrien
490860484Sobrienint
4909218822Sdimppc_frob_symbol (symbolS *sym)
491060484Sobrien{
491160484Sobrien  static symbolS *ppc_last_function;
491260484Sobrien  static symbolS *set_end;
491360484Sobrien
491460484Sobrien  /* Discard symbols that should not be included in the output symbol
491560484Sobrien     table.  */
491660484Sobrien  if (! symbol_used_in_reloc_p (sym)
491760484Sobrien      && ((symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) != 0
4918218822Sdim	  || (! (S_IS_EXTERNAL (sym) || S_IS_WEAK (sym))
491960484Sobrien	      && ! symbol_get_tc (sym)->output
492060484Sobrien	      && S_GET_STORAGE_CLASS (sym) != C_FILE)))
492160484Sobrien    return 1;
492260484Sobrien
4923130561Sobrien  /* This one will disappear anyway.  Don't make a csect sym for it.  */
4924130561Sobrien  if (sym == abs_section_sym)
4925130561Sobrien    return 1;
4926130561Sobrien
492760484Sobrien  if (symbol_get_tc (sym)->real_name != (char *) NULL)
492860484Sobrien    S_SET_NAME (sym, symbol_get_tc (sym)->real_name);
492960484Sobrien  else
493060484Sobrien    {
493160484Sobrien      const char *name;
493260484Sobrien      const char *s;
493360484Sobrien
493460484Sobrien      name = S_GET_NAME (sym);
493560484Sobrien      s = strchr (name, '[');
493660484Sobrien      if (s != (char *) NULL)
493760484Sobrien	{
493860484Sobrien	  unsigned int len;
493960484Sobrien	  char *snew;
494060484Sobrien
494160484Sobrien	  len = s - name;
494260484Sobrien	  snew = xmalloc (len + 1);
494360484Sobrien	  memcpy (snew, name, len);
494460484Sobrien	  snew[len] = '\0';
494560484Sobrien
494660484Sobrien	  S_SET_NAME (sym, snew);
494760484Sobrien	}
494860484Sobrien    }
494960484Sobrien
495060484Sobrien  if (set_end != (symbolS *) NULL)
495160484Sobrien    {
495260484Sobrien      SA_SET_SYM_ENDNDX (set_end, sym);
495360484Sobrien      set_end = NULL;
495460484Sobrien    }
495560484Sobrien
495660484Sobrien  if (SF_GET_FUNCTION (sym))
495760484Sobrien    {
495860484Sobrien      if (ppc_last_function != (symbolS *) NULL)
495960484Sobrien	as_bad (_("two .function pseudo-ops with no intervening .ef"));
496060484Sobrien      ppc_last_function = sym;
496160484Sobrien      if (symbol_get_tc (sym)->size != (symbolS *) NULL)
496260484Sobrien	{
496389857Sobrien	  resolve_symbol_value (symbol_get_tc (sym)->size);
496460484Sobrien	  SA_SET_SYM_FSIZE (sym,
496560484Sobrien			    (long) S_GET_VALUE (symbol_get_tc (sym)->size));
496660484Sobrien	}
496760484Sobrien    }
496860484Sobrien  else if (S_GET_STORAGE_CLASS (sym) == C_FCN
496960484Sobrien	   && strcmp (S_GET_NAME (sym), ".ef") == 0)
497060484Sobrien    {
497160484Sobrien      if (ppc_last_function == (symbolS *) NULL)
497260484Sobrien	as_bad (_(".ef with no preceding .function"));
497360484Sobrien      else
497460484Sobrien	{
497560484Sobrien	  set_end = ppc_last_function;
497660484Sobrien	  ppc_last_function = NULL;
497760484Sobrien
497860484Sobrien	  /* We don't have a C_EFCN symbol, but we need to force the
497960484Sobrien	     COFF backend to believe that it has seen one.  */
498060484Sobrien	  coff_last_function = NULL;
498160484Sobrien	}
498260484Sobrien    }
498360484Sobrien
4984218822Sdim  if (! (S_IS_EXTERNAL (sym) || S_IS_WEAK (sym))
498560484Sobrien      && (symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) == 0
498660484Sobrien      && S_GET_STORAGE_CLASS (sym) != C_FILE
498760484Sobrien      && S_GET_STORAGE_CLASS (sym) != C_FCN
498860484Sobrien      && S_GET_STORAGE_CLASS (sym) != C_BLOCK
498960484Sobrien      && S_GET_STORAGE_CLASS (sym) != C_BSTAT
499060484Sobrien      && S_GET_STORAGE_CLASS (sym) != C_ESTAT
499160484Sobrien      && S_GET_STORAGE_CLASS (sym) != C_BINCL
499260484Sobrien      && S_GET_STORAGE_CLASS (sym) != C_EINCL
499360484Sobrien      && S_GET_SEGMENT (sym) != ppc_coff_debug_section)
499460484Sobrien    S_SET_STORAGE_CLASS (sym, C_HIDEXT);
499560484Sobrien
499660484Sobrien  if (S_GET_STORAGE_CLASS (sym) == C_EXT
499760484Sobrien      || S_GET_STORAGE_CLASS (sym) == C_HIDEXT)
499860484Sobrien    {
499960484Sobrien      int i;
500060484Sobrien      union internal_auxent *a;
500160484Sobrien
500260484Sobrien      /* Create a csect aux.  */
500360484Sobrien      i = S_GET_NUMBER_AUXILIARY (sym);
500460484Sobrien      S_SET_NUMBER_AUXILIARY (sym, i + 1);
500560484Sobrien      a = &coffsymbol (symbol_get_bfdsym (sym))->native[i + 1].u.auxent;
500660484Sobrien      if (symbol_get_tc (sym)->class == XMC_TC0)
500760484Sobrien	{
500860484Sobrien	  /* This is the TOC table.  */
500960484Sobrien	  know (strcmp (S_GET_NAME (sym), "TOC") == 0);
501060484Sobrien	  a->x_csect.x_scnlen.l = 0;
501160484Sobrien	  a->x_csect.x_smtyp = (2 << 3) | XTY_SD;
501260484Sobrien	}
501360484Sobrien      else if (symbol_get_tc (sym)->subseg != 0)
501460484Sobrien	{
501560484Sobrien	  /* This is a csect symbol.  x_scnlen is the size of the
501660484Sobrien	     csect.  */
501760484Sobrien	  if (symbol_get_tc (sym)->next == (symbolS *) NULL)
501860484Sobrien	    a->x_csect.x_scnlen.l = (bfd_section_size (stdoutput,
501960484Sobrien						       S_GET_SEGMENT (sym))
502060484Sobrien				     - S_GET_VALUE (sym));
502160484Sobrien	  else
502260484Sobrien	    {
502389857Sobrien	      resolve_symbol_value (symbol_get_tc (sym)->next);
502460484Sobrien	      a->x_csect.x_scnlen.l = (S_GET_VALUE (symbol_get_tc (sym)->next)
502560484Sobrien				       - S_GET_VALUE (sym));
502660484Sobrien	    }
502760484Sobrien	  a->x_csect.x_smtyp = (symbol_get_tc (sym)->align << 3) | XTY_SD;
502860484Sobrien	}
502960484Sobrien      else if (S_GET_SEGMENT (sym) == bss_section)
503060484Sobrien	{
503160484Sobrien	  /* This is a common symbol.  */
503260484Sobrien	  a->x_csect.x_scnlen.l = symbol_get_frag (sym)->fr_offset;
503360484Sobrien	  a->x_csect.x_smtyp = (symbol_get_tc (sym)->align << 3) | XTY_CM;
503460484Sobrien	  if (S_IS_EXTERNAL (sym))
503560484Sobrien	    symbol_get_tc (sym)->class = XMC_RW;
503660484Sobrien	  else
503760484Sobrien	    symbol_get_tc (sym)->class = XMC_BS;
503860484Sobrien	}
503960484Sobrien      else if (S_GET_SEGMENT (sym) == absolute_section)
504060484Sobrien	{
504160484Sobrien	  /* This is an absolute symbol.  The csect will be created by
504289857Sobrien	     ppc_adjust_symtab.  */
5043130561Sobrien	  ppc_saw_abs = TRUE;
504460484Sobrien	  a->x_csect.x_smtyp = XTY_LD;
504560484Sobrien	  if (symbol_get_tc (sym)->class == -1)
504660484Sobrien	    symbol_get_tc (sym)->class = XMC_XO;
504760484Sobrien	}
504860484Sobrien      else if (! S_IS_DEFINED (sym))
504960484Sobrien	{
505060484Sobrien	  /* This is an external symbol.  */
505160484Sobrien	  a->x_csect.x_scnlen.l = 0;
505260484Sobrien	  a->x_csect.x_smtyp = XTY_ER;
505360484Sobrien	}
505460484Sobrien      else if (symbol_get_tc (sym)->class == XMC_TC)
505560484Sobrien	{
505660484Sobrien	  symbolS *next;
505760484Sobrien
505860484Sobrien	  /* This is a TOC definition.  x_scnlen is the size of the
505960484Sobrien	     TOC entry.  */
506060484Sobrien	  next = symbol_next (sym);
506160484Sobrien	  while (symbol_get_tc (next)->class == XMC_TC0)
506260484Sobrien	    next = symbol_next (next);
506360484Sobrien	  if (next == (symbolS *) NULL
506460484Sobrien	      || symbol_get_tc (next)->class != XMC_TC)
506560484Sobrien	    {
506660484Sobrien	      if (ppc_after_toc_frag == (fragS *) NULL)
506760484Sobrien		a->x_csect.x_scnlen.l = (bfd_section_size (stdoutput,
506860484Sobrien							   data_section)
506960484Sobrien					 - S_GET_VALUE (sym));
507060484Sobrien	      else
507160484Sobrien		a->x_csect.x_scnlen.l = (ppc_after_toc_frag->fr_address
507260484Sobrien					 - S_GET_VALUE (sym));
507360484Sobrien	    }
507460484Sobrien	  else
507560484Sobrien	    {
507689857Sobrien	      resolve_symbol_value (next);
507760484Sobrien	      a->x_csect.x_scnlen.l = (S_GET_VALUE (next)
507860484Sobrien				       - S_GET_VALUE (sym));
507960484Sobrien	    }
508060484Sobrien	  a->x_csect.x_smtyp = (2 << 3) | XTY_SD;
508160484Sobrien	}
508260484Sobrien      else
508360484Sobrien	{
508460484Sobrien	  symbolS *csect;
508560484Sobrien
508660484Sobrien	  /* This is a normal symbol definition.  x_scnlen is the
508760484Sobrien	     symbol index of the containing csect.  */
508860484Sobrien	  if (S_GET_SEGMENT (sym) == text_section)
508960484Sobrien	    csect = ppc_text_csects;
509060484Sobrien	  else if (S_GET_SEGMENT (sym) == data_section)
509160484Sobrien	    csect = ppc_data_csects;
509260484Sobrien	  else
509360484Sobrien	    abort ();
509460484Sobrien
509560484Sobrien	  /* Skip the initial dummy symbol.  */
509660484Sobrien	  csect = symbol_get_tc (csect)->next;
509760484Sobrien
509860484Sobrien	  if (csect == (symbolS *) NULL)
509960484Sobrien	    {
510060484Sobrien	      as_warn (_("warning: symbol %s has no csect"), S_GET_NAME (sym));
510160484Sobrien	      a->x_csect.x_scnlen.l = 0;
510260484Sobrien	    }
510360484Sobrien	  else
510460484Sobrien	    {
510560484Sobrien	      while (symbol_get_tc (csect)->next != (symbolS *) NULL)
510660484Sobrien		{
510789857Sobrien		  resolve_symbol_value (symbol_get_tc (csect)->next);
510860484Sobrien		  if (S_GET_VALUE (symbol_get_tc (csect)->next)
510960484Sobrien		      > S_GET_VALUE (sym))
511060484Sobrien		    break;
511160484Sobrien		  csect = symbol_get_tc (csect)->next;
511260484Sobrien		}
511360484Sobrien
511460484Sobrien	      a->x_csect.x_scnlen.p =
511560484Sobrien		coffsymbol (symbol_get_bfdsym (csect))->native;
511660484Sobrien	      coffsymbol (symbol_get_bfdsym (sym))->native[i + 1].fix_scnlen =
511760484Sobrien		1;
511860484Sobrien	    }
511960484Sobrien	  a->x_csect.x_smtyp = XTY_LD;
512060484Sobrien	}
512177298Sobrien
512260484Sobrien      a->x_csect.x_parmhash = 0;
512360484Sobrien      a->x_csect.x_snhash = 0;
512460484Sobrien      if (symbol_get_tc (sym)->class == -1)
512560484Sobrien	a->x_csect.x_smclas = XMC_PR;
512660484Sobrien      else
512760484Sobrien	a->x_csect.x_smclas = symbol_get_tc (sym)->class;
512860484Sobrien      a->x_csect.x_stab = 0;
512960484Sobrien      a->x_csect.x_snstab = 0;
513060484Sobrien
513160484Sobrien      /* Don't let the COFF backend resort these symbols.  */
513260484Sobrien      symbol_get_bfdsym (sym)->flags |= BSF_NOT_AT_END;
513360484Sobrien    }
513460484Sobrien  else if (S_GET_STORAGE_CLASS (sym) == C_BSTAT)
513560484Sobrien    {
513660484Sobrien      /* We want the value to be the symbol index of the referenced
513760484Sobrien	 csect symbol.  BFD will do that for us if we set the right
513860484Sobrien	 flags.  */
5139130561Sobrien      asymbol *bsym = symbol_get_bfdsym (symbol_get_tc (sym)->within);
5140130561Sobrien      combined_entry_type *c = coffsymbol (bsym)->native;
5141130561Sobrien
5142130561Sobrien      S_SET_VALUE (sym, (valueT) (size_t) c);
514360484Sobrien      coffsymbol (symbol_get_bfdsym (sym))->native->fix_value = 1;
514460484Sobrien    }
514560484Sobrien  else if (S_GET_STORAGE_CLASS (sym) == C_STSYM)
514660484Sobrien    {
514760484Sobrien      symbolS *block;
514860484Sobrien      symbolS *csect;
514960484Sobrien
515060484Sobrien      /* The value is the offset from the enclosing csect.  */
515160484Sobrien      block = symbol_get_tc (sym)->within;
515260484Sobrien      csect = symbol_get_tc (block)->within;
515389857Sobrien      resolve_symbol_value (csect);
515460484Sobrien      S_SET_VALUE (sym, S_GET_VALUE (sym) - S_GET_VALUE (csect));
515560484Sobrien    }
515660484Sobrien  else if (S_GET_STORAGE_CLASS (sym) == C_BINCL
515760484Sobrien	   || S_GET_STORAGE_CLASS (sym) == C_EINCL)
515860484Sobrien    {
515960484Sobrien      /* We want the value to be a file offset into the line numbers.
516089857Sobrien	 BFD will do that for us if we set the right flags.  We have
516189857Sobrien	 already set the value correctly.  */
516260484Sobrien      coffsymbol (symbol_get_bfdsym (sym))->native->fix_line = 1;
516360484Sobrien    }
516460484Sobrien
516560484Sobrien  return 0;
516660484Sobrien}
516760484Sobrien
516860484Sobrien/* Adjust the symbol table.  This creates csect symbols for all
516960484Sobrien   absolute symbols.  */
517060484Sobrien
517160484Sobrienvoid
5172218822Sdimppc_adjust_symtab (void)
517360484Sobrien{
517460484Sobrien  symbolS *sym;
517560484Sobrien
517660484Sobrien  if (! ppc_saw_abs)
517760484Sobrien    return;
517860484Sobrien
517960484Sobrien  for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
518060484Sobrien    {
518160484Sobrien      symbolS *csect;
518260484Sobrien      int i;
518360484Sobrien      union internal_auxent *a;
518460484Sobrien
518560484Sobrien      if (S_GET_SEGMENT (sym) != absolute_section)
518660484Sobrien	continue;
518760484Sobrien
518860484Sobrien      csect = symbol_create (".abs[XO]", absolute_section,
518960484Sobrien			     S_GET_VALUE (sym), &zero_address_frag);
519060484Sobrien      symbol_get_bfdsym (csect)->value = S_GET_VALUE (sym);
519160484Sobrien      S_SET_STORAGE_CLASS (csect, C_HIDEXT);
519260484Sobrien      i = S_GET_NUMBER_AUXILIARY (csect);
519360484Sobrien      S_SET_NUMBER_AUXILIARY (csect, i + 1);
519460484Sobrien      a = &coffsymbol (symbol_get_bfdsym (csect))->native[i + 1].u.auxent;
519560484Sobrien      a->x_csect.x_scnlen.l = 0;
519660484Sobrien      a->x_csect.x_smtyp = XTY_SD;
519760484Sobrien      a->x_csect.x_parmhash = 0;
519860484Sobrien      a->x_csect.x_snhash = 0;
519960484Sobrien      a->x_csect.x_smclas = XMC_XO;
520060484Sobrien      a->x_csect.x_stab = 0;
520160484Sobrien      a->x_csect.x_snstab = 0;
520260484Sobrien
520360484Sobrien      symbol_insert (csect, sym, &symbol_rootP, &symbol_lastP);
520460484Sobrien
520560484Sobrien      i = S_GET_NUMBER_AUXILIARY (sym);
520660484Sobrien      a = &coffsymbol (symbol_get_bfdsym (sym))->native[i].u.auxent;
520760484Sobrien      a->x_csect.x_scnlen.p = coffsymbol (symbol_get_bfdsym (csect))->native;
520860484Sobrien      coffsymbol (symbol_get_bfdsym (sym))->native[i].fix_scnlen = 1;
520960484Sobrien    }
521060484Sobrien
5211130561Sobrien  ppc_saw_abs = FALSE;
521260484Sobrien}
521360484Sobrien
521460484Sobrien/* Set the VMA for a section.  This is called on all the sections in
521560484Sobrien   turn.  */
521660484Sobrien
521760484Sobrienvoid
5218218822Sdimppc_frob_section (asection *sec)
521960484Sobrien{
5220130561Sobrien  static bfd_vma vma = 0;
522160484Sobrien
5222130561Sobrien  vma = md_section_align (sec, vma);
522360484Sobrien  bfd_set_section_vma (stdoutput, sec, vma);
522460484Sobrien  vma += bfd_section_size (stdoutput, sec);
522560484Sobrien}
522660484Sobrien
522760484Sobrien#endif /* OBJ_XCOFF */
522860484Sobrien
522960484Sobrien/* Turn a string in input_line_pointer into a floating point constant
523077298Sobrien   of type TYPE, and store the appropriate bytes in *LITP.  The number
523177298Sobrien   of LITTLENUMS emitted is stored in *SIZEP.  An error message is
523260484Sobrien   returned, or NULL on OK.  */
523360484Sobrien
523460484Sobrienchar *
5235218822Sdimmd_atof (int type, char *litp, int *sizep)
523660484Sobrien{
523760484Sobrien  int prec;
523860484Sobrien  LITTLENUM_TYPE words[4];
523960484Sobrien  char *t;
524060484Sobrien  int i;
524160484Sobrien
524260484Sobrien  switch (type)
524360484Sobrien    {
524460484Sobrien    case 'f':
524560484Sobrien      prec = 2;
524660484Sobrien      break;
524760484Sobrien
524860484Sobrien    case 'd':
524960484Sobrien      prec = 4;
525060484Sobrien      break;
525160484Sobrien
525260484Sobrien    default:
525360484Sobrien      *sizep = 0;
525460484Sobrien      return _("bad call to md_atof");
525560484Sobrien    }
525660484Sobrien
525760484Sobrien  t = atof_ieee (input_line_pointer, type, words);
525860484Sobrien  if (t)
525960484Sobrien    input_line_pointer = t;
526060484Sobrien
526160484Sobrien  *sizep = prec * 2;
526260484Sobrien
526360484Sobrien  if (target_big_endian)
526460484Sobrien    {
526560484Sobrien      for (i = 0; i < prec; i++)
526660484Sobrien	{
526760484Sobrien	  md_number_to_chars (litp, (valueT) words[i], 2);
526860484Sobrien	  litp += 2;
526960484Sobrien	}
527060484Sobrien    }
527160484Sobrien  else
527260484Sobrien    {
527360484Sobrien      for (i = prec - 1; i >= 0; i--)
527460484Sobrien	{
527560484Sobrien	  md_number_to_chars (litp, (valueT) words[i], 2);
527660484Sobrien	  litp += 2;
527760484Sobrien	}
527860484Sobrien    }
527977298Sobrien
528060484Sobrien  return NULL;
528160484Sobrien}
528260484Sobrien
528360484Sobrien/* Write a value out to the object file, using the appropriate
528460484Sobrien   endianness.  */
528560484Sobrien
528660484Sobrienvoid
5287218822Sdimmd_number_to_chars (char *buf, valueT val, int n)
528860484Sobrien{
528960484Sobrien  if (target_big_endian)
529060484Sobrien    number_to_chars_bigendian (buf, val, n);
529160484Sobrien  else
529260484Sobrien    number_to_chars_littleendian (buf, val, n);
529360484Sobrien}
529460484Sobrien
529560484Sobrien/* Align a section (I don't know why this is machine dependent).  */
529660484Sobrien
529760484SobrienvalueT
5298218822Sdimmd_section_align (asection *seg ATTRIBUTE_UNUSED, valueT addr)
529960484Sobrien{
5300218822Sdim#ifdef OBJ_ELF
5301218822Sdim  return addr;
5302218822Sdim#else
530360484Sobrien  int align = bfd_get_section_alignment (stdoutput, seg);
530460484Sobrien
530560484Sobrien  return ((addr + (1 << align) - 1) & (-1 << align));
5306218822Sdim#endif
530760484Sobrien}
530860484Sobrien
530960484Sobrien/* We don't have any form of relaxing.  */
531060484Sobrien
531160484Sobrienint
5312218822Sdimmd_estimate_size_before_relax (fragS *fragp ATTRIBUTE_UNUSED,
5313218822Sdim			       asection *seg ATTRIBUTE_UNUSED)
531460484Sobrien{
531560484Sobrien  abort ();
531660484Sobrien  return 0;
531760484Sobrien}
531860484Sobrien
531960484Sobrien/* Convert a machine dependent frag.  We never generate these.  */
532060484Sobrien
532160484Sobrienvoid
5322218822Sdimmd_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
5323218822Sdim		 asection *sec ATTRIBUTE_UNUSED,
5324218822Sdim		 fragS *fragp ATTRIBUTE_UNUSED)
532560484Sobrien{
532660484Sobrien  abort ();
532760484Sobrien}
532860484Sobrien
532960484Sobrien/* We have no need to default values of symbols.  */
533060484Sobrien
533160484SobriensymbolS *
5332218822Sdimmd_undefined_symbol (char *name ATTRIBUTE_UNUSED)
533360484Sobrien{
533460484Sobrien  return 0;
533560484Sobrien}
533660484Sobrien
533760484Sobrien/* Functions concerning relocs.  */
533860484Sobrien
533960484Sobrien/* The location from which a PC relative jump should be calculated,
534060484Sobrien   given a PC relative reloc.  */
534160484Sobrien
534260484Sobrienlong
5343218822Sdimmd_pcrel_from_section (fixS *fixp, segT sec ATTRIBUTE_UNUSED)
534460484Sobrien{
534560484Sobrien  return fixp->fx_frag->fr_address + fixp->fx_where;
534660484Sobrien}
534760484Sobrien
534860484Sobrien#ifdef OBJ_XCOFF
534960484Sobrien
535060484Sobrien/* This is called to see whether a fixup should be adjusted to use a
535160484Sobrien   section symbol.  We take the opportunity to change a fixup against
535260484Sobrien   a symbol in the TOC subsegment into a reloc against the
535360484Sobrien   corresponding .tc symbol.  */
535460484Sobrien
535560484Sobrienint
5356218822Sdimppc_fix_adjustable (fixS *fix)
535760484Sobrien{
5358130561Sobrien  valueT val = resolve_symbol_value (fix->fx_addsy);
5359130561Sobrien  segT symseg = S_GET_SEGMENT (fix->fx_addsy);
5360130561Sobrien  TC_SYMFIELD_TYPE *tc;
536160484Sobrien
5362130561Sobrien  if (symseg == absolute_section)
5363130561Sobrien    return 0;
5364130561Sobrien
536560484Sobrien  if (ppc_toc_csect != (symbolS *) NULL
536660484Sobrien      && fix->fx_addsy != ppc_toc_csect
5367130561Sobrien      && symseg == data_section
536860484Sobrien      && val >= ppc_toc_frag->fr_address
536960484Sobrien      && (ppc_after_toc_frag == (fragS *) NULL
537060484Sobrien	  || val < ppc_after_toc_frag->fr_address))
537160484Sobrien    {
537260484Sobrien      symbolS *sy;
537360484Sobrien
537460484Sobrien      for (sy = symbol_next (ppc_toc_csect);
537560484Sobrien	   sy != (symbolS *) NULL;
537660484Sobrien	   sy = symbol_next (sy))
537760484Sobrien	{
5378130561Sobrien	  TC_SYMFIELD_TYPE *sy_tc = symbol_get_tc (sy);
5379130561Sobrien
5380130561Sobrien	  if (sy_tc->class == XMC_TC0)
538160484Sobrien	    continue;
5382130561Sobrien	  if (sy_tc->class != XMC_TC)
538360484Sobrien	    break;
5384130561Sobrien	  if (val == resolve_symbol_value (sy))
538560484Sobrien	    {
538660484Sobrien	      fix->fx_addsy = sy;
538760484Sobrien	      fix->fx_addnumber = val - ppc_toc_frag->fr_address;
538860484Sobrien	      return 0;
538960484Sobrien	    }
539060484Sobrien	}
539160484Sobrien
539260484Sobrien      as_bad_where (fix->fx_file, fix->fx_line,
539360484Sobrien		    _("symbol in .toc does not match any .tc"));
539460484Sobrien    }
539560484Sobrien
539660484Sobrien  /* Possibly adjust the reloc to be against the csect.  */
5397130561Sobrien  tc = symbol_get_tc (fix->fx_addsy);
5398130561Sobrien  if (tc->subseg == 0
5399130561Sobrien      && tc->class != XMC_TC0
5400130561Sobrien      && tc->class != XMC_TC
5401130561Sobrien      && symseg != bss_section
540260484Sobrien      /* Don't adjust if this is a reloc in the toc section.  */
5403130561Sobrien      && (symseg != data_section
540460484Sobrien	  || ppc_toc_csect == NULL
540560484Sobrien	  || val < ppc_toc_frag->fr_address
540660484Sobrien	  || (ppc_after_toc_frag != NULL
540760484Sobrien	      && val >= ppc_after_toc_frag->fr_address)))
540860484Sobrien    {
540960484Sobrien      symbolS *csect;
5410130561Sobrien      symbolS *next_csect;
541160484Sobrien
5412130561Sobrien      if (symseg == text_section)
541360484Sobrien	csect = ppc_text_csects;
5414130561Sobrien      else if (symseg == data_section)
541560484Sobrien	csect = ppc_data_csects;
541660484Sobrien      else
541760484Sobrien	abort ();
541860484Sobrien
541960484Sobrien      /* Skip the initial dummy symbol.  */
542060484Sobrien      csect = symbol_get_tc (csect)->next;
542160484Sobrien
542260484Sobrien      if (csect != (symbolS *) NULL)
542360484Sobrien	{
5424130561Sobrien	  while ((next_csect = symbol_get_tc (csect)->next) != (symbolS *) NULL
5425130561Sobrien		 && (symbol_get_frag (next_csect)->fr_address <= val))
542660484Sobrien	    {
542760484Sobrien	      /* If the csect address equals the symbol value, then we
542889857Sobrien		 have to look through the full symbol table to see
542989857Sobrien		 whether this is the csect we want.  Note that we will
543089857Sobrien		 only get here if the csect has zero length.  */
5431130561Sobrien	      if (symbol_get_frag (csect)->fr_address == val
5432130561Sobrien		  && S_GET_VALUE (csect) == val)
543360484Sobrien		{
543460484Sobrien		  symbolS *scan;
543560484Sobrien
543660484Sobrien		  for (scan = symbol_next (csect);
543760484Sobrien		       scan != NULL;
543860484Sobrien		       scan = symbol_next (scan))
543960484Sobrien		    {
544060484Sobrien		      if (symbol_get_tc (scan)->subseg != 0)
544160484Sobrien			break;
544260484Sobrien		      if (scan == fix->fx_addsy)
544360484Sobrien			break;
544460484Sobrien		    }
544560484Sobrien
544660484Sobrien		  /* If we found the symbol before the next csect
544789857Sobrien		     symbol, then this is the csect we want.  */
544860484Sobrien		  if (scan == fix->fx_addsy)
544960484Sobrien		    break;
545060484Sobrien		}
545160484Sobrien
5452130561Sobrien	      csect = next_csect;
545360484Sobrien	    }
545460484Sobrien
5455130561Sobrien	  fix->fx_offset += val - symbol_get_frag (csect)->fr_address;
545660484Sobrien	  fix->fx_addsy = csect;
545760484Sobrien	}
5458130561Sobrien      return 0;
545960484Sobrien    }
546060484Sobrien
546160484Sobrien  /* Adjust a reloc against a .lcomm symbol to be against the base
546260484Sobrien     .lcomm.  */
5463130561Sobrien  if (symseg == bss_section
546460484Sobrien      && ! S_IS_EXTERNAL (fix->fx_addsy))
546560484Sobrien    {
5466130561Sobrien      symbolS *sy = symbol_get_frag (fix->fx_addsy)->fr_symbol;
5467130561Sobrien
5468130561Sobrien      fix->fx_offset += val - resolve_symbol_value (sy);
5469130561Sobrien      fix->fx_addsy = sy;
547060484Sobrien    }
547160484Sobrien
547260484Sobrien  return 0;
547360484Sobrien}
547460484Sobrien
547560484Sobrien/* A reloc from one csect to another must be kept.  The assembler
547660484Sobrien   will, of course, keep relocs between sections, and it will keep
547760484Sobrien   absolute relocs, but we need to force it to keep PC relative relocs
547860484Sobrien   between two csects in the same section.  */
547960484Sobrien
548060484Sobrienint
5481218822Sdimppc_force_relocation (fixS *fix)
548260484Sobrien{
548360484Sobrien  /* At this point fix->fx_addsy should already have been converted to
548460484Sobrien     a csect symbol.  If the csect does not include the fragment, then
548560484Sobrien     we need to force the relocation.  */
548660484Sobrien  if (fix->fx_pcrel
548760484Sobrien      && fix->fx_addsy != NULL
548860484Sobrien      && symbol_get_tc (fix->fx_addsy)->subseg != 0
548960484Sobrien      && ((symbol_get_frag (fix->fx_addsy)->fr_address
549060484Sobrien	   > fix->fx_frag->fr_address)
549160484Sobrien	  || (symbol_get_tc (fix->fx_addsy)->next != NULL
549260484Sobrien	      && (symbol_get_frag (symbol_get_tc (fix->fx_addsy)->next)->fr_address
549360484Sobrien		  <= fix->fx_frag->fr_address))))
549460484Sobrien    return 1;
549560484Sobrien
5496130561Sobrien  return generic_force_reloc (fix);
549760484Sobrien}
549860484Sobrien
549960484Sobrien#endif /* OBJ_XCOFF */
550060484Sobrien
550189857Sobrien#ifdef OBJ_ELF
5502130561Sobrien/* If this function returns non-zero, it guarantees that a relocation
5503130561Sobrien   will be emitted for a fixup.  */
5504130561Sobrien
550589857Sobrienint
5506218822Sdimppc_force_relocation (fixS *fix)
5507130561Sobrien{
5508130561Sobrien  /* Branch prediction relocations must force a relocation, as must
5509130561Sobrien     the vtable description relocs.  */
5510130561Sobrien  switch (fix->fx_r_type)
5511130561Sobrien    {
5512130561Sobrien    case BFD_RELOC_PPC_B16_BRTAKEN:
5513130561Sobrien    case BFD_RELOC_PPC_B16_BRNTAKEN:
5514130561Sobrien    case BFD_RELOC_PPC_BA16_BRTAKEN:
5515130561Sobrien    case BFD_RELOC_PPC_BA16_BRNTAKEN:
5516218822Sdim    case BFD_RELOC_24_PLT_PCREL:
5517130561Sobrien    case BFD_RELOC_PPC64_TOC:
5518130561Sobrien      return 1;
5519130561Sobrien    default:
5520130561Sobrien      break;
5521130561Sobrien    }
5522130561Sobrien
5523130561Sobrien  if (fix->fx_r_type >= BFD_RELOC_PPC_TLS
5524130561Sobrien      && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA)
5525130561Sobrien    return 1;
5526130561Sobrien
5527130561Sobrien  return generic_force_reloc (fix);
5528130561Sobrien}
5529130561Sobrien
5530130561Sobrienint
5531218822Sdimppc_fix_adjustable (fixS *fix)
553260484Sobrien{
553389857Sobrien  return (fix->fx_r_type != BFD_RELOC_16_GOTOFF
553489857Sobrien	  && fix->fx_r_type != BFD_RELOC_LO16_GOTOFF
553589857Sobrien	  && fix->fx_r_type != BFD_RELOC_HI16_GOTOFF
553689857Sobrien	  && fix->fx_r_type != BFD_RELOC_HI16_S_GOTOFF
553789857Sobrien	  && fix->fx_r_type != BFD_RELOC_GPREL16
553889857Sobrien	  && fix->fx_r_type != BFD_RELOC_VTABLE_INHERIT
553989857Sobrien	  && fix->fx_r_type != BFD_RELOC_VTABLE_ENTRY
5540130561Sobrien	  && !(fix->fx_r_type >= BFD_RELOC_PPC_TLS
5541218822Sdim	       && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA));
554289857Sobrien}
554360484Sobrien#endif
554460484Sobrien
5545218822Sdim/* Implement HANDLE_ALIGN.  This writes the NOP pattern into an
5546218822Sdim   rs_align_code frag.  */
5547218822Sdim
5548218822Sdimvoid
5549218822Sdimppc_handle_align (struct frag *fragP)
5550218822Sdim{
5551218822Sdim  valueT count = (fragP->fr_next->fr_address
5552218822Sdim		  - (fragP->fr_address + fragP->fr_fix));
5553218822Sdim
5554218822Sdim  if (count != 0 && (count & 3) == 0)
5555218822Sdim    {
5556218822Sdim      char *dest = fragP->fr_literal + fragP->fr_fix;
5557218822Sdim
5558218822Sdim      fragP->fr_var = 4;
5559218822Sdim      md_number_to_chars (dest, 0x60000000, 4);
5560218822Sdim
5561218822Sdim      if ((ppc_cpu & PPC_OPCODE_POWER6) != 0)
5562218822Sdim	{
5563218822Sdim	  /* For power6, we want the last nop to be a group terminating
5564218822Sdim	     one, "ori 1,1,0".  Do this by inserting an rs_fill frag
5565218822Sdim	     immediately after this one, with its address set to the last
5566218822Sdim	     nop location.  This will automatically reduce the number of
5567218822Sdim	     nops in the current frag by one.  */
5568218822Sdim	  if (count > 4)
5569218822Sdim	    {
5570218822Sdim	      struct frag *group_nop = xmalloc (SIZEOF_STRUCT_FRAG + 4);
5571218822Sdim
5572218822Sdim	      memcpy (group_nop, fragP, SIZEOF_STRUCT_FRAG);
5573218822Sdim	      group_nop->fr_address = group_nop->fr_next->fr_address - 4;
5574218822Sdim	      group_nop->fr_fix = 0;
5575218822Sdim	      group_nop->fr_offset = 1;
5576218822Sdim	      group_nop->fr_type = rs_fill;
5577218822Sdim	      fragP->fr_next = group_nop;
5578218822Sdim	      dest = group_nop->fr_literal;
5579218822Sdim	    }
5580218822Sdim
5581218822Sdim	  md_number_to_chars (dest, 0x60210000, 4);
5582218822Sdim	}
5583218822Sdim    }
5584218822Sdim}
5585218822Sdim
558660484Sobrien/* Apply a fixup to the object code.  This is called for all the
558760484Sobrien   fixups we generated by the call to fix_new_exp, above.  In the call
558860484Sobrien   above we used a reloc code which was the largest legal reloc code
558960484Sobrien   plus the operand index.  Here we undo that to recover the operand
559060484Sobrien   index.  At this point all symbol values should be fully resolved,
559160484Sobrien   and we attempt to completely resolve the reloc.  If we can not do
559260484Sobrien   that, we determine the correct reloc code and put it back in the
559360484Sobrien   fixup.  */
559460484Sobrien
559589857Sobrienvoid
5596218822Sdimmd_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
559760484Sobrien{
559889857Sobrien  valueT value = * valP;
559960484Sobrien
560060484Sobrien#ifdef OBJ_ELF
560189857Sobrien  if (fixP->fx_addsy != NULL)
560260484Sobrien    {
5603130561Sobrien      /* Hack around bfd_install_relocation brain damage.  */
560489857Sobrien      if (fixP->fx_pcrel)
560589857Sobrien	value += fixP->fx_frag->fr_address + fixP->fx_where;
560660484Sobrien    }
560760484Sobrien  else
560889857Sobrien    fixP->fx_done = 1;
560960484Sobrien#else
5610130561Sobrien  /* FIXME FIXME FIXME: The value we are passed in *valP includes
5611218822Sdim     the symbol values.  If we are doing this relocation the code in
5612218822Sdim     write.c is going to call bfd_install_relocation, which is also
5613218822Sdim     going to use the symbol value.  That means that if the reloc is
5614218822Sdim     fully resolved we want to use *valP since bfd_install_relocation is
5615218822Sdim     not being used.
561660484Sobrien     However, if the reloc is not fully resolved we do not want to use
5617130561Sobrien     *valP, and must use fx_offset instead.  However, if the reloc
5618130561Sobrien     is PC relative, we do want to use *valP since it includes the
561960484Sobrien     result of md_pcrel_from.  This is confusing.  */
562089857Sobrien  if (fixP->fx_addsy == (symbolS *) NULL)
562189857Sobrien    fixP->fx_done = 1;
562289857Sobrien
562389857Sobrien  else if (fixP->fx_pcrel)
562489857Sobrien    ;
562589857Sobrien
562660484Sobrien  else
5627130561Sobrien    value = fixP->fx_offset;
5628130561Sobrien#endif
5629130561Sobrien
5630130561Sobrien  if (fixP->fx_subsy != (symbolS *) NULL)
563160484Sobrien    {
5632130561Sobrien      /* We can't actually support subtracting a symbol.  */
5633130561Sobrien      as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
563460484Sobrien    }
563560484Sobrien
563689857Sobrien  if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
563760484Sobrien    {
563860484Sobrien      int opindex;
563960484Sobrien      const struct powerpc_operand *operand;
564060484Sobrien      char *where;
564160484Sobrien      unsigned long insn;
564260484Sobrien
564389857Sobrien      opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
564460484Sobrien
564560484Sobrien      operand = &powerpc_operands[opindex];
564660484Sobrien
564760484Sobrien#ifdef OBJ_XCOFF
564889857Sobrien      /* An instruction like `lwz 9,sym(30)' when `sym' is not a TOC symbol
564989857Sobrien	 does not generate a reloc.  It uses the offset of `sym' within its
565089857Sobrien	 csect.  Other usages, such as `.long sym', generate relocs.  This
565189857Sobrien	 is the documented behaviour of non-TOC symbols.  */
565260484Sobrien      if ((operand->flags & PPC_OPERAND_PARENS) != 0
5653218822Sdim	  && (operand->bitm & 0xfff0) == 0xfff0
565460484Sobrien	  && operand->shift == 0
5655104834Sobrien	  && (operand->insert == NULL || ppc_obj64)
565689857Sobrien	  && fixP->fx_addsy != NULL
565789857Sobrien	  && symbol_get_tc (fixP->fx_addsy)->subseg != 0
565889857Sobrien	  && symbol_get_tc (fixP->fx_addsy)->class != XMC_TC
565989857Sobrien	  && symbol_get_tc (fixP->fx_addsy)->class != XMC_TC0
566089857Sobrien	  && S_GET_SEGMENT (fixP->fx_addsy) != bss_section)
566160484Sobrien	{
566289857Sobrien	  value = fixP->fx_offset;
566389857Sobrien	  fixP->fx_done = 1;
566460484Sobrien	}
566560484Sobrien#endif
566660484Sobrien
566760484Sobrien      /* Fetch the instruction, insert the fully resolved operand
566860484Sobrien	 value, and stuff the instruction back again.  */
566989857Sobrien      where = fixP->fx_frag->fr_literal + fixP->fx_where;
567060484Sobrien      if (target_big_endian)
567160484Sobrien	insn = bfd_getb32 ((unsigned char *) where);
567260484Sobrien      else
567360484Sobrien	insn = bfd_getl32 ((unsigned char *) where);
567460484Sobrien      insn = ppc_insert_operand (insn, operand, (offsetT) value,
567589857Sobrien				 fixP->fx_file, fixP->fx_line);
567660484Sobrien      if (target_big_endian)
567760484Sobrien	bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
567860484Sobrien      else
567960484Sobrien	bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
568060484Sobrien
568189857Sobrien      if (fixP->fx_done)
568289857Sobrien	/* Nothing else to do here.  */
568389857Sobrien	return;
568460484Sobrien
568589857Sobrien      assert (fixP->fx_addsy != NULL);
568689857Sobrien
568760484Sobrien      /* Determine a BFD reloc value based on the operand information.
568860484Sobrien	 We are only prepared to turn a few of the operands into
568989857Sobrien	 relocs.  */
569060484Sobrien      if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
5691218822Sdim	  && operand->bitm == 0x3fffffc
569260484Sobrien	  && operand->shift == 0)
569389857Sobrien	fixP->fx_r_type = BFD_RELOC_PPC_B26;
569460484Sobrien      else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
5695218822Sdim	  && operand->bitm == 0xfffc
569660484Sobrien	  && operand->shift == 0)
5697104834Sobrien	{
5698104834Sobrien	  fixP->fx_r_type = BFD_RELOC_PPC_B16;
5699104834Sobrien#ifdef OBJ_XCOFF
5700104834Sobrien	  fixP->fx_size = 2;
5701104834Sobrien	  if (target_big_endian)
5702104834Sobrien	    fixP->fx_where += 2;
5703104834Sobrien#endif
5704104834Sobrien	}
570560484Sobrien      else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0
5706218822Sdim	       && operand->bitm == 0x3fffffc
570760484Sobrien	       && operand->shift == 0)
570889857Sobrien	fixP->fx_r_type = BFD_RELOC_PPC_BA26;
570960484Sobrien      else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0
5710218822Sdim	       && operand->bitm == 0xfffc
571160484Sobrien	       && operand->shift == 0)
5712104834Sobrien	{
5713104834Sobrien	  fixP->fx_r_type = BFD_RELOC_PPC_BA16;
5714104834Sobrien#ifdef OBJ_XCOFF
5715104834Sobrien	  fixP->fx_size = 2;
5716104834Sobrien	  if (target_big_endian)
5717104834Sobrien	    fixP->fx_where += 2;
5718104834Sobrien#endif
5719104834Sobrien	}
572089857Sobrien#if defined (OBJ_XCOFF) || defined (OBJ_ELF)
572160484Sobrien      else if ((operand->flags & PPC_OPERAND_PARENS) != 0
5722218822Sdim	       && (operand->bitm & 0xfff0) == 0xfff0
5723130561Sobrien	       && operand->shift == 0)
572460484Sobrien	{
5725130561Sobrien	  if (ppc_is_toc_sym (fixP->fx_addsy))
5726130561Sobrien	    {
5727130561Sobrien	      fixP->fx_r_type = BFD_RELOC_PPC_TOC16;
572889857Sobrien#ifdef OBJ_ELF
5729130561Sobrien	      if (ppc_obj64
5730130561Sobrien		  && (operand->flags & PPC_OPERAND_DS) != 0)
5731130561Sobrien		fixP->fx_r_type = BFD_RELOC_PPC64_TOC16_DS;
573289857Sobrien#endif
5733130561Sobrien	    }
5734130561Sobrien	  else
5735130561Sobrien	    {
5736130561Sobrien	      fixP->fx_r_type = BFD_RELOC_16;
5737130561Sobrien#ifdef OBJ_ELF
5738130561Sobrien	      if (ppc_obj64
5739130561Sobrien		  && (operand->flags & PPC_OPERAND_DS) != 0)
5740130561Sobrien		fixP->fx_r_type = BFD_RELOC_PPC64_ADDR16_DS;
5741130561Sobrien#endif
5742130561Sobrien	    }
574389857Sobrien	  fixP->fx_size = 2;
574460484Sobrien	  if (target_big_endian)
574589857Sobrien	    fixP->fx_where += 2;
574660484Sobrien	}
574789857Sobrien#endif /* defined (OBJ_XCOFF) || defined (OBJ_ELF) */
574860484Sobrien      else
574960484Sobrien	{
575060484Sobrien	  char *sfile;
575160484Sobrien	  unsigned int sline;
575260484Sobrien
575360484Sobrien	  /* Use expr_symbol_where to see if this is an expression
575489857Sobrien	     symbol.  */
575589857Sobrien	  if (expr_symbol_where (fixP->fx_addsy, &sfile, &sline))
575689857Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
575760484Sobrien			  _("unresolved expression that must be resolved"));
575860484Sobrien	  else
575989857Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
576089857Sobrien			  _("unsupported relocation against %s"),
576189857Sobrien			  S_GET_NAME (fixP->fx_addsy));
576289857Sobrien	  fixP->fx_done = 1;
576389857Sobrien	  return;
576460484Sobrien	}
576560484Sobrien    }
576660484Sobrien  else
576760484Sobrien    {
576860484Sobrien#ifdef OBJ_ELF
576989857Sobrien      ppc_elf_validate_fix (fixP, seg);
577060484Sobrien#endif
577189857Sobrien      switch (fixP->fx_r_type)
577260484Sobrien	{
577360484Sobrien	case BFD_RELOC_CTOR:
5774104834Sobrien	  if (ppc_obj64)
577589857Sobrien	    goto ctor64;
577689857Sobrien	  /* fall through */
577760484Sobrien
577889857Sobrien	case BFD_RELOC_32:
577989857Sobrien	  if (fixP->fx_pcrel)
578089857Sobrien	    fixP->fx_r_type = BFD_RELOC_32_PCREL;
578189857Sobrien	  /* fall through */
578289857Sobrien
578360484Sobrien	case BFD_RELOC_RVA:
578460484Sobrien	case BFD_RELOC_32_PCREL:
578560484Sobrien	case BFD_RELOC_PPC_EMB_NADDR32:
578689857Sobrien	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
578760484Sobrien			      value, 4);
578860484Sobrien	  break;
578960484Sobrien
579077298Sobrien	case BFD_RELOC_64:
579189857Sobrien	ctor64:
579289857Sobrien	  if (fixP->fx_pcrel)
579389857Sobrien	    fixP->fx_r_type = BFD_RELOC_64_PCREL;
579489857Sobrien	  /* fall through */
579589857Sobrien
579677298Sobrien	case BFD_RELOC_64_PCREL:
579789857Sobrien	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
579877298Sobrien			      value, 8);
579977298Sobrien	  break;
580089857Sobrien
580160484Sobrien	case BFD_RELOC_GPREL16:
580260484Sobrien	case BFD_RELOC_16_GOT_PCREL:
580360484Sobrien	case BFD_RELOC_16_GOTOFF:
580460484Sobrien	case BFD_RELOC_LO16_GOTOFF:
580560484Sobrien	case BFD_RELOC_HI16_GOTOFF:
580660484Sobrien	case BFD_RELOC_HI16_S_GOTOFF:
580799461Sobrien	case BFD_RELOC_16_BASEREL:
580860484Sobrien	case BFD_RELOC_LO16_BASEREL:
580960484Sobrien	case BFD_RELOC_HI16_BASEREL:
581060484Sobrien	case BFD_RELOC_HI16_S_BASEREL:
581160484Sobrien	case BFD_RELOC_PPC_EMB_NADDR16:
581260484Sobrien	case BFD_RELOC_PPC_EMB_NADDR16_LO:
581360484Sobrien	case BFD_RELOC_PPC_EMB_NADDR16_HI:
581460484Sobrien	case BFD_RELOC_PPC_EMB_NADDR16_HA:
581560484Sobrien	case BFD_RELOC_PPC_EMB_SDAI16:
581660484Sobrien	case BFD_RELOC_PPC_EMB_SDA2REL:
581760484Sobrien	case BFD_RELOC_PPC_EMB_SDA2I16:
581860484Sobrien	case BFD_RELOC_PPC_EMB_RELSEC16:
581960484Sobrien	case BFD_RELOC_PPC_EMB_RELST_LO:
582060484Sobrien	case BFD_RELOC_PPC_EMB_RELST_HI:
582160484Sobrien	case BFD_RELOC_PPC_EMB_RELST_HA:
582260484Sobrien	case BFD_RELOC_PPC_EMB_RELSDA:
582360484Sobrien	case BFD_RELOC_PPC_TOC16:
582489857Sobrien#ifdef OBJ_ELF
582589857Sobrien	case BFD_RELOC_PPC64_TOC16_LO:
582689857Sobrien	case BFD_RELOC_PPC64_TOC16_HI:
582789857Sobrien	case BFD_RELOC_PPC64_TOC16_HA:
582889857Sobrien#endif
582989857Sobrien	  if (fixP->fx_pcrel)
583060484Sobrien	    {
583189857Sobrien	      if (fixP->fx_addsy != NULL)
583289857Sobrien		as_bad_where (fixP->fx_file, fixP->fx_line,
583360484Sobrien			      _("cannot emit PC relative %s relocation against %s"),
583489857Sobrien			      bfd_get_reloc_code_name (fixP->fx_r_type),
583589857Sobrien			      S_GET_NAME (fixP->fx_addsy));
583660484Sobrien	      else
583789857Sobrien		as_bad_where (fixP->fx_file, fixP->fx_line,
583860484Sobrien			      _("cannot emit PC relative %s relocation"),
583989857Sobrien			      bfd_get_reloc_code_name (fixP->fx_r_type));
584060484Sobrien	    }
584160484Sobrien
584289857Sobrien	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
584360484Sobrien			      value, 2);
584460484Sobrien	  break;
584560484Sobrien
5846218822Sdim	case BFD_RELOC_16:
5847218822Sdim	  if (fixP->fx_pcrel)
5848218822Sdim	    fixP->fx_r_type = BFD_RELOC_16_PCREL;
5849218822Sdim	  /* fall through */
5850218822Sdim
5851218822Sdim	case BFD_RELOC_16_PCREL:
5852218822Sdim	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
5853218822Sdim			      value, 2);
5854218822Sdim	  break;
5855218822Sdim
5856218822Sdim	case BFD_RELOC_LO16:
5857218822Sdim	  if (fixP->fx_pcrel)
5858218822Sdim	    fixP->fx_r_type = BFD_RELOC_LO16_PCREL;
5859218822Sdim	  /* fall through */
5860218822Sdim
5861218822Sdim	case BFD_RELOC_LO16_PCREL:
5862218822Sdim	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
5863218822Sdim			      value, 2);
5864218822Sdim	  break;
5865218822Sdim
586660484Sobrien	  /* This case happens when you write, for example,
586760484Sobrien	     lis %r3,(L1-L2)@ha
586860484Sobrien	     where L1 and L2 are defined later.  */
586960484Sobrien	case BFD_RELOC_HI16:
587089857Sobrien	  if (fixP->fx_pcrel)
5871218822Sdim	    fixP->fx_r_type = BFD_RELOC_HI16_PCREL;
5872218822Sdim	  /* fall through */
5873218822Sdim
5874218822Sdim	case BFD_RELOC_HI16_PCREL:
587589857Sobrien	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
587689857Sobrien			      PPC_HI (value), 2);
587760484Sobrien	  break;
587889857Sobrien
587960484Sobrien	case BFD_RELOC_HI16_S:
588089857Sobrien	  if (fixP->fx_pcrel)
5881218822Sdim	    fixP->fx_r_type = BFD_RELOC_HI16_S_PCREL;
5882218822Sdim	  /* fall through */
5883218822Sdim
5884218822Sdim	case BFD_RELOC_HI16_S_PCREL:
588589857Sobrien	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
588689857Sobrien			      PPC_HA (value), 2);
588760484Sobrien	  break;
588860484Sobrien
588989857Sobrien#ifdef OBJ_ELF
589089857Sobrien	case BFD_RELOC_PPC64_HIGHER:
589189857Sobrien	  if (fixP->fx_pcrel)
589289857Sobrien	    abort ();
589389857Sobrien	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
589489857Sobrien			      PPC_HIGHER (value), 2);
589589857Sobrien	  break;
589689857Sobrien
589789857Sobrien	case BFD_RELOC_PPC64_HIGHER_S:
589889857Sobrien	  if (fixP->fx_pcrel)
589989857Sobrien	    abort ();
590089857Sobrien	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
590189857Sobrien			      PPC_HIGHERA (value), 2);
590289857Sobrien	  break;
590389857Sobrien
590489857Sobrien	case BFD_RELOC_PPC64_HIGHEST:
590589857Sobrien	  if (fixP->fx_pcrel)
590689857Sobrien	    abort ();
590789857Sobrien	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
590889857Sobrien			      PPC_HIGHEST (value), 2);
590989857Sobrien	  break;
591089857Sobrien
591189857Sobrien	case BFD_RELOC_PPC64_HIGHEST_S:
591289857Sobrien	  if (fixP->fx_pcrel)
591389857Sobrien	    abort ();
591489857Sobrien	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
591589857Sobrien			      PPC_HIGHESTA (value), 2);
591689857Sobrien	  break;
591789857Sobrien
591889857Sobrien	case BFD_RELOC_PPC64_ADDR16_DS:
591989857Sobrien	case BFD_RELOC_PPC64_ADDR16_LO_DS:
592089857Sobrien	case BFD_RELOC_PPC64_GOT16_DS:
592189857Sobrien	case BFD_RELOC_PPC64_GOT16_LO_DS:
592289857Sobrien	case BFD_RELOC_PPC64_PLT16_LO_DS:
592389857Sobrien	case BFD_RELOC_PPC64_SECTOFF_DS:
592489857Sobrien	case BFD_RELOC_PPC64_SECTOFF_LO_DS:
592589857Sobrien	case BFD_RELOC_PPC64_TOC16_DS:
592689857Sobrien	case BFD_RELOC_PPC64_TOC16_LO_DS:
592789857Sobrien	case BFD_RELOC_PPC64_PLTGOT16_DS:
592889857Sobrien	case BFD_RELOC_PPC64_PLTGOT16_LO_DS:
592989857Sobrien	  if (fixP->fx_pcrel)
593089857Sobrien	    abort ();
593189857Sobrien	  {
5932218822Sdim	    char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
5933130561Sobrien	    unsigned long val, mask;
593489857Sobrien
593589857Sobrien	    if (target_big_endian)
5936130561Sobrien	      val = bfd_getb32 (where - 2);
593789857Sobrien	    else
5938130561Sobrien	      val = bfd_getl32 (where);
5939130561Sobrien	    mask = 0xfffc;
5940130561Sobrien	    /* lq insns reserve the four lsbs.  */
5941130561Sobrien	    if ((ppc_cpu & PPC_OPCODE_POWER4) != 0
5942130561Sobrien		&& (val & (0x3f << 26)) == (56u << 26))
5943130561Sobrien	      mask = 0xfff0;
5944130561Sobrien	    val |= value & mask;
594589857Sobrien	    if (target_big_endian)
594689857Sobrien	      bfd_putb16 ((bfd_vma) val, where);
594789857Sobrien	    else
594889857Sobrien	      bfd_putl16 ((bfd_vma) val, where);
594989857Sobrien	  }
595089857Sobrien	  break;
5951130561Sobrien
5952130561Sobrien	case BFD_RELOC_PPC_B16_BRTAKEN:
5953130561Sobrien	case BFD_RELOC_PPC_B16_BRNTAKEN:
5954130561Sobrien	case BFD_RELOC_PPC_BA16_BRTAKEN:
5955130561Sobrien	case BFD_RELOC_PPC_BA16_BRNTAKEN:
5956130561Sobrien	  break;
5957130561Sobrien
5958130561Sobrien	case BFD_RELOC_PPC_TLS:
5959275873Sjhibbits	case BFD_RELOC_PPC_TLSLD:
5960275873Sjhibbits	case BFD_RELOC_PPC_TLSGD:
5961218822Sdim	  break;
5962218822Sdim
5963130561Sobrien	case BFD_RELOC_PPC_DTPMOD:
5964130561Sobrien	case BFD_RELOC_PPC_TPREL16:
5965130561Sobrien	case BFD_RELOC_PPC_TPREL16_LO:
5966130561Sobrien	case BFD_RELOC_PPC_TPREL16_HI:
5967130561Sobrien	case BFD_RELOC_PPC_TPREL16_HA:
5968130561Sobrien	case BFD_RELOC_PPC_TPREL:
5969130561Sobrien	case BFD_RELOC_PPC_DTPREL16:
5970130561Sobrien	case BFD_RELOC_PPC_DTPREL16_LO:
5971130561Sobrien	case BFD_RELOC_PPC_DTPREL16_HI:
5972130561Sobrien	case BFD_RELOC_PPC_DTPREL16_HA:
5973130561Sobrien	case BFD_RELOC_PPC_DTPREL:
5974130561Sobrien	case BFD_RELOC_PPC_GOT_TLSGD16:
5975130561Sobrien	case BFD_RELOC_PPC_GOT_TLSGD16_LO:
5976130561Sobrien	case BFD_RELOC_PPC_GOT_TLSGD16_HI:
5977130561Sobrien	case BFD_RELOC_PPC_GOT_TLSGD16_HA:
5978130561Sobrien	case BFD_RELOC_PPC_GOT_TLSLD16:
5979130561Sobrien	case BFD_RELOC_PPC_GOT_TLSLD16_LO:
5980130561Sobrien	case BFD_RELOC_PPC_GOT_TLSLD16_HI:
5981130561Sobrien	case BFD_RELOC_PPC_GOT_TLSLD16_HA:
5982130561Sobrien	case BFD_RELOC_PPC_GOT_TPREL16:
5983130561Sobrien	case BFD_RELOC_PPC_GOT_TPREL16_LO:
5984130561Sobrien	case BFD_RELOC_PPC_GOT_TPREL16_HI:
5985130561Sobrien	case BFD_RELOC_PPC_GOT_TPREL16_HA:
5986130561Sobrien	case BFD_RELOC_PPC_GOT_DTPREL16:
5987130561Sobrien	case BFD_RELOC_PPC_GOT_DTPREL16_LO:
5988130561Sobrien	case BFD_RELOC_PPC_GOT_DTPREL16_HI:
5989130561Sobrien	case BFD_RELOC_PPC_GOT_DTPREL16_HA:
5990130561Sobrien	case BFD_RELOC_PPC64_TPREL16_DS:
5991130561Sobrien	case BFD_RELOC_PPC64_TPREL16_LO_DS:
5992130561Sobrien	case BFD_RELOC_PPC64_TPREL16_HIGHER:
5993130561Sobrien	case BFD_RELOC_PPC64_TPREL16_HIGHERA:
5994130561Sobrien	case BFD_RELOC_PPC64_TPREL16_HIGHEST:
5995130561Sobrien	case BFD_RELOC_PPC64_TPREL16_HIGHESTA:
5996130561Sobrien	case BFD_RELOC_PPC64_DTPREL16_DS:
5997130561Sobrien	case BFD_RELOC_PPC64_DTPREL16_LO_DS:
5998130561Sobrien	case BFD_RELOC_PPC64_DTPREL16_HIGHER:
5999130561Sobrien	case BFD_RELOC_PPC64_DTPREL16_HIGHERA:
6000130561Sobrien	case BFD_RELOC_PPC64_DTPREL16_HIGHEST:
6001130561Sobrien	case BFD_RELOC_PPC64_DTPREL16_HIGHESTA:
6002218822Sdim	  S_SET_THREAD_LOCAL (fixP->fx_addsy);
6003130561Sobrien	  break;
600489857Sobrien#endif
600560484Sobrien	  /* Because SDA21 modifies the register field, the size is set to 4
600689857Sobrien	     bytes, rather than 2, so offset it here appropriately.  */
600760484Sobrien	case BFD_RELOC_PPC_EMB_SDA21:
600889857Sobrien	  if (fixP->fx_pcrel)
600960484Sobrien	    abort ();
601060484Sobrien
601189857Sobrien	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where
601260484Sobrien			      + ((target_big_endian) ? 2 : 0),
601360484Sobrien			      value, 2);
601460484Sobrien	  break;
601560484Sobrien
601660484Sobrien	case BFD_RELOC_8:
601789857Sobrien	  if (fixP->fx_pcrel)
6018130561Sobrien	    {
6019130561Sobrien	      /* This can occur if there is a bug in the input assembler, eg:
6020130561Sobrien		 ".byte <undefined_symbol> - ."  */
6021130561Sobrien	      if (fixP->fx_addsy)
6022130561Sobrien		as_bad (_("Unable to handle reference to symbol %s"),
6023130561Sobrien			S_GET_NAME (fixP->fx_addsy));
6024130561Sobrien	      else
6025130561Sobrien		as_bad (_("Unable to resolve expression"));
6026130561Sobrien	      fixP->fx_done = 1;
6027130561Sobrien	    }
6028130561Sobrien	  else
6029130561Sobrien	    md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
6030130561Sobrien				value, 1);
603160484Sobrien	  break;
603260484Sobrien
603360484Sobrien	case BFD_RELOC_24_PLT_PCREL:
603460484Sobrien	case BFD_RELOC_PPC_LOCAL24PC:
603589857Sobrien	  if (!fixP->fx_pcrel && !fixP->fx_done)
603660484Sobrien	    abort ();
603760484Sobrien
603889857Sobrien	  if (fixP->fx_done)
603989857Sobrien	    {
604089857Sobrien	      char *where;
604189857Sobrien	      unsigned long insn;
604277298Sobrien
604389857Sobrien	      /* Fetch the instruction, insert the fully resolved operand
604489857Sobrien		 value, and stuff the instruction back again.  */
604589857Sobrien	      where = fixP->fx_frag->fr_literal + fixP->fx_where;
604689857Sobrien	      if (target_big_endian)
604789857Sobrien		insn = bfd_getb32 ((unsigned char *) where);
604889857Sobrien	      else
604989857Sobrien		insn = bfd_getl32 ((unsigned char *) where);
605089857Sobrien	      if ((value & 3) != 0)
605189857Sobrien		as_bad_where (fixP->fx_file, fixP->fx_line,
605289857Sobrien			      _("must branch to an address a multiple of 4"));
605389857Sobrien	      if ((offsetT) value < -0x40000000
605489857Sobrien		  || (offsetT) value >= 0x40000000)
605589857Sobrien		as_bad_where (fixP->fx_file, fixP->fx_line,
605689857Sobrien			      _("@local or @plt branch destination is too far away, %ld bytes"),
605789857Sobrien			      (long) value);
605889857Sobrien	      insn = insn | (value & 0x03fffffc);
605989857Sobrien	      if (target_big_endian)
606089857Sobrien		bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
606189857Sobrien	      else
606289857Sobrien		bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
606389857Sobrien	    }
606460484Sobrien	  break;
606560484Sobrien
606660484Sobrien	case BFD_RELOC_VTABLE_INHERIT:
606789857Sobrien	  fixP->fx_done = 0;
606889857Sobrien	  if (fixP->fx_addsy
606989857Sobrien	      && !S_IS_DEFINED (fixP->fx_addsy)
607089857Sobrien	      && !S_IS_WEAK (fixP->fx_addsy))
607189857Sobrien	    S_SET_WEAK (fixP->fx_addsy);
607260484Sobrien	  break;
607360484Sobrien
607460484Sobrien	case BFD_RELOC_VTABLE_ENTRY:
607589857Sobrien	  fixP->fx_done = 0;
607660484Sobrien	  break;
607760484Sobrien
607889857Sobrien#ifdef OBJ_ELF
607989857Sobrien	  /* Generated by reference to `sym@tocbase'.  The sym is
608089857Sobrien	     ignored by the linker.  */
608189857Sobrien	case BFD_RELOC_PPC64_TOC:
608289857Sobrien	  fixP->fx_done = 0;
608389857Sobrien	  break;
608489857Sobrien#endif
608560484Sobrien	default:
608677298Sobrien	  fprintf (stderr,
608789857Sobrien		   _("Gas failure, reloc value %d\n"), fixP->fx_r_type);
608889857Sobrien	  fflush (stderr);
608960484Sobrien	  abort ();
609060484Sobrien	}
609160484Sobrien    }
609260484Sobrien
609360484Sobrien#ifdef OBJ_ELF
609489857Sobrien  fixP->fx_addnumber = value;
6095218822Sdim
6096218822Sdim  /* PowerPC uses RELA relocs, ie. the reloc addend is stored separately
6097218822Sdim     from the section contents.  If we are going to be emitting a reloc
6098218822Sdim     then the section contents are immaterial, so don't warn if they
6099218822Sdim     happen to overflow.  Leave such warnings to ld.  */
6100218822Sdim  if (!fixP->fx_done)
6101218822Sdim    fixP->fx_no_overflow = 1;
610260484Sobrien#else
610389857Sobrien  if (fixP->fx_r_type != BFD_RELOC_PPC_TOC16)
610489857Sobrien    fixP->fx_addnumber = 0;
610560484Sobrien  else
610660484Sobrien    {
610760484Sobrien#ifdef TE_PE
610889857Sobrien      fixP->fx_addnumber = 0;
610960484Sobrien#else
611060484Sobrien      /* We want to use the offset within the data segment of the
611160484Sobrien	 symbol, not the actual VMA of the symbol.  */
611289857Sobrien      fixP->fx_addnumber =
611389857Sobrien	- bfd_get_section_vma (stdoutput, S_GET_SEGMENT (fixP->fx_addsy));
611460484Sobrien#endif
611560484Sobrien    }
611660484Sobrien#endif
611760484Sobrien}
611860484Sobrien
611960484Sobrien/* Generate a reloc for a fixup.  */
612060484Sobrien
612160484Sobrienarelent *
6122218822Sdimtc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
612360484Sobrien{
612460484Sobrien  arelent *reloc;
612560484Sobrien
612660484Sobrien  reloc = (arelent *) xmalloc (sizeof (arelent));
612760484Sobrien
612860484Sobrien  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
612960484Sobrien  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
613060484Sobrien  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
613160484Sobrien  reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
613260484Sobrien  if (reloc->howto == (reloc_howto_type *) NULL)
613360484Sobrien    {
613460484Sobrien      as_bad_where (fixp->fx_file, fixp->fx_line,
613589857Sobrien		    _("reloc %d not supported by object file format"),
613689857Sobrien		    (int) fixp->fx_r_type);
613760484Sobrien      return NULL;
613860484Sobrien    }
613960484Sobrien  reloc->addend = fixp->fx_addnumber;
614060484Sobrien
614160484Sobrien  return reloc;
614260484Sobrien}
6143130561Sobrien
6144130561Sobrienvoid
6145218822Sdimppc_cfi_frame_initial_instructions (void)
6146130561Sobrien{
6147130561Sobrien  cfi_add_CFA_def_cfa (1, 0);
6148130561Sobrien}
6149130561Sobrien
6150130561Sobrienint
6151218822Sdimtc_ppc_regname_to_dw2regnum (char *regname)
6152130561Sobrien{
6153130561Sobrien  unsigned int regnum = -1;
6154130561Sobrien  unsigned int i;
6155130561Sobrien  const char *p;
6156130561Sobrien  char *q;
6157130561Sobrien  static struct { char *name; int dw2regnum; } regnames[] =
6158130561Sobrien    {
6159130561Sobrien      { "sp", 1 }, { "r.sp", 1 }, { "rtoc", 2 }, { "r.toc", 2 },
6160130561Sobrien      { "mq", 64 }, { "lr", 65 }, { "ctr", 66 }, { "ap", 67 },
6161218822Sdim      { "cr", 70 }, { "xer", 76 }, { "vrsave", 109 }, { "vscr", 110 },
6162130561Sobrien      { "spe_acc", 111 }, { "spefscr", 112 }
6163130561Sobrien    };
6164130561Sobrien
6165130561Sobrien  for (i = 0; i < ARRAY_SIZE (regnames); ++i)
6166130561Sobrien    if (strcmp (regnames[i].name, regname) == 0)
6167130561Sobrien      return regnames[i].dw2regnum;
6168130561Sobrien
6169130561Sobrien  if (regname[0] == 'r' || regname[0] == 'f' || regname[0] == 'v')
6170130561Sobrien    {
6171130561Sobrien      p = regname + 1 + (regname[1] == '.');
6172130561Sobrien      regnum = strtoul (p, &q, 10);
6173130561Sobrien      if (p == q || *q || regnum >= 32)
6174130561Sobrien	return -1;
6175130561Sobrien      if (regname[0] == 'f')
6176130561Sobrien	regnum += 32;
6177130561Sobrien      else if (regname[0] == 'v')
6178130561Sobrien	regnum += 77;
6179130561Sobrien    }
6180130561Sobrien  else if (regname[0] == 'c' && regname[1] == 'r')
6181130561Sobrien    {
6182130561Sobrien      p = regname + 2 + (regname[2] == '.');
6183130561Sobrien      if (p[0] < '0' || p[0] > '7' || p[1])
6184130561Sobrien	return -1;
6185130561Sobrien      regnum = p[0] - '0' + 68;
6186130561Sobrien    }
6187130561Sobrien  return regnum;
6188130561Sobrien}
6189