OpenCores
URL https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [gnu/] [binutils/] [gas/] [config/] [tc-ppc.c] - Diff between revs 160 and 166

Only display areas with differences | Details | Blame | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.