* config/tc-ppc.c (md_apply_fix3): Allow BRTAKEN, BRNTAKEN relocs.
[deliverable/binutils-gdb.git] / gas / config / tc-ppc.c
index 6be2b437ffe1ea3c22dedfa3f66d21cd2cd78858..c4c32d1aeab00689d296b4954e3c0431d1517ae3 100644 (file)
@@ -1,5 +1,5 @@
 /* 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
+   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
    Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
    Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
@@ -47,9 +47,9 @@ static int set_target_endian = 0;
 /* Whether to use user friendly register names.  */
 #ifndef TARGET_REG_NAMES_P
 #ifdef TE_PE
 /* Whether to use user friendly register names.  */
 #ifndef TARGET_REG_NAMES_P
 #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
 
@@ -68,14 +68,14 @@ static int set_target_endian = 0;
 #define PPC_HA(v) PPC_HI ((v) + 0x8000)
 
 /* #higher(value) denotes bits 32 through 47 of the indicated value.  */
 #define PPC_HA(v) PPC_HI ((v) + 0x8000)
 
 /* #higher(value) denotes bits 32 through 47 of the indicated value.  */
-#define PPC_HIGHER(v) (((v) >> 32) & 0xffff)
+#define PPC_HIGHER(v) (((v) >> 16 >> 16) & 0xffff)
 
 /* #highera(value) denotes bits 32 through 47 of the indicated value,
    compensating for #lo() being treated as a signed number.  */
 #define PPC_HIGHERA(v) PPC_HIGHER ((v) + 0x8000)
 
 /* #highest(value) denotes bits 48 through 63 of the indicated value.  */
 
 /* #highera(value) denotes bits 32 through 47 of the indicated value,
    compensating for #lo() being treated as a signed number.  */
 #define PPC_HIGHERA(v) PPC_HIGHER ((v) + 0x8000)
 
 /* #highest(value) denotes bits 48 through 63 of the indicated value.  */
-#define PPC_HIGHEST(v) (((v) >> 48) & 0xffff)
+#define PPC_HIGHEST(v) (((v) >> 24 >> 24) & 0xffff)
 
 /* #highesta(value) denotes bits 48 through 63 of the indicated value,
    compensating for #lo being treated as a signed number.  */
 
 /* #highesta(value) denotes bits 48 through 63 of the indicated value,
    compensating for #lo being treated as a signed number.  */
@@ -83,9 +83,9 @@ static int set_target_endian = 0;
 
 #define SEX16(val) ((((val) & 0xffff) ^ 0x8000) - 0x8000)
 
 
 #define SEX16(val) ((((val) & 0xffff) ^ 0x8000) - 0x8000)
 
-static boolean reg_names_p = TARGET_REG_NAMES_P;
+static bfd_boolean reg_names_p = TARGET_REG_NAMES_P;
 
 
-static boolean register_name PARAMS ((expressionS *));
+static bfd_boolean register_name PARAMS ((expressionS *));
 static void ppc_set_cpu PARAMS ((void));
 static unsigned long ppc_insert_operand
   PARAMS ((unsigned long insn, const struct powerpc_operand *operand,
 static void ppc_set_cpu PARAMS ((void));
 static unsigned long ppc_insert_operand
   PARAMS ((unsigned long insn, const struct powerpc_operand *operand,
@@ -130,7 +130,7 @@ static void ppc_elf_cons PARAMS ((int));
 static void ppc_elf_rdata PARAMS ((int));
 static void ppc_elf_lcomm PARAMS ((int));
 static void ppc_elf_validate_fix PARAMS ((fixS *, segT));
 static void ppc_elf_rdata PARAMS ((int));
 static void ppc_elf_lcomm PARAMS ((int));
 static void ppc_elf_validate_fix PARAMS ((fixS *, segT));
-static void ppc_apuinfo_section_add PARAMS((unsigned int apu, unsigned int version));
+static void ppc_apuinfo_section_add PARAMS ((unsigned int apu, unsigned int version));
 #endif
 
 #ifdef TE_PE
 #endif
 
 #ifdef TE_PE
@@ -182,6 +182,10 @@ const char EXP_CHARS[] = "eE";
 /* Characters which mean that a number is a floating point constant,
    as in 0d1.0.  */
 const char FLT_CHARS[] = "dD";
 /* Characters which mean that a number is a floating point constant,
    as in 0d1.0.  */
 const char FLT_CHARS[] = "dD";
+
+/* '+' and '-' can be used as postfix predicate predictors for conditional 
+   branches.  So they need to be accepted as symbol characters.  */
+const char ppc_symbol_chars[] = "+-";
 \f
 /* The target specific pseudo-ops which we support.  */
 
 \f
 /* The target specific pseudo-ops which we support.  */
 
@@ -233,8 +237,6 @@ const pseudo_typeS md_pseudo_table[] =
   { "rdata",   ppc_elf_rdata,  0 },
   { "rodata",  ppc_elf_rdata,  0 },
   { "lcomm",   ppc_elf_lcomm,  0 },
   { "rdata",   ppc_elf_rdata,  0 },
   { "rodata",  ppc_elf_rdata,  0 },
   { "lcomm",   ppc_elf_lcomm,  0 },
-  { "file",    (void (*) PARAMS ((int))) dwarf2_directive_file, 0 },
-  { "loc",     dwarf2_directive_loc, 0 },
 #endif
 
 #ifdef TE_PE
 #endif
 
 #ifdef TE_PE
@@ -603,7 +605,7 @@ reg_name_search (regs, regcount, name)
  *      original state.
  */
 
  *      original state.
  */
 
-static boolean
+static bfd_boolean
 register_name (expressionP)
      expressionS *expressionP;
 {
 register_name (expressionP)
      expressionS *expressionP;
 {
@@ -618,7 +620,7 @@ register_name (expressionP)
     name = ++input_line_pointer;
 
   else if (!reg_names_p || !ISALPHA (name[0]))
     name = ++input_line_pointer;
 
   else if (!reg_names_p || !ISALPHA (name[0]))
-    return false;
+    return FALSE;
 
   c = get_symbol_end ();
   reg_number = reg_name_search (pre_defined_registers, REG_NAME_CNT, name);
 
   c = get_symbol_end ();
   reg_number = reg_name_search (pre_defined_registers, REG_NAME_CNT, name);
@@ -635,12 +637,12 @@ register_name (expressionP)
       /* Make the rest nice.  */
       expressionP->X_add_symbol = NULL;
       expressionP->X_op_symbol = NULL;
       /* Make the rest nice.  */
       expressionP->X_add_symbol = NULL;
       expressionP->X_op_symbol = NULL;
-      return true;
+      return TRUE;
     }
 
   /* Reset the line as if we had not done anything.  */
   input_line_pointer = start;
     }
 
   /* Reset the line as if we had not done anything.  */
   input_line_pointer = start;
-  return false;
+  return FALSE;
 }
 \f
 /* This function is called for each symbol seen in an expression.  It
 }
 \f
 /* This function is called for each symbol seen in an expression.  It
@@ -648,7 +650,7 @@ register_name (expressionP)
    to use for condition codes.  */
 
 /* Whether to do the special parsing.  */
    to use for condition codes.  */
 
 /* Whether to do the special parsing.  */
-static boolean cr_operand;
+static bfd_boolean cr_operand;
 
 /* Names to recognize in a condition code.  This table is sorted.  */
 static const struct pd_reg cr_names[] =
 
 /* Names to recognize in a condition code.  This table is sorted.  */
 static const struct pd_reg cr_names[] =
@@ -716,12 +718,12 @@ static flagword ppc_flags = 0;
 
 /* Whether this is Solaris or not.  */
 #ifdef TARGET_SOLARIS_COMMENT
 
 /* Whether this is Solaris or not.  */
 #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 boolean msolaris = SOLARIS_P;
+static bfd_boolean msolaris = SOLARIS_P;
 #endif
 
 #ifdef OBJ_XCOFF
 #endif
 
 #ifdef OBJ_XCOFF
@@ -796,8 +798,8 @@ symbolS *GOT_symbol;                /* Pre-defined "_GLOBAL_OFFSET_TABLE" */
 #define PPC_APUINFO_EFS                0x101
 #define PPC_APUINFO_BRLOCK     0x102
 
 #define PPC_APUINFO_EFS                0x101
 #define PPC_APUINFO_BRLOCK     0x102
 
-/* 
- * We keep a list of APUinfo 
+/*
+ * We keep a list of APUinfo
  */
 unsigned long *ppc_apuinfo_list;
 unsigned int ppc_apuinfo_num;
  */
 unsigned long *ppc_apuinfo_list;
 unsigned int ppc_apuinfo_num;
@@ -867,7 +869,13 @@ md_parse_option (c, arg)
       /* a64 and a32 determine whether to use XCOFF64 or XCOFF32.  */
     case 'a':
       if (strcmp (arg, "64") == 0)
       /* a64 and a32 determine whether to use XCOFF64 or XCOFF32.  */
     case 'a':
       if (strcmp (arg, "64") == 0)
-       ppc_obj64 = 1;
+       {
+#ifdef BFD64
+         ppc_obj64 = 1;
+#else
+         as_fatal (_("%s unsupported"), "-a64");
+#endif
+       }
       else if (strcmp (arg, "32") == 0)
        ppc_obj64 = 0;
       else
       else if (strcmp (arg, "32") == 0)
        ppc_obj64 = 0;
       else
@@ -885,8 +893,8 @@ md_parse_option (c, arg)
       /* -m601 means to assemble for the PowerPC 601, which includes
         instructions that are holdovers from the Power.  */
       else if (strcmp (arg, "601") == 0)
       /* -m601 means to assemble for the PowerPC 601, which includes
         instructions that are holdovers from the Power.  */
       else if (strcmp (arg, "601") == 0)
-       ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
-                 | PPC_OPCODE_601 | PPC_OPCODE_32;
+       ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
+                  | PPC_OPCODE_601 | PPC_OPCODE_32);
       /* -mppc, -mppc32, -m603, and -m604 mean to assemble for the
         PowerPC 603/604.  */
       else if (strcmp (arg, "ppc") == 0
       /* -mppc, -mppc32, -m603, and -m604 mean to assemble for the
         PowerPC 603/604.  */
       else if (strcmp (arg, "ppc") == 0
@@ -896,28 +904,29 @@ md_parse_option (c, arg)
        ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32;
       /* -m403 and -m405 mean to assemble for the PowerPC 403/405.  */
       else if (strcmp (arg, "403") == 0
        ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32;
       /* -m403 and -m405 mean to assemble for the PowerPC 403/405.  */
       else if (strcmp (arg, "403") == 0
-               || strcmp (arg, "405") == 0)
-       ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
-                  | PPC_OPCODE_403 | PPC_OPCODE_32;
+              || strcmp (arg, "405") == 0)
+       ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
+                  | PPC_OPCODE_403 | PPC_OPCODE_32);
       else if (strcmp (arg, "7400") == 0
       else if (strcmp (arg, "7400") == 0
-               || strcmp (arg, "7410") == 0
-               || strcmp (arg, "7450") == 0
-               || strcmp (arg, "7455") == 0)
-       ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
-                  | PPC_OPCODE_ALTIVEC | PPC_OPCODE_32;
+              || strcmp (arg, "7410") == 0
+              || strcmp (arg, "7450") == 0
+              || strcmp (arg, "7455") == 0)
+       ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
+                  | PPC_OPCODE_ALTIVEC | PPC_OPCODE_32);
       else if (strcmp (arg, "altivec") == 0)
       else if (strcmp (arg, "altivec") == 0)
-        {
-          if (ppc_cpu == 0)
-            ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_ALTIVEC;
-          else
-            ppc_cpu |= PPC_OPCODE_ALTIVEC;
-        }
+       {
+         if (ppc_cpu == 0)
+           ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_ALTIVEC;
+         else
+           ppc_cpu |= PPC_OPCODE_ALTIVEC;
+       }
       else if (strcmp (arg, "e500") == 0 || strcmp (arg, "e500x2") == 0)
        {
       else if (strcmp (arg, "e500") == 0 || strcmp (arg, "e500x2") == 0)
        {
-         ppc_cpu = PPC_OPCODE_PPC  | PPC_OPCODE_BOOKE    | PPC_OPCODE_SPE
-                 | PPC_OPCODE_ISEL | PPC_OPCODE_EFS      | PPC_OPCODE_BRLOCK
-                 | PPC_OPCODE_PMR  | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI;
-        }
+         ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_SPE
+                    | PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
+                    | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK
+                    | PPC_OPCODE_RFMCI);
+       }
       else if (strcmp (arg, "spe") == 0)
        {
          if (ppc_cpu == 0)
       else if (strcmp (arg, "spe") == 0)
        {
          if (ppc_cpu == 0)
@@ -933,8 +942,8 @@ md_parse_option (c, arg)
        }
       else if (strcmp (arg, "ppc64bridge") == 0)
        {
        }
       else if (strcmp (arg, "ppc64bridge") == 0)
        {
-         ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
-                    | PPC_OPCODE_64_BRIDGE | PPC_OPCODE_64;
+         ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
+                    | PPC_OPCODE_64_BRIDGE | PPC_OPCODE_64);
        }
       /* -mbooke/-mbooke32 mean enable 32-bit BookE support.  */
       else if (strcmp (arg, "booke") == 0 || strcmp (arg, "booke32") == 0)
        }
       /* -mbooke/-mbooke32 mean enable 32-bit BookE support.  */
       else if (strcmp (arg, "booke") == 0 || strcmp (arg, "booke32") == 0)
