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.  */
684263177Sjhibbitsstatic 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
1213104834Sobrien	  ? (ppc_obj64 ? "elf64-powerpc" : "elf32-powerpc")
1214104834Sobrien	  : (ppc_obj64 ? "elf64-powerpcle" : "elf32-powerpcle"));
1215218822Sdim# endif
121677298Sobrien#endif
121777298Sobrien}
121877298Sobrien
1219130561Sobrien/* Insert opcodes and macros into hash tables.  Called at startup and
1220130561Sobrien   for .cpu pseudo.  */
122160484Sobrien
1222130561Sobrienstatic void
1223130561Sobrienppc_setup_opcodes (void)
122460484Sobrien{
1225218822Sdim  const struct powerpc_opcode *op;
122660484Sobrien  const struct powerpc_opcode *op_end;
122760484Sobrien  const struct powerpc_macro *macro;
122860484Sobrien  const struct powerpc_macro *macro_end;
1229218822Sdim  bfd_boolean bad_insn = FALSE;
123060484Sobrien
1231130561Sobrien  if (ppc_hash != NULL)
1232130561Sobrien    hash_die (ppc_hash);
1233130561Sobrien  if (ppc_macro_hash != NULL)
1234130561Sobrien    hash_die (ppc_macro_hash);
123560484Sobrien
123660484Sobrien  /* Insert the opcodes into a hash table.  */
123760484Sobrien  ppc_hash = hash_new ();
123860484Sobrien
1239218822Sdim  if (ENABLE_CHECKING)
1240218822Sdim    {
1241218822Sdim      unsigned int i;
1242218822Sdim
1243218822Sdim      /* Check operand masks.  Code here and in the disassembler assumes
1244218822Sdim	 all the 1's in the mask are contiguous.  */
1245218822Sdim      for (i = 0; i < num_powerpc_operands; ++i)
1246218822Sdim	{
1247218822Sdim	  unsigned long mask = powerpc_operands[i].bitm;
1248218822Sdim	  unsigned long right_bit;
1249218822Sdim	  unsigned int j;
1250218822Sdim
1251218822Sdim	  right_bit = mask & -mask;
1252218822Sdim	  mask += right_bit;
1253218822Sdim	  right_bit = mask & -mask;
1254218822Sdim	  if (mask != right_bit)
1255218822Sdim	    {
1256218822Sdim	      as_bad (_("powerpc_operands[%d].bitm invalid"), i);
1257218822Sdim	      bad_insn = TRUE;
1258218822Sdim	    }
1259218822Sdim	  for (j = i + 1; j < num_powerpc_operands; ++j)
1260218822Sdim	    if (memcmp (&powerpc_operands[i], &powerpc_operands[j],
1261218822Sdim			sizeof (powerpc_operands[0])) == 0)
1262218822Sdim	      {
1263218822Sdim		as_bad (_("powerpc_operands[%d] duplicates powerpc_operands[%d]"),
1264218822Sdim			j, i);
1265218822Sdim		bad_insn = TRUE;
1266218822Sdim	      }
1267218822Sdim	}
1268218822Sdim    }
1269218822Sdim
127060484Sobrien  op_end = powerpc_opcodes + powerpc_num_opcodes;
127160484Sobrien  for (op = powerpc_opcodes; op < op_end; op++)
127260484Sobrien    {
1273218822Sdim      if (ENABLE_CHECKING)
1274218822Sdim	{
1275218822Sdim	  const unsigned char *o;
1276218822Sdim	  unsigned long omask = op->mask;
127760484Sobrien
1278218822Sdim	  /* The mask had better not trim off opcode bits.  */
1279218822Sdim	  if ((op->opcode & omask) != op->opcode)
1280218822Sdim	    {
1281218822Sdim	      as_bad (_("mask trims opcode bits for %s"),
1282218822Sdim		      op->name);
1283218822Sdim	      bad_insn = TRUE;
1284218822Sdim	    }
1285218822Sdim
1286218822Sdim	  /* The operands must not overlap the opcode or each other.  */
1287218822Sdim	  for (o = op->operands; *o; ++o)
1288218822Sdim	    if (*o >= num_powerpc_operands)
1289218822Sdim	      {
1290218822Sdim		as_bad (_("operand index error for %s"),
1291218822Sdim			op->name);
1292218822Sdim		bad_insn = TRUE;
1293218822Sdim	      }
1294218822Sdim	    else
1295218822Sdim	      {
1296218822Sdim		const struct powerpc_operand *operand = &powerpc_operands[*o];
1297218822Sdim		if (operand->shift >= 0)
1298218822Sdim		  {
1299218822Sdim		    unsigned long mask = operand->bitm << operand->shift;
1300218822Sdim		    if (omask & mask)
1301218822Sdim		      {
1302218822Sdim			as_bad (_("operand %d overlap in %s"),
1303218822Sdim				(int) (o - op->operands), op->name);
1304218822Sdim			bad_insn = TRUE;
1305218822Sdim		      }
1306218822Sdim		    omask |= mask;
1307218822Sdim		  }
1308218822Sdim	      }
1309218822Sdim	}
1310218822Sdim
1311104834Sobrien      if ((op->flags & ppc_cpu & ~(PPC_OPCODE_32 | PPC_OPCODE_64)) != 0
131260484Sobrien	  && ((op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64)) == 0
1313104834Sobrien	      || ((op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64))
1314104834Sobrien		  == (ppc_cpu & (PPC_OPCODE_32 | PPC_OPCODE_64)))
131592828Sobrien	      || (ppc_cpu & PPC_OPCODE_64_BRIDGE) != 0)
1316104834Sobrien	  /* Certain instructions (eg: extsw) do not exist in the
1317104834Sobrien	     32-bit BookE instruction set, but they do exist in the
1318104834Sobrien	     64-bit BookE instruction set, and other PPC instruction
1319104834Sobrien	     sets.  Check to see if the opcode has the BOOKE64 flag set.
1320104834Sobrien	     If it does make sure that the target CPU is not the BookE32.  */
1321104834Sobrien	  && ((op->flags & PPC_OPCODE_BOOKE64) == 0
1322104834Sobrien	      || (ppc_cpu & PPC_OPCODE_BOOKE64) == PPC_OPCODE_BOOKE64
1323104834Sobrien	      || (ppc_cpu & PPC_OPCODE_BOOKE) == 0)
132492828Sobrien	  && ((op->flags & (PPC_OPCODE_POWER4 | PPC_OPCODE_NOPOWER4)) == 0
132592828Sobrien	      || ((op->flags & PPC_OPCODE_POWER4)
1326218822Sdim		  == (ppc_cpu & PPC_OPCODE_POWER4)))
1327218822Sdim	  && ((op->flags & PPC_OPCODE_POWER5) == 0
1328218822Sdim	      || ((op->flags & PPC_OPCODE_POWER5)
1329218822Sdim		  == (ppc_cpu & PPC_OPCODE_POWER5)))
1330218822Sdim	  && ((op->flags & PPC_OPCODE_POWER6) == 0
1331218822Sdim	      || ((op->flags & PPC_OPCODE_POWER6)
1332218822Sdim		  == (ppc_cpu & PPC_OPCODE_POWER6))))
133360484Sobrien	{
133460484Sobrien	  const char *retval;
133560484Sobrien
1336218822Sdim	  retval = hash_insert (ppc_hash, op->name, (void *) op);
1337130561Sobrien	  if (retval != NULL)
133860484Sobrien	    {
133989857Sobrien	      /* Ignore Power duplicates for -m601.  */
134060484Sobrien	      if ((ppc_cpu & PPC_OPCODE_601) != 0
134160484Sobrien		  && (op->flags & PPC_OPCODE_POWER) != 0)
134260484Sobrien		continue;
134360484Sobrien
1344218822Sdim	      as_bad (_("duplicate instruction %s"),
134589857Sobrien		      op->name);
1346218822Sdim	      bad_insn = TRUE;
134760484Sobrien	    }
134860484Sobrien	}
134960484Sobrien    }
135060484Sobrien
1351130561Sobrien  if ((ppc_cpu & PPC_OPCODE_ANY) != 0)
1352130561Sobrien    for (op = powerpc_opcodes; op < op_end; op++)
1353218822Sdim      hash_insert (ppc_hash, op->name, (void *) op);
1354130561Sobrien
135560484Sobrien  /* Insert the macros into a hash table.  */
135660484Sobrien  ppc_macro_hash = hash_new ();
135760484Sobrien
135860484Sobrien  macro_end = powerpc_macros + powerpc_num_macros;
135960484Sobrien  for (macro = powerpc_macros; macro < macro_end; macro++)
136060484Sobrien    {
136160484Sobrien      if ((macro->flags & ppc_cpu) != 0)
136260484Sobrien	{
136360484Sobrien	  const char *retval;
136460484Sobrien
1365218822Sdim	  retval = hash_insert (ppc_macro_hash, macro->name, (void *) macro);
136660484Sobrien	  if (retval != (const char *) NULL)
136760484Sobrien	    {
1368218822Sdim	      as_bad (_("duplicate macro %s"), macro->name);
1369218822Sdim	      bad_insn = TRUE;
137060484Sobrien	    }
137160484Sobrien	}
137260484Sobrien    }
137360484Sobrien
1374218822Sdim  if (bad_insn)
137560484Sobrien    abort ();
1376130561Sobrien}
137760484Sobrien
1378130561Sobrien/* This function is called when the assembler starts up.  It is called
1379130561Sobrien   after the options have been parsed and the output file has been
1380130561Sobrien   opened.  */
1381130561Sobrien
1382130561Sobrienvoid
1383218822Sdimmd_begin (void)
1384130561Sobrien{
1385130561Sobrien  ppc_set_cpu ();
1386130561Sobrien
1387130561Sobrien  ppc_cie_data_alignment = ppc_obj64 ? -8 : -4;
1388130561Sobrien
1389130561Sobrien#ifdef OBJ_ELF
1390130561Sobrien  /* Set the ELF flags if desired.  */
1391130561Sobrien  if (ppc_flags && !msolaris)
1392130561Sobrien    bfd_set_private_flags (stdoutput, ppc_flags);
1393130561Sobrien#endif
1394130561Sobrien
1395130561Sobrien  ppc_setup_opcodes ();
1396130561Sobrien
1397130561Sobrien  /* Tell the main code what the endianness is if it is not overridden
139889857Sobrien     by the user.  */
139960484Sobrien  if (!set_target_endian)
140060484Sobrien    {
140160484Sobrien      set_target_endian = 1;
140260484Sobrien      target_big_endian = PPC_BIG_ENDIAN;
140360484Sobrien    }
140460484Sobrien
140560484Sobrien#ifdef OBJ_XCOFF
140660484Sobrien  ppc_coff_debug_section = coff_section_from_bfd_index (stdoutput, N_DEBUG);
140760484Sobrien
140860484Sobrien  /* Create dummy symbols to serve as initial csects.  This forces the
140960484Sobrien     text csects to precede the data csects.  These symbols will not
141060484Sobrien     be output.  */
141160484Sobrien  ppc_text_csects = symbol_make ("dummy\001");
141260484Sobrien  symbol_get_tc (ppc_text_csects)->within = ppc_text_csects;
141360484Sobrien  ppc_data_csects = symbol_make ("dummy\001");
141460484Sobrien  symbol_get_tc (ppc_data_csects)->within = ppc_data_csects;
141560484Sobrien#endif
141660484Sobrien
141760484Sobrien#ifdef TE_PE
141860484Sobrien
141960484Sobrien  ppc_current_section = text_section;
142077298Sobrien  ppc_previous_section = 0;
142160484Sobrien
142260484Sobrien#endif
142360484Sobrien}
142460484Sobrien
1425130561Sobrienvoid
1426218822Sdimppc_cleanup (void)
1427130561Sobrien{
1428130561Sobrien#ifdef OBJ_ELF
1429130561Sobrien  if (ppc_apuinfo_list == NULL)
1430130561Sobrien    return;
1431130561Sobrien
1432130561Sobrien  /* Ok, so write the section info out.  We have this layout:
1433130561Sobrien
1434130561Sobrien  byte	data		what
1435130561Sobrien  ----	----		----
1436130561Sobrien  0	8		length of "APUinfo\0"
1437130561Sobrien  4	(n*4)		number of APU's (4 bytes each)
1438130561Sobrien  8	2		note type 2
1439130561Sobrien  12	"APUinfo\0"	name
1440130561Sobrien  20	APU#1		first APU's info
1441130561Sobrien  24	APU#2		second APU's info
1442130561Sobrien  ...	...
1443130561Sobrien  */
1444130561Sobrien  {
1445130561Sobrien    char *p;
1446130561Sobrien    asection *seg = now_seg;
1447130561Sobrien    subsegT subseg = now_subseg;
1448130561Sobrien    asection *apuinfo_secp = (asection *) NULL;
1449130561Sobrien    unsigned int i;
1450130561Sobrien
1451130561Sobrien    /* Create the .PPC.EMB.apuinfo section.  */
1452130561Sobrien    apuinfo_secp = subseg_new (".PPC.EMB.apuinfo", 0);
1453130561Sobrien    bfd_set_section_flags (stdoutput,
1454130561Sobrien			   apuinfo_secp,
1455130561Sobrien			   SEC_HAS_CONTENTS | SEC_READONLY);
1456130561Sobrien
1457130561Sobrien    p = frag_more (4);
1458130561Sobrien    md_number_to_chars (p, (valueT) 8, 4);
1459130561Sobrien
1460130561Sobrien    p = frag_more (4);
1461130561Sobrien    md_number_to_chars (p, (valueT) ppc_apuinfo_num * 4, 4);
1462130561Sobrien
1463130561Sobrien    p = frag_more (4);
1464130561Sobrien    md_number_to_chars (p, (valueT) 2, 4);
1465130561Sobrien
1466130561Sobrien    p = frag_more (8);
1467130561Sobrien    strcpy (p, "APUinfo");
1468130561Sobrien
1469130561Sobrien    for (i = 0; i < ppc_apuinfo_num; i++)
1470130561Sobrien      {
1471130561Sobrien	p = frag_more (4);
1472130561Sobrien	md_number_to_chars (p, (valueT) ppc_apuinfo_list[i], 4);
1473130561Sobrien      }
1474130561Sobrien
1475130561Sobrien    frag_align (2, 0, 0);
1476130561Sobrien
1477130561Sobrien    /* We probably can't restore the current segment, for there likely
1478130561Sobrien       isn't one yet...  */
1479130561Sobrien    if (seg && subseg)
1480130561Sobrien      subseg_set (seg, subseg);
1481130561Sobrien  }
1482130561Sobrien#endif
1483130561Sobrien}
1484130561Sobrien
148560484Sobrien/* Insert an operand value into an instruction.  */
148660484Sobrien
148760484Sobrienstatic unsigned long
1488218822Sdimppc_insert_operand (unsigned long insn,
1489218822Sdim		    const struct powerpc_operand *operand,
1490218822Sdim		    offsetT val,
1491218822Sdim		    char *file,
1492218822Sdim		    unsigned int line)
149360484Sobrien{
1494218822Sdim  long min, max, right;
1495218822Sdim
1496218822Sdim  max = operand->bitm;
1497218822Sdim  right = max & -max;
1498218822Sdim  min = 0;
1499218822Sdim
1500218822Sdim  if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
150160484Sobrien    {
1502218822Sdim      if ((operand->flags & PPC_OPERAND_SIGNOPT) == 0)
1503218822Sdim	max = (max >> 1) & -right;
1504218822Sdim      min = ~max & -right;
1505218822Sdim    }
150660484Sobrien
1507218822Sdim  if ((operand->flags & PPC_OPERAND_PLUS1) != 0)
1508218822Sdim    max++;
150960484Sobrien
1510218822Sdim  if ((operand->flags & PPC_OPERAND_NEGATIVE) != 0)
1511218822Sdim    {
1512218822Sdim      long tmp = min;
1513218822Sdim      min = -max;
1514218822Sdim      max = -tmp;
1515218822Sdim    }
151660484Sobrien
1517218822Sdim  if (min <= max)
1518218822Sdim    {
1519218822Sdim      /* Some people write constants with the sign extension done by
1520218822Sdim	 hand but only up to 32 bits.  This shouldn't really be valid,
1521218822Sdim	 but, to permit this code to assemble on a 64-bit host, we
1522218822Sdim	 sign extend the 32-bit value to 64 bits if so doing makes the
1523218822Sdim	 value valid.  */
1524218822Sdim      if (val > max
1525218822Sdim	  && (offsetT) (val - 0x80000000 - 0x80000000) >= min
1526218822Sdim	  && (offsetT) (val - 0x80000000 - 0x80000000) <= max
1527218822Sdim	  && ((val - 0x80000000 - 0x80000000) & (right - 1)) == 0)
1528218822Sdim	val = val - 0x80000000 - 0x80000000;
152960484Sobrien
1530218822Sdim      /* Similarly, people write expressions like ~(1<<15), and expect
1531218822Sdim	 this to be OK for a 32-bit unsigned value.  */
1532218822Sdim      else if (val < min
1533218822Sdim	       && (offsetT) (val + 0x80000000 + 0x80000000) >= min
1534218822Sdim	       && (offsetT) (val + 0x80000000 + 0x80000000) <= max
1535218822Sdim	       && ((val + 0x80000000 + 0x80000000) & (right - 1)) == 0)
1536218822Sdim	val = val + 0x80000000 + 0x80000000;
153760484Sobrien
1538218822Sdim      else if (val < min
1539218822Sdim	       || val > max
1540218822Sdim	       || (val & (right - 1)) != 0)
1541218822Sdim	as_bad_value_out_of_range (_("operand"), val, min, max, file, line);
154260484Sobrien    }
154360484Sobrien
154460484Sobrien  if (operand->insert)
154560484Sobrien    {
154660484Sobrien      const char *errmsg;
154760484Sobrien
154860484Sobrien      errmsg = NULL;
1549104834Sobrien      insn = (*operand->insert) (insn, (long) val, ppc_cpu, &errmsg);
155060484Sobrien      if (errmsg != (const char *) NULL)
155189857Sobrien	as_bad_where (file, line, errmsg);
155260484Sobrien    }
155360484Sobrien  else
1554218822Sdim    insn |= ((long) val & operand->bitm) << operand->shift;
155560484Sobrien
155660484Sobrien  return insn;
155760484Sobrien}
155860484Sobrien
155960484Sobrien
156060484Sobrien#ifdef OBJ_ELF
156160484Sobrien/* Parse @got, etc. and return the desired relocation.  */
156260484Sobrienstatic bfd_reloc_code_real_type
1563218822Sdimppc_elf_suffix (char **str_p, expressionS *exp_p)
156460484Sobrien{
156560484Sobrien  struct map_bfd {
156660484Sobrien    char *string;
1567130561Sobrien    unsigned int length : 8;
1568130561Sobrien    unsigned int valid32 : 1;
1569130561Sobrien    unsigned int valid64 : 1;
1570130561Sobrien    unsigned int reloc;
157160484Sobrien  };
157260484Sobrien
157360484Sobrien  char ident[20];
157460484Sobrien  char *str = *str_p;
157560484Sobrien  char *str2;
157660484Sobrien  int ch;
157760484Sobrien  int len;
157889857Sobrien  const struct map_bfd *ptr;
157960484Sobrien
1580130561Sobrien#define MAP(str, reloc)   { str, sizeof (str) - 1, 1, 1, reloc }
1581130561Sobrien#define MAP32(str, reloc) { str, sizeof (str) - 1, 1, 0, reloc }
1582130561Sobrien#define MAP64(str, reloc) { str, sizeof (str) - 1, 0, 1, reloc }
158360484Sobrien
158489857Sobrien  static const struct map_bfd mapping[] = {
1585130561Sobrien    MAP ("l",			BFD_RELOC_LO16),
1586130561Sobrien    MAP ("h",			BFD_RELOC_HI16),
1587130561Sobrien    MAP ("ha",			BFD_RELOC_HI16_S),
1588130561Sobrien    MAP ("brtaken",		BFD_RELOC_PPC_B16_BRTAKEN),
1589130561Sobrien    MAP ("brntaken",		BFD_RELOC_PPC_B16_BRNTAKEN),
1590130561Sobrien    MAP ("got",			BFD_RELOC_16_GOTOFF),
1591130561Sobrien    MAP ("got@l",		BFD_RELOC_LO16_GOTOFF),
1592130561Sobrien    MAP ("got@h",		BFD_RELOC_HI16_GOTOFF),
1593130561Sobrien    MAP ("got@ha",		BFD_RELOC_HI16_S_GOTOFF),
1594130561Sobrien    MAP ("plt@l",		BFD_RELOC_LO16_PLTOFF),
1595130561Sobrien    MAP ("plt@h",		BFD_RELOC_HI16_PLTOFF),
1596130561Sobrien    MAP ("plt@ha",		BFD_RELOC_HI16_S_PLTOFF),
1597130561Sobrien    MAP ("copy",		BFD_RELOC_PPC_COPY),
1598130561Sobrien    MAP ("globdat",		BFD_RELOC_PPC_GLOB_DAT),
1599130561Sobrien    MAP ("sectoff",		BFD_RELOC_16_BASEREL),
1600130561Sobrien    MAP ("sectoff@l",		BFD_RELOC_LO16_BASEREL),
1601130561Sobrien    MAP ("sectoff@h",		BFD_RELOC_HI16_BASEREL),
1602130561Sobrien    MAP ("sectoff@ha",		BFD_RELOC_HI16_S_BASEREL),
1603130561Sobrien    MAP ("tls",			BFD_RELOC_PPC_TLS),
1604130561Sobrien    MAP ("dtpmod",		BFD_RELOC_PPC_DTPMOD),
1605130561Sobrien    MAP ("dtprel",		BFD_RELOC_PPC_DTPREL),
1606130561Sobrien    MAP ("dtprel@l",		BFD_RELOC_PPC_DTPREL16_LO),
1607130561Sobrien    MAP ("dtprel@h",		BFD_RELOC_PPC_DTPREL16_HI),
1608130561Sobrien    MAP ("dtprel@ha",		BFD_RELOC_PPC_DTPREL16_HA),
1609130561Sobrien    MAP ("tprel",		BFD_RELOC_PPC_TPREL),
1610130561Sobrien    MAP ("tprel@l",		BFD_RELOC_PPC_TPREL16_LO),
1611130561Sobrien    MAP ("tprel@h",		BFD_RELOC_PPC_TPREL16_HI),
1612130561Sobrien    MAP ("tprel@ha",		BFD_RELOC_PPC_TPREL16_HA),
1613130561Sobrien    MAP ("got@tlsgd",		BFD_RELOC_PPC_GOT_TLSGD16),
1614130561Sobrien    MAP ("got@tlsgd@l",		BFD_RELOC_PPC_GOT_TLSGD16_LO),
1615130561Sobrien    MAP ("got@tlsgd@h",		BFD_RELOC_PPC_GOT_TLSGD16_HI),
1616130561Sobrien    MAP ("got@tlsgd@ha",	BFD_RELOC_PPC_GOT_TLSGD16_HA),
1617130561Sobrien    MAP ("got@tlsld",		BFD_RELOC_PPC_GOT_TLSLD16),
1618130561Sobrien    MAP ("got@tlsld@l",		BFD_RELOC_PPC_GOT_TLSLD16_LO),
1619130561Sobrien    MAP ("got@tlsld@h",		BFD_RELOC_PPC_GOT_TLSLD16_HI),
1620130561Sobrien    MAP ("got@tlsld@ha",	BFD_RELOC_PPC_GOT_TLSLD16_HA),
1621130561Sobrien    MAP ("got@dtprel",		BFD_RELOC_PPC_GOT_DTPREL16),
1622130561Sobrien    MAP ("got@dtprel@l",	BFD_RELOC_PPC_GOT_DTPREL16_LO),
1623130561Sobrien    MAP ("got@dtprel@h",	BFD_RELOC_PPC_GOT_DTPREL16_HI),
1624130561Sobrien    MAP ("got@dtprel@ha",	BFD_RELOC_PPC_GOT_DTPREL16_HA),
1625130561Sobrien    MAP ("got@tprel",		BFD_RELOC_PPC_GOT_TPREL16),
1626130561Sobrien    MAP ("got@tprel@l",		BFD_RELOC_PPC_GOT_TPREL16_LO),
1627130561Sobrien    MAP ("got@tprel@h",		BFD_RELOC_PPC_GOT_TPREL16_HI),
1628130561Sobrien    MAP ("got@tprel@ha",	BFD_RELOC_PPC_GOT_TPREL16_HA),
1629130561Sobrien    MAP32 ("fixup",		BFD_RELOC_CTOR),
1630130561Sobrien    MAP32 ("plt",		BFD_RELOC_24_PLT_PCREL),
1631130561Sobrien    MAP32 ("pltrel24",		BFD_RELOC_24_PLT_PCREL),
1632130561Sobrien    MAP32 ("local24pc",		BFD_RELOC_PPC_LOCAL24PC),
1633130561Sobrien    MAP32 ("local",		BFD_RELOC_PPC_LOCAL24PC),
1634130561Sobrien    MAP32 ("pltrel",		BFD_RELOC_32_PLT_PCREL),
1635130561Sobrien    MAP32 ("sdarel",		BFD_RELOC_GPREL16),
1636130561Sobrien    MAP32 ("naddr",		BFD_RELOC_PPC_EMB_NADDR32),
1637130561Sobrien    MAP32 ("naddr16",		BFD_RELOC_PPC_EMB_NADDR16),
1638130561Sobrien    MAP32 ("naddr@l",		BFD_RELOC_PPC_EMB_NADDR16_LO),
1639130561Sobrien    MAP32 ("naddr@h",		BFD_RELOC_PPC_EMB_NADDR16_HI),
1640130561Sobrien    MAP32 ("naddr@ha",		BFD_RELOC_PPC_EMB_NADDR16_HA),
1641130561Sobrien    MAP32 ("sdai16",		BFD_RELOC_PPC_EMB_SDAI16),
1642130561Sobrien    MAP32 ("sda2rel",		BFD_RELOC_PPC_EMB_SDA2REL),
1643130561Sobrien    MAP32 ("sda2i16",		BFD_RELOC_PPC_EMB_SDA2I16),
1644130561Sobrien    MAP32 ("sda21",		BFD_RELOC_PPC_EMB_SDA21),
1645130561Sobrien    MAP32 ("mrkref",		BFD_RELOC_PPC_EMB_MRKREF),
1646130561Sobrien    MAP32 ("relsect",		BFD_RELOC_PPC_EMB_RELSEC16),
1647130561Sobrien    MAP32 ("relsect@l",		BFD_RELOC_PPC_EMB_RELST_LO),
1648130561Sobrien    MAP32 ("relsect@h",		BFD_RELOC_PPC_EMB_RELST_HI),
1649130561Sobrien    MAP32 ("relsect@ha",	BFD_RELOC_PPC_EMB_RELST_HA),
1650130561Sobrien    MAP32 ("bitfld",		BFD_RELOC_PPC_EMB_BIT_FLD),
1651130561Sobrien    MAP32 ("relsda",		BFD_RELOC_PPC_EMB_RELSDA),
1652130561Sobrien    MAP32 ("xgot",		BFD_RELOC_PPC_TOC16),
1653130561Sobrien    MAP64 ("higher",		BFD_RELOC_PPC64_HIGHER),
1654130561Sobrien    MAP64 ("highera",		BFD_RELOC_PPC64_HIGHER_S),
1655130561Sobrien    MAP64 ("highest",		BFD_RELOC_PPC64_HIGHEST),
1656130561Sobrien    MAP64 ("highesta",		BFD_RELOC_PPC64_HIGHEST_S),
1657130561Sobrien    MAP64 ("tocbase",		BFD_RELOC_PPC64_TOC),
1658130561Sobrien    MAP64 ("toc",		BFD_RELOC_PPC_TOC16),
1659130561Sobrien    MAP64 ("toc@l",		BFD_RELOC_PPC64_TOC16_LO),
1660130561Sobrien    MAP64 ("toc@h",		BFD_RELOC_PPC64_TOC16_HI),
1661130561Sobrien    MAP64 ("toc@ha",		BFD_RELOC_PPC64_TOC16_HA),
1662130561Sobrien    MAP64 ("dtprel@higher",	BFD_RELOC_PPC64_DTPREL16_HIGHER),
1663130561Sobrien    MAP64 ("dtprel@highera",	BFD_RELOC_PPC64_DTPREL16_HIGHERA),
1664130561Sobrien    MAP64 ("dtprel@highest",	BFD_RELOC_PPC64_DTPREL16_HIGHEST),
1665130561Sobrien    MAP64 ("dtprel@highesta",	BFD_RELOC_PPC64_DTPREL16_HIGHESTA),
1666130561Sobrien    MAP64 ("tprel@higher",	BFD_RELOC_PPC64_TPREL16_HIGHER),
1667130561Sobrien    MAP64 ("tprel@highera",	BFD_RELOC_PPC64_TPREL16_HIGHERA),
1668130561Sobrien    MAP64 ("tprel@highest",	BFD_RELOC_PPC64_TPREL16_HIGHEST),
1669130561Sobrien    MAP64 ("tprel@highesta",	BFD_RELOC_PPC64_TPREL16_HIGHESTA),
1670130561Sobrien    { (char *) 0, 0, 0, 0,	BFD_RELOC_UNUSED }
167160484Sobrien  };
167260484Sobrien
167360484Sobrien  if (*str++ != '@')
167460484Sobrien    return BFD_RELOC_UNUSED;
167560484Sobrien
167660484Sobrien  for (ch = *str, str2 = ident;
167760484Sobrien       (str2 < ident + sizeof (ident) - 1
167889857Sobrien	&& (ISALNUM (ch) || ch == '@'));
167960484Sobrien       ch = *++str)
168060484Sobrien    {
168189857Sobrien      *str2++ = TOLOWER (ch);
168260484Sobrien    }
168360484Sobrien
168460484Sobrien  *str2 = '\0';
168560484Sobrien  len = str2 - ident;
168660484Sobrien
168760484Sobrien  ch = ident[0];
168860484Sobrien  for (ptr = &mapping[0]; ptr->length > 0; ptr++)
168960484Sobrien    if (ch == ptr->string[0]
169060484Sobrien	&& len == ptr->length
1691130561Sobrien	&& memcmp (ident, ptr->string, ptr->length) == 0
1692130561Sobrien	&& (ppc_obj64 ? ptr->valid64 : ptr->valid32))
169360484Sobrien      {
169489857Sobrien	int reloc = ptr->reloc;
169589857Sobrien
1696130561Sobrien	if (!ppc_obj64)
1697130561Sobrien	  if (exp_p->X_add_number != 0
1698130561Sobrien	      && (reloc == (int) BFD_RELOC_16_GOTOFF
1699130561Sobrien		  || reloc == (int) BFD_RELOC_LO16_GOTOFF
1700130561Sobrien		  || reloc == (int) BFD_RELOC_HI16_GOTOFF
1701130561Sobrien		  || reloc == (int) BFD_RELOC_HI16_S_GOTOFF))
1702130561Sobrien	    as_warn (_("identifier+constant@got means identifier@got+constant"));
170389857Sobrien
170489857Sobrien	/* Now check for identifier@suffix+constant.  */
170560484Sobrien	if (*str == '-' || *str == '+')
170660484Sobrien	  {
170760484Sobrien	    char *orig_line = input_line_pointer;
170860484Sobrien	    expressionS new_exp;
170960484Sobrien
171060484Sobrien	    input_line_pointer = str;
171160484Sobrien	    expression (&new_exp);
171260484Sobrien	    if (new_exp.X_op == O_constant)
171360484Sobrien	      {
171460484Sobrien		exp_p->X_add_number += new_exp.X_add_number;
171560484Sobrien		str = input_line_pointer;
171660484Sobrien	      }
171760484Sobrien
171860484Sobrien	    if (&input_line_pointer != str_p)
171960484Sobrien	      input_line_pointer = orig_line;
172060484Sobrien	  }
172189857Sobrien	*str_p = str;
172260484Sobrien
1723104834Sobrien	if (reloc == (int) BFD_RELOC_PPC64_TOC
1724130561Sobrien	    && exp_p->X_op == O_symbol
1725130561Sobrien	    && strcmp (S_GET_NAME (exp_p->X_add_symbol), ".TOC.") == 0)
172689857Sobrien	  {
1727130561Sobrien	    /* Change the symbol so that the dummy .TOC. symbol can be
1728130561Sobrien	       omitted from the object file.  */
172989857Sobrien	    exp_p->X_add_symbol = &abs_symbol;
173089857Sobrien	  }
173189857Sobrien
173289857Sobrien	return (bfd_reloc_code_real_type) reloc;
173360484Sobrien      }
173460484Sobrien
173560484Sobrien  return BFD_RELOC_UNUSED;
173660484Sobrien}
173760484Sobrien
173889857Sobrien/* Like normal .long/.short/.word, except support @got, etc.
173989857Sobrien   Clobbers input_line_pointer, checks end-of-line.  */
174060484Sobrienstatic void
1741218822Sdimppc_elf_cons (int nbytes /* 1=.byte, 2=.word, 4=.long, 8=.llong */)
174260484Sobrien{
174360484Sobrien  expressionS exp;
174460484Sobrien  bfd_reloc_code_real_type reloc;
174560484Sobrien
174660484Sobrien  if (is_it_end_of_statement ())
174760484Sobrien    {
174860484Sobrien      demand_empty_rest_of_line ();
174960484Sobrien      return;
175060484Sobrien    }
175160484Sobrien
175260484Sobrien  do
175360484Sobrien    {
175460484Sobrien      expression (&exp);
175560484Sobrien      if (exp.X_op == O_symbol
175660484Sobrien	  && *input_line_pointer == '@'
175789857Sobrien	  && (reloc = ppc_elf_suffix (&input_line_pointer,
175889857Sobrien				      &exp)) != BFD_RELOC_UNUSED)
175960484Sobrien	{
176089857Sobrien	  reloc_howto_type *reloc_howto;
176189857Sobrien	  int size;
176260484Sobrien
176389857Sobrien	  reloc_howto = bfd_reloc_type_lookup (stdoutput, reloc);
176489857Sobrien	  size = bfd_get_reloc_size (reloc_howto);
176589857Sobrien
176660484Sobrien	  if (size > nbytes)
176789857Sobrien	    {
176889857Sobrien	      as_bad (_("%s relocations do not fit in %d bytes\n"),
176989857Sobrien		      reloc_howto->name, nbytes);
177089857Sobrien	    }
177160484Sobrien	  else
177260484Sobrien	    {
177389857Sobrien	      char *p;
177489857Sobrien	      int offset;
177560484Sobrien
177689857Sobrien	      p = frag_more (nbytes);
177789857Sobrien	      offset = 0;
177889857Sobrien	      if (target_big_endian)
177989857Sobrien		offset = nbytes - size;
178089857Sobrien	      fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size,
178189857Sobrien			   &exp, 0, reloc);
178260484Sobrien	    }
178360484Sobrien	}
178460484Sobrien      else
178560484Sobrien	emit_expr (&exp, (unsigned int) nbytes);
178660484Sobrien    }
178760484Sobrien  while (*input_line_pointer++ == ',');
178860484Sobrien
178989857Sobrien  /* Put terminator back into stream.  */
179089857Sobrien  input_line_pointer--;
179160484Sobrien  demand_empty_rest_of_line ();
179260484Sobrien}
179360484Sobrien
179460484Sobrien/* Solaris pseduo op to change to the .rodata section.  */
179560484Sobrienstatic void
1796218822Sdimppc_elf_rdata (int xxx)
179760484Sobrien{
179860484Sobrien  char *save_line = input_line_pointer;
179960484Sobrien  static char section[] = ".rodata\n";
180060484Sobrien
180189857Sobrien  /* Just pretend this is .section .rodata  */
180260484Sobrien  input_line_pointer = section;
180360484Sobrien  obj_elf_section (xxx);
180460484Sobrien
180560484Sobrien  input_line_pointer = save_line;
180660484Sobrien}
180760484Sobrien
180889857Sobrien/* Pseudo op to make file scope bss items.  */
180960484Sobrienstatic void
1810218822Sdimppc_elf_lcomm (int xxx ATTRIBUTE_UNUSED)
181160484Sobrien{
1812218822Sdim  char *name;
1813218822Sdim  char c;
1814218822Sdim  char *p;
181560484Sobrien  offsetT size;
1816218822Sdim  symbolS *symbolP;
181760484Sobrien  offsetT align;
181860484Sobrien  segT old_sec;
181960484Sobrien  int old_subsec;
182060484Sobrien  char *pfrag;
182160484Sobrien  int align2;
182260484Sobrien
182360484Sobrien  name = input_line_pointer;
182460484Sobrien  c = get_symbol_end ();
182560484Sobrien
182689857Sobrien  /* just after name is now '\0'.  */
182760484Sobrien  p = input_line_pointer;
182860484Sobrien  *p = c;
182960484Sobrien  SKIP_WHITESPACE ();
183060484Sobrien  if (*input_line_pointer != ',')
183160484Sobrien    {
183260484Sobrien      as_bad (_("Expected comma after symbol-name: rest of line ignored."));
183360484Sobrien      ignore_rest_of_line ();
183460484Sobrien      return;
183560484Sobrien    }
183660484Sobrien
183760484Sobrien  input_line_pointer++;		/* skip ',' */
183860484Sobrien  if ((size = get_absolute_expression ()) < 0)
183960484Sobrien    {
184060484Sobrien      as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) size);
184160484Sobrien      ignore_rest_of_line ();
184260484Sobrien      return;
184360484Sobrien    }
184460484Sobrien
184560484Sobrien  /* The third argument to .lcomm is the alignment.  */
184660484Sobrien  if (*input_line_pointer != ',')
184760484Sobrien    align = 8;
184860484Sobrien  else
184960484Sobrien    {
185060484Sobrien      ++input_line_pointer;
185160484Sobrien      align = get_absolute_expression ();
185260484Sobrien      if (align <= 0)
185360484Sobrien	{
185460484Sobrien	  as_warn (_("ignoring bad alignment"));
185560484Sobrien	  align = 8;
185660484Sobrien	}
185760484Sobrien    }
185860484Sobrien
185960484Sobrien  *p = 0;
186060484Sobrien  symbolP = symbol_find_or_make (name);
186160484Sobrien  *p = c;
186260484Sobrien
186360484Sobrien  if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP))
186460484Sobrien    {
186560484Sobrien      as_bad (_("Ignoring attempt to re-define symbol `%s'."),
186660484Sobrien	      S_GET_NAME (symbolP));
186760484Sobrien      ignore_rest_of_line ();
186860484Sobrien      return;
186960484Sobrien    }
187060484Sobrien
187160484Sobrien  if (S_GET_VALUE (symbolP) && S_GET_VALUE (symbolP) != (valueT) size)
187260484Sobrien    {
187360484Sobrien      as_bad (_("Length of .lcomm \"%s\" is already %ld. Not changed to %ld."),
187460484Sobrien	      S_GET_NAME (symbolP),
187560484Sobrien	      (long) S_GET_VALUE (symbolP),
187660484Sobrien	      (long) size);
187760484Sobrien
187860484Sobrien      ignore_rest_of_line ();
187960484Sobrien      return;
188060484Sobrien    }
188160484Sobrien
188289857Sobrien  /* Allocate_bss.  */
188360484Sobrien  old_sec = now_seg;
188460484Sobrien  old_subsec = now_subseg;
188560484Sobrien  if (align)
188660484Sobrien    {
188789857Sobrien      /* Convert to a power of 2 alignment.  */
188860484Sobrien      for (align2 = 0; (align & 1) == 0; align >>= 1, ++align2);
188960484Sobrien      if (align != 1)
189060484Sobrien	{
189160484Sobrien	  as_bad (_("Common alignment not a power of 2"));
189260484Sobrien	  ignore_rest_of_line ();
189360484Sobrien	  return;
189460484Sobrien	}
189560484Sobrien    }
189660484Sobrien  else
189760484Sobrien    align2 = 0;
189860484Sobrien
189960484Sobrien  record_alignment (bss_section, align2);
190060484Sobrien  subseg_set (bss_section, 0);
190160484Sobrien  if (align2)
190260484Sobrien    frag_align (align2, 0, 0);
190360484Sobrien  if (S_GET_SEGMENT (symbolP) == bss_section)
190460484Sobrien    symbol_get_frag (symbolP)->fr_symbol = 0;
190560484Sobrien  symbol_set_frag (symbolP, frag_now);
190660484Sobrien  pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, size,
190760484Sobrien		    (char *) 0);
190860484Sobrien  *pfrag = 0;
190960484Sobrien  S_SET_SIZE (symbolP, size);
191060484Sobrien  S_SET_SEGMENT (symbolP, bss_section);
191160484Sobrien  subseg_set (old_sec, old_subsec);
191260484Sobrien  demand_empty_rest_of_line ();
191360484Sobrien}
191460484Sobrien
191560484Sobrien/* Validate any relocations emitted for -mrelocatable, possibly adding
191660484Sobrien   fixups for word relocations in writable segments, so we can adjust
191760484Sobrien   them at runtime.  */
191860484Sobrienstatic void
1919218822Sdimppc_elf_validate_fix (fixS *fixp, segT seg)
192060484Sobrien{
192160484Sobrien  if (fixp->fx_done || fixp->fx_pcrel)
192260484Sobrien    return;
192360484Sobrien
192460484Sobrien  switch (shlib)
192560484Sobrien    {
192660484Sobrien    case SHLIB_NONE:
192760484Sobrien    case SHLIB_PIC:
192860484Sobrien      return;
192960484Sobrien
193077298Sobrien    case SHLIB_MRELOCATABLE:
193160484Sobrien      if (fixp->fx_r_type <= BFD_RELOC_UNUSED
193260484Sobrien	  && fixp->fx_r_type != BFD_RELOC_16_GOTOFF
193360484Sobrien	  && fixp->fx_r_type != BFD_RELOC_HI16_GOTOFF
193460484Sobrien	  && fixp->fx_r_type != BFD_RELOC_LO16_GOTOFF
193560484Sobrien	  && fixp->fx_r_type != BFD_RELOC_HI16_S_GOTOFF
193699461Sobrien	  && fixp->fx_r_type != BFD_RELOC_16_BASEREL
193760484Sobrien	  && fixp->fx_r_type != BFD_RELOC_LO16_BASEREL
193860484Sobrien	  && fixp->fx_r_type != BFD_RELOC_HI16_BASEREL
193960484Sobrien	  && fixp->fx_r_type != BFD_RELOC_HI16_S_BASEREL
194089857Sobrien	  && (seg->flags & SEC_LOAD) != 0
194160484Sobrien	  && strcmp (segment_name (seg), ".got2") != 0
194260484Sobrien	  && strcmp (segment_name (seg), ".dtors") != 0
194360484Sobrien	  && strcmp (segment_name (seg), ".ctors") != 0
194460484Sobrien	  && strcmp (segment_name (seg), ".fixup") != 0
194560484Sobrien	  && strcmp (segment_name (seg), ".gcc_except_table") != 0
194660484Sobrien	  && strcmp (segment_name (seg), ".eh_frame") != 0
194760484Sobrien	  && strcmp (segment_name (seg), ".ex_shared") != 0)
194860484Sobrien	{
194960484Sobrien	  if ((seg->flags & (SEC_READONLY | SEC_CODE)) != 0
195060484Sobrien	      || fixp->fx_r_type != BFD_RELOC_CTOR)
195160484Sobrien	    {
195260484Sobrien	      as_bad_where (fixp->fx_file, fixp->fx_line,
195360484Sobrien			    _("Relocation cannot be done when using -mrelocatable"));
195460484Sobrien	    }
195560484Sobrien	}
195660484Sobrien      return;
195760484Sobrien    }
195860484Sobrien}
195989857Sobrien
1960104834Sobrien/* Prevent elf_frob_file_before_adjust removing a weak undefined
1961104834Sobrien   function descriptor sym if the corresponding code sym is used.  */
1962104834Sobrien
1963104834Sobrienvoid
1964218822Sdimppc_frob_file_before_adjust (void)
196589857Sobrien{
1966104834Sobrien  symbolS *symp;
1967218822Sdim  asection *toc;
196889857Sobrien
1969104834Sobrien  if (!ppc_obj64)
1970104834Sobrien    return;
1971104834Sobrien
1972104834Sobrien  for (symp = symbol_rootP; symp; symp = symbol_next (symp))
197389857Sobrien    {
1974104834Sobrien      const char *name;
1975104834Sobrien      char *dotname;
1976104834Sobrien      symbolS *dotsym;
1977104834Sobrien      size_t len;
1978104834Sobrien
1979104834Sobrien      name = S_GET_NAME (symp);
1980104834Sobrien      if (name[0] == '.')
1981104834Sobrien	continue;
1982104834Sobrien
1983104834Sobrien      if (! S_IS_WEAK (symp)
1984104834Sobrien	  || S_IS_DEFINED (symp))
1985104834Sobrien	continue;
1986104834Sobrien
1987104834Sobrien      len = strlen (name) + 1;
1988104834Sobrien      dotname = xmalloc (len + 1);
1989104834Sobrien      dotname[0] = '.';
1990104834Sobrien      memcpy (dotname + 1, name, len);
1991218822Sdim      dotsym = symbol_find_noref (dotname, 1);
1992104834Sobrien      free (dotname);
1993104834Sobrien      if (dotsym != NULL && (symbol_used_p (dotsym)
1994104834Sobrien			     || symbol_used_in_reloc_p (dotsym)))
1995218822Sdim	symbol_mark_used (symp);
1996218822Sdim
199789857Sobrien    }
199889857Sobrien
1999218822Sdim  toc = bfd_get_section_by_name (stdoutput, ".toc");
2000218822Sdim  if (toc != NULL
2001218822Sdim      && bfd_section_size (stdoutput, toc) > 0x10000)
2002218822Sdim    as_warn (_("TOC section size exceeds 64k"));
2003218822Sdim
2004104834Sobrien  /* Don't emit .TOC. symbol.  */
2005104834Sobrien  symp = symbol_find (".TOC.");
2006104834Sobrien  if (symp != NULL)
2007104834Sobrien    symbol_remove (symp, &symbol_rootP, &symbol_lastP);
200889857Sobrien}
200960484Sobrien#endif /* OBJ_ELF */
201060484Sobrien
201160484Sobrien#ifdef TE_PE
201260484Sobrien
201360484Sobrien/*
201489857Sobrien * Summary of parse_toc_entry.
201560484Sobrien *
201660484Sobrien * in:	Input_line_pointer points to the '[' in one of:
201760484Sobrien *
201860484Sobrien *        [toc] [tocv] [toc32] [toc64]
201960484Sobrien *
202060484Sobrien *      Anything else is an error of one kind or another.
202160484Sobrien *
202277298Sobrien * out:
202360484Sobrien *   return value: success or failure
202460484Sobrien *   toc_kind:     kind of toc reference
202560484Sobrien *   input_line_pointer:
202660484Sobrien *     success: first char after the ']'
202760484Sobrien *     failure: unchanged
202860484Sobrien *
202960484Sobrien * settings:
203060484Sobrien *
203160484Sobrien *     [toc]   - rv == success, toc_kind = default_toc
203260484Sobrien *     [tocv]  - rv == success, toc_kind = data_in_toc
203360484Sobrien *     [toc32] - rv == success, toc_kind = must_be_32
203460484Sobrien *     [toc64] - rv == success, toc_kind = must_be_64
203560484Sobrien *
203660484Sobrien */
203760484Sobrien
203877298Sobrienenum toc_size_qualifier
203977298Sobrien{
204060484Sobrien  default_toc, /* The toc cell constructed should be the system default size */
204160484Sobrien  data_in_toc, /* This is a direct reference to a toc cell                   */
204260484Sobrien  must_be_32,  /* The toc cell constructed must be 32 bits wide              */
204360484Sobrien  must_be_64   /* The toc cell constructed must be 64 bits wide              */
204460484Sobrien};
204560484Sobrien
204660484Sobrienstatic int
2047218822Sdimparse_toc_entry (enum toc_size_qualifier *toc_kind)
204860484Sobrien{
204960484Sobrien  char *start;
205060484Sobrien  char *toc_spec;
205160484Sobrien  char c;
205260484Sobrien  enum toc_size_qualifier t;
205360484Sobrien
205489857Sobrien  /* Save the input_line_pointer.  */
205560484Sobrien  start = input_line_pointer;
205660484Sobrien
205789857Sobrien  /* Skip over the '[' , and whitespace.  */
205860484Sobrien  ++input_line_pointer;
205960484Sobrien  SKIP_WHITESPACE ();
206077298Sobrien
206189857Sobrien  /* Find the spelling of the operand.  */
206260484Sobrien  toc_spec = input_line_pointer;
206360484Sobrien  c = get_symbol_end ();
206460484Sobrien
206589857Sobrien  if (strcmp (toc_spec, "toc") == 0)
206660484Sobrien    {
206760484Sobrien      t = default_toc;
206860484Sobrien    }
206989857Sobrien  else if (strcmp (toc_spec, "tocv") == 0)
207060484Sobrien    {
207160484Sobrien      t = data_in_toc;
207260484Sobrien    }
207389857Sobrien  else if (strcmp (toc_spec, "toc32") == 0)
207460484Sobrien    {
207560484Sobrien      t = must_be_32;
207660484Sobrien    }
207789857Sobrien  else if (strcmp (toc_spec, "toc64") == 0)
207860484Sobrien    {
207960484Sobrien      t = must_be_64;
208060484Sobrien    }
208160484Sobrien  else
208260484Sobrien    {
208360484Sobrien      as_bad (_("syntax error: invalid toc specifier `%s'"), toc_spec);
208489857Sobrien      *input_line_pointer = c;
208589857Sobrien      input_line_pointer = start;
208660484Sobrien      return 0;
208760484Sobrien    }
208860484Sobrien
208989857Sobrien  /* Now find the ']'.  */
209089857Sobrien  *input_line_pointer = c;
209160484Sobrien
209277298Sobrien  SKIP_WHITESPACE ();	     /* leading whitespace could be there.  */
209377298Sobrien  c = *input_line_pointer++; /* input_line_pointer->past char in c.  */
209460484Sobrien
209560484Sobrien  if (c != ']')
209660484Sobrien    {
209760484Sobrien      as_bad (_("syntax error: expected `]', found  `%c'"), c);
209889857Sobrien      input_line_pointer = start;
209960484Sobrien      return 0;
210060484Sobrien    }
210160484Sobrien
210289857Sobrien  *toc_kind = t;
210360484Sobrien  return 1;
210460484Sobrien}
210560484Sobrien#endif
210660484Sobrien
210760484Sobrien
2108130561Sobrien#ifdef OBJ_ELF
2109130561Sobrien#define APUID(a,v)	((((a) & 0xffff) << 16) | ((v) & 0xffff))
2110130561Sobrienstatic void
2111218822Sdimppc_apuinfo_section_add (unsigned int apu, unsigned int version)
2112130561Sobrien{
2113130561Sobrien  unsigned int i;
2114130561Sobrien
2115130561Sobrien  /* Check we don't already exist.  */
2116130561Sobrien  for (i = 0; i < ppc_apuinfo_num; i++)
2117130561Sobrien    if (ppc_apuinfo_list[i] == APUID (apu, version))
2118130561Sobrien      return;
2119130561Sobrien
2120130561Sobrien  if (ppc_apuinfo_num == ppc_apuinfo_num_alloc)
2121130561Sobrien    {
2122130561Sobrien      if (ppc_apuinfo_num_alloc == 0)
2123130561Sobrien	{
2124130561Sobrien	  ppc_apuinfo_num_alloc = 4;
2125130561Sobrien	  ppc_apuinfo_list = (unsigned long *)
2126130561Sobrien	      xmalloc (sizeof (unsigned long) * ppc_apuinfo_num_alloc);
2127130561Sobrien	}
2128130561Sobrien      else
2129130561Sobrien	{
2130130561Sobrien	  ppc_apuinfo_num_alloc += 4;
2131130561Sobrien	  ppc_apuinfo_list = (unsigned long *) xrealloc (ppc_apuinfo_list,
2132130561Sobrien	      sizeof (unsigned long) * ppc_apuinfo_num_alloc);
2133130561Sobrien	}
2134130561Sobrien    }
2135130561Sobrien  ppc_apuinfo_list[ppc_apuinfo_num++] = APUID (apu, version);
2136130561Sobrien}
2137130561Sobrien#undef APUID
2138130561Sobrien#endif
2139130561Sobrien
2140130561Sobrien
214160484Sobrien/* We need to keep a list of fixups.  We can't simply generate them as
214260484Sobrien   we go, because that would require us to first create the frag, and
214360484Sobrien   that would screw up references to ``.''.  */
214460484Sobrien
214560484Sobrienstruct ppc_fixup
214660484Sobrien{
214760484Sobrien  expressionS exp;
214860484Sobrien  int opindex;
214960484Sobrien  bfd_reloc_code_real_type reloc;
215060484Sobrien};
215160484Sobrien
215260484Sobrien#define MAX_INSN_FIXUPS (5)
215360484Sobrien
215460484Sobrien/* This routine is called for each instruction to be assembled.  */
215560484Sobrien
215660484Sobrienvoid
2157218822Sdimmd_assemble (char *str)
215860484Sobrien{
215960484Sobrien  char *s;
216060484Sobrien  const struct powerpc_opcode *opcode;
216160484Sobrien  unsigned long insn;
216260484Sobrien  const unsigned char *opindex_ptr;
216360484Sobrien  int skip_optional;
216460484Sobrien  int need_paren;
216560484Sobrien  int next_opindex;
216660484Sobrien  struct ppc_fixup fixups[MAX_INSN_FIXUPS];
216760484Sobrien  int fc;
216860484Sobrien  char *f;
2169218822Sdim  int addr_mod;
217060484Sobrien  int i;
217160484Sobrien#ifdef OBJ_ELF
217260484Sobrien  bfd_reloc_code_real_type reloc;
217360484Sobrien#endif
217460484Sobrien
217560484Sobrien  /* Get the opcode.  */
217689857Sobrien  for (s = str; *s != '\0' && ! ISSPACE (*s); s++)
217760484Sobrien    ;
217860484Sobrien  if (*s != '\0')
217960484Sobrien    *s++ = '\0';
218060484Sobrien
218160484Sobrien  /* Look up the opcode in the hash table.  */
218260484Sobrien  opcode = (const struct powerpc_opcode *) hash_find (ppc_hash, str);
218360484Sobrien  if (opcode == (const struct powerpc_opcode *) NULL)
218460484Sobrien    {
218560484Sobrien      const struct powerpc_macro *macro;
218660484Sobrien
218760484Sobrien      macro = (const struct powerpc_macro *) hash_find (ppc_macro_hash, str);
218860484Sobrien      if (macro == (const struct powerpc_macro *) NULL)
218960484Sobrien	as_bad (_("Unrecognized opcode: `%s'"), str);
219060484Sobrien      else
219160484Sobrien	ppc_macro (s, macro);
219260484Sobrien
219360484Sobrien      return;
219460484Sobrien    }
219560484Sobrien
219660484Sobrien  insn = opcode->opcode;
219760484Sobrien
219860484Sobrien  str = s;
219989857Sobrien  while (ISSPACE (*str))
220060484Sobrien    ++str;
220160484Sobrien
220260484Sobrien  /* PowerPC operands are just expressions.  The only real issue is
220360484Sobrien     that a few operand types are optional.  All cases which might use
2204130561Sobrien     an optional operand separate the operands only with commas (in some
2205130561Sobrien     cases parentheses are used, as in ``lwz 1,0(1)'' but such cases never
2206130561Sobrien     have optional operands).  Most instructions with optional operands
2207130561Sobrien     have only one.  Those that have more than one optional operand can
2208130561Sobrien     take either all their operands or none.  So, before we start seriously
2209130561Sobrien     parsing the operands, we check to see if we have optional operands,
2210130561Sobrien     and if we do, we count the number of commas to see which operands
2211130561Sobrien     have been omitted.  */
221260484Sobrien  skip_optional = 0;
221360484Sobrien  for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++)
221460484Sobrien    {
221560484Sobrien      const struct powerpc_operand *operand;
221660484Sobrien
221760484Sobrien      operand = &powerpc_operands[*opindex_ptr];
221860484Sobrien      if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0)
221960484Sobrien	{
222060484Sobrien	  unsigned int opcount;
2221104834Sobrien	  unsigned int num_operands_expected;
2222104834Sobrien	  unsigned int i;
222360484Sobrien
222460484Sobrien	  /* There is an optional operand.  Count the number of
222560484Sobrien	     commas in the input line.  */
222660484Sobrien	  if (*str == '\0')
222760484Sobrien	    opcount = 0;
222860484Sobrien	  else
222960484Sobrien	    {
223060484Sobrien	      opcount = 1;
223160484Sobrien	      s = str;
223260484Sobrien	      while ((s = strchr (s, ',')) != (char *) NULL)
223360484Sobrien		{
223460484Sobrien		  ++opcount;
223560484Sobrien		  ++s;
223660484Sobrien		}
223760484Sobrien	    }
223860484Sobrien
2239104834Sobrien	  /* Compute the number of expected operands.
2240104834Sobrien	     Do not count fake operands.  */
2241104834Sobrien	  for (num_operands_expected = 0, i = 0; opcode->operands[i]; i ++)
2242104834Sobrien	    if ((powerpc_operands [opcode->operands[i]].flags & PPC_OPERAND_FAKE) == 0)
2243104834Sobrien	      ++ num_operands_expected;
2244104834Sobrien
224560484Sobrien	  /* If there are fewer operands in the line then are called
224660484Sobrien	     for by the instruction, we want to skip the optional
2247130561Sobrien	     operands.  */
2248104834Sobrien	  if (opcount < num_operands_expected)
224960484Sobrien	    skip_optional = 1;
225060484Sobrien
225160484Sobrien	  break;
225260484Sobrien	}
225360484Sobrien    }
225460484Sobrien
225560484Sobrien  /* Gather the operands.  */
225660484Sobrien  need_paren = 0;
225760484Sobrien  next_opindex = 0;
225860484Sobrien  fc = 0;
225960484Sobrien  for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++)
226060484Sobrien    {
226160484Sobrien      const struct powerpc_operand *operand;
226260484Sobrien      const char *errmsg;
226360484Sobrien      char *hold;
226460484Sobrien      expressionS ex;
226560484Sobrien      char endc;
226660484Sobrien
226760484Sobrien      if (next_opindex == 0)
226860484Sobrien	operand = &powerpc_operands[*opindex_ptr];
226960484Sobrien      else
227060484Sobrien	{
227160484Sobrien	  operand = &powerpc_operands[next_opindex];
227260484Sobrien	  next_opindex = 0;
227360484Sobrien	}
227460484Sobrien      errmsg = NULL;
227560484Sobrien
227660484Sobrien      /* If this is a fake operand, then we do not expect anything
227760484Sobrien	 from the input.  */
227860484Sobrien      if ((operand->flags & PPC_OPERAND_FAKE) != 0)
227960484Sobrien	{
2280104834Sobrien	  insn = (*operand->insert) (insn, 0L, ppc_cpu, &errmsg);
228160484Sobrien	  if (errmsg != (const char *) NULL)
228260484Sobrien	    as_bad (errmsg);
228360484Sobrien	  continue;
228460484Sobrien	}
228560484Sobrien
228660484Sobrien      /* If this is an optional operand, and we are skipping it, just
228760484Sobrien	 insert a zero.  */
228860484Sobrien      if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
228960484Sobrien	  && skip_optional)
229060484Sobrien	{
229160484Sobrien	  if (operand->insert)
229260484Sobrien	    {
2293104834Sobrien	      insn = (*operand->insert) (insn, 0L, ppc_cpu, &errmsg);
229460484Sobrien	      if (errmsg != (const char *) NULL)
229560484Sobrien		as_bad (errmsg);
229660484Sobrien	    }
229760484Sobrien	  if ((operand->flags & PPC_OPERAND_NEXT) != 0)
229860484Sobrien	    next_opindex = *opindex_ptr + 1;
229960484Sobrien	  continue;
230060484Sobrien	}
230160484Sobrien
230260484Sobrien      /* Gather the operand.  */
230360484Sobrien      hold = input_line_pointer;
230460484Sobrien      input_line_pointer = str;
230560484Sobrien
230660484Sobrien#ifdef TE_PE
230777298Sobrien      if (*input_line_pointer == '[')
230860484Sobrien	{
230960484Sobrien	  /* We are expecting something like the second argument here:
231089857Sobrien	   *
231189857Sobrien	   *    lwz r4,[toc].GS.0.static_int(rtoc)
231289857Sobrien	   *           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
231389857Sobrien	   * The argument following the `]' must be a symbol name, and the
231489857Sobrien	   * register must be the toc register: 'rtoc' or '2'
231589857Sobrien	   *
231689857Sobrien	   * The effect is to 0 as the displacement field
231789857Sobrien	   * in the instruction, and issue an IMAGE_REL_PPC_TOCREL16 (or
231889857Sobrien	   * the appropriate variation) reloc against it based on the symbol.
231989857Sobrien	   * The linker will build the toc, and insert the resolved toc offset.
232089857Sobrien	   *
232189857Sobrien	   * Note:
232289857Sobrien	   * o The size of the toc entry is currently assumed to be
232389857Sobrien	   *   32 bits. This should not be assumed to be a hard coded
232489857Sobrien	   *   number.
232589857Sobrien	   * o In an effort to cope with a change from 32 to 64 bits,
232689857Sobrien	   *   there are also toc entries that are specified to be
232789857Sobrien	   *   either 32 or 64 bits:
232889857Sobrien	   *     lwz r4,[toc32].GS.0.static_int(rtoc)
232989857Sobrien	   *     lwz r4,[toc64].GS.0.static_int(rtoc)
233089857Sobrien	   *   These demand toc entries of the specified size, and the
233189857Sobrien	   *   instruction probably requires it.
233289857Sobrien	   */
233360484Sobrien
233460484Sobrien	  int valid_toc;
233560484Sobrien	  enum toc_size_qualifier toc_kind;
233660484Sobrien	  bfd_reloc_code_real_type toc_reloc;
233760484Sobrien
233889857Sobrien	  /* Go parse off the [tocXX] part.  */
233989857Sobrien	  valid_toc = parse_toc_entry (&toc_kind);
234060484Sobrien
234177298Sobrien	  if (!valid_toc)
234260484Sobrien	    {
234389857Sobrien	      /* Note: message has already been issued.
234489857Sobrien		 FIXME: what sort of recovery should we do?
234589857Sobrien		 demand_rest_of_line (); return; ?  */
234660484Sobrien	    }
234760484Sobrien
234889857Sobrien	  /* Now get the symbol following the ']'.  */
234989857Sobrien	  expression (&ex);
235060484Sobrien
235160484Sobrien	  switch (toc_kind)
235260484Sobrien	    {
235360484Sobrien	    case default_toc:
235489857Sobrien	      /* In this case, we may not have seen the symbol yet,
235589857Sobrien		 since  it is allowed to appear on a .extern or .globl
235689857Sobrien		 or just be a label in the .data section.  */
235760484Sobrien	      toc_reloc = BFD_RELOC_PPC_TOC16;
235860484Sobrien	      break;
235960484Sobrien	    case data_in_toc:
236089857Sobrien	      /* 1. The symbol must be defined and either in the toc
236189857Sobrien		 section, or a global.
236289857Sobrien		 2. The reloc generated must have the TOCDEFN flag set
236389857Sobrien		 in upper bit mess of the reloc type.
236489857Sobrien		 FIXME: It's a little confusing what the tocv
236589857Sobrien		 qualifier can be used for.  At the very least, I've
236689857Sobrien		 seen three uses, only one of which I'm sure I can
236789857Sobrien		 explain.  */
236877298Sobrien	      if (ex.X_op == O_symbol)
236977298Sobrien		{
237060484Sobrien		  assert (ex.X_add_symbol != NULL);
237160484Sobrien		  if (symbol_get_bfdsym (ex.X_add_symbol)->section
237260484Sobrien		      != tocdata_section)
237360484Sobrien		    {
237489857Sobrien		      as_bad (_("[tocv] symbol is not a toc symbol"));
237560484Sobrien		    }
237660484Sobrien		}
237760484Sobrien
237860484Sobrien	      toc_reloc = BFD_RELOC_PPC_TOC16;
237960484Sobrien	      break;
238060484Sobrien	    case must_be_32:
238189857Sobrien	      /* FIXME: these next two specifically specify 32/64 bit
238289857Sobrien		 toc entries.  We don't support them today.  Is this
238389857Sobrien		 the right way to say that?  */
238460484Sobrien	      toc_reloc = BFD_RELOC_UNUSED;
238560484Sobrien	      as_bad (_("Unimplemented toc32 expression modifier"));
238660484Sobrien	      break;
238760484Sobrien	    case must_be_64:
238889857Sobrien	      /* FIXME: see above.  */
238960484Sobrien	      toc_reloc = BFD_RELOC_UNUSED;
239060484Sobrien	      as_bad (_("Unimplemented toc64 expression modifier"));
239160484Sobrien	      break;
239260484Sobrien	    default:
239377298Sobrien	      fprintf (stderr,
239489857Sobrien		       _("Unexpected return value [%d] from parse_toc_entry!\n"),
239589857Sobrien		       toc_kind);
239677298Sobrien	      abort ();
239760484Sobrien	      break;
239860484Sobrien	    }
239960484Sobrien
240060484Sobrien	  /* We need to generate a fixup for this expression.  */
240160484Sobrien	  if (fc >= MAX_INSN_FIXUPS)
240260484Sobrien	    as_fatal (_("too many fixups"));
240360484Sobrien
240460484Sobrien	  fixups[fc].reloc = toc_reloc;
240560484Sobrien	  fixups[fc].exp = ex;
240660484Sobrien	  fixups[fc].opindex = *opindex_ptr;
240760484Sobrien	  ++fc;
240860484Sobrien
240989857Sobrien	  /* Ok. We've set up the fixup for the instruction. Now make it
241089857Sobrien	     look like the constant 0 was found here.  */
241160484Sobrien	  ex.X_unsigned = 1;
241260484Sobrien	  ex.X_op = O_constant;
241360484Sobrien	  ex.X_add_number = 0;
241460484Sobrien	  ex.X_add_symbol = NULL;
241560484Sobrien	  ex.X_op_symbol = NULL;
241660484Sobrien	}
241760484Sobrien
241860484Sobrien      else
241960484Sobrien#endif		/* TE_PE */
242060484Sobrien	{
242160484Sobrien	  if (! register_name (&ex))
242260484Sobrien	    {
242360484Sobrien	      if ((operand->flags & PPC_OPERAND_CR) != 0)
2424130561Sobrien		cr_operand = TRUE;
242560484Sobrien	      expression (&ex);
2426130561Sobrien	      cr_operand = FALSE;
242760484Sobrien	    }
242860484Sobrien	}
242960484Sobrien
243060484Sobrien      str = input_line_pointer;
243160484Sobrien      input_line_pointer = hold;
243260484Sobrien
243360484Sobrien      if (ex.X_op == O_illegal)
243460484Sobrien	as_bad (_("illegal operand"));
243560484Sobrien      else if (ex.X_op == O_absent)
243660484Sobrien	as_bad (_("missing operand"));
243760484Sobrien      else if (ex.X_op == O_register)
243860484Sobrien	{
243960484Sobrien	  insn = ppc_insert_operand (insn, operand, ex.X_add_number,
244060484Sobrien				     (char *) NULL, 0);
244160484Sobrien	}
244260484Sobrien      else if (ex.X_op == O_constant)
244360484Sobrien	{
244460484Sobrien#ifdef OBJ_ELF
244577298Sobrien	  /* Allow @HA, @L, @H on constants.  */
244660484Sobrien	  char *orig_str = str;
244760484Sobrien
244860484Sobrien	  if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)
244960484Sobrien	    switch (reloc)
245060484Sobrien	      {
245160484Sobrien	      default:
245260484Sobrien		str = orig_str;
245360484Sobrien		break;
245460484Sobrien
245560484Sobrien	      case BFD_RELOC_LO16:
245660484Sobrien		/* X_unsigned is the default, so if the user has done
245789857Sobrien		   something which cleared it, we always produce a
245889857Sobrien		   signed value.  */
245989857Sobrien		if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
246060484Sobrien		  ex.X_add_number &= 0xffff;
246160484Sobrien		else
246289857Sobrien		  ex.X_add_number = SEX16 (ex.X_add_number);
246360484Sobrien		break;
246460484Sobrien
246560484Sobrien	      case BFD_RELOC_HI16:
246689857Sobrien		if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
246789857Sobrien		  ex.X_add_number = PPC_HI (ex.X_add_number);
246889857Sobrien		else
246989857Sobrien		  ex.X_add_number = SEX16 (PPC_HI (ex.X_add_number));
247060484Sobrien		break;
247160484Sobrien
247260484Sobrien	      case BFD_RELOC_HI16_S:
247389857Sobrien		if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
247489857Sobrien		  ex.X_add_number = PPC_HA (ex.X_add_number);
247589857Sobrien		else
247689857Sobrien		  ex.X_add_number = SEX16 (PPC_HA (ex.X_add_number));
247760484Sobrien		break;
247889857Sobrien
247989857Sobrien	      case BFD_RELOC_PPC64_HIGHER:
248089857Sobrien		if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
248189857Sobrien		  ex.X_add_number = PPC_HIGHER (ex.X_add_number);
248289857Sobrien		else
248389857Sobrien		  ex.X_add_number = SEX16 (PPC_HIGHER (ex.X_add_number));
248489857Sobrien		break;
248589857Sobrien
248689857Sobrien	      case BFD_RELOC_PPC64_HIGHER_S:
248789857Sobrien		if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
248889857Sobrien		  ex.X_add_number = PPC_HIGHERA (ex.X_add_number);
248989857Sobrien		else
249089857Sobrien		  ex.X_add_number = SEX16 (PPC_HIGHERA (ex.X_add_number));
249189857Sobrien		break;
249289857Sobrien
249389857Sobrien	      case BFD_RELOC_PPC64_HIGHEST:
249489857Sobrien		if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
249589857Sobrien		  ex.X_add_number = PPC_HIGHEST (ex.X_add_number);
249689857Sobrien		else
249789857Sobrien		  ex.X_add_number = SEX16 (PPC_HIGHEST (ex.X_add_number));
249889857Sobrien		break;
249989857Sobrien
250089857Sobrien	      case BFD_RELOC_PPC64_HIGHEST_S:
250189857Sobrien		if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
250289857Sobrien		  ex.X_add_number = PPC_HIGHESTA (ex.X_add_number);
250389857Sobrien		else
250489857Sobrien		  ex.X_add_number = SEX16 (PPC_HIGHESTA (ex.X_add_number));
250589857Sobrien		break;
250660484Sobrien	      }
250789857Sobrien#endif /* OBJ_ELF */
250860484Sobrien	  insn = ppc_insert_operand (insn, operand, ex.X_add_number,
250960484Sobrien				     (char *) NULL, 0);
251060484Sobrien	}
251160484Sobrien#ifdef OBJ_ELF
251260484Sobrien      else if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)
251360484Sobrien	{
2514130561Sobrien	  /* Some TLS tweaks.  */
2515130561Sobrien	  switch (reloc)
2516130561Sobrien	    {
2517130561Sobrien	    default:
2518130561Sobrien	      break;
2519130561Sobrien	    case BFD_RELOC_PPC_TLS:
2520130561Sobrien	      insn = ppc_insert_operand (insn, operand, ppc_obj64 ? 13 : 2,
2521130561Sobrien					 (char *) NULL, 0);
2522130561Sobrien	      break;
2523130561Sobrien	  /* We'll only use the 32 (or 64) bit form of these relocations
2524130561Sobrien	     in constants.  Instructions get the 16 bit form.  */
2525130561Sobrien	    case BFD_RELOC_PPC_DTPREL:
2526130561Sobrien	      reloc = BFD_RELOC_PPC_DTPREL16;
2527130561Sobrien	      break;
2528130561Sobrien	    case BFD_RELOC_PPC_TPREL:
2529130561Sobrien	      reloc = BFD_RELOC_PPC_TPREL16;
2530130561Sobrien	      break;
2531130561Sobrien	    }
2532130561Sobrien
253389857Sobrien	  /* For the absolute forms of branches, convert the PC
253489857Sobrien	     relative form back into the absolute.  */
253560484Sobrien	  if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
253660484Sobrien	    {
253760484Sobrien	      switch (reloc)
253860484Sobrien		{
253960484Sobrien		case BFD_RELOC_PPC_B26:
254060484Sobrien		  reloc = BFD_RELOC_PPC_BA26;
254160484Sobrien		  break;
254260484Sobrien		case BFD_RELOC_PPC_B16:
254360484Sobrien		  reloc = BFD_RELOC_PPC_BA16;
254460484Sobrien		  break;
254560484Sobrien		case BFD_RELOC_PPC_B16_BRTAKEN:
254660484Sobrien		  reloc = BFD_RELOC_PPC_BA16_BRTAKEN;
254760484Sobrien		  break;
254860484Sobrien		case BFD_RELOC_PPC_B16_BRNTAKEN:
254960484Sobrien		  reloc = BFD_RELOC_PPC_BA16_BRNTAKEN;
255060484Sobrien		  break;
255160484Sobrien		default:
255260484Sobrien		  break;
255360484Sobrien		}
255460484Sobrien	    }
255560484Sobrien
2556104834Sobrien	  if (ppc_obj64
2557130561Sobrien	      && (operand->flags & (PPC_OPERAND_DS | PPC_OPERAND_DQ)) != 0)
255889857Sobrien	    {
255989857Sobrien	      switch (reloc)
256089857Sobrien		{
256189857Sobrien		case BFD_RELOC_16:
256289857Sobrien		  reloc = BFD_RELOC_PPC64_ADDR16_DS;
256389857Sobrien		  break;
256489857Sobrien		case BFD_RELOC_LO16:
256589857Sobrien		  reloc = BFD_RELOC_PPC64_ADDR16_LO_DS;
256689857Sobrien		  break;
256789857Sobrien		case BFD_RELOC_16_GOTOFF:
256889857Sobrien		  reloc = BFD_RELOC_PPC64_GOT16_DS;
256989857Sobrien		  break;
257089857Sobrien		case BFD_RELOC_LO16_GOTOFF:
257189857Sobrien		  reloc = BFD_RELOC_PPC64_GOT16_LO_DS;
257289857Sobrien		  break;
257389857Sobrien		case BFD_RELOC_LO16_PLTOFF:
257489857Sobrien		  reloc = BFD_RELOC_PPC64_PLT16_LO_DS;
257589857Sobrien		  break;
257699461Sobrien		case BFD_RELOC_16_BASEREL:
257789857Sobrien		  reloc = BFD_RELOC_PPC64_SECTOFF_DS;
257889857Sobrien		  break;
257989857Sobrien		case BFD_RELOC_LO16_BASEREL:
258089857Sobrien		  reloc = BFD_RELOC_PPC64_SECTOFF_LO_DS;
258189857Sobrien		  break;
258289857Sobrien		case BFD_RELOC_PPC_TOC16:
258389857Sobrien		  reloc = BFD_RELOC_PPC64_TOC16_DS;
258489857Sobrien		  break;
258589857Sobrien		case BFD_RELOC_PPC64_TOC16_LO:
258689857Sobrien		  reloc = BFD_RELOC_PPC64_TOC16_LO_DS;
258789857Sobrien		  break;
258889857Sobrien		case BFD_RELOC_PPC64_PLTGOT16:
258989857Sobrien		  reloc = BFD_RELOC_PPC64_PLTGOT16_DS;
259089857Sobrien		  break;
259189857Sobrien		case BFD_RELOC_PPC64_PLTGOT16_LO:
259289857Sobrien		  reloc = BFD_RELOC_PPC64_PLTGOT16_LO_DS;
259389857Sobrien		  break;
2594130561Sobrien		case BFD_RELOC_PPC_DTPREL16:
2595130561Sobrien		  reloc = BFD_RELOC_PPC64_DTPREL16_DS;
2596130561Sobrien		  break;
2597130561Sobrien		case BFD_RELOC_PPC_DTPREL16_LO:
2598130561Sobrien		  reloc = BFD_RELOC_PPC64_DTPREL16_LO_DS;
2599130561Sobrien		  break;
2600130561Sobrien		case BFD_RELOC_PPC_TPREL16:
2601130561Sobrien		  reloc = BFD_RELOC_PPC64_TPREL16_DS;
2602130561Sobrien		  break;
2603130561Sobrien		case BFD_RELOC_PPC_TPREL16_LO:
2604130561Sobrien		  reloc = BFD_RELOC_PPC64_TPREL16_LO_DS;
2605130561Sobrien		  break;
2606130561Sobrien		case BFD_RELOC_PPC_GOT_DTPREL16:
2607130561Sobrien		case BFD_RELOC_PPC_GOT_DTPREL16_LO:
2608130561Sobrien		case BFD_RELOC_PPC_GOT_TPREL16:
2609130561Sobrien		case BFD_RELOC_PPC_GOT_TPREL16_LO:
2610130561Sobrien		  break;
261189857Sobrien		default:
261289857Sobrien		  as_bad (_("unsupported relocation for DS offset field"));
261389857Sobrien		  break;
261489857Sobrien		}
261589857Sobrien	    }
261689857Sobrien
261760484Sobrien	  /* We need to generate a fixup for this expression.  */
261860484Sobrien	  if (fc >= MAX_INSN_FIXUPS)
261960484Sobrien	    as_fatal (_("too many fixups"));
262060484Sobrien	  fixups[fc].exp = ex;
262160484Sobrien	  fixups[fc].opindex = 0;
262260484Sobrien	  fixups[fc].reloc = reloc;
262360484Sobrien	  ++fc;
262460484Sobrien	}
262560484Sobrien#endif /* OBJ_ELF */
262660484Sobrien
262760484Sobrien      else
262860484Sobrien	{
262960484Sobrien	  /* We need to generate a fixup for this expression.  */
263060484Sobrien	  if (fc >= MAX_INSN_FIXUPS)
263160484Sobrien	    as_fatal (_("too many fixups"));
263260484Sobrien	  fixups[fc].exp = ex;
263360484Sobrien	  fixups[fc].opindex = *opindex_ptr;
263460484Sobrien	  fixups[fc].reloc = BFD_RELOC_UNUSED;
263560484Sobrien	  ++fc;
263660484Sobrien	}
263760484Sobrien
263860484Sobrien      if (need_paren)
263960484Sobrien	{
264060484Sobrien	  endc = ')';
264160484Sobrien	  need_paren = 0;
264260484Sobrien	}
264360484Sobrien      else if ((operand->flags & PPC_OPERAND_PARENS) != 0)
264460484Sobrien	{
264560484Sobrien	  endc = '(';
264660484Sobrien	  need_paren = 1;
264760484Sobrien	}
264860484Sobrien      else
264960484Sobrien	endc = ',';
265060484Sobrien
265160484Sobrien      /* The call to expression should have advanced str past any
265260484Sobrien	 whitespace.  */
265360484Sobrien      if (*str != endc
265460484Sobrien	  && (endc != ',' || *str != '\0'))
265560484Sobrien	{
265660484Sobrien	  as_bad (_("syntax error; found `%c' but expected `%c'"), *str, endc);
265760484Sobrien	  break;
265860484Sobrien	}
265960484Sobrien
266060484Sobrien      if (*str != '\0')
266160484Sobrien	++str;
266260484Sobrien    }
266360484Sobrien
266489857Sobrien  while (ISSPACE (*str))
266560484Sobrien    ++str;
266660484Sobrien
266760484Sobrien  if (*str != '\0')
266860484Sobrien    as_bad (_("junk at end of line: `%s'"), str);
266960484Sobrien
2670130561Sobrien#ifdef OBJ_ELF
2671130561Sobrien  /* Do we need/want a APUinfo section? */
2672130561Sobrien  if (ppc_cpu & (PPC_OPCODE_SPE
2673130561Sobrien   	       | PPC_OPCODE_ISEL | PPC_OPCODE_EFS
2674130561Sobrien	       | PPC_OPCODE_BRLOCK | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK
2675130561Sobrien	       | PPC_OPCODE_RFMCI))
2676130561Sobrien    {
2677130561Sobrien      /* These are all version "1".  */
2678130561Sobrien      if (opcode->flags & PPC_OPCODE_SPE)
2679130561Sobrien	ppc_apuinfo_section_add (PPC_APUINFO_SPE, 1);
2680130561Sobrien      if (opcode->flags & PPC_OPCODE_ISEL)
2681130561Sobrien	ppc_apuinfo_section_add (PPC_APUINFO_ISEL, 1);
2682130561Sobrien      if (opcode->flags & PPC_OPCODE_EFS)
2683130561Sobrien	ppc_apuinfo_section_add (PPC_APUINFO_EFS, 1);
2684130561Sobrien      if (opcode->flags & PPC_OPCODE_BRLOCK)
2685130561Sobrien	ppc_apuinfo_section_add (PPC_APUINFO_BRLOCK, 1);
2686130561Sobrien      if (opcode->flags & PPC_OPCODE_PMR)
2687130561Sobrien	ppc_apuinfo_section_add (PPC_APUINFO_PMR, 1);
2688130561Sobrien      if (opcode->flags & PPC_OPCODE_CACHELCK)
2689130561Sobrien	ppc_apuinfo_section_add (PPC_APUINFO_CACHELCK, 1);
2690130561Sobrien      if (opcode->flags & PPC_OPCODE_RFMCI)
2691130561Sobrien	ppc_apuinfo_section_add (PPC_APUINFO_RFMCI, 1);
2692130561Sobrien    }
2693130561Sobrien#endif
2694130561Sobrien
269560484Sobrien  /* Write out the instruction.  */
269660484Sobrien  f = frag_more (4);
2697218822Sdim  addr_mod = frag_now_fix () & 3;
2698218822Sdim  if (frag_now->has_code && frag_now->insn_addr != addr_mod)
2699218822Sdim    as_bad (_("instruction address is not a multiple of 4"));
2700218822Sdim  frag_now->insn_addr = addr_mod;
2701218822Sdim  frag_now->has_code = 1;
270260484Sobrien  md_number_to_chars (f, insn, 4);
270360484Sobrien
270477298Sobrien#ifdef OBJ_ELF
270577298Sobrien  dwarf2_emit_insn (4);
270677298Sobrien#endif
270777298Sobrien
270860484Sobrien  /* Create any fixups.  At this point we do not use a
270960484Sobrien     bfd_reloc_code_real_type, but instead just use the
271060484Sobrien     BFD_RELOC_UNUSED plus the operand index.  This lets us easily
271160484Sobrien     handle fixups for any operand type, although that is admittedly
271260484Sobrien     not a very exciting feature.  We pick a BFD reloc type in
2713218822Sdim     md_apply_fix.  */
271460484Sobrien  for (i = 0; i < fc; i++)
271560484Sobrien    {
271660484Sobrien      const struct powerpc_operand *operand;
271760484Sobrien
271860484Sobrien      operand = &powerpc_operands[fixups[i].opindex];
271960484Sobrien      if (fixups[i].reloc != BFD_RELOC_UNUSED)
272060484Sobrien	{
272189857Sobrien	  reloc_howto_type *reloc_howto;
272260484Sobrien	  int size;
272360484Sobrien	  int offset;
272460484Sobrien	  fixS *fixP;
272560484Sobrien
272689857Sobrien	  reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc);
272760484Sobrien	  if (!reloc_howto)
272860484Sobrien	    abort ();
272960484Sobrien
273060484Sobrien	  size = bfd_get_reloc_size (reloc_howto);
273160484Sobrien	  offset = target_big_endian ? (4 - size) : 0;
273260484Sobrien
273360484Sobrien	  if (size < 1 || size > 4)
273477298Sobrien	    abort ();
273560484Sobrien
273689857Sobrien	  fixP = fix_new_exp (frag_now,
273789857Sobrien			      f - frag_now->fr_literal + offset,
273889857Sobrien			      size,
273989857Sobrien			      &fixups[i].exp,
274089857Sobrien			      reloc_howto->pc_relative,
274160484Sobrien			      fixups[i].reloc);
274260484Sobrien
274360484Sobrien	  /* Turn off complaints that the addend is too large for things like
274460484Sobrien	     foo+100000@ha.  */
274560484Sobrien	  switch (fixups[i].reloc)
274660484Sobrien	    {
274760484Sobrien	    case BFD_RELOC_16_GOTOFF:
274860484Sobrien	    case BFD_RELOC_PPC_TOC16:
274960484Sobrien	    case BFD_RELOC_LO16:
275060484Sobrien	    case BFD_RELOC_HI16:
275160484Sobrien	    case BFD_RELOC_HI16_S:
275289857Sobrien#ifdef OBJ_ELF
275389857Sobrien	    case BFD_RELOC_PPC64_HIGHER:
275489857Sobrien	    case BFD_RELOC_PPC64_HIGHER_S:
275589857Sobrien	    case BFD_RELOC_PPC64_HIGHEST:
275689857Sobrien	    case BFD_RELOC_PPC64_HIGHEST_S:
275789857Sobrien#endif
275860484Sobrien	      fixP->fx_no_overflow = 1;
275960484Sobrien	      break;
276060484Sobrien	    default:
276160484Sobrien	      break;
276260484Sobrien	    }
276360484Sobrien	}
276460484Sobrien      else
276589857Sobrien	fix_new_exp (frag_now,
276689857Sobrien		     f - frag_now->fr_literal,
276789857Sobrien		     4,
276860484Sobrien		     &fixups[i].exp,
276960484Sobrien		     (operand->flags & PPC_OPERAND_RELATIVE) != 0,
277060484Sobrien		     ((bfd_reloc_code_real_type)
277189857Sobrien		      (fixups[i].opindex + (int) BFD_RELOC_UNUSED)));
277260484Sobrien    }
277360484Sobrien}
277460484Sobrien
277560484Sobrien/* Handle a macro.  Gather all the operands, transform them as
277660484Sobrien   described by the macro, and call md_assemble recursively.  All the
277760484Sobrien   operands are separated by commas; we don't accept parentheses
277860484Sobrien   around operands here.  */
277960484Sobrien
278060484Sobrienstatic void
2781218822Sdimppc_macro (char *str, const struct powerpc_macro *macro)
278260484Sobrien{
278360484Sobrien  char *operands[10];
278460484Sobrien  unsigned int count;
278560484Sobrien  char *s;
278660484Sobrien  unsigned int len;
278760484Sobrien  const char *format;
2788218822Sdim  unsigned int arg;
278960484Sobrien  char *send;
279060484Sobrien  char *complete;
279160484Sobrien
279260484Sobrien  /* Gather the users operands into the operands array.  */
279360484Sobrien  count = 0;
279460484Sobrien  s = str;
279560484Sobrien  while (1)
279660484Sobrien    {
279760484Sobrien      if (count >= sizeof operands / sizeof operands[0])
279860484Sobrien	break;
279960484Sobrien      operands[count++] = s;
280060484Sobrien      s = strchr (s, ',');
280160484Sobrien      if (s == (char *) NULL)
280260484Sobrien	break;
280360484Sobrien      *s++ = '\0';
280477298Sobrien    }
280560484Sobrien
280660484Sobrien  if (count != macro->operands)
280760484Sobrien    {
280860484Sobrien      as_bad (_("wrong number of operands"));
280960484Sobrien      return;
281060484Sobrien    }
281160484Sobrien
281260484Sobrien  /* Work out how large the string must be (the size is unbounded
281360484Sobrien     because it includes user input).  */
281460484Sobrien  len = 0;
281560484Sobrien  format = macro->format;
281660484Sobrien  while (*format != '\0')
281760484Sobrien    {
281860484Sobrien      if (*format != '%')
281960484Sobrien	{
282060484Sobrien	  ++len;
282160484Sobrien	  ++format;
282260484Sobrien	}
282360484Sobrien      else
282460484Sobrien	{
282560484Sobrien	  arg = strtol (format + 1, &send, 10);
2826218822Sdim	  know (send != format && arg < count);
282760484Sobrien	  len += strlen (operands[arg]);
282860484Sobrien	  format = send;
282960484Sobrien	}
283060484Sobrien    }
283160484Sobrien
283260484Sobrien  /* Put the string together.  */
283360484Sobrien  complete = s = (char *) alloca (len + 1);
283460484Sobrien  format = macro->format;
283560484Sobrien  while (*format != '\0')
283660484Sobrien    {
283760484Sobrien      if (*format != '%')
283860484Sobrien	*s++ = *format++;
283960484Sobrien      else
284060484Sobrien	{
284160484Sobrien	  arg = strtol (format + 1, &send, 10);
284260484Sobrien	  strcpy (s, operands[arg]);
284360484Sobrien	  s += strlen (s);
284460484Sobrien	  format = send;
284560484Sobrien	}
284660484Sobrien    }
284760484Sobrien  *s = '\0';
284860484Sobrien
284960484Sobrien  /* Assemble the constructed instruction.  */
285060484Sobrien  md_assemble (complete);
285177298Sobrien}
285260484Sobrien
285360484Sobrien#ifdef OBJ_ELF
285489857Sobrien/* For ELF, add support for SHF_EXCLUDE and SHT_ORDERED.  */
285560484Sobrien
285660484Sobrienint
2857218822Sdimppc_section_letter (int letter, char **ptr_msg)
285860484Sobrien{
285960484Sobrien  if (letter == 'e')
286060484Sobrien    return SHF_EXCLUDE;
286160484Sobrien
2862104834Sobrien  *ptr_msg = _("Bad .section directive: want a,e,w,x,M,S,G,T in string");
2863130561Sobrien  return -1;
286460484Sobrien}
286560484Sobrien
286660484Sobrienint
2867218822Sdimppc_section_word (char *str, size_t len)
286860484Sobrien{
286960484Sobrien  if (len == 7 && strncmp (str, "exclude", 7) == 0)
287060484Sobrien    return SHF_EXCLUDE;
287160484Sobrien
287260484Sobrien  return -1;
287360484Sobrien}
287460484Sobrien
287560484Sobrienint
2876218822Sdimppc_section_type (char *str, size_t len)
287760484Sobrien{
287860484Sobrien  if (len == 7 && strncmp (str, "ordered", 7) == 0)
287960484Sobrien    return SHT_ORDERED;
288060484Sobrien
288160484Sobrien  return -1;
288260484Sobrien}
288360484Sobrien
288460484Sobrienint
2885218822Sdimppc_section_flags (int flags, int attr, int type)
288660484Sobrien{
288760484Sobrien  if (type == SHT_ORDERED)
288860484Sobrien    flags |= SEC_ALLOC | SEC_LOAD | SEC_SORT_ENTRIES;
288960484Sobrien
289060484Sobrien  if (attr & SHF_EXCLUDE)
289160484Sobrien    flags |= SEC_EXCLUDE;
289260484Sobrien
289360484Sobrien  return flags;
289460484Sobrien}
289560484Sobrien#endif /* OBJ_ELF */
289660484Sobrien
289760484Sobrien
289860484Sobrien/* Pseudo-op handling.  */
289960484Sobrien
290060484Sobrien/* The .byte pseudo-op.  This is similar to the normal .byte
290160484Sobrien   pseudo-op, but it can also take a single ASCII string.  */
290260484Sobrien
290360484Sobrienstatic void
2904218822Sdimppc_byte (int ignore ATTRIBUTE_UNUSED)
290560484Sobrien{
290660484Sobrien  if (*input_line_pointer != '\"')
290760484Sobrien    {
290860484Sobrien      cons (1);
290960484Sobrien      return;
291060484Sobrien    }
291160484Sobrien
291260484Sobrien  /* Gather characters.  A real double quote is doubled.  Unusual
291360484Sobrien     characters are not permitted.  */
291460484Sobrien  ++input_line_pointer;
291560484Sobrien  while (1)
291660484Sobrien    {
291760484Sobrien      char c;
291860484Sobrien
291960484Sobrien      c = *input_line_pointer++;
292060484Sobrien
292160484Sobrien      if (c == '\"')
292260484Sobrien	{
292360484Sobrien	  if (*input_line_pointer != '\"')
292460484Sobrien	    break;
292560484Sobrien	  ++input_line_pointer;
292660484Sobrien	}
292760484Sobrien
292860484Sobrien      FRAG_APPEND_1_CHAR (c);
292960484Sobrien    }
293060484Sobrien
293160484Sobrien  demand_empty_rest_of_line ();
293260484Sobrien}
293360484Sobrien
293460484Sobrien#ifdef OBJ_XCOFF
293560484Sobrien
293660484Sobrien/* XCOFF specific pseudo-op handling.  */
293760484Sobrien
293860484Sobrien/* This is set if we are creating a .stabx symbol, since we don't want
293960484Sobrien   to handle symbol suffixes for such symbols.  */
2940130561Sobrienstatic bfd_boolean ppc_stab_symbol;
294160484Sobrien
294260484Sobrien/* The .comm and .lcomm pseudo-ops for XCOFF.  XCOFF puts common
294360484Sobrien   symbols in the .bss segment as though they were local common
2944130561Sobrien   symbols, and uses a different smclas.  The native Aix 4.3.3 assembler
294580016Sobrien   aligns .comm and .lcomm to 4 bytes.  */
294660484Sobrien
294760484Sobrienstatic void
2948218822Sdimppc_comm (int lcomm)
294960484Sobrien{
295060484Sobrien  asection *current_seg = now_seg;
295160484Sobrien  subsegT current_subseg = now_subseg;
295260484Sobrien  char *name;
295360484Sobrien  char endc;
295460484Sobrien  char *end_name;
295560484Sobrien  offsetT size;
295660484Sobrien  offsetT align;
295760484Sobrien  symbolS *lcomm_sym = NULL;
295860484Sobrien  symbolS *sym;
295960484Sobrien  char *pfrag;
296060484Sobrien
296160484Sobrien  name = input_line_pointer;
296260484Sobrien  endc = get_symbol_end ();
296360484Sobrien  end_name = input_line_pointer;
296460484Sobrien  *end_name = endc;
296560484Sobrien
296660484Sobrien  if (*input_line_pointer != ',')
296760484Sobrien    {
296860484Sobrien      as_bad (_("missing size"));
296960484Sobrien      ignore_rest_of_line ();
297060484Sobrien      return;
297160484Sobrien    }
297260484Sobrien  ++input_line_pointer;
297360484Sobrien
297460484Sobrien  size = get_absolute_expression ();
297560484Sobrien  if (size < 0)
297660484Sobrien    {
297760484Sobrien      as_bad (_("negative size"));
297860484Sobrien      ignore_rest_of_line ();
297960484Sobrien      return;
298060484Sobrien    }
298160484Sobrien
298260484Sobrien  if (! lcomm)
298360484Sobrien    {
298460484Sobrien      /* The third argument to .comm is the alignment.  */
298560484Sobrien      if (*input_line_pointer != ',')
298680016Sobrien	align = 2;
298760484Sobrien      else
298860484Sobrien	{
298960484Sobrien	  ++input_line_pointer;
299060484Sobrien	  align = get_absolute_expression ();
299160484Sobrien	  if (align <= 0)
299260484Sobrien	    {
299360484Sobrien	      as_warn (_("ignoring bad alignment"));
299480016Sobrien	      align = 2;
299560484Sobrien	    }
299660484Sobrien	}
299760484Sobrien    }
299860484Sobrien  else
299960484Sobrien    {
300060484Sobrien      char *lcomm_name;
300160484Sobrien      char lcomm_endc;
300260484Sobrien
300380016Sobrien      if (size <= 4)
300460484Sobrien	align = 2;
300560484Sobrien      else
300660484Sobrien	align = 3;
300760484Sobrien
300860484Sobrien      /* The third argument to .lcomm appears to be the real local
300960484Sobrien	 common symbol to create.  References to the symbol named in
301060484Sobrien	 the first argument are turned into references to the third
301160484Sobrien	 argument.  */
301260484Sobrien      if (*input_line_pointer != ',')
301360484Sobrien	{
301460484Sobrien	  as_bad (_("missing real symbol name"));
301560484Sobrien	  ignore_rest_of_line ();
301660484Sobrien	  return;
301760484Sobrien	}
301860484Sobrien      ++input_line_pointer;
301960484Sobrien
302060484Sobrien      lcomm_name = input_line_pointer;
302160484Sobrien      lcomm_endc = get_symbol_end ();
302277298Sobrien
302360484Sobrien      lcomm_sym = symbol_find_or_make (lcomm_name);
302460484Sobrien
302560484Sobrien      *input_line_pointer = lcomm_endc;
302660484Sobrien    }
302760484Sobrien
302860484Sobrien  *end_name = '\0';
302960484Sobrien  sym = symbol_find_or_make (name);
303060484Sobrien  *end_name = endc;
303160484Sobrien
303260484Sobrien  if (S_IS_DEFINED (sym)
303360484Sobrien      || S_GET_VALUE (sym) != 0)
303460484Sobrien    {
303560484Sobrien      as_bad (_("attempt to redefine symbol"));
303660484Sobrien      ignore_rest_of_line ();
303760484Sobrien      return;
303860484Sobrien    }
303977298Sobrien
304060484Sobrien  record_alignment (bss_section, align);
304177298Sobrien
304260484Sobrien  if (! lcomm
304360484Sobrien      || ! S_IS_DEFINED (lcomm_sym))
304460484Sobrien    {
304560484Sobrien      symbolS *def_sym;
304660484Sobrien      offsetT def_size;
304760484Sobrien
304860484Sobrien      if (! lcomm)
304960484Sobrien	{
305060484Sobrien	  def_sym = sym;
305160484Sobrien	  def_size = size;
305260484Sobrien	  S_SET_EXTERNAL (sym);
305360484Sobrien	}
305460484Sobrien      else
305560484Sobrien	{
305660484Sobrien	  symbol_get_tc (lcomm_sym)->output = 1;
305760484Sobrien	  def_sym = lcomm_sym;
305860484Sobrien	  def_size = 0;
305960484Sobrien	}
306060484Sobrien
306160484Sobrien      subseg_set (bss_section, 1);
306260484Sobrien      frag_align (align, 0, 0);
306377298Sobrien
306460484Sobrien      symbol_set_frag (def_sym, frag_now);
306560484Sobrien      pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, def_sym,
306660484Sobrien			def_size, (char *) NULL);
306760484Sobrien      *pfrag = 0;
306860484Sobrien      S_SET_SEGMENT (def_sym, bss_section);
306960484Sobrien      symbol_get_tc (def_sym)->align = align;
307060484Sobrien    }
307160484Sobrien  else if (lcomm)
307260484Sobrien    {
307360484Sobrien      /* Align the size of lcomm_sym.  */
307460484Sobrien      symbol_get_frag (lcomm_sym)->fr_offset =
307560484Sobrien	((symbol_get_frag (lcomm_sym)->fr_offset + (1 << align) - 1)
307660484Sobrien	 &~ ((1 << align) - 1));
307760484Sobrien      if (align > symbol_get_tc (lcomm_sym)->align)
307860484Sobrien	symbol_get_tc (lcomm_sym)->align = align;
307960484Sobrien    }
308060484Sobrien
308160484Sobrien  if (lcomm)
308260484Sobrien    {
308360484Sobrien      /* Make sym an offset from lcomm_sym.  */
308460484Sobrien      S_SET_SEGMENT (sym, bss_section);
308560484Sobrien      symbol_set_frag (sym, symbol_get_frag (lcomm_sym));
308660484Sobrien      S_SET_VALUE (sym, symbol_get_frag (lcomm_sym)->fr_offset);
308760484Sobrien      symbol_get_frag (lcomm_sym)->fr_offset += size;
308860484Sobrien    }
308960484Sobrien
309060484Sobrien  subseg_set (current_seg, current_subseg);
309160484Sobrien
309260484Sobrien  demand_empty_rest_of_line ();
309360484Sobrien}
309460484Sobrien
309560484Sobrien/* The .csect pseudo-op.  This switches us into a different
309660484Sobrien   subsegment.  The first argument is a symbol whose value is the
309760484Sobrien   start of the .csect.  In COFF, csect symbols get special aux
309860484Sobrien   entries defined by the x_csect field of union internal_auxent.  The
309960484Sobrien   optional second argument is the alignment (the default is 2).  */
310060484Sobrien
310160484Sobrienstatic void
3102218822Sdimppc_csect (int ignore ATTRIBUTE_UNUSED)
310360484Sobrien{
310460484Sobrien  char *name;
310560484Sobrien  char endc;
310660484Sobrien  symbolS *sym;
3107130561Sobrien  offsetT align;
310860484Sobrien
310960484Sobrien  name = input_line_pointer;
311060484Sobrien  endc = get_symbol_end ();
311177298Sobrien
311260484Sobrien  sym = symbol_find_or_make (name);
311360484Sobrien
311460484Sobrien  *input_line_pointer = endc;
311560484Sobrien
311660484Sobrien  if (S_GET_NAME (sym)[0] == '\0')
311760484Sobrien    {
311860484Sobrien      /* An unnamed csect is assumed to be [PR].  */
311960484Sobrien      symbol_get_tc (sym)->class = XMC_PR;
312060484Sobrien    }
312160484Sobrien
3122130561Sobrien  align = 2;
312360484Sobrien  if (*input_line_pointer == ',')
312460484Sobrien    {
312560484Sobrien      ++input_line_pointer;
3126130561Sobrien      align = get_absolute_expression ();
312760484Sobrien    }
312860484Sobrien
3129130561Sobrien  ppc_change_csect (sym, align);
3130130561Sobrien
313160484Sobrien  demand_empty_rest_of_line ();
313260484Sobrien}
313360484Sobrien
313460484Sobrien/* Change to a different csect.  */
313560484Sobrien
313660484Sobrienstatic void
3137218822Sdimppc_change_csect (symbolS *sym, offsetT align)
313860484Sobrien{
313960484Sobrien  if (S_IS_DEFINED (sym))
314060484Sobrien    subseg_set (S_GET_SEGMENT (sym), symbol_get_tc (sym)->subseg);
314160484Sobrien  else
314260484Sobrien    {
314360484Sobrien      symbolS **list_ptr;
314460484Sobrien      int after_toc;
314560484Sobrien      int hold_chunksize;
314660484Sobrien      symbolS *list;
3147130561Sobrien      int is_code;
3148130561Sobrien      segT sec;
314960484Sobrien
315060484Sobrien      /* This is a new csect.  We need to look at the symbol class to
315160484Sobrien	 figure out whether it should go in the text section or the
315260484Sobrien	 data section.  */
315360484Sobrien      after_toc = 0;
3154130561Sobrien      is_code = 0;
315560484Sobrien      switch (symbol_get_tc (sym)->class)
315660484Sobrien	{
315760484Sobrien	case XMC_PR:
315860484Sobrien	case XMC_RO:
315960484Sobrien	case XMC_DB:
316060484Sobrien	case XMC_GL:
316160484Sobrien	case XMC_XO:
316260484Sobrien	case XMC_SV:
316360484Sobrien	case XMC_TI:
316460484Sobrien	case XMC_TB:
316560484Sobrien	  S_SET_SEGMENT (sym, text_section);
316660484Sobrien	  symbol_get_tc (sym)->subseg = ppc_text_subsegment;
316760484Sobrien	  ++ppc_text_subsegment;
316860484Sobrien	  list_ptr = &ppc_text_csects;
3169130561Sobrien	  is_code = 1;
317060484Sobrien	  break;
317160484Sobrien	case XMC_RW:
317260484Sobrien	case XMC_TC0:
317360484Sobrien	case XMC_TC:
317460484Sobrien	case XMC_DS:
317560484Sobrien	case XMC_UA:
317660484Sobrien	case XMC_BS:
317760484Sobrien	case XMC_UC:
317860484Sobrien	  if (ppc_toc_csect != NULL
317960484Sobrien	      && (symbol_get_tc (ppc_toc_csect)->subseg + 1
318060484Sobrien		  == ppc_data_subsegment))
318160484Sobrien	    after_toc = 1;
318260484Sobrien	  S_SET_SEGMENT (sym, data_section);
318360484Sobrien	  symbol_get_tc (sym)->subseg = ppc_data_subsegment;
318460484Sobrien	  ++ppc_data_subsegment;
318560484Sobrien	  list_ptr = &ppc_data_csects;
318660484Sobrien	  break;
318760484Sobrien	default:
318860484Sobrien	  abort ();
318960484Sobrien	}
319060484Sobrien
319160484Sobrien      /* We set the obstack chunk size to a small value before
319289857Sobrien	 changing subsegments, so that we don't use a lot of memory
319389857Sobrien	 space for what may be a small section.  */
319460484Sobrien      hold_chunksize = chunksize;
319560484Sobrien      chunksize = 64;
319660484Sobrien
3197130561Sobrien      sec = subseg_new (segment_name (S_GET_SEGMENT (sym)),
3198130561Sobrien			symbol_get_tc (sym)->subseg);
319960484Sobrien
320060484Sobrien      chunksize = hold_chunksize;
320160484Sobrien
320260484Sobrien      if (after_toc)
320360484Sobrien	ppc_after_toc_frag = frag_now;
320460484Sobrien
3205130561Sobrien      record_alignment (sec, align);
3206130561Sobrien      if (is_code)
3207130561Sobrien	frag_align_code (align, 0);
3208130561Sobrien      else
3209130561Sobrien	frag_align (align, 0, 0);
3210130561Sobrien
321160484Sobrien      symbol_set_frag (sym, frag_now);
321260484Sobrien      S_SET_VALUE (sym, (valueT) frag_now_fix ());
321360484Sobrien
3214130561Sobrien      symbol_get_tc (sym)->align = align;
321560484Sobrien      symbol_get_tc (sym)->output = 1;
321660484Sobrien      symbol_get_tc (sym)->within = sym;
321777298Sobrien
321860484Sobrien      for (list = *list_ptr;
321960484Sobrien	   symbol_get_tc (list)->next != (symbolS *) NULL;
322060484Sobrien	   list = symbol_get_tc (list)->next)
322160484Sobrien	;
322260484Sobrien      symbol_get_tc (list)->next = sym;
322377298Sobrien
322460484Sobrien      symbol_remove (sym, &symbol_rootP, &symbol_lastP);
322560484Sobrien      symbol_append (sym, symbol_get_tc (list)->within, &symbol_rootP,
322660484Sobrien		     &symbol_lastP);
322760484Sobrien    }
322860484Sobrien
322960484Sobrien  ppc_current_csect = sym;
323060484Sobrien}
323160484Sobrien
323260484Sobrien/* This function handles the .text and .data pseudo-ops.  These
323360484Sobrien   pseudo-ops aren't really used by XCOFF; we implement them for the
323460484Sobrien   convenience of people who aren't used to XCOFF.  */
323560484Sobrien
323660484Sobrienstatic void
3237218822Sdimppc_section (int type)
323860484Sobrien{
323960484Sobrien  const char *name;
324060484Sobrien  symbolS *sym;
324160484Sobrien
324260484Sobrien  if (type == 't')
324360484Sobrien    name = ".text[PR]";
324460484Sobrien  else if (type == 'd')
324560484Sobrien    name = ".data[RW]";
324660484Sobrien  else
324760484Sobrien    abort ();
324860484Sobrien
324960484Sobrien  sym = symbol_find_or_make (name);
325060484Sobrien
3251130561Sobrien  ppc_change_csect (sym, 2);
325260484Sobrien
325360484Sobrien  demand_empty_rest_of_line ();
325460484Sobrien}
325560484Sobrien
325660484Sobrien/* This function handles the .section pseudo-op.  This is mostly to
325760484Sobrien   give an error, since XCOFF only supports .text, .data and .bss, but
325860484Sobrien   we do permit the user to name the text or data section.  */
325960484Sobrien
326060484Sobrienstatic void
3261218822Sdimppc_named_section (int ignore ATTRIBUTE_UNUSED)
326260484Sobrien{
326360484Sobrien  char *user_name;
326460484Sobrien  const char *real_name;
326560484Sobrien  char c;
326660484Sobrien  symbolS *sym;
326760484Sobrien
326860484Sobrien  user_name = input_line_pointer;
326960484Sobrien  c = get_symbol_end ();
327060484Sobrien
327160484Sobrien  if (strcmp (user_name, ".text") == 0)
327260484Sobrien    real_name = ".text[PR]";
327360484Sobrien  else if (strcmp (user_name, ".data") == 0)
327460484Sobrien    real_name = ".data[RW]";
327560484Sobrien  else
327660484Sobrien    {
327760484Sobrien      as_bad (_("The XCOFF file format does not support arbitrary sections"));
327860484Sobrien      *input_line_pointer = c;
327960484Sobrien      ignore_rest_of_line ();
328060484Sobrien      return;
328160484Sobrien    }
328260484Sobrien
328360484Sobrien  *input_line_pointer = c;
328460484Sobrien
328560484Sobrien  sym = symbol_find_or_make (real_name);
328660484Sobrien
3287130561Sobrien  ppc_change_csect (sym, 2);
328860484Sobrien
328960484Sobrien  demand_empty_rest_of_line ();
329060484Sobrien}
329160484Sobrien
329260484Sobrien/* The .extern pseudo-op.  We create an undefined symbol.  */
329360484Sobrien
329460484Sobrienstatic void
3295218822Sdimppc_extern (int ignore ATTRIBUTE_UNUSED)
329660484Sobrien{
329760484Sobrien  char *name;
329860484Sobrien  char endc;
329960484Sobrien
330060484Sobrien  name = input_line_pointer;
330160484Sobrien  endc = get_symbol_end ();
330260484Sobrien
330360484Sobrien  (void) symbol_find_or_make (name);
330460484Sobrien
330560484Sobrien  *input_line_pointer = endc;
330660484Sobrien
330760484Sobrien  demand_empty_rest_of_line ();
330860484Sobrien}
330960484Sobrien
331060484Sobrien/* The .lglobl pseudo-op.  Keep the symbol in the symbol table.  */
331160484Sobrien
331260484Sobrienstatic void
3313218822Sdimppc_lglobl (int ignore ATTRIBUTE_UNUSED)
331460484Sobrien{
331560484Sobrien  char *name;
331660484Sobrien  char endc;
331760484Sobrien  symbolS *sym;
331860484Sobrien
331960484Sobrien  name = input_line_pointer;
332060484Sobrien  endc = get_symbol_end ();
332160484Sobrien
332260484Sobrien  sym = symbol_find_or_make (name);
332360484Sobrien
332460484Sobrien  *input_line_pointer = endc;
332560484Sobrien
332660484Sobrien  symbol_get_tc (sym)->output = 1;
332760484Sobrien
332860484Sobrien  demand_empty_rest_of_line ();
332960484Sobrien}
333060484Sobrien
333160484Sobrien/* The .rename pseudo-op.  The RS/6000 assembler can rename symbols,
333260484Sobrien   although I don't know why it bothers.  */
333360484Sobrien
333460484Sobrienstatic void
3335218822Sdimppc_rename (int ignore ATTRIBUTE_UNUSED)
333660484Sobrien{
333760484Sobrien  char *name;
333860484Sobrien  char endc;
333960484Sobrien  symbolS *sym;
334060484Sobrien  int len;
334160484Sobrien
334260484Sobrien  name = input_line_pointer;
334360484Sobrien  endc = get_symbol_end ();
334460484Sobrien
334560484Sobrien  sym = symbol_find_or_make (name);
334660484Sobrien
334760484Sobrien  *input_line_pointer = endc;
334860484Sobrien
334960484Sobrien  if (*input_line_pointer != ',')
335060484Sobrien    {
335160484Sobrien      as_bad (_("missing rename string"));
335260484Sobrien      ignore_rest_of_line ();
335360484Sobrien      return;
335460484Sobrien    }
335560484Sobrien  ++input_line_pointer;
335660484Sobrien
335760484Sobrien  symbol_get_tc (sym)->real_name = demand_copy_C_string (&len);
335860484Sobrien
335960484Sobrien  demand_empty_rest_of_line ();
336060484Sobrien}
336160484Sobrien
336260484Sobrien/* The .stabx pseudo-op.  This is similar to a normal .stabs
336360484Sobrien   pseudo-op, but slightly different.  A sample is
336460484Sobrien       .stabx "main:F-1",.main,142,0
336560484Sobrien   The first argument is the symbol name to create.  The second is the
336660484Sobrien   value, and the third is the storage class.  The fourth seems to be
336760484Sobrien   always zero, and I am assuming it is the type.  */
336860484Sobrien
336960484Sobrienstatic void
3370218822Sdimppc_stabx (int ignore ATTRIBUTE_UNUSED)
337160484Sobrien{
337260484Sobrien  char *name;
337360484Sobrien  int len;
337460484Sobrien  symbolS *sym;
337560484Sobrien  expressionS exp;
337660484Sobrien
337760484Sobrien  name = demand_copy_C_string (&len);
337860484Sobrien
337960484Sobrien  if (*input_line_pointer != ',')
338060484Sobrien    {
338160484Sobrien      as_bad (_("missing value"));
338260484Sobrien      return;
338360484Sobrien    }
338460484Sobrien  ++input_line_pointer;
338560484Sobrien
3386130561Sobrien  ppc_stab_symbol = TRUE;
338760484Sobrien  sym = symbol_make (name);
3388130561Sobrien  ppc_stab_symbol = FALSE;
338960484Sobrien
339060484Sobrien  symbol_get_tc (sym)->real_name = name;
339160484Sobrien
339260484Sobrien  (void) expression (&exp);
339360484Sobrien
339460484Sobrien  switch (exp.X_op)
339560484Sobrien    {
339660484Sobrien    case O_illegal:
339760484Sobrien    case O_absent:
339860484Sobrien    case O_big:
339960484Sobrien      as_bad (_("illegal .stabx expression; zero assumed"));
340060484Sobrien      exp.X_add_number = 0;
340160484Sobrien      /* Fall through.  */
340260484Sobrien    case O_constant:
340360484Sobrien      S_SET_VALUE (sym, (valueT) exp.X_add_number);
340460484Sobrien      symbol_set_frag (sym, &zero_address_frag);
340560484Sobrien      break;
340660484Sobrien
340760484Sobrien    case O_symbol:
340860484Sobrien      if (S_GET_SEGMENT (exp.X_add_symbol) == undefined_section)
340960484Sobrien	symbol_set_value_expression (sym, &exp);
341060484Sobrien      else
341160484Sobrien	{
341260484Sobrien	  S_SET_VALUE (sym,
341360484Sobrien		       exp.X_add_number + S_GET_VALUE (exp.X_add_symbol));
341460484Sobrien	  symbol_set_frag (sym, symbol_get_frag (exp.X_add_symbol));
341560484Sobrien	}
341660484Sobrien      break;
341760484Sobrien
341860484Sobrien    default:
341960484Sobrien      /* The value is some complex expression.  This will probably
342089857Sobrien	 fail at some later point, but this is probably the right
342189857Sobrien	 thing to do here.  */
342260484Sobrien      symbol_set_value_expression (sym, &exp);
342360484Sobrien      break;
342460484Sobrien    }
342560484Sobrien
342660484Sobrien  S_SET_SEGMENT (sym, ppc_coff_debug_section);
342760484Sobrien  symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING;
342860484Sobrien
342960484Sobrien  if (*input_line_pointer != ',')
343060484Sobrien    {
343160484Sobrien      as_bad (_("missing class"));
343260484Sobrien      return;
343360484Sobrien    }
343460484Sobrien  ++input_line_pointer;
343560484Sobrien
343660484Sobrien  S_SET_STORAGE_CLASS (sym, get_absolute_expression ());
343760484Sobrien
343860484Sobrien  if (*input_line_pointer != ',')
343960484Sobrien    {
344060484Sobrien      as_bad (_("missing type"));
344160484Sobrien      return;
344260484Sobrien    }
344360484Sobrien  ++input_line_pointer;
344460484Sobrien
344560484Sobrien  S_SET_DATA_TYPE (sym, get_absolute_expression ());
344660484Sobrien
344760484Sobrien  symbol_get_tc (sym)->output = 1;
344860484Sobrien
344978828Sobrien  if (S_GET_STORAGE_CLASS (sym) == C_STSYM) {
345089857Sobrien
345160484Sobrien    symbol_get_tc (sym)->within = ppc_current_block;
345260484Sobrien
345378828Sobrien    /* In this case :
345489857Sobrien
345578828Sobrien       .bs name
345678828Sobrien       .stabx	"z",arrays_,133,0
345778828Sobrien       .es
345889857Sobrien
345978828Sobrien       .comm arrays_,13768,3
346089857Sobrien
346178828Sobrien       resolve_symbol_value will copy the exp's "within" into sym's when the
346278828Sobrien       offset is 0.  Since this seems to be corner case problem,
346378828Sobrien       only do the correction for storage class C_STSYM.  A better solution
346489857Sobrien       would be to have the tc field updated in ppc_symbol_new_hook.  */
346589857Sobrien
346689857Sobrien    if (exp.X_op == O_symbol)
346778828Sobrien      {
346878828Sobrien	symbol_get_tc (exp.X_add_symbol)->within = ppc_current_block;
346978828Sobrien      }
347078828Sobrien  }
347178828Sobrien
347260484Sobrien  if (exp.X_op != O_symbol
347360484Sobrien      || ! S_IS_EXTERNAL (exp.X_add_symbol)
347460484Sobrien      || S_GET_SEGMENT (exp.X_add_symbol) != bss_section)
347560484Sobrien    ppc_frob_label (sym);
347660484Sobrien  else
347760484Sobrien    {
347860484Sobrien      symbol_remove (sym, &symbol_rootP, &symbol_lastP);
347960484Sobrien      symbol_append (sym, exp.X_add_symbol, &symbol_rootP, &symbol_lastP);
348060484Sobrien      if (symbol_get_tc (ppc_current_csect)->within == exp.X_add_symbol)
348160484Sobrien	symbol_get_tc (ppc_current_csect)->within = sym;
348260484Sobrien    }
348360484Sobrien
348460484Sobrien  demand_empty_rest_of_line ();
348560484Sobrien}
348660484Sobrien
348760484Sobrien/* The .function pseudo-op.  This takes several arguments.  The first
348860484Sobrien   argument seems to be the external name of the symbol.  The second
3489130561Sobrien   argument seems to be the label for the start of the function.  gcc
349060484Sobrien   uses the same name for both.  I have no idea what the third and
349160484Sobrien   fourth arguments are meant to be.  The optional fifth argument is
349260484Sobrien   an expression for the size of the function.  In COFF this symbol
349360484Sobrien   gets an aux entry like that used for a csect.  */
349460484Sobrien
349560484Sobrienstatic void
3496218822Sdimppc_function (int ignore ATTRIBUTE_UNUSED)
349760484Sobrien{
349860484Sobrien  char *name;
349960484Sobrien  char endc;
350060484Sobrien  char *s;
350160484Sobrien  symbolS *ext_sym;
350260484Sobrien  symbolS *lab_sym;
350360484Sobrien
350460484Sobrien  name = input_line_pointer;
350560484Sobrien  endc = get_symbol_end ();
350660484Sobrien
350760484Sobrien  /* Ignore any [PR] suffix.  */
350860484Sobrien  name = ppc_canonicalize_symbol_name (name);
350960484Sobrien  s = strchr (name, '[');
351060484Sobrien  if (s != (char *) NULL
351160484Sobrien      && strcmp (s + 1, "PR]") == 0)
351260484Sobrien    *s = '\0';
351360484Sobrien
351460484Sobrien  ext_sym = symbol_find_or_make (name);
351560484Sobrien
351660484Sobrien  *input_line_pointer = endc;
351760484Sobrien
351860484Sobrien  if (*input_line_pointer != ',')
351960484Sobrien    {
352060484Sobrien      as_bad (_("missing symbol name"));
352160484Sobrien      ignore_rest_of_line ();
352260484Sobrien      return;
352360484Sobrien    }
352460484Sobrien  ++input_line_pointer;
352560484Sobrien
352660484Sobrien  name = input_line_pointer;
352760484Sobrien  endc = get_symbol_end ();
352860484Sobrien
352960484Sobrien  lab_sym = symbol_find_or_make (name);
353060484Sobrien
353160484Sobrien  *input_line_pointer = endc;
353260484Sobrien
353360484Sobrien  if (ext_sym != lab_sym)
353460484Sobrien    {
353560484Sobrien      expressionS exp;
353660484Sobrien
353760484Sobrien      exp.X_op = O_symbol;
353860484Sobrien      exp.X_add_symbol = lab_sym;
353960484Sobrien      exp.X_op_symbol = NULL;
354060484Sobrien      exp.X_add_number = 0;
354160484Sobrien      exp.X_unsigned = 0;
354260484Sobrien      symbol_set_value_expression (ext_sym, &exp);
354360484Sobrien    }
354460484Sobrien
354560484Sobrien  if (symbol_get_tc (ext_sym)->class == -1)
354660484Sobrien    symbol_get_tc (ext_sym)->class = XMC_PR;
354760484Sobrien  symbol_get_tc (ext_sym)->output = 1;
354860484Sobrien
354960484Sobrien  if (*input_line_pointer == ',')
355060484Sobrien    {
355160484Sobrien      expressionS ignore;
355260484Sobrien
355360484Sobrien      /* Ignore the third argument.  */
355460484Sobrien      ++input_line_pointer;
355560484Sobrien      expression (&ignore);
355660484Sobrien      if (*input_line_pointer == ',')
355760484Sobrien	{
355860484Sobrien	  /* Ignore the fourth argument.  */
355960484Sobrien	  ++input_line_pointer;
356060484Sobrien	  expression (&ignore);
356160484Sobrien	  if (*input_line_pointer == ',')
356260484Sobrien	    {
356360484Sobrien	      /* The fifth argument is the function size.  */
356460484Sobrien	      ++input_line_pointer;
356560484Sobrien	      symbol_get_tc (ext_sym)->size = symbol_new ("L0\001",
356660484Sobrien							  absolute_section,
356760484Sobrien							  (valueT) 0,
356860484Sobrien							  &zero_address_frag);
356960484Sobrien	      pseudo_set (symbol_get_tc (ext_sym)->size);
357060484Sobrien	    }
357160484Sobrien	}
357260484Sobrien    }
357360484Sobrien
357460484Sobrien  S_SET_DATA_TYPE (ext_sym, DT_FCN << N_BTSHFT);
357560484Sobrien  SF_SET_FUNCTION (ext_sym);
357660484Sobrien  SF_SET_PROCESS (ext_sym);
357760484Sobrien  coff_add_linesym (ext_sym);
357860484Sobrien
357960484Sobrien  demand_empty_rest_of_line ();
358060484Sobrien}
358160484Sobrien
358260484Sobrien/* The .bf pseudo-op.  This is just like a COFF C_FCN symbol named
358389857Sobrien   ".bf".  If the pseudo op .bi was seen before .bf, patch the .bi sym
358489857Sobrien   with the correct line number */
3585104834Sobrien
358689857Sobrienstatic symbolS *saved_bi_sym = 0;
358760484Sobrien
358860484Sobrienstatic void
3589218822Sdimppc_bf (int ignore ATTRIBUTE_UNUSED)
359060484Sobrien{
359160484Sobrien  symbolS *sym;
359260484Sobrien
359360484Sobrien  sym = symbol_make (".bf");
359460484Sobrien  S_SET_SEGMENT (sym, text_section);
359560484Sobrien  symbol_set_frag (sym, frag_now);
359660484Sobrien  S_SET_VALUE (sym, frag_now_fix ());
359760484Sobrien  S_SET_STORAGE_CLASS (sym, C_FCN);
359860484Sobrien
359960484Sobrien  coff_line_base = get_absolute_expression ();
360060484Sobrien
360160484Sobrien  S_SET_NUMBER_AUXILIARY (sym, 1);
360260484Sobrien  SA_SET_SYM_LNNO (sym, coff_line_base);
360360484Sobrien
360489857Sobrien  /* Line number for bi.  */
3605104834Sobrien  if (saved_bi_sym)
360689857Sobrien    {
360789857Sobrien      S_SET_VALUE (saved_bi_sym, coff_n_line_nos);
360889857Sobrien      saved_bi_sym = 0;
360989857Sobrien    }
361089857Sobrien
3611104834Sobrien
361260484Sobrien  symbol_get_tc (sym)->output = 1;
361360484Sobrien
361460484Sobrien  ppc_frob_label (sym);
361560484Sobrien
361660484Sobrien  demand_empty_rest_of_line ();
361760484Sobrien}
361860484Sobrien
361960484Sobrien/* The .ef pseudo-op.  This is just like a COFF C_FCN symbol named
362060484Sobrien   ".ef", except that the line number is absolute, not relative to the
362160484Sobrien   most recent ".bf" symbol.  */
362260484Sobrien
362360484Sobrienstatic void
3624218822Sdimppc_ef (int ignore ATTRIBUTE_UNUSED)
362560484Sobrien{
362660484Sobrien  symbolS *sym;
362760484Sobrien
362860484Sobrien  sym = symbol_make (".ef");
362960484Sobrien  S_SET_SEGMENT (sym, text_section);
363060484Sobrien  symbol_set_frag (sym, frag_now);
363160484Sobrien  S_SET_VALUE (sym, frag_now_fix ());
363260484Sobrien  S_SET_STORAGE_CLASS (sym, C_FCN);
363360484Sobrien  S_SET_NUMBER_AUXILIARY (sym, 1);
363460484Sobrien  SA_SET_SYM_LNNO (sym, get_absolute_expression ());
363560484Sobrien  symbol_get_tc (sym)->output = 1;
363660484Sobrien
363760484Sobrien  ppc_frob_label (sym);
363860484Sobrien
363960484Sobrien  demand_empty_rest_of_line ();
364060484Sobrien}
364160484Sobrien
364260484Sobrien/* The .bi and .ei pseudo-ops.  These take a string argument and
364360484Sobrien   generates a C_BINCL or C_EINCL symbol, which goes at the start of
364489857Sobrien   the symbol list.  The value of .bi will be know when the next .bf
364589857Sobrien   is encountered.  */
364660484Sobrien
364760484Sobrienstatic void
3648218822Sdimppc_biei (int ei)
364960484Sobrien{
365060484Sobrien  static symbolS *last_biei;
365160484Sobrien
365260484Sobrien  char *name;
365360484Sobrien  int len;
365460484Sobrien  symbolS *sym;
365560484Sobrien  symbolS *look;
365660484Sobrien
365760484Sobrien  name = demand_copy_C_string (&len);
365860484Sobrien
365960484Sobrien  /* The value of these symbols is actually file offset.  Here we set
366060484Sobrien     the value to the index into the line number entries.  In
366160484Sobrien     ppc_frob_symbols we set the fix_line field, which will cause BFD
366260484Sobrien     to do the right thing.  */
366360484Sobrien
366460484Sobrien  sym = symbol_make (name);
366560484Sobrien  /* obj-coff.c currently only handles line numbers correctly in the
366660484Sobrien     .text section.  */
366760484Sobrien  S_SET_SEGMENT (sym, text_section);
366860484Sobrien  S_SET_VALUE (sym, coff_n_line_nos);
366960484Sobrien  symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING;
367060484Sobrien
367160484Sobrien  S_SET_STORAGE_CLASS (sym, ei ? C_EINCL : C_BINCL);
367260484Sobrien  symbol_get_tc (sym)->output = 1;
367377298Sobrien
367489857Sobrien  /* Save bi.  */
3675104834Sobrien  if (ei)
367689857Sobrien    saved_bi_sym = 0;
367789857Sobrien  else
367889857Sobrien    saved_bi_sym = sym;
367989857Sobrien
368060484Sobrien  for (look = last_biei ? last_biei : symbol_rootP;
368160484Sobrien       (look != (symbolS *) NULL
368260484Sobrien	&& (S_GET_STORAGE_CLASS (look) == C_FILE
368360484Sobrien	    || S_GET_STORAGE_CLASS (look) == C_BINCL
368460484Sobrien	    || S_GET_STORAGE_CLASS (look) == C_EINCL));
368560484Sobrien       look = symbol_next (look))
368660484Sobrien    ;
368760484Sobrien  if (look != (symbolS *) NULL)
368860484Sobrien    {
368960484Sobrien      symbol_remove (sym, &symbol_rootP, &symbol_lastP);
369060484Sobrien      symbol_insert (sym, look, &symbol_rootP, &symbol_lastP);
369160484Sobrien      last_biei = sym;
369260484Sobrien    }
369360484Sobrien
369460484Sobrien  demand_empty_rest_of_line ();
369560484Sobrien}
369660484Sobrien
369760484Sobrien/* The .bs pseudo-op.  This generates a C_BSTAT symbol named ".bs".
369860484Sobrien   There is one argument, which is a csect symbol.  The value of the
369960484Sobrien   .bs symbol is the index of this csect symbol.  */
370060484Sobrien
370160484Sobrienstatic void
3702218822Sdimppc_bs (int ignore ATTRIBUTE_UNUSED)
370360484Sobrien{
370460484Sobrien  char *name;
370560484Sobrien  char endc;
370660484Sobrien  symbolS *csect;
370760484Sobrien  symbolS *sym;
370860484Sobrien
370960484Sobrien  if (ppc_current_block != NULL)
371060484Sobrien    as_bad (_("nested .bs blocks"));
371160484Sobrien
371260484Sobrien  name = input_line_pointer;
371360484Sobrien  endc = get_symbol_end ();
371460484Sobrien
371560484Sobrien  csect = symbol_find_or_make (name);
371660484Sobrien
371760484Sobrien  *input_line_pointer = endc;
371860484Sobrien
371960484Sobrien  sym = symbol_make (".bs");
372060484Sobrien  S_SET_SEGMENT (sym, now_seg);
372160484Sobrien  S_SET_STORAGE_CLASS (sym, C_BSTAT);
372260484Sobrien  symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING;
372360484Sobrien  symbol_get_tc (sym)->output = 1;
372460484Sobrien
372560484Sobrien  symbol_get_tc (sym)->within = csect;
372660484Sobrien
372760484Sobrien  ppc_frob_label (sym);
372860484Sobrien
372960484Sobrien  ppc_current_block = sym;
373060484Sobrien
373160484Sobrien  demand_empty_rest_of_line ();
373260484Sobrien}
373360484Sobrien
373460484Sobrien/* The .es pseudo-op.  Generate a C_ESTART symbol named .es.  */
373560484Sobrien
373660484Sobrienstatic void
3737218822Sdimppc_es (int ignore ATTRIBUTE_UNUSED)
373860484Sobrien{
373960484Sobrien  symbolS *sym;
374060484Sobrien
374160484Sobrien  if (ppc_current_block == NULL)
374260484Sobrien    as_bad (_(".es without preceding .bs"));
374360484Sobrien
374460484Sobrien  sym = symbol_make (".es");
374560484Sobrien  S_SET_SEGMENT (sym, now_seg);
374660484Sobrien  S_SET_STORAGE_CLASS (sym, C_ESTAT);
374760484Sobrien  symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING;
374860484Sobrien  symbol_get_tc (sym)->output = 1;
374960484Sobrien
375060484Sobrien  ppc_frob_label (sym);
375160484Sobrien
375260484Sobrien  ppc_current_block = NULL;
375360484Sobrien
375460484Sobrien  demand_empty_rest_of_line ();
375560484Sobrien}
375660484Sobrien
375760484Sobrien/* The .bb pseudo-op.  Generate a C_BLOCK symbol named .bb, with a
375860484Sobrien   line number.  */
375960484Sobrien
376060484Sobrienstatic void
3761218822Sdimppc_bb (int ignore ATTRIBUTE_UNUSED)
376260484Sobrien{
376360484Sobrien  symbolS *sym;
376460484Sobrien
376560484Sobrien  sym = symbol_make (".bb");
376660484Sobrien  S_SET_SEGMENT (sym, text_section);
376760484Sobrien  symbol_set_frag (sym, frag_now);
376860484Sobrien  S_SET_VALUE (sym, frag_now_fix ());
376960484Sobrien  S_SET_STORAGE_CLASS (sym, C_BLOCK);
377060484Sobrien
377160484Sobrien  S_SET_NUMBER_AUXILIARY (sym, 1);
377260484Sobrien  SA_SET_SYM_LNNO (sym, get_absolute_expression ());
377360484Sobrien
377460484Sobrien  symbol_get_tc (sym)->output = 1;
377560484Sobrien
377660484Sobrien  SF_SET_PROCESS (sym);
377760484Sobrien
377860484Sobrien  ppc_frob_label (sym);
377960484Sobrien
378060484Sobrien  demand_empty_rest_of_line ();
378160484Sobrien}
378260484Sobrien
378360484Sobrien/* The .eb pseudo-op.  Generate a C_BLOCK symbol named .eb, with a
378460484Sobrien   line number.  */
378560484Sobrien
378660484Sobrienstatic void
3787218822Sdimppc_eb (int ignore ATTRIBUTE_UNUSED)
378860484Sobrien{
378960484Sobrien  symbolS *sym;
379060484Sobrien
379160484Sobrien  sym = symbol_make (".eb");
379260484Sobrien  S_SET_SEGMENT (sym, text_section);
379360484Sobrien  symbol_set_frag (sym, frag_now);
379460484Sobrien  S_SET_VALUE (sym, frag_now_fix ());
379560484Sobrien  S_SET_STORAGE_CLASS (sym, C_BLOCK);
379660484Sobrien  S_SET_NUMBER_AUXILIARY (sym, 1);
379760484Sobrien  SA_SET_SYM_LNNO (sym, get_absolute_expression ());
379860484Sobrien  symbol_get_tc (sym)->output = 1;
379960484Sobrien
380060484Sobrien  SF_SET_PROCESS (sym);
380160484Sobrien
380260484Sobrien  ppc_frob_label (sym);
380360484Sobrien
380460484Sobrien  demand_empty_rest_of_line ();
380560484Sobrien}
380660484Sobrien
380760484Sobrien/* The .bc pseudo-op.  This just creates a C_BCOMM symbol with a
380860484Sobrien   specified name.  */
380960484Sobrien
381060484Sobrienstatic void
3811218822Sdimppc_bc (int ignore ATTRIBUTE_UNUSED)
381260484Sobrien{
381360484Sobrien  char *name;
381460484Sobrien  int len;
381560484Sobrien  symbolS *sym;
381660484Sobrien
381760484Sobrien  name = demand_copy_C_string (&len);
381860484Sobrien  sym = symbol_make (name);
381960484Sobrien  S_SET_SEGMENT (sym, ppc_coff_debug_section);
382060484Sobrien  symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING;
382160484Sobrien  S_SET_STORAGE_CLASS (sym, C_BCOMM);
382260484Sobrien  S_SET_VALUE (sym, 0);
382360484Sobrien  symbol_get_tc (sym)->output = 1;
382460484Sobrien
382560484Sobrien  ppc_frob_label (sym);
382660484Sobrien
382760484Sobrien  demand_empty_rest_of_line ();
382860484Sobrien}
382960484Sobrien
383060484Sobrien/* The .ec pseudo-op.  This just creates a C_ECOMM symbol.  */
383160484Sobrien
383260484Sobrienstatic void
3833218822Sdimppc_ec (int ignore ATTRIBUTE_UNUSED)
383460484Sobrien{
383560484Sobrien  symbolS *sym;
383660484Sobrien
383760484Sobrien  sym = symbol_make (".ec");
383860484Sobrien  S_SET_SEGMENT (sym, ppc_coff_debug_section);
383960484Sobrien  symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING;
384060484Sobrien  S_SET_STORAGE_CLASS (sym, C_ECOMM);
384160484Sobrien  S_SET_VALUE (sym, 0);
384260484Sobrien  symbol_get_tc (sym)->output = 1;
384360484Sobrien
384460484Sobrien  ppc_frob_label (sym);
384560484Sobrien
384660484Sobrien  demand_empty_rest_of_line ();
384760484Sobrien}
384860484Sobrien
384960484Sobrien/* The .toc pseudo-op.  Switch to the .toc subsegment.  */
385060484Sobrien
385160484Sobrienstatic void
3852218822Sdimppc_toc (int ignore ATTRIBUTE_UNUSED)
385360484Sobrien{
385460484Sobrien  if (ppc_toc_csect != (symbolS *) NULL)
385560484Sobrien    subseg_set (data_section, symbol_get_tc (ppc_toc_csect)->subseg);
385660484Sobrien  else
385760484Sobrien    {
385860484Sobrien      subsegT subseg;
385960484Sobrien      symbolS *sym;
386060484Sobrien      symbolS *list;
386177298Sobrien
386260484Sobrien      subseg = ppc_data_subsegment;
386360484Sobrien      ++ppc_data_subsegment;
386460484Sobrien
386560484Sobrien      subseg_new (segment_name (data_section), subseg);
386660484Sobrien      ppc_toc_frag = frag_now;
386760484Sobrien
386860484Sobrien      sym = symbol_find_or_make ("TOC[TC0]");
386960484Sobrien      symbol_set_frag (sym, frag_now);
387060484Sobrien      S_SET_SEGMENT (sym, data_section);
387160484Sobrien      S_SET_VALUE (sym, (valueT) frag_now_fix ());
387260484Sobrien      symbol_get_tc (sym)->subseg = subseg;
387360484Sobrien      symbol_get_tc (sym)->output = 1;
387460484Sobrien      symbol_get_tc (sym)->within = sym;
387560484Sobrien
387660484Sobrien      ppc_toc_csect = sym;
387777298Sobrien
387860484Sobrien      for (list = ppc_data_csects;
387960484Sobrien	   symbol_get_tc (list)->next != (symbolS *) NULL;
388060484Sobrien	   list = symbol_get_tc (list)->next)
388160484Sobrien	;
388260484Sobrien      symbol_get_tc (list)->next = sym;
388360484Sobrien
388460484Sobrien      symbol_remove (sym, &symbol_rootP, &symbol_lastP);
388560484Sobrien      symbol_append (sym, symbol_get_tc (list)->within, &symbol_rootP,
388660484Sobrien		     &symbol_lastP);
388760484Sobrien    }
388860484Sobrien
388960484Sobrien  ppc_current_csect = ppc_toc_csect;
389060484Sobrien
389160484Sobrien  demand_empty_rest_of_line ();
389260484Sobrien}
389360484Sobrien
389460484Sobrien/* The AIX assembler automatically aligns the operands of a .long or
389560484Sobrien   .short pseudo-op, and we want to be compatible.  */
389660484Sobrien
389760484Sobrienstatic void
3898218822Sdimppc_xcoff_cons (int log_size)
389960484Sobrien{
390060484Sobrien  frag_align (log_size, 0, 0);
390160484Sobrien  record_alignment (now_seg, log_size);
390260484Sobrien  cons (1 << log_size);
390360484Sobrien}
390460484Sobrien
390560484Sobrienstatic void
3906218822Sdimppc_vbyte (int dummy ATTRIBUTE_UNUSED)
390760484Sobrien{
390860484Sobrien  expressionS exp;
390960484Sobrien  int byte_count;
391060484Sobrien
391160484Sobrien  (void) expression (&exp);
391260484Sobrien
391360484Sobrien  if (exp.X_op != O_constant)
391460484Sobrien    {
391560484Sobrien      as_bad (_("non-constant byte count"));
391660484Sobrien      return;
391760484Sobrien    }
391860484Sobrien
391960484Sobrien  byte_count = exp.X_add_number;
392060484Sobrien
392160484Sobrien  if (*input_line_pointer != ',')
392260484Sobrien    {
392360484Sobrien      as_bad (_("missing value"));
392460484Sobrien      return;
392560484Sobrien    }
392660484Sobrien
392760484Sobrien  ++input_line_pointer;
392860484Sobrien  cons (byte_count);
392960484Sobrien}
393060484Sobrien
393160484Sobrien#endif /* OBJ_XCOFF */
393289857Sobrien#if defined (OBJ_XCOFF) || defined (OBJ_ELF)
393360484Sobrien
393460484Sobrien/* The .tc pseudo-op.  This is used when generating either XCOFF or
393560484Sobrien   ELF.  This takes two or more arguments.
393660484Sobrien
393760484Sobrien   When generating XCOFF output, the first argument is the name to
393860484Sobrien   give to this location in the toc; this will be a symbol with class
393989857Sobrien   TC.  The rest of the arguments are N-byte values to actually put at
394060484Sobrien   this location in the TOC; often there is just one more argument, a
3941130561Sobrien   relocatable symbol reference.  The size of the value to store
394289857Sobrien   depends on target word size.  A 32-bit target uses 4-byte values, a
394389857Sobrien   64-bit target uses 8-byte values.
394460484Sobrien
394560484Sobrien   When not generating XCOFF output, the arguments are the same, but
394660484Sobrien   the first argument is simply ignored.  */
394760484Sobrien
394860484Sobrienstatic void
3949218822Sdimppc_tc (int ignore ATTRIBUTE_UNUSED)
395060484Sobrien{
395160484Sobrien#ifdef OBJ_XCOFF
395260484Sobrien
395360484Sobrien  /* Define the TOC symbol name.  */
395460484Sobrien  {
395560484Sobrien    char *name;
395660484Sobrien    char endc;
395760484Sobrien    symbolS *sym;
395860484Sobrien
395960484Sobrien    if (ppc_toc_csect == (symbolS *) NULL
396060484Sobrien	|| ppc_toc_csect != ppc_current_csect)
396160484Sobrien      {
396260484Sobrien	as_bad (_(".tc not in .toc section"));
396360484Sobrien	ignore_rest_of_line ();
396460484Sobrien	return;
396560484Sobrien      }
396660484Sobrien
396760484Sobrien    name = input_line_pointer;
396860484Sobrien    endc = get_symbol_end ();
396960484Sobrien
397060484Sobrien    sym = symbol_find_or_make (name);
397160484Sobrien
397260484Sobrien    *input_line_pointer = endc;
397360484Sobrien
397460484Sobrien    if (S_IS_DEFINED (sym))
397560484Sobrien      {
397660484Sobrien	symbolS *label;
397760484Sobrien
397860484Sobrien	label = symbol_get_tc (ppc_current_csect)->within;
397960484Sobrien	if (symbol_get_tc (label)->class != XMC_TC0)
398060484Sobrien	  {
398160484Sobrien	    as_bad (_(".tc with no label"));
398260484Sobrien	    ignore_rest_of_line ();
398360484Sobrien	    return;
398460484Sobrien	  }
398560484Sobrien
398660484Sobrien	S_SET_SEGMENT (label, S_GET_SEGMENT (sym));
398760484Sobrien	symbol_set_frag (label, symbol_get_frag (sym));
398860484Sobrien	S_SET_VALUE (label, S_GET_VALUE (sym));
398960484Sobrien
399060484Sobrien	while (! is_end_of_line[(unsigned char) *input_line_pointer])
399160484Sobrien	  ++input_line_pointer;
399260484Sobrien
399360484Sobrien	return;
399460484Sobrien      }
399560484Sobrien
399660484Sobrien    S_SET_SEGMENT (sym, now_seg);
399760484Sobrien    symbol_set_frag (sym, frag_now);
399860484Sobrien    S_SET_VALUE (sym, (valueT) frag_now_fix ());
399960484Sobrien    symbol_get_tc (sym)->class = XMC_TC;
400060484Sobrien    symbol_get_tc (sym)->output = 1;
400160484Sobrien
400260484Sobrien    ppc_frob_label (sym);
400360484Sobrien  }
400460484Sobrien
400589857Sobrien#endif /* OBJ_XCOFF */
400689857Sobrien#ifdef OBJ_ELF
400789857Sobrien  int align;
400860484Sobrien
400960484Sobrien  /* Skip the TOC symbol name.  */
401060484Sobrien  while (is_part_of_name (*input_line_pointer)
401160484Sobrien	 || *input_line_pointer == '['
401260484Sobrien	 || *input_line_pointer == ']'
401360484Sobrien	 || *input_line_pointer == '{'
401460484Sobrien	 || *input_line_pointer == '}')
401560484Sobrien    ++input_line_pointer;
401660484Sobrien
401789857Sobrien  /* Align to a four/eight byte boundary.  */
4018104834Sobrien  align = ppc_obj64 ? 3 : 2;
401989857Sobrien  frag_align (align, 0, 0);
402089857Sobrien  record_alignment (now_seg, align);
402189857Sobrien#endif /* OBJ_ELF */
402260484Sobrien
402360484Sobrien  if (*input_line_pointer != ',')
402460484Sobrien    demand_empty_rest_of_line ();
402560484Sobrien  else
402660484Sobrien    {
402760484Sobrien      ++input_line_pointer;
4028104834Sobrien      cons (ppc_obj64 ? 8 : 4);
402960484Sobrien    }
403060484Sobrien}
403189857Sobrien
403289857Sobrien/* Pseudo-op .machine.  */
403389857Sobrien
403489857Sobrienstatic void
4035218822Sdimppc_machine (int ignore ATTRIBUTE_UNUSED)
403689857Sobrien{
4037130561Sobrien  char *cpu_string;
4038130561Sobrien#define MAX_HISTORY 100
4039130561Sobrien  static unsigned long *cpu_history;
4040130561Sobrien  static int curr_hist;
4041130561Sobrien
4042130561Sobrien  SKIP_WHITESPACE ();
4043130561Sobrien
4044130561Sobrien  if (*input_line_pointer == '"')
4045130561Sobrien    {
4046130561Sobrien      int len;
4047130561Sobrien      cpu_string = demand_copy_C_string (&len);
4048130561Sobrien    }
4049130561Sobrien  else
4050130561Sobrien    {
4051130561Sobrien      char c;
4052130561Sobrien      cpu_string = input_line_pointer;
4053130561Sobrien      c = get_symbol_end ();
4054130561Sobrien      cpu_string = xstrdup (cpu_string);
4055130561Sobrien      *input_line_pointer = c;
4056130561Sobrien    }
4057130561Sobrien
4058130561Sobrien  if (cpu_string != NULL)
4059130561Sobrien    {
4060130561Sobrien      unsigned long old_cpu = ppc_cpu;
4061130561Sobrien      char *p;
4062130561Sobrien
4063130561Sobrien      for (p = cpu_string; *p != 0; p++)
4064130561Sobrien	*p = TOLOWER (*p);
4065130561Sobrien
4066130561Sobrien      if (strcmp (cpu_string, "push") == 0)
4067130561Sobrien	{
4068130561Sobrien	  if (cpu_history == NULL)
4069130561Sobrien	    cpu_history = xmalloc (MAX_HISTORY * sizeof (*cpu_history));
4070130561Sobrien
4071130561Sobrien	  if (curr_hist >= MAX_HISTORY)
4072130561Sobrien	    as_bad (_(".machine stack overflow"));
4073130561Sobrien	  else
4074130561Sobrien	    cpu_history[curr_hist++] = ppc_cpu;
4075130561Sobrien	}
4076130561Sobrien      else if (strcmp (cpu_string, "pop") == 0)
4077130561Sobrien	{
4078130561Sobrien	  if (curr_hist <= 0)
4079130561Sobrien	    as_bad (_(".machine stack underflow"));
4080130561Sobrien	  else
4081130561Sobrien	    ppc_cpu = cpu_history[--curr_hist];
4082130561Sobrien	}
4083130561Sobrien      else if (parse_cpu (cpu_string))
4084130561Sobrien	;
4085130561Sobrien      else
4086130561Sobrien	as_bad (_("invalid machine `%s'"), cpu_string);
4087130561Sobrien
4088130561Sobrien      if (ppc_cpu != old_cpu)
4089130561Sobrien	ppc_setup_opcodes ();
4090130561Sobrien    }
4091130561Sobrien
4092130561Sobrien  demand_empty_rest_of_line ();
409389857Sobrien}
409489857Sobrien
409589857Sobrien/* See whether a symbol is in the TOC section.  */
409689857Sobrien
409789857Sobrienstatic int
4098218822Sdimppc_is_toc_sym (symbolS *sym)
409989857Sobrien{
410089857Sobrien#ifdef OBJ_XCOFF
410189857Sobrien  return symbol_get_tc (sym)->class == XMC_TC;
410289857Sobrien#endif
410389857Sobrien#ifdef OBJ_ELF
410489857Sobrien  const char *sname = segment_name (S_GET_SEGMENT (sym));
4105104834Sobrien  if (ppc_obj64)
410689857Sobrien    return strcmp (sname, ".toc") == 0;
410789857Sobrien  else
410889857Sobrien    return strcmp (sname, ".got") == 0;
410989857Sobrien#endif
411089857Sobrien}
411189857Sobrien#endif /* defined (OBJ_XCOFF) || defined (OBJ_ELF) */
411260484Sobrien
411360484Sobrien#ifdef TE_PE
411460484Sobrien
411589857Sobrien/* Pseudo-ops specific to the Windows NT PowerPC PE (coff) format.  */
411660484Sobrien
411760484Sobrien/* Set the current section.  */
411860484Sobrienstatic void
4119218822Sdimppc_set_current_section (segT new)
412060484Sobrien{
412160484Sobrien  ppc_previous_section = ppc_current_section;
412260484Sobrien  ppc_current_section = new;
412360484Sobrien}
412460484Sobrien
412560484Sobrien/* pseudo-op: .previous
412660484Sobrien   behaviour: toggles the current section with the previous section.
412760484Sobrien   errors:    None
412889857Sobrien   warnings:  "No previous section"  */
412989857Sobrien
413060484Sobrienstatic void
4131218822Sdimppc_previous (int ignore ATTRIBUTE_UNUSED)
413260484Sobrien{
413360484Sobrien  symbolS *tmp;
413460484Sobrien
413577298Sobrien  if (ppc_previous_section == NULL)
413660484Sobrien    {
413789857Sobrien      as_warn (_("No previous section to return to. Directive ignored."));
413860484Sobrien      return;
413960484Sobrien    }
414060484Sobrien
414189857Sobrien  subseg_set (ppc_previous_section, 0);
414260484Sobrien
414389857Sobrien  ppc_set_current_section (ppc_previous_section);
414460484Sobrien}
414560484Sobrien
414660484Sobrien/* pseudo-op: .pdata
414760484Sobrien   behaviour: predefined read only data section
4148130561Sobrien	      double word aligned
414960484Sobrien   errors:    None
415060484Sobrien   warnings:  None
415160484Sobrien   initial:   .section .pdata "adr3"
4152130561Sobrien	      a - don't know -- maybe a misprint
415360484Sobrien	      d - initialized data
415460484Sobrien	      r - readable
415560484Sobrien	      3 - double word aligned (that would be 4 byte boundary)
415660484Sobrien
415760484Sobrien   commentary:
415860484Sobrien   Tag index tables (also known as the function table) for exception
415989857Sobrien   handling, debugging, etc.  */
416060484Sobrien
416160484Sobrienstatic void
4162218822Sdimppc_pdata (int ignore ATTRIBUTE_UNUSED)
416360484Sobrien{
416477298Sobrien  if (pdata_section == 0)
416560484Sobrien    {
416660484Sobrien      pdata_section = subseg_new (".pdata", 0);
416777298Sobrien
416860484Sobrien      bfd_set_section_flags (stdoutput, pdata_section,
416960484Sobrien			     (SEC_ALLOC | SEC_LOAD | SEC_RELOC
417060484Sobrien			      | SEC_READONLY | SEC_DATA ));
417177298Sobrien
417260484Sobrien      bfd_set_section_alignment (stdoutput, pdata_section, 2);
417360484Sobrien    }
417460484Sobrien  else
417560484Sobrien    {
417689857Sobrien      pdata_section = subseg_new (".pdata", 0);
417760484Sobrien    }
417889857Sobrien  ppc_set_current_section (pdata_section);
417960484Sobrien}
418060484Sobrien
418160484Sobrien/* pseudo-op: .ydata
418260484Sobrien   behaviour: predefined read only data section
4183130561Sobrien	      double word aligned
418460484Sobrien   errors:    None
418560484Sobrien   warnings:  None
418660484Sobrien   initial:   .section .ydata "drw3"
4187130561Sobrien	      a - don't know -- maybe a misprint
418860484Sobrien	      d - initialized data
418960484Sobrien	      r - readable
419060484Sobrien	      3 - double word aligned (that would be 4 byte boundary)
419160484Sobrien   commentary:
419260484Sobrien   Tag tables (also known as the scope table) for exception handling,
419389857Sobrien   debugging, etc.  */
419489857Sobrien
419560484Sobrienstatic void
4196218822Sdimppc_ydata (int ignore ATTRIBUTE_UNUSED)
419760484Sobrien{
419877298Sobrien  if (ydata_section == 0)
419960484Sobrien    {
420060484Sobrien      ydata_section = subseg_new (".ydata", 0);
420160484Sobrien      bfd_set_section_flags (stdoutput, ydata_section,
420289857Sobrien			     (SEC_ALLOC | SEC_LOAD | SEC_RELOC
420389857Sobrien			      | SEC_READONLY | SEC_DATA ));
420460484Sobrien
420560484Sobrien      bfd_set_section_alignment (stdoutput, ydata_section, 3);
420660484Sobrien    }
420760484Sobrien  else
420860484Sobrien    {
420960484Sobrien      ydata_section = subseg_new (".ydata", 0);
421060484Sobrien    }
421189857Sobrien  ppc_set_current_section (ydata_section);
421260484Sobrien}
421360484Sobrien
421460484Sobrien/* pseudo-op: .reldata
421560484Sobrien   behaviour: predefined read write data section
4216130561Sobrien	      double word aligned (4-byte)
421760484Sobrien	      FIXME: relocation is applied to it
421860484Sobrien	      FIXME: what's the difference between this and .data?
421960484Sobrien   errors:    None
422060484Sobrien   warnings:  None
422160484Sobrien   initial:   .section .reldata "drw3"
422260484Sobrien	      d - initialized data
422360484Sobrien	      r - readable
422460484Sobrien	      w - writeable
422560484Sobrien	      3 - double word aligned (that would be 8 byte boundary)
422660484Sobrien
422760484Sobrien   commentary:
422860484Sobrien   Like .data, but intended to hold data subject to relocation, such as
422989857Sobrien   function descriptors, etc.  */
423089857Sobrien
423160484Sobrienstatic void
4232218822Sdimppc_reldata (int ignore ATTRIBUTE_UNUSED)
423360484Sobrien{
423460484Sobrien  if (reldata_section == 0)
423560484Sobrien    {
423660484Sobrien      reldata_section = subseg_new (".reldata", 0);
423760484Sobrien
423860484Sobrien      bfd_set_section_flags (stdoutput, reldata_section,
423989857Sobrien			     (SEC_ALLOC | SEC_LOAD | SEC_RELOC
424089857Sobrien			      | SEC_DATA));
424160484Sobrien
424260484Sobrien      bfd_set_section_alignment (stdoutput, reldata_section, 2);
424360484Sobrien    }
424460484Sobrien  else
424560484Sobrien    {
424660484Sobrien      reldata_section = subseg_new (".reldata", 0);
424760484Sobrien    }
424889857Sobrien  ppc_set_current_section (reldata_section);
424960484Sobrien}
425060484Sobrien
425160484Sobrien/* pseudo-op: .rdata
425260484Sobrien   behaviour: predefined read only data section
4253130561Sobrien	      double word aligned
425460484Sobrien   errors:    None
425560484Sobrien   warnings:  None
425660484Sobrien   initial:   .section .rdata "dr3"
425760484Sobrien	      d - initialized data
425860484Sobrien	      r - readable
425989857Sobrien	      3 - double word aligned (that would be 4 byte boundary)  */
426089857Sobrien
426160484Sobrienstatic void
4262218822Sdimppc_rdata (int ignore ATTRIBUTE_UNUSED)
426360484Sobrien{
426460484Sobrien  if (rdata_section == 0)
426560484Sobrien    {
426660484Sobrien      rdata_section = subseg_new (".rdata", 0);
426760484Sobrien      bfd_set_section_flags (stdoutput, rdata_section,
426860484Sobrien			     (SEC_ALLOC | SEC_LOAD | SEC_RELOC
426960484Sobrien			      | SEC_READONLY | SEC_DATA ));
427060484Sobrien
427160484Sobrien      bfd_set_section_alignment (stdoutput, rdata_section, 2);
427260484Sobrien    }
427360484Sobrien  else
427460484Sobrien    {
427560484Sobrien      rdata_section = subseg_new (".rdata", 0);
427660484Sobrien    }
427789857Sobrien  ppc_set_current_section (rdata_section);
427860484Sobrien}
427960484Sobrien
428060484Sobrien/* pseudo-op: .ualong
428177298Sobrien   behaviour: much like .int, with the exception that no alignment is
4282130561Sobrien	      performed.
428360484Sobrien	      FIXME: test the alignment statement
428460484Sobrien   errors:    None
428589857Sobrien   warnings:  None  */
428689857Sobrien
428760484Sobrienstatic void
4288218822Sdimppc_ualong (int ignore ATTRIBUTE_UNUSED)
428960484Sobrien{
429089857Sobrien  /* Try for long.  */
429189857Sobrien  cons (4);
429260484Sobrien}
429360484Sobrien
429460484Sobrien/* pseudo-op: .znop  <symbol name>
429560484Sobrien   behaviour: Issue a nop instruction
4296130561Sobrien	      Issue a IMAGE_REL_PPC_IFGLUE relocation against it, using
429760484Sobrien	      the supplied symbol name.
429860484Sobrien   errors:    None
429989857Sobrien   warnings:  Missing symbol name  */
430089857Sobrien
430160484Sobrienstatic void
4302218822Sdimppc_znop (int ignore ATTRIBUTE_UNUSED)
430360484Sobrien{
430460484Sobrien  unsigned long insn;
430560484Sobrien  const struct powerpc_opcode *opcode;
430660484Sobrien  expressionS ex;
430760484Sobrien  char *f;
430860484Sobrien  symbolS *sym;
430960484Sobrien  char *symbol_name;
431060484Sobrien  char c;
431160484Sobrien  char *name;
431260484Sobrien  unsigned int exp;
431360484Sobrien  flagword flags;
431460484Sobrien  asection *sec;
431560484Sobrien
431689857Sobrien  /* Strip out the symbol name.  */
431760484Sobrien  symbol_name = input_line_pointer;
431860484Sobrien  c = get_symbol_end ();
431960484Sobrien
432060484Sobrien  name = xmalloc (input_line_pointer - symbol_name + 1);
432160484Sobrien  strcpy (name, symbol_name);
432260484Sobrien
432360484Sobrien  sym = symbol_find_or_make (name);
432460484Sobrien
432560484Sobrien  *input_line_pointer = c;
432660484Sobrien
432760484Sobrien  SKIP_WHITESPACE ();
432860484Sobrien
432960484Sobrien  /* Look up the opcode in the hash table.  */
433060484Sobrien  opcode = (const struct powerpc_opcode *) hash_find (ppc_hash, "nop");
433160484Sobrien
433289857Sobrien  /* Stick in the nop.  */
433360484Sobrien  insn = opcode->opcode;
433460484Sobrien
433560484Sobrien  /* Write out the instruction.  */
433660484Sobrien  f = frag_more (4);
433760484Sobrien  md_number_to_chars (f, insn, 4);
433860484Sobrien  fix_new (frag_now,
433960484Sobrien	   f - frag_now->fr_literal,
434060484Sobrien	   4,
434160484Sobrien	   sym,
434260484Sobrien	   0,
434360484Sobrien	   0,
434460484Sobrien	   BFD_RELOC_16_GOT_PCREL);
434560484Sobrien
434660484Sobrien}
434760484Sobrien
434877298Sobrien/* pseudo-op:
434977298Sobrien   behaviour:
435077298Sobrien   errors:
435189857Sobrien   warnings:  */
435289857Sobrien
435360484Sobrienstatic void
4354218822Sdimppc_pe_comm (int lcomm)
435560484Sobrien{
4356218822Sdim  char *name;
4357218822Sdim  char c;
4358218822Sdim  char *p;
435960484Sobrien  offsetT temp;
4360218822Sdim  symbolS *symbolP;
436160484Sobrien  offsetT align;
436260484Sobrien
436360484Sobrien  name = input_line_pointer;
436460484Sobrien  c = get_symbol_end ();
436560484Sobrien
436689857Sobrien  /* just after name is now '\0'.  */
436760484Sobrien  p = input_line_pointer;
436860484Sobrien  *p = c;
436960484Sobrien  SKIP_WHITESPACE ();
437060484Sobrien  if (*input_line_pointer != ',')
437160484Sobrien    {
437260484Sobrien      as_bad (_("Expected comma after symbol-name: rest of line ignored."));
437360484Sobrien      ignore_rest_of_line ();
437460484Sobrien      return;
437560484Sobrien    }
437660484Sobrien
437760484Sobrien  input_line_pointer++;		/* skip ',' */
437860484Sobrien  if ((temp = get_absolute_expression ()) < 0)
437960484Sobrien    {
438060484Sobrien      as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) temp);
438160484Sobrien      ignore_rest_of_line ();
438260484Sobrien      return;
438360484Sobrien    }
438460484Sobrien
438560484Sobrien  if (! lcomm)
438660484Sobrien    {
438760484Sobrien      /* The third argument to .comm is the alignment.  */
438860484Sobrien      if (*input_line_pointer != ',')
438960484Sobrien	align = 3;
439060484Sobrien      else
439160484Sobrien	{
439260484Sobrien	  ++input_line_pointer;
439360484Sobrien	  align = get_absolute_expression ();
439460484Sobrien	  if (align <= 0)
439560484Sobrien	    {
439660484Sobrien	      as_warn (_("ignoring bad alignment"));
439760484Sobrien	      align = 3;
439860484Sobrien	    }
439960484Sobrien	}
440060484Sobrien    }
440160484Sobrien
440260484Sobrien  *p = 0;
440360484Sobrien  symbolP = symbol_find_or_make (name);
440460484Sobrien
440560484Sobrien  *p = c;
440660484Sobrien  if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP))
440760484Sobrien    {
440860484Sobrien      as_bad (_("Ignoring attempt to re-define symbol `%s'."),
440960484Sobrien	      S_GET_NAME (symbolP));
441060484Sobrien      ignore_rest_of_line ();
441160484Sobrien      return;
441260484Sobrien    }
441360484Sobrien
441460484Sobrien  if (S_GET_VALUE (symbolP))
441560484Sobrien    {
441660484Sobrien      if (S_GET_VALUE (symbolP) != (valueT) temp)
441760484Sobrien	as_bad (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."),
441860484Sobrien		S_GET_NAME (symbolP),
441960484Sobrien		(long) S_GET_VALUE (symbolP),
442060484Sobrien		(long) temp);
442160484Sobrien    }
442260484Sobrien  else
442360484Sobrien    {
442460484Sobrien      S_SET_VALUE (symbolP, (valueT) temp);
442560484Sobrien      S_SET_EXTERNAL (symbolP);
4426218822Sdim      S_SET_SEGMENT (symbolP, bfd_com_section_ptr);
442760484Sobrien    }
442860484Sobrien
442960484Sobrien  demand_empty_rest_of_line ();
443060484Sobrien}
443160484Sobrien
443260484Sobrien/*
443360484Sobrien * implement the .section pseudo op:
443460484Sobrien *	.section name {, "flags"}
443560484Sobrien *                ^         ^
443660484Sobrien *                |         +--- optional flags: 'b' for bss
443760484Sobrien *                |                              'i' for info
443860484Sobrien *                +-- section name               'l' for lib
443960484Sobrien *                                               'n' for noload
444060484Sobrien *                                               'o' for over
444160484Sobrien *                                               'w' for data
444260484Sobrien *						 'd' (apparently m88k for data)
444360484Sobrien *                                               'x' for text
444460484Sobrien * But if the argument is not a quoted string, treat it as a
444560484Sobrien * subsegment number.
444660484Sobrien *
444760484Sobrien * FIXME: this is a copy of the section processing from obj-coff.c, with
444860484Sobrien * additions/changes for the moto-pas assembler support. There are three
444960484Sobrien * categories:
445060484Sobrien *
445177298Sobrien * FIXME: I just noticed this. This doesn't work at all really. It it
445260484Sobrien *        setting bits that bfd probably neither understands or uses. The
445360484Sobrien *        correct approach (?) will have to incorporate extra fields attached
445460484Sobrien *        to the section to hold the system specific stuff. (krk)
445560484Sobrien *
445660484Sobrien * Section Contents:
445760484Sobrien * 'a' - unknown - referred to in documentation, but no definition supplied
445860484Sobrien * 'c' - section has code
445960484Sobrien * 'd' - section has initialized data
446060484Sobrien * 'u' - section has uninitialized data
446160484Sobrien * 'i' - section contains directives (info)
446260484Sobrien * 'n' - section can be discarded
446360484Sobrien * 'R' - remove section at link time
446460484Sobrien *
446560484Sobrien * Section Protection:
446660484Sobrien * 'r' - section is readable
446760484Sobrien * 'w' - section is writeable
446860484Sobrien * 'x' - section is executable
446960484Sobrien * 's' - section is sharable
447060484Sobrien *
447160484Sobrien * Section Alignment:
447260484Sobrien * '0' - align to byte boundary
447360484Sobrien * '1' - align to halfword undary
447460484Sobrien * '2' - align to word boundary
447560484Sobrien * '3' - align to doubleword boundary
447660484Sobrien * '4' - align to quadword boundary
447760484Sobrien * '5' - align to 32 byte boundary
447860484Sobrien * '6' - align to 64 byte boundary
447960484Sobrien *
448060484Sobrien */
448160484Sobrien
448260484Sobrienvoid
4483218822Sdimppc_pe_section (int ignore ATTRIBUTE_UNUSED)
448460484Sobrien{
448589857Sobrien  /* Strip out the section name.  */
448660484Sobrien  char *section_name;
448760484Sobrien  char c;
448860484Sobrien  char *name;
448960484Sobrien  unsigned int exp;
449060484Sobrien  flagword flags;
449160484Sobrien  segT sec;
449260484Sobrien  int align;
449360484Sobrien
449460484Sobrien  section_name = input_line_pointer;
449560484Sobrien  c = get_symbol_end ();
449660484Sobrien
449760484Sobrien  name = xmalloc (input_line_pointer - section_name + 1);
449860484Sobrien  strcpy (name, section_name);
449960484Sobrien
450060484Sobrien  *input_line_pointer = c;
450160484Sobrien
450260484Sobrien  SKIP_WHITESPACE ();
450360484Sobrien
450460484Sobrien  exp = 0;
450560484Sobrien  flags = SEC_NO_FLAGS;
450660484Sobrien
450760484Sobrien  if (strcmp (name, ".idata$2") == 0)
450860484Sobrien    {
450960484Sobrien      align = 0;
451060484Sobrien    }
451160484Sobrien  else if (strcmp (name, ".idata$3") == 0)
451260484Sobrien    {
451360484Sobrien      align = 0;
451460484Sobrien    }
451560484Sobrien  else if (strcmp (name, ".idata$4") == 0)
451660484Sobrien    {
451760484Sobrien      align = 2;
451860484Sobrien    }
451960484Sobrien  else if (strcmp (name, ".idata$5") == 0)
452060484Sobrien    {
452160484Sobrien      align = 2;
452260484Sobrien    }
452360484Sobrien  else if (strcmp (name, ".idata$6") == 0)
452460484Sobrien    {
452560484Sobrien      align = 1;
452660484Sobrien    }
452760484Sobrien  else
452889857Sobrien    /* Default alignment to 16 byte boundary.  */
452989857Sobrien    align = 4;
453060484Sobrien
453160484Sobrien  if (*input_line_pointer == ',')
453260484Sobrien    {
453360484Sobrien      ++input_line_pointer;
453460484Sobrien      SKIP_WHITESPACE ();
453560484Sobrien      if (*input_line_pointer != '"')
453660484Sobrien	exp = get_absolute_expression ();
453760484Sobrien      else
453860484Sobrien	{
453960484Sobrien	  ++input_line_pointer;
454060484Sobrien	  while (*input_line_pointer != '"'
454160484Sobrien		 && ! is_end_of_line[(unsigned char) *input_line_pointer])
454260484Sobrien	    {
454360484Sobrien	      switch (*input_line_pointer)
454460484Sobrien		{
454560484Sobrien		  /* Section Contents */
454660484Sobrien		case 'a': /* unknown */
454760484Sobrien		  as_bad (_("Unsupported section attribute -- 'a'"));
454860484Sobrien		  break;
454960484Sobrien		case 'c': /* code section */
455077298Sobrien		  flags |= SEC_CODE;
455160484Sobrien		  break;
455260484Sobrien		case 'd': /* section has initialized data */
455360484Sobrien		  flags |= SEC_DATA;
455460484Sobrien		  break;
455560484Sobrien		case 'u': /* section has uninitialized data */
455660484Sobrien		  /* FIXME: This is IMAGE_SCN_CNT_UNINITIALIZED_DATA
455760484Sobrien		     in winnt.h */
455860484Sobrien		  flags |= SEC_ROM;
455960484Sobrien		  break;
456060484Sobrien		case 'i': /* section contains directives (info) */
456160484Sobrien		  /* FIXME: This is IMAGE_SCN_LNK_INFO
456260484Sobrien		     in winnt.h */
456360484Sobrien		  flags |= SEC_HAS_CONTENTS;
456460484Sobrien		  break;
456560484Sobrien		case 'n': /* section can be discarded */
456677298Sobrien		  flags &=~ SEC_LOAD;
456760484Sobrien		  break;
456860484Sobrien		case 'R': /* Remove section at link time */
456960484Sobrien		  flags |= SEC_NEVER_LOAD;
457060484Sobrien		  break;
4571218822Sdim#if IFLICT_BRAIN_DAMAGE
457260484Sobrien		  /* Section Protection */
457360484Sobrien		case 'r': /* section is readable */
457460484Sobrien		  flags |= IMAGE_SCN_MEM_READ;
457560484Sobrien		  break;
457660484Sobrien		case 'w': /* section is writeable */
457760484Sobrien		  flags |= IMAGE_SCN_MEM_WRITE;
457860484Sobrien		  break;
457960484Sobrien		case 'x': /* section is executable */
458060484Sobrien		  flags |= IMAGE_SCN_MEM_EXECUTE;
458160484Sobrien		  break;
458260484Sobrien		case 's': /* section is sharable */
458360484Sobrien		  flags |= IMAGE_SCN_MEM_SHARED;
458460484Sobrien		  break;
458560484Sobrien
458660484Sobrien		  /* Section Alignment */
458760484Sobrien		case '0': /* align to byte boundary */
458860484Sobrien		  flags |= IMAGE_SCN_ALIGN_1BYTES;
458960484Sobrien		  align = 0;
459060484Sobrien		  break;
459160484Sobrien		case '1':  /* align to halfword boundary */
459260484Sobrien		  flags |= IMAGE_SCN_ALIGN_2BYTES;
459360484Sobrien		  align = 1;
459460484Sobrien		  break;
459560484Sobrien		case '2':  /* align to word boundary */
459660484Sobrien		  flags |= IMAGE_SCN_ALIGN_4BYTES;
459760484Sobrien		  align = 2;
459860484Sobrien		  break;
459960484Sobrien		case '3':  /* align to doubleword boundary */
460060484Sobrien		  flags |= IMAGE_SCN_ALIGN_8BYTES;
460160484Sobrien		  align = 3;
460260484Sobrien		  break;
460360484Sobrien		case '4':  /* align to quadword boundary */
460460484Sobrien		  flags |= IMAGE_SCN_ALIGN_16BYTES;
460560484Sobrien		  align = 4;
460660484Sobrien		  break;
460760484Sobrien		case '5':  /* align to 32 byte boundary */
460860484Sobrien		  flags |= IMAGE_SCN_ALIGN_32BYTES;
460960484Sobrien		  align = 5;
461060484Sobrien		  break;
461160484Sobrien		case '6':  /* align to 64 byte boundary */
461260484Sobrien		  flags |= IMAGE_SCN_ALIGN_64BYTES;
461360484Sobrien		  align = 6;
461460484Sobrien		  break;
4615218822Sdim#endif
461660484Sobrien		default:
461789857Sobrien		  as_bad (_("unknown section attribute '%c'"),
461889857Sobrien			  *input_line_pointer);
461960484Sobrien		  break;
462060484Sobrien		}
462160484Sobrien	      ++input_line_pointer;
462260484Sobrien	    }
462360484Sobrien	  if (*input_line_pointer == '"')
462460484Sobrien	    ++input_line_pointer;
462560484Sobrien	}
462660484Sobrien    }
462760484Sobrien
462860484Sobrien  sec = subseg_new (name, (subsegT) exp);
462960484Sobrien
463089857Sobrien  ppc_set_current_section (sec);
463160484Sobrien
463260484Sobrien  if (flags != SEC_NO_FLAGS)
463360484Sobrien    {
463460484Sobrien      if (! bfd_set_section_flags (stdoutput, sec, flags))
463560484Sobrien	as_bad (_("error setting flags for \"%s\": %s"),
463660484Sobrien		bfd_section_name (stdoutput, sec),
463760484Sobrien		bfd_errmsg (bfd_get_error ()));
463860484Sobrien    }
463960484Sobrien
464089857Sobrien  bfd_set_section_alignment (stdoutput, sec, align);
464160484Sobrien}
464260484Sobrien
464360484Sobrienstatic void
4644218822Sdimppc_pe_function (int ignore ATTRIBUTE_UNUSED)
464560484Sobrien{
464660484Sobrien  char *name;
464760484Sobrien  char endc;
464860484Sobrien  symbolS *ext_sym;
464960484Sobrien
465060484Sobrien  name = input_line_pointer;
465160484Sobrien  endc = get_symbol_end ();
465260484Sobrien
465360484Sobrien  ext_sym = symbol_find_or_make (name);
465460484Sobrien
465560484Sobrien  *input_line_pointer = endc;
465660484Sobrien
465760484Sobrien  S_SET_DATA_TYPE (ext_sym, DT_FCN << N_BTSHFT);
465860484Sobrien  SF_SET_FUNCTION (ext_sym);
465960484Sobrien  SF_SET_PROCESS (ext_sym);
466060484Sobrien  coff_add_linesym (ext_sym);
466160484Sobrien
466260484Sobrien  demand_empty_rest_of_line ();
466360484Sobrien}
466460484Sobrien
466560484Sobrienstatic void
4666218822Sdimppc_pe_tocd (int ignore ATTRIBUTE_UNUSED)
466760484Sobrien{
466860484Sobrien  if (tocdata_section == 0)
466960484Sobrien    {
467060484Sobrien      tocdata_section = subseg_new (".tocd", 0);
467189857Sobrien      /* FIXME: section flags won't work.  */
467260484Sobrien      bfd_set_section_flags (stdoutput, tocdata_section,
467360484Sobrien			     (SEC_ALLOC | SEC_LOAD | SEC_RELOC
467489857Sobrien			      | SEC_READONLY | SEC_DATA));
467560484Sobrien
467660484Sobrien      bfd_set_section_alignment (stdoutput, tocdata_section, 2);
467760484Sobrien    }
467860484Sobrien  else
467960484Sobrien    {
468060484Sobrien      rdata_section = subseg_new (".tocd", 0);
468160484Sobrien    }
468260484Sobrien
468389857Sobrien  ppc_set_current_section (tocdata_section);
468460484Sobrien
468560484Sobrien  demand_empty_rest_of_line ();
468660484Sobrien}
468760484Sobrien
468860484Sobrien/* Don't adjust TOC relocs to use the section symbol.  */
468960484Sobrien
469060484Sobrienint
4691218822Sdimppc_pe_fix_adjustable (fixS *fix)
469260484Sobrien{
469360484Sobrien  return fix->fx_r_type != BFD_RELOC_PPC_TOC16;
469460484Sobrien}
469560484Sobrien
469660484Sobrien#endif
469760484Sobrien
469860484Sobrien#ifdef OBJ_XCOFF
469960484Sobrien
470060484Sobrien/* XCOFF specific symbol and file handling.  */
470160484Sobrien
470260484Sobrien/* Canonicalize the symbol name.  We use the to force the suffix, if
470360484Sobrien   any, to use square brackets, and to be in upper case.  */
470460484Sobrien
470560484Sobrienchar *
4706218822Sdimppc_canonicalize_symbol_name (char *name)
470760484Sobrien{
470860484Sobrien  char *s;
470960484Sobrien
471060484Sobrien  if (ppc_stab_symbol)
471160484Sobrien    return name;
471260484Sobrien
471360484Sobrien  for (s = name; *s != '\0' && *s != '{' && *s != '['; s++)
471460484Sobrien    ;
471560484Sobrien  if (*s != '\0')
471660484Sobrien    {
471760484Sobrien      char brac;
471860484Sobrien
471960484Sobrien      if (*s == '[')
472060484Sobrien	brac = ']';
472160484Sobrien      else
472260484Sobrien	{
472360484Sobrien	  *s = '[';
472460484Sobrien	  brac = '}';
472560484Sobrien	}
472660484Sobrien
472760484Sobrien      for (s++; *s != '\0' && *s != brac; s++)
472889857Sobrien	*s = TOUPPER (*s);
472960484Sobrien
473060484Sobrien      if (*s == '\0' || s[1] != '\0')
473160484Sobrien	as_bad (_("bad symbol suffix"));
473260484Sobrien
473360484Sobrien      *s = ']';
473460484Sobrien    }
473560484Sobrien
473660484Sobrien  return name;
473760484Sobrien}
473860484Sobrien
473960484Sobrien/* Set the class of a symbol based on the suffix, if any.  This is
474060484Sobrien   called whenever a new symbol is created.  */
474160484Sobrien
474260484Sobrienvoid
4743218822Sdimppc_symbol_new_hook (symbolS *sym)
474460484Sobrien{
474560484Sobrien  struct ppc_tc_sy *tc;
474660484Sobrien  const char *s;
474760484Sobrien
474860484Sobrien  tc = symbol_get_tc (sym);
474960484Sobrien  tc->next = NULL;
475060484Sobrien  tc->output = 0;
475160484Sobrien  tc->class = -1;
475260484Sobrien  tc->real_name = NULL;
475360484Sobrien  tc->subseg = 0;
475460484Sobrien  tc->align = 0;
475560484Sobrien  tc->size = NULL;
475660484Sobrien  tc->within = NULL;
475760484Sobrien
475860484Sobrien  if (ppc_stab_symbol)
475960484Sobrien    return;
476060484Sobrien
476160484Sobrien  s = strchr (S_GET_NAME (sym), '[');
476260484Sobrien  if (s == (const char *) NULL)
476360484Sobrien    {
476460484Sobrien      /* There is no suffix.  */
476560484Sobrien      return;
476660484Sobrien    }
476760484Sobrien
476860484Sobrien  ++s;
476960484Sobrien
477060484Sobrien  switch (s[0])
477160484Sobrien    {
477260484Sobrien    case 'B':
477360484Sobrien      if (strcmp (s, "BS]") == 0)
477460484Sobrien	tc->class = XMC_BS;
477560484Sobrien      break;
477660484Sobrien    case 'D':
477760484Sobrien      if (strcmp (s, "DB]") == 0)
477860484Sobrien	tc->class = XMC_DB;
477960484Sobrien      else if (strcmp (s, "DS]") == 0)
478060484Sobrien	tc->class = XMC_DS;
478160484Sobrien      break;
478260484Sobrien    case 'G':
478360484Sobrien      if (strcmp (s, "GL]") == 0)
478460484Sobrien	tc->class = XMC_GL;
478560484Sobrien      break;
478660484Sobrien    case 'P':
478760484Sobrien      if (strcmp (s, "PR]") == 0)
478860484Sobrien	tc->class = XMC_PR;
478960484Sobrien      break;
479060484Sobrien    case 'R':
479160484Sobrien      if (strcmp (s, "RO]") == 0)
479260484Sobrien	tc->class = XMC_RO;
479360484Sobrien      else if (strcmp (s, "RW]") == 0)
479460484Sobrien	tc->class = XMC_RW;
479560484Sobrien      break;
479660484Sobrien    case 'S':
479760484Sobrien      if (strcmp (s, "SV]") == 0)
479860484Sobrien	tc->class = XMC_SV;
479960484Sobrien      break;
480060484Sobrien    case 'T':
480160484Sobrien      if (strcmp (s, "TC]") == 0)
480260484Sobrien	tc->class = XMC_TC;
480360484Sobrien      else if (strcmp (s, "TI]") == 0)
480460484Sobrien	tc->class = XMC_TI;
480560484Sobrien      else if (strcmp (s, "TB]") == 0)
480660484Sobrien	tc->class = XMC_TB;
480760484Sobrien      else if (strcmp (s, "TC0]") == 0 || strcmp (s, "T0]") == 0)
480860484Sobrien	tc->class = XMC_TC0;
480960484Sobrien      break;
481060484Sobrien    case 'U':
481160484Sobrien      if (strcmp (s, "UA]") == 0)
481260484Sobrien	tc->class = XMC_UA;
481360484Sobrien      else if (strcmp (s, "UC]") == 0)
481460484Sobrien	tc->class = XMC_UC;
481560484Sobrien      break;
481660484Sobrien    case 'X':
481760484Sobrien      if (strcmp (s, "XO]") == 0)
481860484Sobrien	tc->class = XMC_XO;
481960484Sobrien      break;
482060484Sobrien    }
482160484Sobrien
482260484Sobrien  if (tc->class == -1)
482360484Sobrien    as_bad (_("Unrecognized symbol suffix"));
482460484Sobrien}
482560484Sobrien
482660484Sobrien/* Set the class of a label based on where it is defined.  This
482760484Sobrien   handles symbols without suffixes.  Also, move the symbol so that it
482860484Sobrien   follows the csect symbol.  */
482960484Sobrien
483060484Sobrienvoid
4831218822Sdimppc_frob_label (symbolS *sym)
483260484Sobrien{
483360484Sobrien  if (ppc_current_csect != (symbolS *) NULL)
483460484Sobrien    {
483560484Sobrien      if (symbol_get_tc (sym)->class == -1)
483660484Sobrien	symbol_get_tc (sym)->class = symbol_get_tc (ppc_current_csect)->class;
483760484Sobrien
483860484Sobrien      symbol_remove (sym, &symbol_rootP, &symbol_lastP);
483960484Sobrien      symbol_append (sym, symbol_get_tc (ppc_current_csect)->within,
484060484Sobrien		     &symbol_rootP, &symbol_lastP);
484160484Sobrien      symbol_get_tc (ppc_current_csect)->within = sym;
484260484Sobrien    }
4843218822Sdim
4844218822Sdim#ifdef OBJ_ELF
4845218822Sdim  dwarf2_emit_label (sym);
4846218822Sdim#endif
484760484Sobrien}
484860484Sobrien
484960484Sobrien/* This variable is set by ppc_frob_symbol if any absolute symbols are
485060484Sobrien   seen.  It tells ppc_adjust_symtab whether it needs to look through
485160484Sobrien   the symbols.  */
485260484Sobrien
4853130561Sobrienstatic bfd_boolean ppc_saw_abs;
485460484Sobrien
485560484Sobrien/* Change the name of a symbol just before writing it out.  Set the
485660484Sobrien   real name if the .rename pseudo-op was used.  Otherwise, remove any
485760484Sobrien   class suffix.  Return 1 if the symbol should not be included in the
485860484Sobrien   symbol table.  */
485960484Sobrien
486060484Sobrienint
4861218822Sdimppc_frob_symbol (symbolS *sym)
486260484Sobrien{
486360484Sobrien  static symbolS *ppc_last_function;
486460484Sobrien  static symbolS *set_end;
486560484Sobrien
486660484Sobrien  /* Discard symbols that should not be included in the output symbol
486760484Sobrien     table.  */
486860484Sobrien  if (! symbol_used_in_reloc_p (sym)
486960484Sobrien      && ((symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) != 0
4870218822Sdim	  || (! (S_IS_EXTERNAL (sym) || S_IS_WEAK (sym))
487160484Sobrien	      && ! symbol_get_tc (sym)->output
487260484Sobrien	      && S_GET_STORAGE_CLASS (sym) != C_FILE)))
487360484Sobrien    return 1;
487460484Sobrien
4875130561Sobrien  /* This one will disappear anyway.  Don't make a csect sym for it.  */
4876130561Sobrien  if (sym == abs_section_sym)
4877130561Sobrien    return 1;
4878130561Sobrien
487960484Sobrien  if (symbol_get_tc (sym)->real_name != (char *) NULL)
488060484Sobrien    S_SET_NAME (sym, symbol_get_tc (sym)->real_name);
488160484Sobrien  else
488260484Sobrien    {
488360484Sobrien      const char *name;
488460484Sobrien      const char *s;
488560484Sobrien
488660484Sobrien      name = S_GET_NAME (sym);
488760484Sobrien      s = strchr (name, '[');
488860484Sobrien      if (s != (char *) NULL)
488960484Sobrien	{
489060484Sobrien	  unsigned int len;
489160484Sobrien	  char *snew;
489260484Sobrien
489360484Sobrien	  len = s - name;
489460484Sobrien	  snew = xmalloc (len + 1);
489560484Sobrien	  memcpy (snew, name, len);
489660484Sobrien	  snew[len] = '\0';
489760484Sobrien
489860484Sobrien	  S_SET_NAME (sym, snew);
489960484Sobrien	}
490060484Sobrien    }
490160484Sobrien
490260484Sobrien  if (set_end != (symbolS *) NULL)
490360484Sobrien    {
490460484Sobrien      SA_SET_SYM_ENDNDX (set_end, sym);
490560484Sobrien      set_end = NULL;
490660484Sobrien    }
490760484Sobrien
490860484Sobrien  if (SF_GET_FUNCTION (sym))
490960484Sobrien    {
491060484Sobrien      if (ppc_last_function != (symbolS *) NULL)
491160484Sobrien	as_bad (_("two .function pseudo-ops with no intervening .ef"));
491260484Sobrien      ppc_last_function = sym;
491360484Sobrien      if (symbol_get_tc (sym)->size != (symbolS *) NULL)
491460484Sobrien	{
491589857Sobrien	  resolve_symbol_value (symbol_get_tc (sym)->size);
491660484Sobrien	  SA_SET_SYM_FSIZE (sym,
491760484Sobrien			    (long) S_GET_VALUE (symbol_get_tc (sym)->size));
491860484Sobrien	}
491960484Sobrien    }
492060484Sobrien  else if (S_GET_STORAGE_CLASS (sym) == C_FCN
492160484Sobrien	   && strcmp (S_GET_NAME (sym), ".ef") == 0)
492260484Sobrien    {
492360484Sobrien      if (ppc_last_function == (symbolS *) NULL)
492460484Sobrien	as_bad (_(".ef with no preceding .function"));
492560484Sobrien      else
492660484Sobrien	{
492760484Sobrien	  set_end = ppc_last_function;
492860484Sobrien	  ppc_last_function = NULL;
492960484Sobrien
493060484Sobrien	  /* We don't have a C_EFCN symbol, but we need to force the
493160484Sobrien	     COFF backend to believe that it has seen one.  */
493260484Sobrien	  coff_last_function = NULL;
493360484Sobrien	}
493460484Sobrien    }
493560484Sobrien
4936218822Sdim  if (! (S_IS_EXTERNAL (sym) || S_IS_WEAK (sym))
493760484Sobrien      && (symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) == 0
493860484Sobrien      && S_GET_STORAGE_CLASS (sym) != C_FILE
493960484Sobrien      && S_GET_STORAGE_CLASS (sym) != C_FCN
494060484Sobrien      && S_GET_STORAGE_CLASS (sym) != C_BLOCK
494160484Sobrien      && S_GET_STORAGE_CLASS (sym) != C_BSTAT
494260484Sobrien      && S_GET_STORAGE_CLASS (sym) != C_ESTAT
494360484Sobrien      && S_GET_STORAGE_CLASS (sym) != C_BINCL
494460484Sobrien      && S_GET_STORAGE_CLASS (sym) != C_EINCL
494560484Sobrien      && S_GET_SEGMENT (sym) != ppc_coff_debug_section)
494660484Sobrien    S_SET_STORAGE_CLASS (sym, C_HIDEXT);
494760484Sobrien
494860484Sobrien  if (S_GET_STORAGE_CLASS (sym) == C_EXT
494960484Sobrien      || S_GET_STORAGE_CLASS (sym) == C_HIDEXT)
495060484Sobrien    {
495160484Sobrien      int i;
495260484Sobrien      union internal_auxent *a;
495360484Sobrien
495460484Sobrien      /* Create a csect aux.  */
495560484Sobrien      i = S_GET_NUMBER_AUXILIARY (sym);
495660484Sobrien      S_SET_NUMBER_AUXILIARY (sym, i + 1);
495760484Sobrien      a = &coffsymbol (symbol_get_bfdsym (sym))->native[i + 1].u.auxent;
495860484Sobrien      if (symbol_get_tc (sym)->class == XMC_TC0)
495960484Sobrien	{
496060484Sobrien	  /* This is the TOC table.  */
496160484Sobrien	  know (strcmp (S_GET_NAME (sym), "TOC") == 0);
496260484Sobrien	  a->x_csect.x_scnlen.l = 0;
496360484Sobrien	  a->x_csect.x_smtyp = (2 << 3) | XTY_SD;
496460484Sobrien	}
496560484Sobrien      else if (symbol_get_tc (sym)->subseg != 0)
496660484Sobrien	{
496760484Sobrien	  /* This is a csect symbol.  x_scnlen is the size of the
496860484Sobrien	     csect.  */
496960484Sobrien	  if (symbol_get_tc (sym)->next == (symbolS *) NULL)
497060484Sobrien	    a->x_csect.x_scnlen.l = (bfd_section_size (stdoutput,
497160484Sobrien						       S_GET_SEGMENT (sym))
497260484Sobrien				     - S_GET_VALUE (sym));
497360484Sobrien	  else
497460484Sobrien	    {
497589857Sobrien	      resolve_symbol_value (symbol_get_tc (sym)->next);
497660484Sobrien	      a->x_csect.x_scnlen.l = (S_GET_VALUE (symbol_get_tc (sym)->next)
497760484Sobrien				       - S_GET_VALUE (sym));
497860484Sobrien	    }
497960484Sobrien	  a->x_csect.x_smtyp = (symbol_get_tc (sym)->align << 3) | XTY_SD;
498060484Sobrien	}
498160484Sobrien      else if (S_GET_SEGMENT (sym) == bss_section)
498260484Sobrien	{
498360484Sobrien	  /* This is a common symbol.  */
498460484Sobrien	  a->x_csect.x_scnlen.l = symbol_get_frag (sym)->fr_offset;
498560484Sobrien	  a->x_csect.x_smtyp = (symbol_get_tc (sym)->align << 3) | XTY_CM;
498660484Sobrien	  if (S_IS_EXTERNAL (sym))
498760484Sobrien	    symbol_get_tc (sym)->class = XMC_RW;
498860484Sobrien	  else
498960484Sobrien	    symbol_get_tc (sym)->class = XMC_BS;
499060484Sobrien	}
499160484Sobrien      else if (S_GET_SEGMENT (sym) == absolute_section)
499260484Sobrien	{
499360484Sobrien	  /* This is an absolute symbol.  The csect will be created by
499489857Sobrien	     ppc_adjust_symtab.  */
4995130561Sobrien	  ppc_saw_abs = TRUE;
499660484Sobrien	  a->x_csect.x_smtyp = XTY_LD;
499760484Sobrien	  if (symbol_get_tc (sym)->class == -1)
499860484Sobrien	    symbol_get_tc (sym)->class = XMC_XO;
499960484Sobrien	}
500060484Sobrien      else if (! S_IS_DEFINED (sym))
500160484Sobrien	{
500260484Sobrien	  /* This is an external symbol.  */
500360484Sobrien	  a->x_csect.x_scnlen.l = 0;
500460484Sobrien	  a->x_csect.x_smtyp = XTY_ER;
500560484Sobrien	}
500660484Sobrien      else if (symbol_get_tc (sym)->class == XMC_TC)
500760484Sobrien	{
500860484Sobrien	  symbolS *next;
500960484Sobrien
501060484Sobrien	  /* This is a TOC definition.  x_scnlen is the size of the
501160484Sobrien	     TOC entry.  */
501260484Sobrien	  next = symbol_next (sym);
501360484Sobrien	  while (symbol_get_tc (next)->class == XMC_TC0)
501460484Sobrien	    next = symbol_next (next);
501560484Sobrien	  if (next == (symbolS *) NULL
501660484Sobrien	      || symbol_get_tc (next)->class != XMC_TC)
501760484Sobrien	    {
501860484Sobrien	      if (ppc_after_toc_frag == (fragS *) NULL)
501960484Sobrien		a->x_csect.x_scnlen.l = (bfd_section_size (stdoutput,
502060484Sobrien							   data_section)
502160484Sobrien					 - S_GET_VALUE (sym));
502260484Sobrien	      else
502360484Sobrien		a->x_csect.x_scnlen.l = (ppc_after_toc_frag->fr_address
502460484Sobrien					 - S_GET_VALUE (sym));
502560484Sobrien	    }
502660484Sobrien	  else
502760484Sobrien	    {
502889857Sobrien	      resolve_symbol_value (next);
502960484Sobrien	      a->x_csect.x_scnlen.l = (S_GET_VALUE (next)
503060484Sobrien				       - S_GET_VALUE (sym));
503160484Sobrien	    }
503260484Sobrien	  a->x_csect.x_smtyp = (2 << 3) | XTY_SD;
503360484Sobrien	}
503460484Sobrien      else
503560484Sobrien	{
503660484Sobrien	  symbolS *csect;
503760484Sobrien
503860484Sobrien	  /* This is a normal symbol definition.  x_scnlen is the
503960484Sobrien	     symbol index of the containing csect.  */
504060484Sobrien	  if (S_GET_SEGMENT (sym) == text_section)
504160484Sobrien	    csect = ppc_text_csects;
504260484Sobrien	  else if (S_GET_SEGMENT (sym) == data_section)
504360484Sobrien	    csect = ppc_data_csects;
504460484Sobrien	  else
504560484Sobrien	    abort ();
504660484Sobrien
504760484Sobrien	  /* Skip the initial dummy symbol.  */
504860484Sobrien	  csect = symbol_get_tc (csect)->next;
504960484Sobrien
505060484Sobrien	  if (csect == (symbolS *) NULL)
505160484Sobrien	    {
505260484Sobrien	      as_warn (_("warning: symbol %s has no csect"), S_GET_NAME (sym));
505360484Sobrien	      a->x_csect.x_scnlen.l = 0;
505460484Sobrien	    }
505560484Sobrien	  else
505660484Sobrien	    {
505760484Sobrien	      while (symbol_get_tc (csect)->next != (symbolS *) NULL)
505860484Sobrien		{
505989857Sobrien		  resolve_symbol_value (symbol_get_tc (csect)->next);
506060484Sobrien		  if (S_GET_VALUE (symbol_get_tc (csect)->next)
506160484Sobrien		      > S_GET_VALUE (sym))
506260484Sobrien		    break;
506360484Sobrien		  csect = symbol_get_tc (csect)->next;
506460484Sobrien		}
506560484Sobrien
506660484Sobrien	      a->x_csect.x_scnlen.p =
506760484Sobrien		coffsymbol (symbol_get_bfdsym (csect))->native;
506860484Sobrien	      coffsymbol (symbol_get_bfdsym (sym))->native[i + 1].fix_scnlen =
506960484Sobrien		1;
507060484Sobrien	    }
507160484Sobrien	  a->x_csect.x_smtyp = XTY_LD;
507260484Sobrien	}
507377298Sobrien
507460484Sobrien      a->x_csect.x_parmhash = 0;
507560484Sobrien      a->x_csect.x_snhash = 0;
507660484Sobrien      if (symbol_get_tc (sym)->class == -1)
507760484Sobrien	a->x_csect.x_smclas = XMC_PR;
507860484Sobrien      else
507960484Sobrien	a->x_csect.x_smclas = symbol_get_tc (sym)->class;
508060484Sobrien      a->x_csect.x_stab = 0;
508160484Sobrien      a->x_csect.x_snstab = 0;
508260484Sobrien
508360484Sobrien      /* Don't let the COFF backend resort these symbols.  */
508460484Sobrien      symbol_get_bfdsym (sym)->flags |= BSF_NOT_AT_END;
508560484Sobrien    }
508660484Sobrien  else if (S_GET_STORAGE_CLASS (sym) == C_BSTAT)
508760484Sobrien    {
508860484Sobrien      /* We want the value to be the symbol index of the referenced
508960484Sobrien	 csect symbol.  BFD will do that for us if we set the right
509060484Sobrien	 flags.  */
5091130561Sobrien      asymbol *bsym = symbol_get_bfdsym (symbol_get_tc (sym)->within);
5092130561Sobrien      combined_entry_type *c = coffsymbol (bsym)->native;
5093130561Sobrien
5094130561Sobrien      S_SET_VALUE (sym, (valueT) (size_t) c);
509560484Sobrien      coffsymbol (symbol_get_bfdsym (sym))->native->fix_value = 1;
509660484Sobrien    }
509760484Sobrien  else if (S_GET_STORAGE_CLASS (sym) == C_STSYM)
509860484Sobrien    {
509960484Sobrien      symbolS *block;
510060484Sobrien      symbolS *csect;
510160484Sobrien
510260484Sobrien      /* The value is the offset from the enclosing csect.  */
510360484Sobrien      block = symbol_get_tc (sym)->within;
510460484Sobrien      csect = symbol_get_tc (block)->within;
510589857Sobrien      resolve_symbol_value (csect);
510660484Sobrien      S_SET_VALUE (sym, S_GET_VALUE (sym) - S_GET_VALUE (csect));
510760484Sobrien    }
510860484Sobrien  else if (S_GET_STORAGE_CLASS (sym) == C_BINCL
510960484Sobrien	   || S_GET_STORAGE_CLASS (sym) == C_EINCL)
511060484Sobrien    {
511160484Sobrien      /* We want the value to be a file offset into the line numbers.
511289857Sobrien	 BFD will do that for us if we set the right flags.  We have
511389857Sobrien	 already set the value correctly.  */
511460484Sobrien      coffsymbol (symbol_get_bfdsym (sym))->native->fix_line = 1;
511560484Sobrien    }
511660484Sobrien
511760484Sobrien  return 0;
511860484Sobrien}
511960484Sobrien
512060484Sobrien/* Adjust the symbol table.  This creates csect symbols for all
512160484Sobrien   absolute symbols.  */
512260484Sobrien
512360484Sobrienvoid
5124218822Sdimppc_adjust_symtab (void)
512560484Sobrien{
512660484Sobrien  symbolS *sym;
512760484Sobrien
512860484Sobrien  if (! ppc_saw_abs)
512960484Sobrien    return;
513060484Sobrien
513160484Sobrien  for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
513260484Sobrien    {
513360484Sobrien      symbolS *csect;
513460484Sobrien      int i;
513560484Sobrien      union internal_auxent *a;
513660484Sobrien
513760484Sobrien      if (S_GET_SEGMENT (sym) != absolute_section)
513860484Sobrien	continue;
513960484Sobrien
514060484Sobrien      csect = symbol_create (".abs[XO]", absolute_section,
514160484Sobrien			     S_GET_VALUE (sym), &zero_address_frag);
514260484Sobrien      symbol_get_bfdsym (csect)->value = S_GET_VALUE (sym);
514360484Sobrien      S_SET_STORAGE_CLASS (csect, C_HIDEXT);
514460484Sobrien      i = S_GET_NUMBER_AUXILIARY (csect);
514560484Sobrien      S_SET_NUMBER_AUXILIARY (csect, i + 1);
514660484Sobrien      a = &coffsymbol (symbol_get_bfdsym (csect))->native[i + 1].u.auxent;
514760484Sobrien      a->x_csect.x_scnlen.l = 0;
514860484Sobrien      a->x_csect.x_smtyp = XTY_SD;
514960484Sobrien      a->x_csect.x_parmhash = 0;
515060484Sobrien      a->x_csect.x_snhash = 0;
515160484Sobrien      a->x_csect.x_smclas = XMC_XO;
515260484Sobrien      a->x_csect.x_stab = 0;
515360484Sobrien      a->x_csect.x_snstab = 0;
515460484Sobrien
515560484Sobrien      symbol_insert (csect, sym, &symbol_rootP, &symbol_lastP);
515660484Sobrien
515760484Sobrien      i = S_GET_NUMBER_AUXILIARY (sym);
515860484Sobrien      a = &coffsymbol (symbol_get_bfdsym (sym))->native[i].u.auxent;
515960484Sobrien      a->x_csect.x_scnlen.p = coffsymbol (symbol_get_bfdsym (csect))->native;
516060484Sobrien      coffsymbol (symbol_get_bfdsym (sym))->native[i].fix_scnlen = 1;
516160484Sobrien    }
516260484Sobrien
5163130561Sobrien  ppc_saw_abs = FALSE;
516460484Sobrien}
516560484Sobrien
516660484Sobrien/* Set the VMA for a section.  This is called on all the sections in
516760484Sobrien   turn.  */
516860484Sobrien
516960484Sobrienvoid
5170218822Sdimppc_frob_section (asection *sec)
517160484Sobrien{
5172130561Sobrien  static bfd_vma vma = 0;
517360484Sobrien
5174130561Sobrien  vma = md_section_align (sec, vma);
517560484Sobrien  bfd_set_section_vma (stdoutput, sec, vma);
517660484Sobrien  vma += bfd_section_size (stdoutput, sec);
517760484Sobrien}
517860484Sobrien
517960484Sobrien#endif /* OBJ_XCOFF */
518060484Sobrien
518160484Sobrien/* Turn a string in input_line_pointer into a floating point constant
518277298Sobrien   of type TYPE, and store the appropriate bytes in *LITP.  The number
518377298Sobrien   of LITTLENUMS emitted is stored in *SIZEP.  An error message is
518460484Sobrien   returned, or NULL on OK.  */
518560484Sobrien
518660484Sobrienchar *
5187218822Sdimmd_atof (int type, char *litp, int *sizep)
518860484Sobrien{
518960484Sobrien  int prec;
519060484Sobrien  LITTLENUM_TYPE words[4];
519160484Sobrien  char *t;
519260484Sobrien  int i;
519360484Sobrien
519460484Sobrien  switch (type)
519560484Sobrien    {
519660484Sobrien    case 'f':
519760484Sobrien      prec = 2;
519860484Sobrien      break;
519960484Sobrien
520060484Sobrien    case 'd':
520160484Sobrien      prec = 4;
520260484Sobrien      break;
520360484Sobrien
520460484Sobrien    default:
520560484Sobrien      *sizep = 0;
520660484Sobrien      return _("bad call to md_atof");
520760484Sobrien    }
520860484Sobrien
520960484Sobrien  t = atof_ieee (input_line_pointer, type, words);
521060484Sobrien  if (t)
521160484Sobrien    input_line_pointer = t;
521260484Sobrien
521360484Sobrien  *sizep = prec * 2;
521460484Sobrien
521560484Sobrien  if (target_big_endian)
521660484Sobrien    {
521760484Sobrien      for (i = 0; i < prec; i++)
521860484Sobrien	{
521960484Sobrien	  md_number_to_chars (litp, (valueT) words[i], 2);
522060484Sobrien	  litp += 2;
522160484Sobrien	}
522260484Sobrien    }
522360484Sobrien  else
522460484Sobrien    {
522560484Sobrien      for (i = prec - 1; i >= 0; i--)
522660484Sobrien	{
522760484Sobrien	  md_number_to_chars (litp, (valueT) words[i], 2);
522860484Sobrien	  litp += 2;
522960484Sobrien	}
523060484Sobrien    }
523177298Sobrien
523260484Sobrien  return NULL;
523360484Sobrien}
523460484Sobrien
523560484Sobrien/* Write a value out to the object file, using the appropriate
523660484Sobrien   endianness.  */
523760484Sobrien
523860484Sobrienvoid
5239218822Sdimmd_number_to_chars (char *buf, valueT val, int n)
524060484Sobrien{
524160484Sobrien  if (target_big_endian)
524260484Sobrien    number_to_chars_bigendian (buf, val, n);
524360484Sobrien  else
524460484Sobrien    number_to_chars_littleendian (buf, val, n);
524560484Sobrien}
524660484Sobrien
524760484Sobrien/* Align a section (I don't know why this is machine dependent).  */
524860484Sobrien
524960484SobrienvalueT
5250218822Sdimmd_section_align (asection *seg ATTRIBUTE_UNUSED, valueT addr)
525160484Sobrien{
5252218822Sdim#ifdef OBJ_ELF
5253218822Sdim  return addr;
5254218822Sdim#else
525560484Sobrien  int align = bfd_get_section_alignment (stdoutput, seg);
525660484Sobrien
525760484Sobrien  return ((addr + (1 << align) - 1) & (-1 << align));
5258218822Sdim#endif
525960484Sobrien}
526060484Sobrien
526160484Sobrien/* We don't have any form of relaxing.  */
526260484Sobrien
526360484Sobrienint
5264218822Sdimmd_estimate_size_before_relax (fragS *fragp ATTRIBUTE_UNUSED,
5265218822Sdim			       asection *seg ATTRIBUTE_UNUSED)
526660484Sobrien{
526760484Sobrien  abort ();
526860484Sobrien  return 0;
526960484Sobrien}
527060484Sobrien
527160484Sobrien/* Convert a machine dependent frag.  We never generate these.  */
527260484Sobrien
527360484Sobrienvoid
5274218822Sdimmd_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
5275218822Sdim		 asection *sec ATTRIBUTE_UNUSED,
5276218822Sdim		 fragS *fragp ATTRIBUTE_UNUSED)
527760484Sobrien{
527860484Sobrien  abort ();
527960484Sobrien}
528060484Sobrien
528160484Sobrien/* We have no need to default values of symbols.  */
528260484Sobrien
528360484SobriensymbolS *
5284218822Sdimmd_undefined_symbol (char *name ATTRIBUTE_UNUSED)
528560484Sobrien{
528660484Sobrien  return 0;
528760484Sobrien}
528860484Sobrien
528960484Sobrien/* Functions concerning relocs.  */
529060484Sobrien
529160484Sobrien/* The location from which a PC relative jump should be calculated,
529260484Sobrien   given a PC relative reloc.  */
529360484Sobrien
529460484Sobrienlong
5295218822Sdimmd_pcrel_from_section (fixS *fixp, segT sec ATTRIBUTE_UNUSED)
529660484Sobrien{
529760484Sobrien  return fixp->fx_frag->fr_address + fixp->fx_where;
529860484Sobrien}
529960484Sobrien
530060484Sobrien#ifdef OBJ_XCOFF
530160484Sobrien
530260484Sobrien/* This is called to see whether a fixup should be adjusted to use a
530360484Sobrien   section symbol.  We take the opportunity to change a fixup against
530460484Sobrien   a symbol in the TOC subsegment into a reloc against the
530560484Sobrien   corresponding .tc symbol.  */
530660484Sobrien
530760484Sobrienint
5308218822Sdimppc_fix_adjustable (fixS *fix)
530960484Sobrien{
5310130561Sobrien  valueT val = resolve_symbol_value (fix->fx_addsy);
5311130561Sobrien  segT symseg = S_GET_SEGMENT (fix->fx_addsy);
5312130561Sobrien  TC_SYMFIELD_TYPE *tc;
531360484Sobrien
5314130561Sobrien  if (symseg == absolute_section)
5315130561Sobrien    return 0;
5316130561Sobrien
531760484Sobrien  if (ppc_toc_csect != (symbolS *) NULL
531860484Sobrien      && fix->fx_addsy != ppc_toc_csect
5319130561Sobrien      && symseg == data_section
532060484Sobrien      && val >= ppc_toc_frag->fr_address
532160484Sobrien      && (ppc_after_toc_frag == (fragS *) NULL
532260484Sobrien	  || val < ppc_after_toc_frag->fr_address))
532360484Sobrien    {
532460484Sobrien      symbolS *sy;
532560484Sobrien
532660484Sobrien      for (sy = symbol_next (ppc_toc_csect);
532760484Sobrien	   sy != (symbolS *) NULL;
532860484Sobrien	   sy = symbol_next (sy))
532960484Sobrien	{
5330130561Sobrien	  TC_SYMFIELD_TYPE *sy_tc = symbol_get_tc (sy);
5331130561Sobrien
5332130561Sobrien	  if (sy_tc->class == XMC_TC0)
533360484Sobrien	    continue;
5334130561Sobrien	  if (sy_tc->class != XMC_TC)
533560484Sobrien	    break;
5336130561Sobrien	  if (val == resolve_symbol_value (sy))
533760484Sobrien	    {
533860484Sobrien	      fix->fx_addsy = sy;
533960484Sobrien	      fix->fx_addnumber = val - ppc_toc_frag->fr_address;
534060484Sobrien	      return 0;
534160484Sobrien	    }
534260484Sobrien	}
534360484Sobrien
534460484Sobrien      as_bad_where (fix->fx_file, fix->fx_line,
534560484Sobrien		    _("symbol in .toc does not match any .tc"));
534660484Sobrien    }
534760484Sobrien
534860484Sobrien  /* Possibly adjust the reloc to be against the csect.  */
5349130561Sobrien  tc = symbol_get_tc (fix->fx_addsy);
5350130561Sobrien  if (tc->subseg == 0
5351130561Sobrien      && tc->class != XMC_TC0
5352130561Sobrien      && tc->class != XMC_TC
5353130561Sobrien      && symseg != bss_section
535460484Sobrien      /* Don't adjust if this is a reloc in the toc section.  */
5355130561Sobrien      && (symseg != data_section
535660484Sobrien	  || ppc_toc_csect == NULL
535760484Sobrien	  || val < ppc_toc_frag->fr_address
535860484Sobrien	  || (ppc_after_toc_frag != NULL
535960484Sobrien	      && val >= ppc_after_toc_frag->fr_address)))
536060484Sobrien    {
536160484Sobrien      symbolS *csect;
5362130561Sobrien      symbolS *next_csect;
536360484Sobrien
5364130561Sobrien      if (symseg == text_section)
536560484Sobrien	csect = ppc_text_csects;
5366130561Sobrien      else if (symseg == data_section)
536760484Sobrien	csect = ppc_data_csects;
536860484Sobrien      else
536960484Sobrien	abort ();
537060484Sobrien
537160484Sobrien      /* Skip the initial dummy symbol.  */
537260484Sobrien      csect = symbol_get_tc (csect)->next;
537360484Sobrien
537460484Sobrien      if (csect != (symbolS *) NULL)
537560484Sobrien	{
5376130561Sobrien	  while ((next_csect = symbol_get_tc (csect)->next) != (symbolS *) NULL
5377130561Sobrien		 && (symbol_get_frag (next_csect)->fr_address <= val))
537860484Sobrien	    {
537960484Sobrien	      /* If the csect address equals the symbol value, then we
538089857Sobrien		 have to look through the full symbol table to see
538189857Sobrien		 whether this is the csect we want.  Note that we will
538289857Sobrien		 only get here if the csect has zero length.  */
5383130561Sobrien	      if (symbol_get_frag (csect)->fr_address == val
5384130561Sobrien		  && S_GET_VALUE (csect) == val)
538560484Sobrien		{
538660484Sobrien		  symbolS *scan;
538760484Sobrien
538860484Sobrien		  for (scan = symbol_next (csect);
538960484Sobrien		       scan != NULL;
539060484Sobrien		       scan = symbol_next (scan))
539160484Sobrien		    {
539260484Sobrien		      if (symbol_get_tc (scan)->subseg != 0)
539360484Sobrien			break;
539460484Sobrien		      if (scan == fix->fx_addsy)
539560484Sobrien			break;
539660484Sobrien		    }
539760484Sobrien
539860484Sobrien		  /* If we found the symbol before the next csect
539989857Sobrien		     symbol, then this is the csect we want.  */
540060484Sobrien		  if (scan == fix->fx_addsy)
540160484Sobrien		    break;
540260484Sobrien		}
540360484Sobrien
5404130561Sobrien	      csect = next_csect;
540560484Sobrien	    }
540660484Sobrien
5407130561Sobrien	  fix->fx_offset += val - symbol_get_frag (csect)->fr_address;
540860484Sobrien	  fix->fx_addsy = csect;
540960484Sobrien	}
5410130561Sobrien      return 0;
541160484Sobrien    }
541260484Sobrien
541360484Sobrien  /* Adjust a reloc against a .lcomm symbol to be against the base
541460484Sobrien     .lcomm.  */
5415130561Sobrien  if (symseg == bss_section
541660484Sobrien      && ! S_IS_EXTERNAL (fix->fx_addsy))
541760484Sobrien    {
5418130561Sobrien      symbolS *sy = symbol_get_frag (fix->fx_addsy)->fr_symbol;
5419130561Sobrien
5420130561Sobrien      fix->fx_offset += val - resolve_symbol_value (sy);
5421130561Sobrien      fix->fx_addsy = sy;
542260484Sobrien    }
542360484Sobrien
542460484Sobrien  return 0;
542560484Sobrien}
542660484Sobrien
542760484Sobrien/* A reloc from one csect to another must be kept.  The assembler
542860484Sobrien   will, of course, keep relocs between sections, and it will keep
542960484Sobrien   absolute relocs, but we need to force it to keep PC relative relocs
543060484Sobrien   between two csects in the same section.  */
543160484Sobrien
543260484Sobrienint
5433218822Sdimppc_force_relocation (fixS *fix)
543460484Sobrien{
543560484Sobrien  /* At this point fix->fx_addsy should already have been converted to
543660484Sobrien     a csect symbol.  If the csect does not include the fragment, then
543760484Sobrien     we need to force the relocation.  */
543860484Sobrien  if (fix->fx_pcrel
543960484Sobrien      && fix->fx_addsy != NULL
544060484Sobrien      && symbol_get_tc (fix->fx_addsy)->subseg != 0
544160484Sobrien      && ((symbol_get_frag (fix->fx_addsy)->fr_address
544260484Sobrien	   > fix->fx_frag->fr_address)
544360484Sobrien	  || (symbol_get_tc (fix->fx_addsy)->next != NULL
544460484Sobrien	      && (symbol_get_frag (symbol_get_tc (fix->fx_addsy)->next)->fr_address
544560484Sobrien		  <= fix->fx_frag->fr_address))))
544660484Sobrien    return 1;
544760484Sobrien
5448130561Sobrien  return generic_force_reloc (fix);
544960484Sobrien}
545060484Sobrien
545160484Sobrien#endif /* OBJ_XCOFF */
545260484Sobrien
545389857Sobrien#ifdef OBJ_ELF
5454130561Sobrien/* If this function returns non-zero, it guarantees that a relocation
5455130561Sobrien   will be emitted for a fixup.  */
5456130561Sobrien
545789857Sobrienint
5458218822Sdimppc_force_relocation (fixS *fix)
5459130561Sobrien{
5460130561Sobrien  /* Branch prediction relocations must force a relocation, as must
5461130561Sobrien     the vtable description relocs.  */
5462130561Sobrien  switch (fix->fx_r_type)
5463130561Sobrien    {
5464130561Sobrien    case BFD_RELOC_PPC_B16_BRTAKEN:
5465130561Sobrien    case BFD_RELOC_PPC_B16_BRNTAKEN:
5466130561Sobrien    case BFD_RELOC_PPC_BA16_BRTAKEN:
5467130561Sobrien    case BFD_RELOC_PPC_BA16_BRNTAKEN:
5468218822Sdim    case BFD_RELOC_24_PLT_PCREL:
5469130561Sobrien    case BFD_RELOC_PPC64_TOC:
5470130561Sobrien      return 1;
5471130561Sobrien    default:
5472130561Sobrien      break;
5473130561Sobrien    }
5474130561Sobrien
5475130561Sobrien  if (fix->fx_r_type >= BFD_RELOC_PPC_TLS
5476130561Sobrien      && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA)
5477130561Sobrien    return 1;
5478130561Sobrien
5479130561Sobrien  return generic_force_reloc (fix);
5480130561Sobrien}
5481130561Sobrien
5482130561Sobrienint
5483218822Sdimppc_fix_adjustable (fixS *fix)
548460484Sobrien{
548589857Sobrien  return (fix->fx_r_type != BFD_RELOC_16_GOTOFF
548689857Sobrien	  && fix->fx_r_type != BFD_RELOC_LO16_GOTOFF
548789857Sobrien	  && fix->fx_r_type != BFD_RELOC_HI16_GOTOFF
548889857Sobrien	  && fix->fx_r_type != BFD_RELOC_HI16_S_GOTOFF
548989857Sobrien	  && fix->fx_r_type != BFD_RELOC_GPREL16
549089857Sobrien	  && fix->fx_r_type != BFD_RELOC_VTABLE_INHERIT
549189857Sobrien	  && fix->fx_r_type != BFD_RELOC_VTABLE_ENTRY
5492130561Sobrien	  && !(fix->fx_r_type >= BFD_RELOC_PPC_TLS
5493218822Sdim	       && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA));
549489857Sobrien}
549560484Sobrien#endif
549660484Sobrien
5497218822Sdim/* Implement HANDLE_ALIGN.  This writes the NOP pattern into an
5498218822Sdim   rs_align_code frag.  */
5499218822Sdim
5500218822Sdimvoid
5501218822Sdimppc_handle_align (struct frag *fragP)
5502218822Sdim{
5503218822Sdim  valueT count = (fragP->fr_next->fr_address
5504218822Sdim		  - (fragP->fr_address + fragP->fr_fix));
5505218822Sdim
5506218822Sdim  if (count != 0 && (count & 3) == 0)
5507218822Sdim    {
5508218822Sdim      char *dest = fragP->fr_literal + fragP->fr_fix;
5509218822Sdim
5510218822Sdim      fragP->fr_var = 4;
5511218822Sdim      md_number_to_chars (dest, 0x60000000, 4);
5512218822Sdim
5513218822Sdim      if ((ppc_cpu & PPC_OPCODE_POWER6) != 0)
5514218822Sdim	{
5515218822Sdim	  /* For power6, we want the last nop to be a group terminating
5516218822Sdim	     one, "ori 1,1,0".  Do this by inserting an rs_fill frag
5517218822Sdim	     immediately after this one, with its address set to the last
5518218822Sdim	     nop location.  This will automatically reduce the number of
5519218822Sdim	     nops in the current frag by one.  */
5520218822Sdim	  if (count > 4)
5521218822Sdim	    {
5522218822Sdim	      struct frag *group_nop = xmalloc (SIZEOF_STRUCT_FRAG + 4);
5523218822Sdim
5524218822Sdim	      memcpy (group_nop, fragP, SIZEOF_STRUCT_FRAG);
5525218822Sdim	      group_nop->fr_address = group_nop->fr_next->fr_address - 4;
5526218822Sdim	      group_nop->fr_fix = 0;
5527218822Sdim	      group_nop->fr_offset = 1;
5528218822Sdim	      group_nop->fr_type = rs_fill;
5529218822Sdim	      fragP->fr_next = group_nop;
5530218822Sdim	      dest = group_nop->fr_literal;
5531218822Sdim	    }
5532218822Sdim
5533218822Sdim	  md_number_to_chars (dest, 0x60210000, 4);
5534218822Sdim	}
5535218822Sdim    }
5536218822Sdim}
5537218822Sdim
553860484Sobrien/* Apply a fixup to the object code.  This is called for all the
553960484Sobrien   fixups we generated by the call to fix_new_exp, above.  In the call
554060484Sobrien   above we used a reloc code which was the largest legal reloc code
554160484Sobrien   plus the operand index.  Here we undo that to recover the operand
554260484Sobrien   index.  At this point all symbol values should be fully resolved,
554360484Sobrien   and we attempt to completely resolve the reloc.  If we can not do
554460484Sobrien   that, we determine the correct reloc code and put it back in the
554560484Sobrien   fixup.  */
554660484Sobrien
554789857Sobrienvoid
5548218822Sdimmd_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
554960484Sobrien{
555089857Sobrien  valueT value = * valP;
555160484Sobrien
555260484Sobrien#ifdef OBJ_ELF
555389857Sobrien  if (fixP->fx_addsy != NULL)
555460484Sobrien    {
5555130561Sobrien      /* Hack around bfd_install_relocation brain damage.  */
555689857Sobrien      if (fixP->fx_pcrel)
555789857Sobrien	value += fixP->fx_frag->fr_address + fixP->fx_where;
555860484Sobrien    }
555960484Sobrien  else
556089857Sobrien    fixP->fx_done = 1;
556160484Sobrien#else
5562130561Sobrien  /* FIXME FIXME FIXME: The value we are passed in *valP includes
5563218822Sdim     the symbol values.  If we are doing this relocation the code in
5564218822Sdim     write.c is going to call bfd_install_relocation, which is also
5565218822Sdim     going to use the symbol value.  That means that if the reloc is
5566218822Sdim     fully resolved we want to use *valP since bfd_install_relocation is
5567218822Sdim     not being used.
556860484Sobrien     However, if the reloc is not fully resolved we do not want to use
5569130561Sobrien     *valP, and must use fx_offset instead.  However, if the reloc
5570130561Sobrien     is PC relative, we do want to use *valP since it includes the
557160484Sobrien     result of md_pcrel_from.  This is confusing.  */
557289857Sobrien  if (fixP->fx_addsy == (symbolS *) NULL)
557389857Sobrien    fixP->fx_done = 1;
557489857Sobrien
557589857Sobrien  else if (fixP->fx_pcrel)
557689857Sobrien    ;
557789857Sobrien
557860484Sobrien  else
5579130561Sobrien    value = fixP->fx_offset;
5580130561Sobrien#endif
5581130561Sobrien
5582130561Sobrien  if (fixP->fx_subsy != (symbolS *) NULL)
558360484Sobrien    {
5584130561Sobrien      /* We can't actually support subtracting a symbol.  */
5585130561Sobrien      as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
558660484Sobrien    }
558760484Sobrien
558889857Sobrien  if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
558960484Sobrien    {
559060484Sobrien      int opindex;
559160484Sobrien      const struct powerpc_operand *operand;
559260484Sobrien      char *where;
559360484Sobrien      unsigned long insn;
559460484Sobrien
559589857Sobrien      opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
559660484Sobrien
559760484Sobrien      operand = &powerpc_operands[opindex];
559860484Sobrien
559960484Sobrien#ifdef OBJ_XCOFF
560089857Sobrien      /* An instruction like `lwz 9,sym(30)' when `sym' is not a TOC symbol
560189857Sobrien	 does not generate a reloc.  It uses the offset of `sym' within its
560289857Sobrien	 csect.  Other usages, such as `.long sym', generate relocs.  This
560389857Sobrien	 is the documented behaviour of non-TOC symbols.  */
560460484Sobrien      if ((operand->flags & PPC_OPERAND_PARENS) != 0
5605218822Sdim	  && (operand->bitm & 0xfff0) == 0xfff0
560660484Sobrien	  && operand->shift == 0
5607104834Sobrien	  && (operand->insert == NULL || ppc_obj64)
560889857Sobrien	  && fixP->fx_addsy != NULL
560989857Sobrien	  && symbol_get_tc (fixP->fx_addsy)->subseg != 0
561089857Sobrien	  && symbol_get_tc (fixP->fx_addsy)->class != XMC_TC
561189857Sobrien	  && symbol_get_tc (fixP->fx_addsy)->class != XMC_TC0
561289857Sobrien	  && S_GET_SEGMENT (fixP->fx_addsy) != bss_section)
561360484Sobrien	{
561489857Sobrien	  value = fixP->fx_offset;
561589857Sobrien	  fixP->fx_done = 1;
561660484Sobrien	}
561760484Sobrien#endif
561860484Sobrien
561960484Sobrien      /* Fetch the instruction, insert the fully resolved operand
562060484Sobrien	 value, and stuff the instruction back again.  */
562189857Sobrien      where = fixP->fx_frag->fr_literal + fixP->fx_where;
562260484Sobrien      if (target_big_endian)
562360484Sobrien	insn = bfd_getb32 ((unsigned char *) where);
562460484Sobrien      else
562560484Sobrien	insn = bfd_getl32 ((unsigned char *) where);
562660484Sobrien      insn = ppc_insert_operand (insn, operand, (offsetT) value,
562789857Sobrien				 fixP->fx_file, fixP->fx_line);
562860484Sobrien      if (target_big_endian)
562960484Sobrien	bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
563060484Sobrien      else
563160484Sobrien	bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
563260484Sobrien
563389857Sobrien      if (fixP->fx_done)
563489857Sobrien	/* Nothing else to do here.  */
563589857Sobrien	return;
563660484Sobrien
563789857Sobrien      assert (fixP->fx_addsy != NULL);
563889857Sobrien
563960484Sobrien      /* Determine a BFD reloc value based on the operand information.
564060484Sobrien	 We are only prepared to turn a few of the operands into
564189857Sobrien	 relocs.  */
564260484Sobrien      if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
5643218822Sdim	  && operand->bitm == 0x3fffffc
564460484Sobrien	  && operand->shift == 0)
564589857Sobrien	fixP->fx_r_type = BFD_RELOC_PPC_B26;
564660484Sobrien      else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
5647218822Sdim	  && operand->bitm == 0xfffc
564860484Sobrien	  && operand->shift == 0)
5649104834Sobrien	{
5650104834Sobrien	  fixP->fx_r_type = BFD_RELOC_PPC_B16;
5651104834Sobrien#ifdef OBJ_XCOFF
5652104834Sobrien	  fixP->fx_size = 2;
5653104834Sobrien	  if (target_big_endian)
5654104834Sobrien	    fixP->fx_where += 2;
5655104834Sobrien#endif
5656104834Sobrien	}
565760484Sobrien      else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0
5658218822Sdim	       && operand->bitm == 0x3fffffc
565960484Sobrien	       && operand->shift == 0)
566089857Sobrien	fixP->fx_r_type = BFD_RELOC_PPC_BA26;
566160484Sobrien      else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0
5662218822Sdim	       && operand->bitm == 0xfffc
566360484Sobrien	       && operand->shift == 0)
5664104834Sobrien	{
5665104834Sobrien	  fixP->fx_r_type = BFD_RELOC_PPC_BA16;
5666104834Sobrien#ifdef OBJ_XCOFF
5667104834Sobrien	  fixP->fx_size = 2;
5668104834Sobrien	  if (target_big_endian)
5669104834Sobrien	    fixP->fx_where += 2;
5670104834Sobrien#endif
5671104834Sobrien	}
567289857Sobrien#if defined (OBJ_XCOFF) || defined (OBJ_ELF)
567360484Sobrien      else if ((operand->flags & PPC_OPERAND_PARENS) != 0
5674218822Sdim	       && (operand->bitm & 0xfff0) == 0xfff0
5675130561Sobrien	       && operand->shift == 0)
567660484Sobrien	{
5677130561Sobrien	  if (ppc_is_toc_sym (fixP->fx_addsy))
5678130561Sobrien	    {
5679130561Sobrien	      fixP->fx_r_type = BFD_RELOC_PPC_TOC16;
568089857Sobrien#ifdef OBJ_ELF
5681130561Sobrien	      if (ppc_obj64
5682130561Sobrien		  && (operand->flags & PPC_OPERAND_DS) != 0)
5683130561Sobrien		fixP->fx_r_type = BFD_RELOC_PPC64_TOC16_DS;
568489857Sobrien#endif
5685130561Sobrien	    }
5686130561Sobrien	  else
5687130561Sobrien	    {
5688130561Sobrien	      fixP->fx_r_type = BFD_RELOC_16;
5689130561Sobrien#ifdef OBJ_ELF
5690130561Sobrien	      if (ppc_obj64
5691130561Sobrien		  && (operand->flags & PPC_OPERAND_DS) != 0)
5692130561Sobrien		fixP->fx_r_type = BFD_RELOC_PPC64_ADDR16_DS;
5693130561Sobrien#endif
5694130561Sobrien	    }
569589857Sobrien	  fixP->fx_size = 2;
569660484Sobrien	  if (target_big_endian)
569789857Sobrien	    fixP->fx_where += 2;
569860484Sobrien	}
569989857Sobrien#endif /* defined (OBJ_XCOFF) || defined (OBJ_ELF) */
570060484Sobrien      else
570160484Sobrien	{
570260484Sobrien	  char *sfile;
570360484Sobrien	  unsigned int sline;
570460484Sobrien
570560484Sobrien	  /* Use expr_symbol_where to see if this is an expression
570689857Sobrien	     symbol.  */
570789857Sobrien	  if (expr_symbol_where (fixP->fx_addsy, &sfile, &sline))
570889857Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
570960484Sobrien			  _("unresolved expression that must be resolved"));
571060484Sobrien	  else
571189857Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
571289857Sobrien			  _("unsupported relocation against %s"),
571389857Sobrien			  S_GET_NAME (fixP->fx_addsy));
571489857Sobrien	  fixP->fx_done = 1;
571589857Sobrien	  return;
571660484Sobrien	}
571760484Sobrien    }
571860484Sobrien  else
571960484Sobrien    {
572060484Sobrien#ifdef OBJ_ELF
572189857Sobrien      ppc_elf_validate_fix (fixP, seg);
572260484Sobrien#endif
572389857Sobrien      switch (fixP->fx_r_type)
572460484Sobrien	{
572560484Sobrien	case BFD_RELOC_CTOR:
5726104834Sobrien	  if (ppc_obj64)
572789857Sobrien	    goto ctor64;
572889857Sobrien	  /* fall through */
572960484Sobrien
573089857Sobrien	case BFD_RELOC_32:
573189857Sobrien	  if (fixP->fx_pcrel)
573289857Sobrien	    fixP->fx_r_type = BFD_RELOC_32_PCREL;
573389857Sobrien	  /* fall through */
573489857Sobrien
573560484Sobrien	case BFD_RELOC_RVA:
573660484Sobrien	case BFD_RELOC_32_PCREL:
573760484Sobrien	case BFD_RELOC_PPC_EMB_NADDR32:
573889857Sobrien	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
573960484Sobrien			      value, 4);
574060484Sobrien	  break;
574160484Sobrien
574277298Sobrien	case BFD_RELOC_64:
574389857Sobrien	ctor64:
574489857Sobrien	  if (fixP->fx_pcrel)
574589857Sobrien	    fixP->fx_r_type = BFD_RELOC_64_PCREL;
574689857Sobrien	  /* fall through */
574789857Sobrien
574877298Sobrien	case BFD_RELOC_64_PCREL:
574989857Sobrien	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
575077298Sobrien			      value, 8);
575177298Sobrien	  break;
575289857Sobrien
575360484Sobrien	case BFD_RELOC_GPREL16:
575460484Sobrien	case BFD_RELOC_16_GOT_PCREL:
575560484Sobrien	case BFD_RELOC_16_GOTOFF:
575660484Sobrien	case BFD_RELOC_LO16_GOTOFF:
575760484Sobrien	case BFD_RELOC_HI16_GOTOFF:
575860484Sobrien	case BFD_RELOC_HI16_S_GOTOFF:
575999461Sobrien	case BFD_RELOC_16_BASEREL:
576060484Sobrien	case BFD_RELOC_LO16_BASEREL:
576160484Sobrien	case BFD_RELOC_HI16_BASEREL:
576260484Sobrien	case BFD_RELOC_HI16_S_BASEREL:
576360484Sobrien	case BFD_RELOC_PPC_EMB_NADDR16:
576460484Sobrien	case BFD_RELOC_PPC_EMB_NADDR16_LO:
576560484Sobrien	case BFD_RELOC_PPC_EMB_NADDR16_HI:
576660484Sobrien	case BFD_RELOC_PPC_EMB_NADDR16_HA:
576760484Sobrien	case BFD_RELOC_PPC_EMB_SDAI16:
576860484Sobrien	case BFD_RELOC_PPC_EMB_SDA2REL:
576960484Sobrien	case BFD_RELOC_PPC_EMB_SDA2I16:
577060484Sobrien	case BFD_RELOC_PPC_EMB_RELSEC16:
577160484Sobrien	case BFD_RELOC_PPC_EMB_RELST_LO:
577260484Sobrien	case BFD_RELOC_PPC_EMB_RELST_HI:
577360484Sobrien	case BFD_RELOC_PPC_EMB_RELST_HA:
577460484Sobrien	case BFD_RELOC_PPC_EMB_RELSDA:
577560484Sobrien	case BFD_RELOC_PPC_TOC16:
577689857Sobrien#ifdef OBJ_ELF
577789857Sobrien	case BFD_RELOC_PPC64_TOC16_LO:
577889857Sobrien	case BFD_RELOC_PPC64_TOC16_HI:
577989857Sobrien	case BFD_RELOC_PPC64_TOC16_HA:
578089857Sobrien#endif
578189857Sobrien	  if (fixP->fx_pcrel)
578260484Sobrien	    {
578389857Sobrien	      if (fixP->fx_addsy != NULL)
578489857Sobrien		as_bad_where (fixP->fx_file, fixP->fx_line,
578560484Sobrien			      _("cannot emit PC relative %s relocation against %s"),
578689857Sobrien			      bfd_get_reloc_code_name (fixP->fx_r_type),
578789857Sobrien			      S_GET_NAME (fixP->fx_addsy));
578860484Sobrien	      else
578989857Sobrien		as_bad_where (fixP->fx_file, fixP->fx_line,
579060484Sobrien			      _("cannot emit PC relative %s relocation"),
579189857Sobrien			      bfd_get_reloc_code_name (fixP->fx_r_type));
579260484Sobrien	    }
579360484Sobrien
579489857Sobrien	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
579560484Sobrien			      value, 2);
579660484Sobrien	  break;
579760484Sobrien
5798218822Sdim	case BFD_RELOC_16:
5799218822Sdim	  if (fixP->fx_pcrel)
5800218822Sdim	    fixP->fx_r_type = BFD_RELOC_16_PCREL;
5801218822Sdim	  /* fall through */
5802218822Sdim
5803218822Sdim	case BFD_RELOC_16_PCREL:
5804218822Sdim	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
5805218822Sdim			      value, 2);
5806218822Sdim	  break;
5807218822Sdim
5808218822Sdim	case BFD_RELOC_LO16:
5809218822Sdim	  if (fixP->fx_pcrel)
5810218822Sdim	    fixP->fx_r_type = BFD_RELOC_LO16_PCREL;
5811218822Sdim	  /* fall through */
5812218822Sdim
5813218822Sdim	case BFD_RELOC_LO16_PCREL:
5814218822Sdim	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
5815218822Sdim			      value, 2);
5816218822Sdim	  break;
5817218822Sdim
581860484Sobrien	  /* This case happens when you write, for example,
581960484Sobrien	     lis %r3,(L1-L2)@ha
582060484Sobrien	     where L1 and L2 are defined later.  */
582160484Sobrien	case BFD_RELOC_HI16:
582289857Sobrien	  if (fixP->fx_pcrel)
5823218822Sdim	    fixP->fx_r_type = BFD_RELOC_HI16_PCREL;
5824218822Sdim	  /* fall through */
5825218822Sdim
5826218822Sdim	case BFD_RELOC_HI16_PCREL:
582789857Sobrien	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
582889857Sobrien			      PPC_HI (value), 2);
582960484Sobrien	  break;
583089857Sobrien
583160484Sobrien	case BFD_RELOC_HI16_S:
583289857Sobrien	  if (fixP->fx_pcrel)
5833218822Sdim	    fixP->fx_r_type = BFD_RELOC_HI16_S_PCREL;
5834218822Sdim	  /* fall through */
5835218822Sdim
5836218822Sdim	case BFD_RELOC_HI16_S_PCREL:
583789857Sobrien	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
583889857Sobrien			      PPC_HA (value), 2);
583960484Sobrien	  break;
584060484Sobrien
584189857Sobrien#ifdef OBJ_ELF
584289857Sobrien	case BFD_RELOC_PPC64_HIGHER:
584389857Sobrien	  if (fixP->fx_pcrel)
584489857Sobrien	    abort ();
584589857Sobrien	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
584689857Sobrien			      PPC_HIGHER (value), 2);
584789857Sobrien	  break;
584889857Sobrien
584989857Sobrien	case BFD_RELOC_PPC64_HIGHER_S:
585089857Sobrien	  if (fixP->fx_pcrel)
585189857Sobrien	    abort ();
585289857Sobrien	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
585389857Sobrien			      PPC_HIGHERA (value), 2);
585489857Sobrien	  break;
585589857Sobrien
585689857Sobrien	case BFD_RELOC_PPC64_HIGHEST:
585789857Sobrien	  if (fixP->fx_pcrel)
585889857Sobrien	    abort ();
585989857Sobrien	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
586089857Sobrien			      PPC_HIGHEST (value), 2);
586189857Sobrien	  break;
586289857Sobrien
586389857Sobrien	case BFD_RELOC_PPC64_HIGHEST_S:
586489857Sobrien	  if (fixP->fx_pcrel)
586589857Sobrien	    abort ();
586689857Sobrien	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
586789857Sobrien			      PPC_HIGHESTA (value), 2);
586889857Sobrien	  break;
586989857Sobrien
587089857Sobrien	case BFD_RELOC_PPC64_ADDR16_DS:
587189857Sobrien	case BFD_RELOC_PPC64_ADDR16_LO_DS:
587289857Sobrien	case BFD_RELOC_PPC64_GOT16_DS:
587389857Sobrien	case BFD_RELOC_PPC64_GOT16_LO_DS:
587489857Sobrien	case BFD_RELOC_PPC64_PLT16_LO_DS:
587589857Sobrien	case BFD_RELOC_PPC64_SECTOFF_DS:
587689857Sobrien	case BFD_RELOC_PPC64_SECTOFF_LO_DS:
587789857Sobrien	case BFD_RELOC_PPC64_TOC16_DS:
587889857Sobrien	case BFD_RELOC_PPC64_TOC16_LO_DS:
587989857Sobrien	case BFD_RELOC_PPC64_PLTGOT16_DS:
588089857Sobrien	case BFD_RELOC_PPC64_PLTGOT16_LO_DS:
588189857Sobrien	  if (fixP->fx_pcrel)
588289857Sobrien	    abort ();
588389857Sobrien	  {
5884218822Sdim	    char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
5885130561Sobrien	    unsigned long val, mask;
588689857Sobrien
588789857Sobrien	    if (target_big_endian)
5888130561Sobrien	      val = bfd_getb32 (where - 2);
588989857Sobrien	    else
5890130561Sobrien	      val = bfd_getl32 (where);
5891130561Sobrien	    mask = 0xfffc;
5892130561Sobrien	    /* lq insns reserve the four lsbs.  */
5893130561Sobrien	    if ((ppc_cpu & PPC_OPCODE_POWER4) != 0
5894130561Sobrien		&& (val & (0x3f << 26)) == (56u << 26))
5895130561Sobrien	      mask = 0xfff0;
5896130561Sobrien	    val |= value & mask;
589789857Sobrien	    if (target_big_endian)
589889857Sobrien	      bfd_putb16 ((bfd_vma) val, where);
589989857Sobrien	    else
590089857Sobrien	      bfd_putl16 ((bfd_vma) val, where);
590189857Sobrien	  }
590289857Sobrien	  break;
5903130561Sobrien
5904130561Sobrien	case BFD_RELOC_PPC_B16_BRTAKEN:
5905130561Sobrien	case BFD_RELOC_PPC_B16_BRNTAKEN:
5906130561Sobrien	case BFD_RELOC_PPC_BA16_BRTAKEN:
5907130561Sobrien	case BFD_RELOC_PPC_BA16_BRNTAKEN:
5908130561Sobrien	  break;
5909130561Sobrien
5910130561Sobrien	case BFD_RELOC_PPC_TLS:
5911218822Sdim	  break;
5912218822Sdim
5913130561Sobrien	case BFD_RELOC_PPC_DTPMOD:
5914130561Sobrien	case BFD_RELOC_PPC_TPREL16:
5915130561Sobrien	case BFD_RELOC_PPC_TPREL16_LO:
5916130561Sobrien	case BFD_RELOC_PPC_TPREL16_HI:
5917130561Sobrien	case BFD_RELOC_PPC_TPREL16_HA:
5918130561Sobrien	case BFD_RELOC_PPC_TPREL:
5919130561Sobrien	case BFD_RELOC_PPC_DTPREL16:
5920130561Sobrien	case BFD_RELOC_PPC_DTPREL16_LO:
5921130561Sobrien	case BFD_RELOC_PPC_DTPREL16_HI:
5922130561Sobrien	case BFD_RELOC_PPC_DTPREL16_HA:
5923130561Sobrien	case BFD_RELOC_PPC_DTPREL:
5924130561Sobrien	case BFD_RELOC_PPC_GOT_TLSGD16:
5925130561Sobrien	case BFD_RELOC_PPC_GOT_TLSGD16_LO:
5926130561Sobrien	case BFD_RELOC_PPC_GOT_TLSGD16_HI:
5927130561Sobrien	case BFD_RELOC_PPC_GOT_TLSGD16_HA:
5928130561Sobrien	case BFD_RELOC_PPC_GOT_TLSLD16:
5929130561Sobrien	case BFD_RELOC_PPC_GOT_TLSLD16_LO:
5930130561Sobrien	case BFD_RELOC_PPC_GOT_TLSLD16_HI:
5931130561Sobrien	case BFD_RELOC_PPC_GOT_TLSLD16_HA:
5932130561Sobrien	case BFD_RELOC_PPC_GOT_TPREL16:
5933130561Sobrien	case BFD_RELOC_PPC_GOT_TPREL16_LO:
5934130561Sobrien	case BFD_RELOC_PPC_GOT_TPREL16_HI:
5935130561Sobrien	case BFD_RELOC_PPC_GOT_TPREL16_HA:
5936130561Sobrien	case BFD_RELOC_PPC_GOT_DTPREL16:
5937130561Sobrien	case BFD_RELOC_PPC_GOT_DTPREL16_LO:
5938130561Sobrien	case BFD_RELOC_PPC_GOT_DTPREL16_HI:
5939130561Sobrien	case BFD_RELOC_PPC_GOT_DTPREL16_HA:
5940130561Sobrien	case BFD_RELOC_PPC64_TPREL16_DS:
5941130561Sobrien	case BFD_RELOC_PPC64_TPREL16_LO_DS:
5942130561Sobrien	case BFD_RELOC_PPC64_TPREL16_HIGHER:
5943130561Sobrien	case BFD_RELOC_PPC64_TPREL16_HIGHERA:
5944130561Sobrien	case BFD_RELOC_PPC64_TPREL16_HIGHEST:
5945130561Sobrien	case BFD_RELOC_PPC64_TPREL16_HIGHESTA:
5946130561Sobrien	case BFD_RELOC_PPC64_DTPREL16_DS:
5947130561Sobrien	case BFD_RELOC_PPC64_DTPREL16_LO_DS:
5948130561Sobrien	case BFD_RELOC_PPC64_DTPREL16_HIGHER:
5949130561Sobrien	case BFD_RELOC_PPC64_DTPREL16_HIGHERA:
5950130561Sobrien	case BFD_RELOC_PPC64_DTPREL16_HIGHEST:
5951130561Sobrien	case BFD_RELOC_PPC64_DTPREL16_HIGHESTA:
5952218822Sdim	  S_SET_THREAD_LOCAL (fixP->fx_addsy);
5953130561Sobrien	  break;
595489857Sobrien#endif
595560484Sobrien	  /* Because SDA21 modifies the register field, the size is set to 4
595689857Sobrien	     bytes, rather than 2, so offset it here appropriately.  */
595760484Sobrien	case BFD_RELOC_PPC_EMB_SDA21:
595889857Sobrien	  if (fixP->fx_pcrel)
595960484Sobrien	    abort ();
596060484Sobrien
596189857Sobrien	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where
596260484Sobrien			      + ((target_big_endian) ? 2 : 0),
596360484Sobrien			      value, 2);
596460484Sobrien	  break;
596560484Sobrien
596660484Sobrien	case BFD_RELOC_8:
596789857Sobrien	  if (fixP->fx_pcrel)
5968130561Sobrien	    {
5969130561Sobrien	      /* This can occur if there is a bug in the input assembler, eg:
5970130561Sobrien		 ".byte <undefined_symbol> - ."  */
5971130561Sobrien	      if (fixP->fx_addsy)
5972130561Sobrien		as_bad (_("Unable to handle reference to symbol %s"),
5973130561Sobrien			S_GET_NAME (fixP->fx_addsy));
5974130561Sobrien	      else
5975130561Sobrien		as_bad (_("Unable to resolve expression"));
5976130561Sobrien	      fixP->fx_done = 1;
5977130561Sobrien	    }
5978130561Sobrien	  else
5979130561Sobrien	    md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
5980130561Sobrien				value, 1);
598160484Sobrien	  break;
598260484Sobrien
598360484Sobrien	case BFD_RELOC_24_PLT_PCREL:
598460484Sobrien	case BFD_RELOC_PPC_LOCAL24PC:
598589857Sobrien	  if (!fixP->fx_pcrel && !fixP->fx_done)
598660484Sobrien	    abort ();
598760484Sobrien
598889857Sobrien	  if (fixP->fx_done)
598989857Sobrien	    {
599089857Sobrien	      char *where;
599189857Sobrien	      unsigned long insn;
599277298Sobrien
599389857Sobrien	      /* Fetch the instruction, insert the fully resolved operand
599489857Sobrien		 value, and stuff the instruction back again.  */
599589857Sobrien	      where = fixP->fx_frag->fr_literal + fixP->fx_where;
599689857Sobrien	      if (target_big_endian)
599789857Sobrien		insn = bfd_getb32 ((unsigned char *) where);
599889857Sobrien	      else
599989857Sobrien		insn = bfd_getl32 ((unsigned char *) where);
600089857Sobrien	      if ((value & 3) != 0)
600189857Sobrien		as_bad_where (fixP->fx_file, fixP->fx_line,
600289857Sobrien			      _("must branch to an address a multiple of 4"));
600389857Sobrien	      if ((offsetT) value < -0x40000000
600489857Sobrien		  || (offsetT) value >= 0x40000000)
600589857Sobrien		as_bad_where (fixP->fx_file, fixP->fx_line,
600689857Sobrien			      _("@local or @plt branch destination is too far away, %ld bytes"),
600789857Sobrien			      (long) value);
600889857Sobrien	      insn = insn | (value & 0x03fffffc);
600989857Sobrien	      if (target_big_endian)
601089857Sobrien		bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
601189857Sobrien	      else
601289857Sobrien		bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
601389857Sobrien	    }
601460484Sobrien	  break;
601560484Sobrien
601660484Sobrien	case BFD_RELOC_VTABLE_INHERIT:
601789857Sobrien	  fixP->fx_done = 0;
601889857Sobrien	  if (fixP->fx_addsy
601989857Sobrien	      && !S_IS_DEFINED (fixP->fx_addsy)
602089857Sobrien	      && !S_IS_WEAK (fixP->fx_addsy))
602189857Sobrien	    S_SET_WEAK (fixP->fx_addsy);
602260484Sobrien	  break;
602360484Sobrien
602460484Sobrien	case BFD_RELOC_VTABLE_ENTRY:
602589857Sobrien	  fixP->fx_done = 0;
602660484Sobrien	  break;
602760484Sobrien
602889857Sobrien#ifdef OBJ_ELF
602989857Sobrien	  /* Generated by reference to `sym@tocbase'.  The sym is
603089857Sobrien	     ignored by the linker.  */
603189857Sobrien	case BFD_RELOC_PPC64_TOC:
603289857Sobrien	  fixP->fx_done = 0;
603389857Sobrien	  break;
603489857Sobrien#endif
603560484Sobrien	default:
603677298Sobrien	  fprintf (stderr,
603789857Sobrien		   _("Gas failure, reloc value %d\n"), fixP->fx_r_type);
603889857Sobrien	  fflush (stderr);
603960484Sobrien	  abort ();
604060484Sobrien	}
604160484Sobrien    }
604260484Sobrien
604360484Sobrien#ifdef OBJ_ELF
604489857Sobrien  fixP->fx_addnumber = value;
6045218822Sdim
6046218822Sdim  /* PowerPC uses RELA relocs, ie. the reloc addend is stored separately
6047218822Sdim     from the section contents.  If we are going to be emitting a reloc
6048218822Sdim     then the section contents are immaterial, so don't warn if they
6049218822Sdim     happen to overflow.  Leave such warnings to ld.  */
6050218822Sdim  if (!fixP->fx_done)
6051218822Sdim    fixP->fx_no_overflow = 1;
605260484Sobrien#else
605389857Sobrien  if (fixP->fx_r_type != BFD_RELOC_PPC_TOC16)
605489857Sobrien    fixP->fx_addnumber = 0;
605560484Sobrien  else
605660484Sobrien    {
605760484Sobrien#ifdef TE_PE
605889857Sobrien      fixP->fx_addnumber = 0;
605960484Sobrien#else
606060484Sobrien      /* We want to use the offset within the data segment of the
606160484Sobrien	 symbol, not the actual VMA of the symbol.  */
606289857Sobrien      fixP->fx_addnumber =
606389857Sobrien	- bfd_get_section_vma (stdoutput, S_GET_SEGMENT (fixP->fx_addsy));
606460484Sobrien#endif
606560484Sobrien    }
606660484Sobrien#endif
606760484Sobrien}
606860484Sobrien
606960484Sobrien/* Generate a reloc for a fixup.  */
607060484Sobrien
607160484Sobrienarelent *
6072218822Sdimtc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
607360484Sobrien{
607460484Sobrien  arelent *reloc;
607560484Sobrien
607660484Sobrien  reloc = (arelent *) xmalloc (sizeof (arelent));
607760484Sobrien
607860484Sobrien  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
607960484Sobrien  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
608060484Sobrien  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
608160484Sobrien  reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
608260484Sobrien  if (reloc->howto == (reloc_howto_type *) NULL)
608360484Sobrien    {
608460484Sobrien      as_bad_where (fixp->fx_file, fixp->fx_line,
608589857Sobrien		    _("reloc %d not supported by object file format"),
608689857Sobrien		    (int) fixp->fx_r_type);
608760484Sobrien      return NULL;
608860484Sobrien    }
608960484Sobrien  reloc->addend = fixp->fx_addnumber;
609060484Sobrien
609160484Sobrien  return reloc;
609260484Sobrien}
6093130561Sobrien
6094130561Sobrienvoid
6095218822Sdimppc_cfi_frame_initial_instructions (void)
6096130561Sobrien{
6097130561Sobrien  cfi_add_CFA_def_cfa (1, 0);
6098130561Sobrien}
6099130561Sobrien
6100130561Sobrienint
6101218822Sdimtc_ppc_regname_to_dw2regnum (char *regname)
6102130561Sobrien{
6103130561Sobrien  unsigned int regnum = -1;
6104130561Sobrien  unsigned int i;
6105130561Sobrien  const char *p;
6106130561Sobrien  char *q;
6107130561Sobrien  static struct { char *name; int dw2regnum; } regnames[] =
6108130561Sobrien    {
6109130561Sobrien      { "sp", 1 }, { "r.sp", 1 }, { "rtoc", 2 }, { "r.toc", 2 },
6110130561Sobrien      { "mq", 64 }, { "lr", 65 }, { "ctr", 66 }, { "ap", 67 },
6111218822Sdim      { "cr", 70 }, { "xer", 76 }, { "vrsave", 109 }, { "vscr", 110 },
6112130561Sobrien      { "spe_acc", 111 }, { "spefscr", 112 }
6113130561Sobrien    };
6114130561Sobrien
6115130561Sobrien  for (i = 0; i < ARRAY_SIZE (regnames); ++i)
6116130561Sobrien    if (strcmp (regnames[i].name, regname) == 0)
6117130561Sobrien      return regnames[i].dw2regnum;
6118130561Sobrien
6119130561Sobrien  if (regname[0] == 'r' || regname[0] == 'f' || regname[0] == 'v')
6120130561Sobrien    {
6121130561Sobrien      p = regname + 1 + (regname[1] == '.');
6122130561Sobrien      regnum = strtoul (p, &q, 10);
6123130561Sobrien      if (p == q || *q || regnum >= 32)
6124130561Sobrien	return -1;
6125130561Sobrien      if (regname[0] == 'f')
6126130561Sobrien	regnum += 32;
6127130561Sobrien      else if (regname[0] == 'v')
6128130561Sobrien	regnum += 77;
6129130561Sobrien    }
6130130561Sobrien  else if (regname[0] == 'c' && regname[1] == 'r')
6131130561Sobrien    {
6132130561Sobrien      p = regname + 2 + (regname[2] == '.');
6133130561Sobrien      if (p[0] < '0' || p[0] > '7' || p[1])
6134130561Sobrien	return -1;
6135130561Sobrien      regnum = p[0] - '0' + 68;
6136130561Sobrien    }
6137130561Sobrien  return regnum;
6138130561Sobrien}
6139