@@ -944,13 +953,13 @@ md_parse_option (c, arg)
       /* -mbooke64 means enable 64-bit BookE support.  */
       else if (strcmp (arg, "booke64") == 0)
        {
       /* -mbooke64 means enable 64-bit BookE support.  */
       else if (strcmp (arg, "booke64") == 0)
        {
-         ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_BOOKE |
-                   PPC_OPCODE_BOOKE64 | PPC_OPCODE_64;
+         ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE
+                    | PPC_OPCODE_BOOKE64 | PPC_OPCODE_64);
        }
       else if (strcmp (arg, "power4") == 0)
        {
        }
       else if (strcmp (arg, "power4") == 0)
        {
-         ppc_cpu = PPC_OPCODE_PPC| PPC_OPCODE_CLASSIC
-                    | PPC_OPCODE_64 | PPC_OPCODE_POWER4;
+         ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
+                    | PPC_OPCODE_64 | PPC_OPCODE_POWER4);
        }
       /* -mcom means assemble for the common intersection between Power
         and PowerPC.  At present, we just allow the union, rather
        }
       /* -mcom means assemble for the common intersection between Power
         and PowerPC.  At present, we just allow the union, rather
@@ -962,10 +971,10 @@ md_parse_option (c, arg)
        ppc_cpu = PPC_OPCODE_ANY | PPC_OPCODE_32;
 
       else if (strcmp (arg, "regnames") == 0)
        ppc_cpu = PPC_OPCODE_ANY | PPC_OPCODE_32;
 
       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
       /* -mrelocatable/-mrelocatable-lib -- warn about initializations
 
 #ifdef OBJ_ELF
       /* -mrelocatable/-mrelocatable-lib -- warn about initializations
@@ -1002,13 +1011,13 @@ md_parse_option (c, arg)
 
       else if (strcmp (arg, "solaris") == 0)
        {
 
       else if (strcmp (arg, "solaris") == 0)
        {
-         msolaris = true;
+         msolaris = TRUE;
          ppc_comment_chars = ppc_solaris_comment_chars;
        }
 
       else if (strcmp (arg, "no-solaris") == 0)
        {
          ppc_comment_chars = ppc_solaris_comment_chars;
        }
 
       else if (strcmp (arg, "no-solaris") == 0)
        {
-         msolaris = false;
+         msolaris = FALSE;
          ppc_comment_chars = ppc_eabi_comment_chars;
        }
 #endif
          ppc_comment_chars = ppc_eabi_comment_chars;
        }
 #endif
@@ -1053,36 +1062,40 @@ md_show_usage (stream)
 {
   fprintf (stream, _("\
 PowerPC options:\n\
 {
   fprintf (stream, _("\
 PowerPC options:\n\
+-a32                   generate ELF32/XCOFF32\n\
+-a64                   generate ELF64/XCOFF64\n\
 -u                     ignored\n\
 -mpwrx, -mpwr2         generate code for POWER/2 (RIOS2)\n\
 -mpwr                  generate code for POWER (RIOS1)\n\
 -m601                  generate code for PowerPC 601\n\
 -mppc, -mppc32, -m603, -m604\n\
                        generate code for PowerPC 603/604\n\
 -u                     ignored\n\
 -mpwrx, -mpwr2         generate code for POWER/2 (RIOS2)\n\
 -mpwr                  generate code for POWER (RIOS1)\n\
 -m601                  generate code for PowerPC 601\n\
 -mppc, -mppc32, -m603, -m604\n\
                        generate code for PowerPC 603/604\n\
--m403, -m405            generate code for PowerPC 403/405\n\
+-m403, -m405           generate code for PowerPC 403/405\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"));
+  fprintf (stream, _("\
 -mppc64, -m620         generate code for PowerPC 620/625/630\n\
 -mppc64bridge          generate code for PowerPC 64, including bridge insns\n\
 -mbooke64              generate code for 64-bit PowerPC BookE\n\
 -mbooke, mbooke32      generate code for 32-bit PowerPC BookE\n\
 -mpower4               generate code for Power4 architecture\n\
 -mppc64, -m620         generate code for PowerPC 620/625/630\n\
 -mppc64bridge          generate code for PowerPC 64, including bridge insns\n\
 -mbooke64              generate code for 64-bit PowerPC BookE\n\
 -mbooke, mbooke32      generate code for 32-bit PowerPC BookE\n\
 -mpower4               generate code for Power4 architecture\n\
--maltivec              generate code for AltiVec\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\
--mregnames             Allow symbolic names for registers\n\
--mno-regnames          Do not allow symbolic names for registers\n"));
+-many                  generate code for any architecture (PWR/PWRX/PPC)\n"));
   fprintf (stream, _("\
   fprintf (stream, _("\
+-maltivec              generate code for AltiVec\n\
 -me500, -me500x2       generate code for Motorola e500 core complex\n\
 -me500, -me500x2       generate code for Motorola e500 core complex\n\
--mspe                  generate code for Motorola SPE instructions\n"));
+-mspe                  generate code for Motorola SPE instructions\n\
+-mregnames             Allow symbolic names for registers\n\
+-mno-regnames          Do not allow symbolic names for registers\n"));
 #ifdef OBJ_ELF
   fprintf (stream, _("\
 -mrelocatable          support for GCC's -mrelocatble option\n\
 -mrelocatable-lib      support for GCC's -mrelocatble-lib option\n\
 -memb                  set PPC_EMB bit in ELF flags\n\
 #ifdef OBJ_ELF
   fprintf (stream, _("\
 -mrelocatable          support for GCC's -mrelocatble option\n\
 -mrelocatable-lib      support for GCC's -mrelocatble-lib option\n\
 -memb                  set PPC_EMB bit in ELF flags\n\
--mlittle, -mlittle-endian\n\
+-mlittle, -mlittle-endian, -l, -le\n\
                        generate code for a little endian machine\n\
                        generate code for a little endian machine\n\
--mbig, -mbig-endian    generate code for a big endian machine\n\
+-mbig, -mbig-endian, -b, -be\n\
+                       generate code for a big endian machine\n\
 -msolaris              generate code for Solaris\n\
 -mno-solaris           do not generate code for Solaris\n\
 -V                     print assembler version number\n\
 -msolaris              generate code for Solaris\n\
 -mno-solaris           do not generate code for Solaris\n\
 -V                     print assembler version number\n\
@@ -1100,20 +1113,22 @@ ppc_set_cpu ()
 
   if (ppc_cpu == 0)
     {
 
   if (ppc_cpu == 0)
     {
-      if (strncmp (default_os, "aix", 3) == 0
-         && default_os[3] >= '4' && default_os[3] <= '9')
+      if (ppc_obj64)
+       ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64;
+      else if (strncmp (default_os, "aix", 3) == 0
+              && default_os[3] >= '4' && default_os[3] <= '9')
        ppc_cpu = PPC_OPCODE_COMMON | PPC_OPCODE_32;
       else if (strncmp (default_os, "aix3", 4) == 0)
        ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_32;
       else if (strcmp (default_cpu, "rs6000") == 0)
        ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_32;
       else if (strncmp (default_cpu, "powerpc", 7) == 0)
        ppc_cpu = PPC_OPCODE_COMMON | PPC_OPCODE_32;
       else if (strncmp (default_os, "aix3", 4) == 0)
        ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_32;
       else if (strcmp (default_cpu, "rs6000") == 0)
        ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_32;
       else if (strncmp (default_cpu, "powerpc", 7) == 0)
-        {
-          if (default_cpu[7] == '6' && default_cpu[8] == '4')
-            ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64;
-          else
-            ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32;
-        }
+       {
+         if (default_cpu[7] == '6' && default_cpu[8] == '4')
+           ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64;
+         else
+           ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32;
+       }
       else
        as_fatal (_("Unknown default cpu = %s, os = %s"),
                  default_cpu, default_os);
       else
        as_fatal (_("Unknown default cpu = %s, os = %s"),
                  default_cpu, default_os);
@@ -1147,7 +1162,12 @@ ppc_arch ()
 unsigned long
 ppc_mach ()
 {
 unsigned long
 ppc_mach ()
 {
-  return ppc_obj64 ? bfd_mach_ppc64 : bfd_mach_ppc;
+  if (ppc_obj64)
+    return bfd_mach_ppc64;
+  else if (ppc_arch () == bfd_arch_rs6000)
+    return bfd_mach_rs6k;
+  else
+    return bfd_mach_ppc;
 }
 
 extern char*
 }
 
 extern char*
@@ -1184,7 +1204,7 @@ md_begin ()
   const struct powerpc_opcode *op_end;
   const struct powerpc_macro *macro;
   const struct powerpc_macro *macro_end;
   const struct powerpc_opcode *op_end;
   const struct powerpc_macro *macro;
   const struct powerpc_macro *macro_end;
-  boolean dup_insn = false;
+  bfd_boolean dup_insn = FALSE;
 
   ppc_set_cpu ();
 
 
   ppc_set_cpu ();
 
@@ -1207,6 +1227,14 @@ md_begin ()
              || ((op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64))
                  == (ppc_cpu & (PPC_OPCODE_32 | PPC_OPCODE_64)))
              || (ppc_cpu & PPC_OPCODE_64_BRIDGE) != 0)
              || ((op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64))
                  == (ppc_cpu & (PPC_OPCODE_32 | PPC_OPCODE_64)))
              || (ppc_cpu & PPC_OPCODE_64_BRIDGE) != 0)
+         /* Certain instructions (eg: extsw) do not exist in the
+            32-bit BookE instruction set, but they do exist in the
+            64-bit BookE instruction set, and other PPC instruction
+            sets.  Check to see if the opcode has the BOOKE64 flag set.
+            If it does make sure that the target CPU is not the BookE32.  */
+         && ((op->flags & PPC_OPCODE_BOOKE64) == 0
+             || (ppc_cpu & PPC_OPCODE_BOOKE64) == PPC_OPCODE_BOOKE64
+             || (ppc_cpu & PPC_OPCODE_BOOKE) == 0)
          && ((op->flags & (PPC_OPCODE_POWER4 | PPC_OPCODE_NOPOWER4)) == 0
              || ((op->flags & PPC_OPCODE_POWER4)
                  == (ppc_cpu & PPC_OPCODE_POWER4))))
          && ((op->flags & (PPC_OPCODE_POWER4 | PPC_OPCODE_NOPOWER4)) == 0
              || ((op->flags & PPC_OPCODE_POWER4)
                  == (ppc_cpu & PPC_OPCODE_POWER4))))
@@ -1223,7 +1251,7 @@ md_begin ()
 
              as_bad (_("Internal assembler error for instruction %s"),
                      op->name);
 
              as_bad (_("Internal assembler error for instruction %s"),
                      op->name);
-             dup_insn = true;
+             dup_insn = TRUE;
            }
        }
     }
            }
        }
     }
@@ -1242,7 +1270,7 @@ md_begin ()
          if (retval != (const char *) NULL)
            {
              as_bad (_("Internal assembler error for macro %s"), macro->name);
          if (retval != (const char *) NULL)
            {
              as_bad (_("Internal assembler error for macro %s"), macro->name);
-             dup_insn = true;
+             dup_insn = TRUE;
            }
        }
     }
            }
        }
     }
@@ -1281,6 +1309,7 @@ md_begin ()
 void
 ppc_cleanup ()
 {
 void
 ppc_cleanup ()
 {
+#ifdef OBJ_ELF
   if (ppc_apuinfo_list == NULL)
     return;
 
   if (ppc_apuinfo_list == NULL)
     return;
 
@@ -1301,13 +1330,13 @@ ppc_cleanup ()
     asection *seg = now_seg;
     subsegT subseg = now_subseg;
     asection *apuinfo_secp = (asection *) NULL;
     asection *seg = now_seg;
     subsegT subseg = now_subseg;
     asection *apuinfo_secp = (asection *) NULL;
-    int i;
+    unsigned int i;
 
     /* Create the .PPC.EMB.apuinfo section.  */
     apuinfo_secp = subseg_new (".PPC.EMB.apuinfo", 0);
     bfd_set_section_flags (stdoutput,
                           apuinfo_secp,
 
     /* Create the .PPC.EMB.apuinfo section.  */
     apuinfo_secp = subseg_new (".PPC.EMB.apuinfo", 0);
     bfd_set_section_flags (stdoutput,
                           apuinfo_secp,
-                          SEC_HAS_CONTENTS | SEC_READONLY | SEC_MERGE);
+                          SEC_HAS_CONTENTS | SEC_READONLY);
 
     p = frag_more (4);
     md_number_to_chars (p, (valueT) 8, 4);
 
     p = frag_more (4);
     md_number_to_chars (p, (valueT) 8, 4);
@@ -1323,8 +1352,8 @@ ppc_cleanup ()
 
     for (i = 0; i < ppc_apuinfo_num; i++)
       {
 
     for (i = 0; i < ppc_apuinfo_num; i++)
       {
-        p = frag_more (4);
-        md_number_to_chars (p, (valueT) ppc_apuinfo_list[i], 4);
+       p = frag_more (4);
+       md_number_to_chars (p, (valueT) ppc_apuinfo_list[i], 4);
       }
 
     frag_align (2, 0, 0);
       }
 
     frag_align (2, 0, 0);
@@ -1334,6 +1363,7 @@ ppc_cleanup ()
     if (seg && subseg)
       subseg_set (seg, subseg);
   }
     if (seg && subseg)
       subseg_set (seg, subseg);
   }
+#endif
 }
 
 /* Insert an operand value into an instruction.  */
 }
 
 /* Insert an operand value into an instruction.  */
@@ -1436,60 +1466,94 @@ ppc_elf_suffix (str_p, exp_p)
 #define MAP(str,reloc) { str, sizeof (str)-1, reloc }
 
   static const struct map_bfd mapping[] = {
 #define MAP(str,reloc) { str, sizeof (str)-1, reloc }
 
   static const struct map_bfd mapping[] = {
-    MAP ("l",          (int) BFD_RELOC_LO16),
-    MAP ("h",          (int) BFD_RELOC_HI16),
-    MAP ("ha",         (int) BFD_RELOC_HI16_S),
-    MAP ("brtaken",    (int) BFD_RELOC_PPC_B16_BRTAKEN),
-    MAP ("brntaken",   (int) BFD_RELOC_PPC_B16_BRNTAKEN),
-    MAP ("got",                (int) BFD_RELOC_16_GOTOFF),
-    MAP ("got@l",      (int) BFD_RELOC_LO16_GOTOFF),
-    MAP ("got@h",      (int) BFD_RELOC_HI16_GOTOFF),
-    MAP ("got@ha",     (int) BFD_RELOC_HI16_S_GOTOFF),
-    MAP ("fixup",      (int) BFD_RELOC_CTOR), /* warning with -mrelocatable */
-    MAP ("plt",                (int) BFD_RELOC_24_PLT_PCREL),
-    MAP ("pltrel24",   (int) BFD_RELOC_24_PLT_PCREL),
-    MAP ("copy",       (int) BFD_RELOC_PPC_COPY),
-    MAP ("globdat",    (int) BFD_RELOC_PPC_GLOB_DAT),
-    MAP ("local24pc",  (int) BFD_RELOC_PPC_LOCAL24PC),
-    MAP ("local",      (int) BFD_RELOC_PPC_LOCAL24PC),
-    MAP ("pltrel",     (int) BFD_RELOC_32_PLT_PCREL),
-    MAP ("plt@l",      (int) BFD_RELOC_LO16_PLTOFF),
-    MAP ("plt@h",      (int) BFD_RELOC_HI16_PLTOFF),
-    MAP ("plt@ha",     (int) BFD_RELOC_HI16_S_PLTOFF),
-    MAP ("sdarel",     (int) BFD_RELOC_GPREL16),
-    MAP ("sectoff",    (int) BFD_RELOC_16_BASEREL),
-    MAP ("sectoff@l",  (int) BFD_RELOC_LO16_BASEREL),
-    MAP ("sectoff@h",  (int) BFD_RELOC_HI16_BASEREL),
-    MAP ("sectoff@ha", (int) BFD_RELOC_HI16_S_BASEREL),
-    MAP ("naddr",      (int) BFD_RELOC_PPC_EMB_NADDR32),
-    MAP ("naddr16",    (int) BFD_RELOC_PPC_EMB_NADDR16),
-    MAP ("naddr@l",    (int) BFD_RELOC_PPC_EMB_NADDR16_LO),
-    MAP ("naddr@h",    (int) BFD_RELOC_PPC_EMB_NADDR16_HI),
-    MAP ("naddr@ha",   (int) BFD_RELOC_PPC_EMB_NADDR16_HA),
-    MAP ("sdai16",     (int) BFD_RELOC_PPC_EMB_SDAI16),
-    MAP ("sda2rel",    (int) BFD_RELOC_PPC_EMB_SDA2REL),
-    MAP ("sda2i16",    (int) BFD_RELOC_PPC_EMB_SDA2I16),
-    MAP ("sda21",      (int) BFD_RELOC_PPC_EMB_SDA21),
-    MAP ("mrkref",     (int) BFD_RELOC_PPC_EMB_MRKREF),
-    MAP ("relsect",    (int) BFD_RELOC_PPC_EMB_RELSEC16),
-    MAP ("relsect@l",  (int) BFD_RELOC_PPC_EMB_RELST_LO),
-    MAP ("relsect@h",  (int) BFD_RELOC_PPC_EMB_RELST_HI),
-    MAP ("relsect@ha", (int) BFD_RELOC_PPC_EMB_RELST_HA),
-    MAP ("bitfld",     (int) BFD_RELOC_PPC_EMB_BIT_FLD),
-    MAP ("relsda",     (int) BFD_RELOC_PPC_EMB_RELSDA),
-    MAP ("xgot",       (int) BFD_RELOC_PPC_TOC16),
+    MAP ("l",                  (int) BFD_RELOC_LO16),
+    MAP ("h",                  (int) BFD_RELOC_HI16),
+    MAP ("ha",                 (int) BFD_RELOC_HI16_S),
+    MAP ("brtaken",            (int) BFD_RELOC_PPC_B16_BRTAKEN),
+    MAP ("brntaken",           (int) BFD_RELOC_PPC_B16_BRNTAKEN),
+    MAP ("got",                        (int) BFD_RELOC_16_GOTOFF),
+    MAP ("got@l",              (int) BFD_RELOC_LO16_GOTOFF),
+    MAP ("got@h",              (int) BFD_RELOC_HI16_GOTOFF),
+    MAP ("got@ha",             (int) BFD_RELOC_HI16_S_GOTOFF),
+    MAP ("fixup",              (int) BFD_RELOC_CTOR),
+    MAP ("plt",                        (int) BFD_RELOC_24_PLT_PCREL),
+    MAP ("pltrel24",           (int) BFD_RELOC_24_PLT_PCREL),
+    MAP ("copy",               (int) BFD_RELOC_PPC_COPY),
+    MAP ("globdat",            (int) BFD_RELOC_PPC_GLOB_DAT),
+    MAP ("local24pc",          (int) BFD_RELOC_PPC_LOCAL24PC),
+    MAP ("local",              (int) BFD_RELOC_PPC_LOCAL24PC),
+    MAP ("pltrel",             (int) BFD_RELOC_32_PLT_PCREL),
+    MAP ("plt@l",              (int) BFD_RELOC_LO16_PLTOFF),
+    MAP ("plt@h",              (int) BFD_RELOC_HI16_PLTOFF),
+    MAP ("plt@ha",             (int) BFD_RELOC_HI16_S_PLTOFF),
+    MAP ("sdarel",             (int) BFD_RELOC_GPREL16),
+    MAP ("sectoff",            (int) BFD_RELOC_16_BASEREL),
+    MAP ("sectoff@l",          (int) BFD_RELOC_LO16_BASEREL),
+    MAP ("sectoff@h",          (int) BFD_RELOC_HI16_BASEREL),
+    MAP ("sectoff@ha",         (int) BFD_RELOC_HI16_S_BASEREL),
+    MAP ("naddr",              (int) BFD_RELOC_PPC_EMB_NADDR32),
+    MAP ("naddr16",            (int) BFD_RELOC_PPC_EMB_NADDR16),
+    MAP ("naddr@l",            (int) BFD_RELOC_PPC_EMB_NADDR16_LO),
+    MAP ("naddr@h",            (int) BFD_RELOC_PPC_EMB_NADDR16_HI),
+    MAP ("naddr@ha",           (int) BFD_RELOC_PPC_EMB_NADDR16_HA),
+    MAP ("sdai16",             (int) BFD_RELOC_PPC_EMB_SDAI16),
+    MAP ("sda2rel",            (int) BFD_RELOC_PPC_EMB_SDA2REL),
+    MAP ("sda2i16",            (int) BFD_RELOC_PPC_EMB_SDA2I16),
+    MAP ("sda21",              (int) BFD_RELOC_PPC_EMB_SDA21),
+    MAP ("mrkref",             (int) BFD_RELOC_PPC_EMB_MRKREF),
+    MAP ("relsect",            (int) BFD_RELOC_PPC_EMB_RELSEC16),
+    MAP ("relsect@l",          (int) BFD_RELOC_PPC_EMB_RELST_LO),
+    MAP ("relsect@h",          (int) BFD_RELOC_PPC_EMB_RELST_HI),
+    MAP ("relsect@ha",         (int) BFD_RELOC_PPC_EMB_RELST_HA),
+    MAP ("bitfld",             (int) BFD_RELOC_PPC_EMB_BIT_FLD),
+    MAP ("relsda",             (int) BFD_RELOC_PPC_EMB_RELSDA),
+    MAP ("xgot",               (int) BFD_RELOC_PPC_TOC16),
+    MAP ("tls",                        (int) BFD_RELOC_PPC_TLS),
+    MAP ("dtpmod",             (int) BFD_RELOC_PPC_DTPMOD),
+    MAP ("dtprel",             (int) BFD_RELOC_PPC_DTPREL),
+    MAP ("dtprel@l",           (int) BFD_RELOC_PPC_DTPREL16_LO),
+    MAP ("dtprel@h",           (int) BFD_RELOC_PPC_DTPREL16_HI),
+    MAP ("dtprel@ha",          (int) BFD_RELOC_PPC_DTPREL16_HA),
+    MAP ("tprel",              (int) BFD_RELOC_PPC_TPREL),
+    MAP ("tprel@l",            (int) BFD_RELOC_PPC_TPREL16_LO),
+    MAP ("tprel@h",            (int) BFD_RELOC_PPC_TPREL16_HI),
+    MAP ("tprel@ha",           (int) BFD_RELOC_PPC_TPREL16_HA),
+    MAP ("got@tlsgd",          (int) BFD_RELOC_PPC_GOT_TLSGD16),
+    MAP ("got@tlsgd@l",                (int) BFD_RELOC_PPC_GOT_TLSGD16_LO),
+    MAP ("got@tlsgd@h",                (int) BFD_RELOC_PPC_GOT_TLSGD16_HI),
+    MAP ("got@tlsgd@ha",       (int) BFD_RELOC_PPC_GOT_TLSGD16_HA),
+    MAP ("got@tlsld",          (int) BFD_RELOC_PPC_GOT_TLSLD16),
+    MAP ("got@tlsld@l",                (int) BFD_RELOC_PPC_GOT_TLSLD16_LO),
+    MAP ("got@tlsld@h",                (int) BFD_RELOC_PPC_GOT_TLSLD16_HI),
+    MAP ("got@tlsld@ha",       (int) BFD_RELOC_PPC_GOT_TLSLD16_HA),
+    MAP ("got@dtprel",         (int) BFD_RELOC_PPC_GOT_DTPREL16),
+    MAP ("got@dtprel@l",       (int) BFD_RELOC_PPC_GOT_DTPREL16_LO),
+    MAP ("got@dtprel@h",       (int) BFD_RELOC_PPC_GOT_DTPREL16_HI),
+    MAP ("got@dtprel@ha",      (int) BFD_RELOC_PPC_GOT_DTPREL16_HA),
+    MAP ("got@tprel",          (int) BFD_RELOC_PPC_GOT_TPREL16),
+    MAP ("got@tprel@l",                (int) BFD_RELOC_PPC_GOT_TPREL16_LO),
+    MAP ("got@tprel@h",                (int) BFD_RELOC_PPC_GOT_TPREL16_HI),
+    MAP ("got@tprel@ha",       (int) BFD_RELOC_PPC_GOT_TPREL16_HA),
     /* The following are only valid for ppc64.  Negative values are
        used instead of a flag.  */
     /* The following are only valid for ppc64.  Negative values are
        used instead of a flag.  */
-    MAP ("higher",     - (int) BFD_RELOC_PPC64_HIGHER),
-    MAP ("highera",    - (int) BFD_RELOC_PPC64_HIGHER_S),
-    MAP ("highest",    - (int) BFD_RELOC_PPC64_HIGHEST),
-    MAP ("highesta",   - (int) BFD_RELOC_PPC64_HIGHEST_S),
-    MAP ("tocbase",    - (int) BFD_RELOC_PPC64_TOC),
-    MAP ("toc",                - (int) BFD_RELOC_PPC_TOC16),
-    MAP ("toc@l",      - (int) BFD_RELOC_PPC64_TOC16_LO),
-    MAP ("toc@h",      - (int) BFD_RELOC_PPC64_TOC16_HI),
-    MAP ("toc@ha",     - (int) BFD_RELOC_PPC64_TOC16_HA),
-    { (char *) 0, 0,   (int) BFD_RELOC_UNUSED }
+    MAP ("higher",             - (int) BFD_RELOC_PPC64_HIGHER),
+    MAP ("highera",            - (int) BFD_RELOC_PPC64_HIGHER_S),
+    MAP ("highest",            - (int) BFD_RELOC_PPC64_HIGHEST),
+    MAP ("highesta",           - (int) BFD_RELOC_PPC64_HIGHEST_S),
+    MAP ("tocbase",            - (int) BFD_RELOC_PPC64_TOC),
+    MAP ("toc",                        - (int) BFD_RELOC_PPC_TOC16),
+    MAP ("toc@l",              - (int) BFD_RELOC_PPC64_TOC16_LO),
+    MAP ("toc@h",              - (int) BFD_RELOC_PPC64_TOC16_HI),
+    MAP ("toc@ha",             - (int) BFD_RELOC_PPC64_TOC16_HA),
+    MAP ("dtprel@higher",      - (int) BFD_RELOC_PPC64_DTPREL16_HIGHER),
+    MAP ("dtprel@highera",     - (int) BFD_RELOC_PPC64_DTPREL16_HIGHERA),
+    MAP ("dtprel@highest",     - (int) BFD_RELOC_PPC64_DTPREL16_HIGHEST),
+    MAP ("dtprel@highesta",    - (int) BFD_RELOC_PPC64_DTPREL16_HIGHESTA),
+    MAP ("tprel@higher",       - (int) BFD_RELOC_PPC64_TPREL16_HIGHER),
+    MAP ("tprel@highera",      - (int) BFD_RELOC_PPC64_TPREL16_HIGHERA),
+    MAP ("tprel@highest",      - (int) BFD_RELOC_PPC64_TPREL16_HIGHEST),
+    MAP ("tprel@highesta",     - (int) BFD_RELOC_PPC64_TPREL16_HIGHESTA),
+    { (char *) 0, 0,           (int) BFD_RELOC_UNUSED }
   };
 
   if (*str++ != '@')
   };
 
   if (*str++ != '@')
@@ -1521,12 +1585,13 @@ ppc_elf_suffix (str_p, exp_p)
            reloc = -reloc;
          }
 
            reloc = -reloc;
          }
 
-       if (exp_p->X_add_number != 0
-           && (reloc == (int) BFD_RELOC_16_GOTOFF
-               || reloc == (int) BFD_RELOC_LO16_GOTOFF
-               || reloc == (int) BFD_RELOC_HI16_GOTOFF
-               || reloc == (int) BFD_RELOC_HI16_S_GOTOFF))
-         as_warn (_("identifier+constant@got means identifier@got+constant"));
+       if (!ppc_obj64)
+         if (exp_p->X_add_number != 0
+             && (reloc == (int) BFD_RELOC_16_GOTOFF
+                 || reloc == (int) BFD_RELOC_LO16_GOTOFF
+                 || reloc == (int) BFD_RELOC_HI16_GOTOFF
+                 || reloc == (int) BFD_RELOC_HI16_S_GOTOFF))
+           as_warn (_("identifier+constant@got means identifier@got+constant"));
 
        /* Now check for identifier@suffix+constant.  */
        if (*str == '-' || *str == '+')
 
        /* Now check for identifier@suffix+constant.  */
        if (*str == '-' || *str == '+')
@@ -1933,18 +1998,19 @@ parse_toc_entry (toc_kind)
 #endif
 \f
 
 #endif
 \f
 
+#ifdef OBJ_ELF
 #define APUID(a,v)     ((((a) & 0xffff) << 16) | ((v) & 0xffff))
 static void
 #define APUID(a,v)     ((((a) & 0xffff) << 16) | ((v) & 0xffff))
 static void
-ppc_apuinfo_section_add(apu, version)
+ppc_apuinfo_section_add (apu, version)
       unsigned int apu, version;
 {
   unsigned int i;
 
   /* Check we don't already exist.  */
   for (i = 0; i < ppc_apuinfo_num; i++)
       unsigned int apu, version;
 {
   unsigned int i;
 
   /* Check we don't already exist.  */
   for (i = 0; i < ppc_apuinfo_num; i++)
-    if (ppc_apuinfo_list[i] == APUID(apu, version))
+    if (ppc_apuinfo_list[i] == APUID (apu, version))
       return;
       return;
-    
+
   if (ppc_apuinfo_num == ppc_apuinfo_num_alloc)
     {
       if (ppc_apuinfo_num_alloc == 0)
   if (ppc_apuinfo_num == ppc_apuinfo_num_alloc)
     {
       if (ppc_apuinfo_num_alloc == 0)
@@ -1960,9 +2026,10 @@ ppc_apuinfo_section_add(apu, version)
              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
 \f
 
 /* We need to keep a list of fixups.  We can't simply generate them as
 \f
 
 /* We need to keep a list of fixups.  We can't simply generate them as
@@ -2044,6 +2111,8 @@ md_assemble (str)
       if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0)
        {
          unsigned int opcount;
       if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0)
        {
          unsigned int opcount;
+         unsigned int num_operands_expected;
+         unsigned int i;
 
          /* There is an optional operand.  Count the number of
             commas in the input line.  */
 
          /* There is an optional operand.  Count the number of
             commas in the input line.  */
@@ -2060,10 +2129,16 @@ md_assemble (str)
                }
            }
 
                }
            }
 
+         /* Compute the number of expected operands.
+            Do not count fake operands.  */
+         for (num_operands_expected = 0, i = 0; opcode->operands[i]; i ++)
+           if ((powerpc_operands [opcode->operands[i]].flags & PPC_OPERAND_FAKE) == 0)
+             ++ num_operands_expected;
+
          /* If there are fewer operands in the line then are called
             for by the instruction, we want to skip the optional
             operand.  */
          /* If there are fewer operands in the line then are called
             for by the instruction, we want to skip the optional
             operand.  */
-         if (opcount < strlen (opcode->operands))
+         if (opcount < num_operands_expected)
            skip_optional = 1;
 
          break;
            skip_optional = 1;
 
          break;
@@ -2239,9 +2314,9 @@ md_assemble (str)
          if (! register_name (&ex))
            {
              if ((operand->flags & PPC_OPERAND_CR) != 0)
          if (! register_name (&ex))
            {
              if ((operand->flags & PPC_OPERAND_CR) != 0)
-               cr_operand = true;
+               cr_operand = TRUE;
              expression (&ex);
              expression (&ex);
-             cr_operand = false;
+             cr_operand = FALSE;
            }
        }
 
            }
        }
 
@@ -2329,6 +2404,25 @@ md_assemble (str)
 #ifdef OBJ_ELF
       else if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)
        {
 #ifdef OBJ_ELF
       else if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)
        {
+         /* Some TLS tweaks.  */
+         switch (reloc)
+           {
+           default:
+             break;
+           case BFD_RELOC_PPC_TLS:
+             insn = ppc_insert_operand (insn, operand, ppc_obj64 ? 13 : 2,
+                                        (char *) NULL, 0);
+             break;
+         /* We'll only use the 32 (or 64) bit form of these relocations
+            in constants.  Instructions get the 16 bit form.  */
+           case BFD_RELOC_PPC_DTPREL:
+             reloc = BFD_RELOC_PPC_DTPREL16;
+             break;
+           case BFD_RELOC_PPC_TPREL:
+             reloc = BFD_RELOC_PPC_TPREL16;
+             break;
+           }
+
          /* For the absolute forms of branches, convert the PC
             relative form back into the absolute.  */
          if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
          /* For the absolute forms of branches, convert the PC
             relative form back into the absolute.  */
          if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
@@ -2353,7 +2447,7 @@ md_assemble (str)
            }
 
          if (ppc_obj64
            }
 
          if (ppc_obj64
-             && (operand->flags & PPC_OPERAND_DS) != 0)
+             && (operand->flags & (PPC_OPERAND_DS | PPC_OPERAND_DQ)) != 0)
            {
              switch (reloc)
                {
            {
              switch (reloc)
                {
@@ -2390,6 +2484,23 @@ md_assemble (str)
                case BFD_RELOC_PPC64_PLTGOT16_LO:
                  reloc = BFD_RELOC_PPC64_PLTGOT16_LO_DS;
                  break;
                case BFD_RELOC_PPC64_PLTGOT16_LO:
                  reloc = BFD_RELOC_PPC64_PLTGOT16_LO_DS;
                  break;
+               case BFD_RELOC_PPC_DTPREL16:
+                 reloc = BFD_RELOC_PPC64_DTPREL16_DS;
+                 break;
+               case BFD_RELOC_PPC_DTPREL16_LO:
+                 reloc = BFD_RELOC_PPC64_DTPREL16_LO_DS;
+                 break;
+               case BFD_RELOC_PPC_TPREL16:
+                 reloc = BFD_RELOC_PPC64_TPREL16_DS;
+                 break;
+               case BFD_RELOC_PPC_TPREL16_LO:
+                 reloc = BFD_RELOC_PPC64_TPREL16_LO_DS;
+                 break;
+               case BFD_RELOC_PPC_GOT_DTPREL16:
+               case BFD_RELOC_PPC_GOT_DTPREL16_LO:
+               case BFD_RELOC_PPC_GOT_TPREL16:
+               case BFD_RELOC_PPC_GOT_TPREL16_LO:
+                 break;
                default:
                  as_bad (_("unsupported relocation for DS offset field"));
                  break;
                default:
                  as_bad (_("unsupported relocation for DS offset field"));
                  break;
@@ -2449,6 +2560,7 @@ md_assemble (str)
   if (*str != '\0')
     as_bad (_("junk at end of line: `%s'"), str);
 
   if (*str != '\0')
     as_bad (_("junk at end of line: `%s'"), str);
 
+#ifdef OBJ_ELF
   /* Do we need/want a APUinfo section? */
   if (ppc_cpu & (PPC_OPCODE_SPE
               | PPC_OPCODE_ISEL | PPC_OPCODE_EFS
   /* Do we need/want a APUinfo section? */
   if (ppc_cpu & (PPC_OPCODE_SPE
               | PPC_OPCODE_ISEL | PPC_OPCODE_EFS
@@ -2457,20 +2569,21 @@ md_assemble (str)
     {
       /* These are all version "1".  */
       if (opcode->flags & PPC_OPCODE_SPE)
     {
       /* These are all version "1".  */
       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
 
   /* Write out the instruction.  */
   f = frag_more (4);
 
   /* Write out the instruction.  */
   f = frag_more (4);
@@ -2639,7 +2752,7 @@ ppc_section_letter (letter, ptr_msg)
     return SHF_EXCLUDE;
 
   *ptr_msg = _("Bad .section directive: want a,e,w,x,M,S,G,T in string");
     return SHF_EXCLUDE;
 
   *ptr_msg = _("Bad .section directive: want a,e,w,x,M,S,G,T in string");
-  return 0;
+  return -1;
 }
 
 int
 }
 
 int
@@ -2724,7 +2837,7 @@ ppc_byte (ignore)
 
 /* This is set if we are creating a .stabx symbol, since we don't want
    to handle symbol suffixes for such symbols.  */
 
 /* This is set if we are creating a .stabx symbol, since we don't want
    to handle symbol suffixes for such symbols.  */
-static boolean ppc_stab_symbol;
+static bfd_boolean ppc_stab_symbol;
 
 /* The .comm and .lcomm pseudo-ops for XCOFF.  XCOFF puts common
    symbols in the .bss segment as though they were local common
 
 /* The .comm and .lcomm pseudo-ops for XCOFF.  XCOFF puts common
    symbols in the .bss segment as though they were local common
@@ -3167,9 +3280,9 @@ ppc_stabx (ignore)
     }
   ++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;
 
@@ -3898,11 +4011,11 @@ ppc_previous (ignore)
 
 /* pseudo-op: .pdata
    behaviour: predefined read only data section
 
 /* pseudo-op: .pdata
    behaviour: predefined read only data section
-              double word aligned
+             double word aligned
    errors:    None
    warnings:  None
    initial:   .section .pdata "adr3"
    errors:    None
    warnings:  None
    initial:   .section .pdata "adr3"
-              a - don't know -- maybe a misprint
+             a - don't know -- maybe a misprint
              d - initialized data
              r - readable
              3 - double word aligned (that would be 4 byte boundary)
              d - initialized data
              r - readable
              3 - double word aligned (that would be 4 byte boundary)
@@ -3934,11 +4047,11 @@ ppc_pdata (ignore)
 
 /* pseudo-op: .ydata
    behaviour: predefined read only data section
 
 /* pseudo-op: .ydata
    behaviour: predefined read only data section
-              double word aligned
+             double word aligned
    errors:    None
    warnings:  None
    initial:   .section .ydata "drw3"
    errors:    None
    warnings:  None
    initial:   .section .ydata "drw3"
-              a - don't know -- maybe a misprint
+             a - don't know -- maybe a misprint
              d - initialized data
              r - readable
              3 - double word aligned (that would be 4 byte boundary)
              d - initialized data
              r - readable
              3 - double word aligned (that would be 4 byte boundary)
@@ -3968,7 +4081,7 @@ ppc_ydata (ignore)
 
 /* pseudo-op: .reldata
    behaviour: predefined read write data section
 
 /* pseudo-op: .reldata
    behaviour: predefined read write data section
-              double word aligned (4-byte)
+             double word aligned (4-byte)
              FIXME: relocation is applied to it
              FIXME: what's the difference between this and .data?
    errors:    None
              FIXME: relocation is applied to it
              FIXME: what's the difference between this and .data?
    errors:    None
@@ -4006,7 +4119,7 @@ ppc_reldata (ignore)
 
 /* pseudo-op: .rdata
    behaviour: predefined read only data section
 
 /* pseudo-op: .rdata
    behaviour: predefined read only data section
-              double word aligned
+             double word aligned
    errors:    None
    warnings:  None
    initial:   .section .rdata "dr3"
    errors:    None
    warnings:  None
    initial:   .section .rdata "dr3"
@@ -4036,7 +4149,7 @@ ppc_rdata (ignore)
 
 /* pseudo-op: .ualong
    behaviour: much like .int, with the exception that no alignment is
 
 /* pseudo-op: .ualong
    behaviour: much like .int, with the exception that no alignment is
-              performed.
+             performed.
              FIXME: test the alignment statement
    errors:    None
    warnings:  None  */
              FIXME: test the alignment statement
    errors:    None
    warnings:  None  */
@@ -4051,7 +4164,7 @@ ppc_ualong (ignore)
 
 /* pseudo-op: .znop  <symbol name>
    behaviour: Issue a nop instruction
 
 /* pseudo-op: .znop  <symbol name>
    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.
    errors:    None
    warnings:  Missing symbol name  */
              the supplied symbol name.
    errors:    None
    warnings:  Missing symbol name  */
@@ -4613,7 +4726,7 @@ ppc_frob_label (sym)
    seen.  It tells ppc_adjust_symtab whether it needs to look through
    the symbols.  */
 
    seen.  It tells ppc_adjust_symtab whether it needs to look through
    the symbols.  */
 
-static boolean ppc_saw_abs;
+static bfd_boolean ppc_saw_abs;
 
 /* Change the name of a symbol just before writing it out.  Set the
    real name if the .rename pseudo-op was used.  Otherwise, remove any
 
 /* 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
@@ -4636,6 +4749,10 @@ ppc_frob_symbol (sym)
              && S_GET_STORAGE_CLASS (sym) != C_FILE)))
     return 1;
 
              && S_GET_STORAGE_CLASS (sym) != C_FILE)))
     return 1;
 
+  /* This one will disappear anyway.  Don't make a csect sym for it.  */
+  if (sym == abs_section_sym)
+    return 1;
+
   if (symbol_get_tc (sym)->real_name != (char *) NULL)
     S_SET_NAME (sym, symbol_get_tc (sym)->real_name);
   else
   if (symbol_get_tc (sym)->real_name != (char *) NULL)
     S_SET_NAME (sym, symbol_get_tc (sym)->real_name);
   else
@@ -4752,7 +4869,7 @@ ppc_frob_symbol (sym)
        {
          /* This is an absolute symbol.  The csect will be created by
             ppc_adjust_symtab.  */
        {
          /* This is an absolute symbol.  The csect will be created by
             ppc_adjust_symtab.  */
-         ppc_saw_abs = true;
+         ppc_saw_abs = TRUE;
          a->x_csect.x_smtyp = XTY_LD;
          if (symbol_get_tc (sym)->class == -1)
            symbol_get_tc (sym)->class = XMC_XO;
          a->x_csect.x_smtyp = XTY_LD;
          if (symbol_get_tc (sym)->class == -1)
            symbol_get_tc (sym)->class = XMC_XO;
@@ -4848,10 +4965,10 @@ ppc_frob_symbol (sym)
       /* We want the value to be the symbol index of the referenced
         csect symbol.  BFD will do that for us if we set the right
         flags.  */
       /* We want the value to be the symbol index of the referenced
         csect symbol.  BFD will do that for us if we set the right
         flags.  */
-      S_SET_VALUE (sym,
-                  ((valueT)
-                   coffsymbol (symbol_get_bfdsym
-                               (symbol_get_tc (sym)->within))->native));
+      asymbol *bsym = symbol_get_bfdsym (symbol_get_tc (sym)->within);
+      combined_entry_type *c = coffsymbol (bsym)->native;
+
+      S_SET_VALUE (sym, (valueT) (size_t) c);
       coffsymbol (symbol_get_bfdsym (sym))->native->fix_value = 1;
     }
   else if (S_GET_STORAGE_CLASS (sym) == C_STSYM)
       coffsymbol (symbol_get_bfdsym (sym))->native->fix_value = 1;
     }
   else if (S_GET_STORAGE_CLASS (sym) == C_STSYM)
@@ -4920,7 +5037,7 @@ ppc_adjust_symtab ()
       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
@@ -5077,14 +5194,16 @@ int
 ppc_fix_adjustable (fix)
      fixS *fix;
 {
 ppc_fix_adjustable (fix)
      fixS *fix;
 {
-  valueT val;
+  valueT val = resolve_symbol_value (fix->fx_addsy);
+  segT symseg = S_GET_SEGMENT (fix->fx_addsy);
+  TC_SYMFIELD_TYPE *tc;
+
+  if (symseg == absolute_section)
+    return 0;
 
 
-  resolve_symbol_value (fix->fx_addsy);
-  val = S_GET_VALUE (fix->fx_addsy);
   if (ppc_toc_csect != (symbolS *) NULL
   if (ppc_toc_csect != (symbolS *) NULL
-      && fix->fx_addsy != (symbolS *) NULL
       && fix->fx_addsy != ppc_toc_csect
       && fix->fx_addsy != ppc_toc_csect
-      && S_GET_SEGMENT (fix->fx_addsy) == data_section
+      && symseg == data_section
       && val >= ppc_toc_frag->fr_address
       && (ppc_after_toc_frag == (fragS *) NULL
          || val < ppc_after_toc_frag->fr_address))
       && val >= ppc_toc_frag->fr_address
       && (ppc_after_toc_frag == (fragS *) NULL
          || val < ppc_after_toc_frag->fr_address))
@@ -5095,12 +5214,13 @@ ppc_fix_adjustable (fix)
           sy != (symbolS *) NULL;
           sy = symbol_next (sy))
        {
           sy != (symbolS *) NULL;
           sy = symbol_next (sy))
        {
-         if (symbol_get_tc (sy)->class == XMC_TC0)
+         TC_SYMFIELD_TYPE *sy_tc = symbol_get_tc (sy);
+
+         if (sy_tc->class == XMC_TC0)
            continue;
            continue;
-         if (symbol_get_tc (sy)->class != XMC_TC)
+         if (sy_tc->class != XMC_TC)
            break;
            break;
-         resolve_symbol_value (sy);
-         if (val == S_GET_VALUE (sy))
+         if (val == resolve_symbol_value (sy))
            {
              fix->fx_addsy = sy;
              fix->fx_addnumber = val - ppc_toc_frag->fr_address;
            {
              fix->fx_addsy = sy;
              fix->fx_addnumber = val - ppc_toc_frag->fr_address;
@@ -5113,23 +5233,24 @@ ppc_fix_adjustable (fix)
     }
 
   /* Possibly adjust the reloc to be against the csect.  */
     }
 
   /* Possibly adjust the reloc to be against the csect.  */
-  if (fix->fx_addsy != (symbolS *) NULL
-      && symbol_get_tc (fix->fx_addsy)->subseg == 0
-      && symbol_get_tc (fix->fx_addsy)->class != XMC_TC0
-      && symbol_get_tc (fix->fx_addsy)->class != XMC_TC
-      && S_GET_SEGMENT (fix->fx_addsy) != bss_section
+  tc = symbol_get_tc (fix->fx_addsy);
+  if (tc->subseg == 0
+      && tc->class != XMC_TC0
+      && tc->class != XMC_TC
+      && 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.  */
-      && (S_GET_SEGMENT (fix->fx_addsy) != data_section
+      && (symseg != data_section
          || ppc_toc_csect == NULL
          || val < ppc_toc_frag->fr_address
          || (ppc_after_toc_frag != NULL
              && val >= ppc_after_toc_frag->fr_address)))
     {
       symbolS *csect;
          || ppc_toc_csect == NULL
          || val < ppc_toc_frag->fr_address
          || (ppc_after_toc_frag != NULL
              && val >= ppc_after_toc_frag->fr_address)))
     {
       symbolS *csect;
+      symbolS *next_csect;
 
 
-      if (S_GET_SEGMENT (fix->fx_addsy) == text_section)
+      if (symseg == text_section)
        csect = ppc_text_csects;
        csect = ppc_text_csects;
-      else if (S_GET_SEGMENT (fix->fx_addsy) == data_section)
+      else if (symseg == data_section)
        csect = ppc_data_csects;
       else
        abort ();
        csect = ppc_data_csects;
       else
        abort ();
@@ -5139,16 +5260,15 @@ ppc_fix_adjustable (fix)
 
       if (csect != (symbolS *) NULL)
        {
 
       if (csect != (symbolS *) NULL)
        {
-         while (symbol_get_tc (csect)->next != (symbolS *) NULL
-                && (symbol_get_frag (symbol_get_tc (csect)->next)->fr_address
-                    <= val))
+         while ((next_csect = symbol_get_tc (csect)->next) != (symbolS *) NULL
+                && (symbol_get_frag (next_csect)->fr_address <= val))
            {
              /* If the csect address equals the symbol value, then we
                 have to look through the full symbol table to see
                 whether this is the csect we want.  Note that we will
                 only get here if the csect has zero length.  */
            {
              /* If the csect address equals the symbol value, then we
                 have to look through the full symbol table to see
                 whether this is the csect we want.  Note that we will
                 only get here if the csect has zero length.  */
-             if ((symbol_get_frag (csect)->fr_address == val)
-                 && S_GET_VALUE (csect) == S_GET_VALUE (fix->fx_addsy))
+             if (symbol_get_frag (csect)->fr_address == val
+                 && S_GET_VALUE (csect) == val)
                {
                  symbolS *scan;
 
                {
                  symbolS *scan;
 
@@ -5168,26 +5288,24 @@ ppc_fix_adjustable (fix)
                    break;
                }
 
                    break;
                }
 
-             csect = symbol_get_tc (csect)->next;
+             csect = next_csect;
            }
 
            }
 
-         fix->fx_offset += (S_GET_VALUE (fix->fx_addsy)
-                            - 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;
     }
 
   /* Adjust a reloc against a .lcomm symbol to be against the base
      .lcomm.  */
     }
 
   /* Adjust a reloc against a .lcomm symbol to be against the base
      .lcomm.  */
-  if (fix->fx_addsy != (symbolS *) NULL
-      && S_GET_SEGMENT (fix->fx_addsy) == bss_section
+  if (symseg == bss_section
       && ! S_IS_EXTERNAL (fix->fx_addsy))
     {
       && ! S_IS_EXTERNAL (fix->fx_addsy))
     {
-      resolve_symbol_value (symbol_get_frag (fix->fx_addsy)->fr_symbol);
-      fix->fx_offset +=
-       (S_GET_VALUE (fix->fx_addsy)
-        - S_GET_VALUE (symbol_get_frag (fix->fx_addsy)->fr_symbol));
-      fix->fx_addsy = 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_addsy = sy;
     }
 
   return 0;
     }
 
   return 0;
@@ -5215,12 +5333,40 @@ ppc_force_relocation (fix)
                  <= fix->fx_frag->fr_address))))
     return 1;
 
                  <= fix->fx_frag->fr_address))))
     return 1;
 
-  return 0;
+  return generic_force_reloc (fix);
 }
 
 #endif /* OBJ_XCOFF */
 
 #ifdef OBJ_ELF
 }
 
 #endif /* OBJ_XCOFF */
 
 #ifdef OBJ_ELF
+/* If this function returns non-zero, it guarantees that a relocation
+   will be emitted for a fixup.  */
+
+int
+ppc_force_relocation (fix)
+     fixS *fix;
+{
+  /* Branch prediction relocations must force a relocation, as must
+     the vtable description relocs.  */
+  switch (fix->fx_r_type)
+    {
+    case BFD_RELOC_PPC_B16_BRTAKEN:
+    case BFD_RELOC_PPC_B16_BRNTAKEN:
+    case BFD_RELOC_PPC_BA16_BRTAKEN:
+    case BFD_RELOC_PPC_BA16_BRNTAKEN:
+    case BFD_RELOC_PPC64_TOC:
+      return 1;
+    default:
+      break;
+    }
+
+  if (fix->fx_r_type >= BFD_RELOC_PPC_TLS
+      && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA)
+    return 1;
+
+  return generic_force_reloc (fix);
+}
+
 int
 ppc_fix_adjustable (fix)
      fixS *fix;
 int
 ppc_fix_adjustable (fix)
      fixS *fix;
@@ -5232,8 +5378,8 @@ ppc_fix_adjustable (fix)
          && fix->fx_r_type != BFD_RELOC_GPREL16
          && fix->fx_r_type != BFD_RELOC_VTABLE_INHERIT
          && fix->fx_r_type != BFD_RELOC_VTABLE_ENTRY
          && fix->fx_r_type != BFD_RELOC_GPREL16
          && fix->fx_r_type != BFD_RELOC_VTABLE_INHERIT
          && fix->fx_r_type != BFD_RELOC_VTABLE_ENTRY
-         && ! S_IS_EXTERNAL (fix->fx_addsy)
-         && ! S_IS_WEAK (fix->fx_addsy)
+         && !(fix->fx_r_type >= BFD_RELOC_PPC_TLS
+              && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA)
          && (fix->fx_pcrel
              || (fix->fx_subsy != NULL
                  && (S_GET_SEGMENT (fix->fx_subsy)
          && (fix->fx_pcrel
              || (fix->fx_subsy != NULL
                  && (S_GET_SEGMENT (fix->fx_subsy)
@@ -5262,32 +5408,22 @@ md_apply_fix3 (fixP, valP, seg)
 #ifdef OBJ_ELF
   if (fixP->fx_addsy != NULL)
     {
 #ifdef OBJ_ELF
   if (fixP->fx_addsy != NULL)
     {
-      /* `*valuep' may contain the value of the symbol on which the reloc
-        will be based; we have to remove it.  */
-      if (symbol_used_in_reloc_p (fixP->fx_addsy)
-         && S_GET_SEGMENT (fixP->fx_addsy) != absolute_section
-         && S_GET_SEGMENT (fixP->fx_addsy) != undefined_section
-         && ! bfd_is_com_section (S_GET_SEGMENT (fixP->fx_addsy)))
-       value -= S_GET_VALUE (fixP->fx_addsy);
-
-      /* FIXME: Why '+'?  Better yet, what exactly is '*valuep'
-        supposed to be?  I think this is related to various similar
-        FIXMEs in tc-i386.c and tc-sparc.c.  */
+      /* Hack around bfd_install_relocation brain damage.  */
       if (fixP->fx_pcrel)
        value += fixP->fx_frag->fr_address + fixP->fx_where;
     }
   else
     fixP->fx_done = 1;
 #else
       if (fixP->fx_pcrel)
        value += fixP->fx_frag->fr_address + fixP->fx_where;
     }
   else
     fixP->fx_done = 1;
 #else
-  /* FIXME FIXME FIXME: The value we are passed in *valuep includes
+  /* FIXME FIXME FIXME: The value we are passed in *valP includes
      the symbol values.  Since we are using BFD_ASSEMBLER, if we are
      doing this relocation the code in write.c is going to call
      bfd_install_relocation, which is also going to use the symbol
      value.  That means that if the reloc is fully resolved we want to
      the symbol values.  Since we are using BFD_ASSEMBLER, if we are
      doing this relocation the code in write.c is going to call
      bfd_install_relocation, which is also going to use the symbol
      value.  That means that if the reloc is fully resolved we want to
-     use *valuep since bfd_install_relocation is not being used.
+     use *valP since bfd_install_relocation is not being used.
      However, if the reloc is not fully resolved we do not want to use
      However, if the reloc is not fully resolved we do not want to use
-     *valuep, and must use fx_offset instead.  However, if the reloc
-     is PC relative, we do want to use *valuep since it includes the
+     *valP, and must use fx_offset instead.  However, if the reloc
+     is PC relative, we do want to use *valP since it includes the
      result of md_pcrel_from.  This is confusing.  */
   if (fixP->fx_addsy == (symbolS *) NULL)
     fixP->fx_done = 1;
      result of md_pcrel_from.  This is confusing.  */
   if (fixP->fx_addsy == (symbolS *) NULL)
     fixP->fx_done = 1;
@@ -5296,21 +5432,14 @@ md_apply_fix3 (fixP, valP, seg)
     ;
 
   else
     ;
 
   else
+    value = fixP->fx_offset;
+#endif
+
+  if (fixP->fx_subsy != (symbolS *) NULL)
     {
     {
-      value = fixP->fx_offset;
-      if (fixP->fx_subsy != (symbolS *) NULL)
-       {
-         if (S_GET_SEGMENT (fixP->fx_subsy) == absolute_section)
-           value -= S_GET_VALUE (fixP->fx_subsy);
-         else
-           {
-             /* We can't actually support subtracting a symbol.  */
-             as_bad_where (fixP->fx_file, fixP->fx_line,
-                           _("expression too complex"));
-           }
-       }
+      /* We can't actually support subtracting a symbol.  */
+      as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
     }
     }
-#endif
 
   if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
     {
 
   if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
     {
@@ -5399,15 +5528,26 @@ md_apply_fix3 (fixP, valP, seg)
 #if defined (OBJ_XCOFF) || defined (OBJ_ELF)
       else if ((operand->flags & PPC_OPERAND_PARENS) != 0
               && operand->bits == 16
 #if defined (OBJ_XCOFF) || defined (OBJ_ELF)
       else if ((operand->flags & PPC_OPERAND_PARENS) != 0
               && operand->bits == 16
-              && operand->shift == 0
-              && ppc_is_toc_sym (fixP->fx_addsy))
+              && operand->shift == 0)
        {
        {
-         fixP->fx_r_type = BFD_RELOC_PPC_TOC16;
+         if (ppc_is_toc_sym (fixP->fx_addsy))
+           {
+             fixP->fx_r_type = BFD_RELOC_PPC_TOC16;
 #ifdef OBJ_ELF
 #ifdef OBJ_ELF
-         if (ppc_obj64
-             && (operand->flags & PPC_OPERAND_DS) != 0)
-           fixP->fx_r_type = BFD_RELOC_PPC64_TOC16_DS;
+             if (ppc_obj64
+                 && (operand->flags & PPC_OPERAND_DS) != 0)
+               fixP->fx_r_type = BFD_RELOC_PPC64_TOC16_DS;
+#endif
+           }
+         else
+           {
+             fixP->fx_r_type = BFD_RELOC_16;
+#ifdef OBJ_ELF
+             if (ppc_obj64
+                 && (operand->flags & PPC_OPERAND_DS) != 0)
+               fixP->fx_r_type = BFD_RELOC_PPC64_ADDR16_DS;
 #endif
 #endif
+           }
          fixP->fx_size = 2;
          if (target_big_endian)
            fixP->fx_where += 2;
          fixP->fx_size = 2;
          if (target_big_endian)
            fixP->fx_where += 2;
@@ -5574,19 +5714,72 @@ md_apply_fix3 (fixP, valP, seg)
            abort ();
          {
            unsigned char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
            abort ();
          {
            unsigned char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
-           unsigned long val;
+           long val, mask;
 
            if (target_big_endian)
 
            if (target_big_endian)
-             val = bfd_getb16 (where);
+             val = bfd_getb32 (where - 2);
            else
            else
-             val = bfd_getl16 (where);
-           val |= (value & 0xfffc);
+             val = bfd_getl32 (where);
+           mask = 0xfffc;
+           /* lq insns reserve the four lsbs.  */
+           if ((ppc_cpu & PPC_OPCODE_POWER4) != 0
+               && (val & (0x3f << 26)) == (56 << 26))
+             mask = 0xfff0;
+           val |= value & mask;
            if (target_big_endian)
              bfd_putb16 ((bfd_vma) val, where);
            else
              bfd_putl16 ((bfd_vma) val, where);
          }
          break;
            if (target_big_endian)
              bfd_putb16 ((bfd_vma) val, where);
            else
              bfd_putl16 ((bfd_vma) val, where);
          }
          break;
+
+       case BFD_RELOC_PPC_B16_BRTAKEN:
+       case BFD_RELOC_PPC_B16_BRNTAKEN:
+       case BFD_RELOC_PPC_BA16_BRTAKEN:
+       case BFD_RELOC_PPC_BA16_BRNTAKEN:
+         break;
+
+       case BFD_RELOC_PPC_TLS:
+       case BFD_RELOC_PPC_DTPMOD:
+       case BFD_RELOC_PPC_TPREL16:
+       case BFD_RELOC_PPC_TPREL16_LO:
+       case BFD_RELOC_PPC_TPREL16_HI:
+       case BFD_RELOC_PPC_TPREL16_HA:
+       case BFD_RELOC_PPC_TPREL:
+       case BFD_RELOC_PPC_DTPREL16:
+       case BFD_RELOC_PPC_DTPREL16_LO:
+       case BFD_RELOC_PPC_DTPREL16_HI:
+       case BFD_RELOC_PPC_DTPREL16_HA:
+       case BFD_RELOC_PPC_DTPREL:
+       case BFD_RELOC_PPC_GOT_TLSGD16:
+       case BFD_RELOC_PPC_GOT_TLSGD16_LO:
+       case BFD_RELOC_PPC_GOT_TLSGD16_HI:
+       case BFD_RELOC_PPC_GOT_TLSGD16_HA:
+       case BFD_RELOC_PPC_GOT_TLSLD16:
+       case BFD_RELOC_PPC_GOT_TLSLD16_LO:
+       case BFD_RELOC_PPC_GOT_TLSLD16_HI:
+       case BFD_RELOC_PPC_GOT_TLSLD16_HA:
+       case BFD_RELOC_PPC_GOT_TPREL16:
+       case BFD_RELOC_PPC_GOT_TPREL16_LO:
+       case BFD_RELOC_PPC_GOT_TPREL16_HI:
+       case BFD_RELOC_PPC_GOT_TPREL16_HA:
+       case BFD_RELOC_PPC_GOT_DTPREL16:
+       case BFD_RELOC_PPC_GOT_DTPREL16_LO:
+       case BFD_RELOC_PPC_GOT_DTPREL16_HI:
+       case BFD_RELOC_PPC_GOT_DTPREL16_HA:
+       case BFD_RELOC_PPC64_TPREL16_DS:
+       case BFD_RELOC_PPC64_TPREL16_LO_DS:
+       case BFD_RELOC_PPC64_TPREL16_HIGHER:
+       case BFD_RELOC_PPC64_TPREL16_HIGHERA:
+       case BFD_RELOC_PPC64_TPREL16_HIGHEST:
+       case BFD_RELOC_PPC64_TPREL16_HIGHESTA:
+       case BFD_RELOC_PPC64_DTPREL16_DS:
+       case BFD_RELOC_PPC64_DTPREL16_LO_DS:
+       case BFD_RELOC_PPC64_DTPREL16_HIGHER:
+       case BFD_RELOC_PPC64_DTPREL16_HIGHERA:
+       case BFD_RELOC_PPC64_DTPREL16_HIGHEST:
+       case BFD_RELOC_PPC64_DTPREL16_HIGHESTA:
+         break;
 #endif
          /* Because SDA21 modifies the register field, the size is set to 4
             bytes, rather than 2, so offset it here appropriately.  */
 #endif
          /* Because SDA21 modifies the register field, the size is set to 4
             bytes, rather than 2, so offset it here appropriately.  */
This page took 0.042965 seconds and 4 git commands to generate.