/* tc-ppc.c -- Assemble for the PowerPC or POWER (RS/6000)
- Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
- Free Software Foundation, Inc.
+ Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+ 2004 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Cygnus Support.
This file is part of GAS, the GNU Assembler.
#include "as.h"
#include "safe-ctype.h"
#include "subsegs.h"
-
+#include "dw2gencfi.h"
#include "opcode/ppc.h"
#ifdef OBJ_ELF
static void ppc_ef PARAMS ((int));
static void ppc_es PARAMS ((int));
static void ppc_csect PARAMS ((int));
-static void ppc_change_csect PARAMS ((symbolS *));
+static void ppc_change_csect PARAMS ((symbolS *, offsetT));
static void ppc_function PARAMS ((int));
static void ppc_extern PARAMS ((int));
static void ppc_lglobl PARAMS ((int));
as in 0d1.0. */
const char FLT_CHARS[] = "dD";
-/* '+' and '-' can be used as postfix predicate predictors for conditional
+/* '+' 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[] = "+-";
+
+/* The dwarf2 data alignment, adjusted for 32 or 64 bit. */
+int ppc_cie_data_alignment;
\f
/* The target specific pseudo-ops which we support. */
};
const size_t md_longopts_size = sizeof (md_longopts);
+
+/* Handle -m options that set cpu type, and .machine arg. */
+
+static int
+parse_cpu (const char *arg)
+{
+ /* -mpwrx and -mpwr2 mean to assemble for the IBM POWER/2
+ (RIOS2). */
+ if (strcmp (arg, "pwrx") == 0 || strcmp (arg, "pwr2") == 0)
+ ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_POWER2 | PPC_OPCODE_32;
+ /* -mpwr means to assemble for the IBM POWER (RIOS1). */
+ else if (strcmp (arg, "pwr") == 0)
+ ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_32;
+ /* -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);
+ /* -mppc, -mppc32, -m603, and -m604 mean to assemble for the
+ PowerPC 603/604. */
+ else if (strcmp (arg, "ppc") == 0
+ || strcmp (arg, "ppc32") == 0
+ || strcmp (arg, "603") == 0
+ || strcmp (arg, "604") == 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);
+ else if (strcmp (arg, "440") == 0)
+ ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_32
+ | PPC_OPCODE_440 | PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI);
+ 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);
+ 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;
+ }
+ 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);
+ }
+ else if (strcmp (arg, "spe") == 0)
+ {
+ if (ppc_cpu == 0)
+ ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_SPE | PPC_OPCODE_EFS;
+ else
+ ppc_cpu |= PPC_OPCODE_SPE;
+ }
+ /* -mppc64 and -m620 mean to assemble for the 64-bit PowerPC
+ 620. */
+ else if (strcmp (arg, "ppc64") == 0 || strcmp (arg, "620") == 0)
+ {
+ ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64;
+ }
+ else if (strcmp (arg, "ppc64bridge") == 0)
+ {
+ 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)
+ {
+ ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_32;
+ }
+ /* -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);
+ }
+ else if (strcmp (arg, "power4") == 0)
+ {
+ 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
+ than the intersection. */
+ else if (strcmp (arg, "com") == 0)
+ ppc_cpu = PPC_OPCODE_COMMON | PPC_OPCODE_32;
+ /* -many means to assemble for any architecture (PWR/PWRX/PPC). */
+ else if (strcmp (arg, "any") == 0)
+ ppc_cpu |= PPC_OPCODE_ANY;
+ else
+ return 0;
+
+ return 1;
+}
+
int
md_parse_option (c, arg)
int c;
break;
case 'm':
- /* -mpwrx and -mpwr2 mean to assemble for the IBM POWER/2
- (RIOS2). */
- if (strcmp (arg, "pwrx") == 0 || strcmp (arg, "pwr2") == 0)
- ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_POWER2 | PPC_OPCODE_32;
- /* -mpwr means to assemble for the IBM POWER (RIOS1). */
- else if (strcmp (arg, "pwr") == 0)
- ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_32;
- /* -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);
- /* -mppc, -mppc32, -m603, and -m604 mean to assemble for the
- PowerPC 603/604. */
- else if (strcmp (arg, "ppc") == 0
- || strcmp (arg, "ppc32") == 0
- || strcmp (arg, "603") == 0
- || strcmp (arg, "604") == 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);
- 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);
- 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;
- }
- 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);
- }
- else if (strcmp (arg, "spe") == 0)
- {
- if (ppc_cpu == 0)
- ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_SPE | PPC_OPCODE_EFS;
- else
- ppc_cpu |= PPC_OPCODE_SPE;
- }
- /* -mppc64 and -m620 mean to assemble for the 64-bit PowerPC
- 620. */
- else if (strcmp (arg, "ppc64") == 0 || strcmp (arg, "620") == 0)
- {
- ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64;
- }
- else if (strcmp (arg, "ppc64bridge") == 0)
- {
- 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)
- {
- ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_32;
- }
- /* -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);
- }
- else if (strcmp (arg, "power4") == 0)
- {
- 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
- than the intersection. */
- else if (strcmp (arg, "com") == 0)
- ppc_cpu = PPC_OPCODE_COMMON | PPC_OPCODE_32;
- /* -many means to assemble for any architecture (PWR/PWRX/PPC). */
- else if (strcmp (arg, "any") == 0)
- ppc_cpu = PPC_OPCODE_ANY | PPC_OPCODE_32;
+ if (parse_cpu (arg))
+ ;
else if (strcmp (arg, "regnames") == 0)
reg_names_p = TRUE;
-mppc, -mppc32, -m603, -m604\n\
generate code for PowerPC 603/604\n\
-m403, -m405 generate code for PowerPC 403/405\n\
+-m440 generate code for PowerPC 440\n\
-m7400, -m7410, -m7450, -m7455\n\
generate code For PowerPC 7400/7410/7450/7455\n"));
fprintf (stream, _("\
const char *default_os = TARGET_OS;
const char *default_cpu = TARGET_CPU;
- if (ppc_cpu == 0)
+ if ((ppc_cpu & ~PPC_OPCODE_ANY) == 0)
{
if (ppc_obj64)
- ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64;
+ 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;
+ ppc_cpu |= PPC_OPCODE_COMMON | PPC_OPCODE_32;
else if (strncmp (default_os, "aix3", 4) == 0)
- ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_32;
+ ppc_cpu |= PPC_OPCODE_POWER | PPC_OPCODE_32;
else if (strcmp (default_cpu, "rs6000") == 0)
- ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_32;
+ 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;
+ ppc_cpu |= PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64;
else
- ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32;
+ ppc_cpu |= PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32;
}
else
as_fatal (_("Unknown default cpu = %s, os = %s"),
}
}
-/* Figure out the BFD architecture to use. */
+/* Figure out the BFD architecture to use. This function and ppc_mach
+ are called well before md_begin, when the output file is opened. */
enum bfd_architecture
ppc_arch ()
#endif
}
-/* This function is called when the assembler starts up. It is called
- after the options have been parsed and the output file has been
- opened. */
+/* Insert opcodes and macros into hash tables. Called at startup and
+ for .cpu pseudo. */
-void
-md_begin ()
+static void
+ppc_setup_opcodes (void)
{
register const struct powerpc_opcode *op;
const struct powerpc_opcode *op_end;
const struct powerpc_macro *macro_end;
bfd_boolean dup_insn = FALSE;
- ppc_set_cpu ();
-
-#ifdef OBJ_ELF
- /* Set the ELF flags if desired. */
- if (ppc_flags && !msolaris)
- bfd_set_private_flags (stdoutput, ppc_flags);
-#endif
+ if (ppc_hash != NULL)
+ hash_die (ppc_hash);
+ if (ppc_macro_hash != NULL)
+ hash_die (ppc_macro_hash);
/* Insert the opcodes into a hash table. */
ppc_hash = hash_new ();
const char *retval;
retval = hash_insert (ppc_hash, op->name, (PTR) op);
- if (retval != (const char *) NULL)
+ if (retval != NULL)
{
/* Ignore Power duplicates for -m601. */
if ((ppc_cpu & PPC_OPCODE_601) != 0
}
}
+ if ((ppc_cpu & PPC_OPCODE_ANY) != 0)
+ for (op = powerpc_opcodes; op < op_end; op++)
+ hash_insert (ppc_hash, op->name, (PTR) op);
+
/* Insert the macros into a hash table. */
ppc_macro_hash = hash_new ();
if (dup_insn)
abort ();
+}
+
+/* This function is called when the assembler starts up. It is called
+ after the options have been parsed and the output file has been
+ opened. */
+
+void
+md_begin ()
+{
+ ppc_set_cpu ();
+
+ ppc_cie_data_alignment = ppc_obj64 ? -8 : -4;
- /* Tell the main code what the endianness is if it is not overidden
+#ifdef OBJ_ELF
+ /* Set the ELF flags if desired. */
+ if (ppc_flags && !msolaris)
+ bfd_set_private_flags (stdoutput, ppc_flags);
+#endif
+
+ ppc_setup_opcodes ();
+
+ /* Tell the main code what the endianness is if it is not overridden
by the user. */
if (!set_target_endian)
{
md_number_to_chars (p, (valueT) 8, 4);
p = frag_more (4);
- md_number_to_chars (p, (valueT) ppc_apuinfo_num, 4);
+ md_number_to_chars (p, (valueT) ppc_apuinfo_num * 4, 4);
p = frag_more (4);
md_number_to_chars (p, (valueT) 2, 4);
test = val;
if (test < (offsetT) min || test > (offsetT) max)
- {
- const char *err =
- _("operand out of range (%s not between %ld and %ld)");
- char buf[100];
-
- sprint_value (buf, test);
- as_bad_where (file, line, err, buf, min, max);
- }
+ as_bad_value_out_of_range (_("operand"), test, (offsetT) min, (offsetT) max, file, line);
}
if (operand->insert)
{
struct map_bfd {
char *string;
- int length;
- int reloc;
+ unsigned int length : 8;
+ unsigned int valid32 : 1;
+ unsigned int valid64 : 1;
+ unsigned int reloc;
};
char ident[20];
int len;
const struct map_bfd *ptr;
-#define MAP(str,reloc) { str, sizeof (str)-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 MAP64(str, reloc) { str, sizeof (str) - 1, 0, 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),
- 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. */
- 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 }
+ MAP ("l", BFD_RELOC_LO16),
+ MAP ("h", BFD_RELOC_HI16),
+ MAP ("ha", BFD_RELOC_HI16_S),
+ MAP ("brtaken", BFD_RELOC_PPC_B16_BRTAKEN),
+ MAP ("brntaken", BFD_RELOC_PPC_B16_BRNTAKEN),
+ MAP ("got", BFD_RELOC_16_GOTOFF),
+ MAP ("got@l", BFD_RELOC_LO16_GOTOFF),
+ MAP ("got@h", BFD_RELOC_HI16_GOTOFF),
+ MAP ("got@ha", BFD_RELOC_HI16_S_GOTOFF),
+ MAP ("plt@l", BFD_RELOC_LO16_PLTOFF),
+ MAP ("plt@h", BFD_RELOC_HI16_PLTOFF),
+ MAP ("plt@ha", BFD_RELOC_HI16_S_PLTOFF),
+ MAP ("copy", BFD_RELOC_PPC_COPY),
+ MAP ("globdat", BFD_RELOC_PPC_GLOB_DAT),
+ MAP ("sectoff", BFD_RELOC_16_BASEREL),
+ MAP ("sectoff@l", BFD_RELOC_LO16_BASEREL),
+ MAP ("sectoff@h", BFD_RELOC_HI16_BASEREL),
+ MAP ("sectoff@ha", BFD_RELOC_HI16_S_BASEREL),
+ MAP ("tls", BFD_RELOC_PPC_TLS),
+ MAP ("dtpmod", BFD_RELOC_PPC_DTPMOD),
+ MAP ("dtprel", BFD_RELOC_PPC_DTPREL),
+ MAP ("dtprel@l", BFD_RELOC_PPC_DTPREL16_LO),
+ MAP ("dtprel@h", BFD_RELOC_PPC_DTPREL16_HI),
+ MAP ("dtprel@ha", BFD_RELOC_PPC_DTPREL16_HA),
+ MAP ("tprel", BFD_RELOC_PPC_TPREL),
+ MAP ("tprel@l", BFD_RELOC_PPC_TPREL16_LO),
+ MAP ("tprel@h", BFD_RELOC_PPC_TPREL16_HI),
+ MAP ("tprel@ha", BFD_RELOC_PPC_TPREL16_HA),
+ MAP ("got@tlsgd", BFD_RELOC_PPC_GOT_TLSGD16),
+ MAP ("got@tlsgd@l", BFD_RELOC_PPC_GOT_TLSGD16_LO),
+ MAP ("got@tlsgd@h", BFD_RELOC_PPC_GOT_TLSGD16_HI),
+ MAP ("got@tlsgd@ha", BFD_RELOC_PPC_GOT_TLSGD16_HA),
+ MAP ("got@tlsld", BFD_RELOC_PPC_GOT_TLSLD16),
+ MAP ("got@tlsld@l", BFD_RELOC_PPC_GOT_TLSLD16_LO),
+ MAP ("got@tlsld@h", BFD_RELOC_PPC_GOT_TLSLD16_HI),
+ MAP ("got@tlsld@ha", BFD_RELOC_PPC_GOT_TLSLD16_HA),
+ MAP ("got@dtprel", BFD_RELOC_PPC_GOT_DTPREL16),
+ MAP ("got@dtprel@l", BFD_RELOC_PPC_GOT_DTPREL16_LO),
+ MAP ("got@dtprel@h", BFD_RELOC_PPC_GOT_DTPREL16_HI),
+ MAP ("got@dtprel@ha", BFD_RELOC_PPC_GOT_DTPREL16_HA),
+ MAP ("got@tprel", BFD_RELOC_PPC_GOT_TPREL16),
+ MAP ("got@tprel@l", BFD_RELOC_PPC_GOT_TPREL16_LO),
+ MAP ("got@tprel@h", BFD_RELOC_PPC_GOT_TPREL16_HI),
+ MAP ("got@tprel@ha", BFD_RELOC_PPC_GOT_TPREL16_HA),
+ MAP32 ("fixup", BFD_RELOC_CTOR),
+ MAP32 ("plt", BFD_RELOC_24_PLT_PCREL),
+ MAP32 ("pltrel24", BFD_RELOC_24_PLT_PCREL),
+ MAP32 ("local24pc", BFD_RELOC_PPC_LOCAL24PC),
+ MAP32 ("local", BFD_RELOC_PPC_LOCAL24PC),
+ MAP32 ("pltrel", BFD_RELOC_32_PLT_PCREL),
+ MAP32 ("sdarel", BFD_RELOC_GPREL16),
+ MAP32 ("naddr", BFD_RELOC_PPC_EMB_NADDR32),
+ MAP32 ("naddr16", BFD_RELOC_PPC_EMB_NADDR16),
+ MAP32 ("naddr@l", BFD_RELOC_PPC_EMB_NADDR16_LO),
+ MAP32 ("naddr@h", BFD_RELOC_PPC_EMB_NADDR16_HI),
+ MAP32 ("naddr@ha", BFD_RELOC_PPC_EMB_NADDR16_HA),
+ MAP32 ("sdai16", BFD_RELOC_PPC_EMB_SDAI16),
+ MAP32 ("sda2rel", BFD_RELOC_PPC_EMB_SDA2REL),
+ MAP32 ("sda2i16", BFD_RELOC_PPC_EMB_SDA2I16),
+ MAP32 ("sda21", BFD_RELOC_PPC_EMB_SDA21),
+ MAP32 ("mrkref", BFD_RELOC_PPC_EMB_MRKREF),
+ MAP32 ("relsect", BFD_RELOC_PPC_EMB_RELSEC16),
+ MAP32 ("relsect@l", BFD_RELOC_PPC_EMB_RELST_LO),
+ MAP32 ("relsect@h", BFD_RELOC_PPC_EMB_RELST_HI),
+ MAP32 ("relsect@ha", BFD_RELOC_PPC_EMB_RELST_HA),
+ MAP32 ("bitfld", BFD_RELOC_PPC_EMB_BIT_FLD),
+ MAP32 ("relsda", BFD_RELOC_PPC_EMB_RELSDA),
+ MAP32 ("xgot", BFD_RELOC_PPC_TOC16),
+ MAP64 ("higher", BFD_RELOC_PPC64_HIGHER),
+ MAP64 ("highera", BFD_RELOC_PPC64_HIGHER_S),
+ MAP64 ("highest", BFD_RELOC_PPC64_HIGHEST),
+ MAP64 ("highesta", BFD_RELOC_PPC64_HIGHEST_S),
+ MAP64 ("tocbase", BFD_RELOC_PPC64_TOC),
+ MAP64 ("toc", BFD_RELOC_PPC_TOC16),
+ MAP64 ("toc@l", BFD_RELOC_PPC64_TOC16_LO),
+ MAP64 ("toc@h", BFD_RELOC_PPC64_TOC16_HI),
+ MAP64 ("toc@ha", BFD_RELOC_PPC64_TOC16_HA),
+ MAP64 ("dtprel@higher", BFD_RELOC_PPC64_DTPREL16_HIGHER),
+ MAP64 ("dtprel@highera", BFD_RELOC_PPC64_DTPREL16_HIGHERA),
+ MAP64 ("dtprel@highest", BFD_RELOC_PPC64_DTPREL16_HIGHEST),
+ MAP64 ("dtprel@highesta", BFD_RELOC_PPC64_DTPREL16_HIGHESTA),
+ MAP64 ("tprel@higher", BFD_RELOC_PPC64_TPREL16_HIGHER),
+ MAP64 ("tprel@highera", BFD_RELOC_PPC64_TPREL16_HIGHERA),
+ MAP64 ("tprel@highest", BFD_RELOC_PPC64_TPREL16_HIGHEST),
+ MAP64 ("tprel@highesta", BFD_RELOC_PPC64_TPREL16_HIGHESTA),
+ { (char *) 0, 0, 0, 0, BFD_RELOC_UNUSED }
};
if (*str++ != '@')
for (ptr = &mapping[0]; ptr->length > 0; ptr++)
if (ch == ptr->string[0]
&& len == ptr->length
- && memcmp (ident, ptr->string, ptr->length) == 0)
+ && memcmp (ident, ptr->string, ptr->length) == 0
+ && (ppc_obj64 ? ptr->valid64 : ptr->valid32))
{
int reloc = ptr->reloc;
- if (reloc < 0)
- {
- if (!ppc_obj64)
- return BFD_RELOC_UNUSED;
- reloc = -reloc;
- }
-
if (!ppc_obj64)
if (exp_p->X_add_number != 0
&& (reloc == (int) BFD_RELOC_16_GOTOFF
*str_p = str;
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)
{
- /* This reloc type ignores the symbol. Change the symbol
- so that the dummy .TOC. symbol can be omitted from the
- object file. */
+ /* Change the symbol so that the dummy .TOC. symbol can be
+ omitted from the object file. */
exp_p->X_add_symbol = &abs_symbol;
}
ppc_frob_file_before_adjust ()
{
symbolS *symp;
+ asection *toc;
if (!ppc_obj64)
return;
free (dotname);
if (dotsym != NULL && (symbol_used_p (dotsym)
|| symbol_used_in_reloc_p (dotsym)))
- {
- symbol_mark_used (symp);
- }
+ symbol_mark_used (symp);
+
}
+ toc = bfd_get_section_by_name (stdoutput, ".toc");
+ if (toc != NULL
+ && bfd_section_size (stdoutput, toc) > 0x10000)
+ as_warn (_("TOC section size exceeds 64k"));
+
/* Don't emit .TOC. symbol. */
symp = symbol_find (".TOC.");
if (symp != NULL)
struct ppc_fixup fixups[MAX_INSN_FIXUPS];
int fc;
char *f;
+ int addr_mod;
int i;
#ifdef OBJ_ELF
bfd_reloc_code_real_type reloc;
/* PowerPC operands are just expressions. The only real issue is
that a few operand types are optional. All cases which might use
- an optional operand separate the operands only with commas (in
- some cases parentheses are used, as in ``lwz 1,0(1)'' but such
- cases never have optional operands). There is never more than
- one optional operand for an instruction. So, before we start
- seriously parsing the operands, we check to see if we have an
- optional operand, and, if we do, we count the number of commas to
- see whether the operand should be omitted. */
+ an optional operand separate the operands only with commas (in some
+ cases parentheses are used, as in ``lwz 1,0(1)'' but such cases never
+ have optional operands). Most instructions with optional operands
+ have only one. Those that have more than one optional operand can
+ take either all their operands or none. So, before we start seriously
+ parsing the operands, we check to see if we have optional operands,
+ and if we do, we count the number of commas to see which operands
+ have been omitted. */
skip_optional = 0;
for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++)
{
/* If there are fewer operands in the line then are called
for by the instruction, we want to skip the optional
- operand. */
+ operands. */
if (opcount < num_operands_expected)
skip_optional = 1;
}
if (ppc_obj64
- && (operand->flags & PPC_OPERAND_DS) != 0)
+ && (operand->flags & (PPC_OPERAND_DS | PPC_OPERAND_DQ)) != 0)
{
switch (reloc)
{
/* Write out the instruction. */
f = frag_more (4);
+ addr_mod = frag_now_fix () & 3;
+ if (frag_now->has_code && frag_now->insn_addr != addr_mod)
+ as_bad (_("instruction address is not a multiple of 4"));
+ frag_now->insn_addr = addr_mod;
+ frag_now->has_code = 1;
md_number_to_chars (f, insn, 4);
#ifdef OBJ_ELF
/* The .comm and .lcomm pseudo-ops for XCOFF. XCOFF puts common
symbols in the .bss segment as though they were local common
- symbols, and uses a different smclas. The native Aix 4.3.3 assember
+ symbols, and uses a different smclas. The native Aix 4.3.3 assembler
aligns .comm and .lcomm to 4 bytes. */
static void
char *name;
char endc;
symbolS *sym;
+ offsetT align;
name = input_line_pointer;
endc = get_symbol_end ();
symbol_get_tc (sym)->class = XMC_PR;
}
- ppc_change_csect (sym);
-
+ align = 2;
if (*input_line_pointer == ',')
{
++input_line_pointer;
- symbol_get_tc (sym)->align = get_absolute_expression ();
+ align = get_absolute_expression ();
}
+ ppc_change_csect (sym, align);
+
demand_empty_rest_of_line ();
}
/* Change to a different csect. */
static void
-ppc_change_csect (sym)
+ppc_change_csect (sym, align)
symbolS *sym;
+ offsetT align;
{
if (S_IS_DEFINED (sym))
subseg_set (S_GET_SEGMENT (sym), symbol_get_tc (sym)->subseg);
int after_toc;
int hold_chunksize;
symbolS *list;
+ int is_code;
+ segT sec;
/* This is a new csect. We need to look at the symbol class to
figure out whether it should go in the text section or the
data section. */
after_toc = 0;
+ is_code = 0;
switch (symbol_get_tc (sym)->class)
{
case XMC_PR:
symbol_get_tc (sym)->subseg = ppc_text_subsegment;
++ppc_text_subsegment;
list_ptr = &ppc_text_csects;
+ is_code = 1;
break;
case XMC_RW:
case XMC_TC0:
hold_chunksize = chunksize;
chunksize = 64;
- subseg_new (segment_name (S_GET_SEGMENT (sym)),
- symbol_get_tc (sym)->subseg);
+ sec = subseg_new (segment_name (S_GET_SEGMENT (sym)),
+ symbol_get_tc (sym)->subseg);
chunksize = hold_chunksize;
if (after_toc)
ppc_after_toc_frag = frag_now;
+ record_alignment (sec, align);
+ if (is_code)
+ frag_align_code (align, 0);
+ else
+ frag_align (align, 0, 0);
+
symbol_set_frag (sym, frag_now);
S_SET_VALUE (sym, (valueT) frag_now_fix ());
- symbol_get_tc (sym)->align = 2;
+ symbol_get_tc (sym)->align = align;
symbol_get_tc (sym)->output = 1;
symbol_get_tc (sym)->within = sym;
sym = symbol_find_or_make (name);
- ppc_change_csect (sym);
+ ppc_change_csect (sym, 2);
demand_empty_rest_of_line ();
}
sym = symbol_find_or_make (real_name);
- ppc_change_csect (sym);
+ ppc_change_csect (sym, 2);
demand_empty_rest_of_line ();
}
/* The .function pseudo-op. This takes several arguments. The first
argument seems to be the external name of the symbol. The second
- argment 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
fourth arguments are meant to be. The optional fifth argument is
an expression for the size of the function. In COFF this symbol
give to this location in the toc; this will be a symbol with class
TC. The rest of the arguments are N-byte values to actually put at
this location in the TOC; often there is just one more argument, a
- relocateable 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
64-bit target uses 8-byte values.
}
/* Pseudo-op .machine. */
-/* FIXME: `.machine' is a nop for the moment. It would be nice to
- accept this directive on the first line of input and set ppc_obj64
- and the target format accordingly. Unfortunately, the target
- format is selected in output-file.c:output_file_create before we
- even get to md_begin, so it's not possible without changing
- as.c:main. */
static void
ppc_machine (ignore)
int ignore ATTRIBUTE_UNUSED;
{
- discard_rest_of_line ();
+ char *cpu_string;
+#define MAX_HISTORY 100
+ static unsigned long *cpu_history;
+ static int curr_hist;
+
+ SKIP_WHITESPACE ();
+
+ if (*input_line_pointer == '"')
+ {
+ int len;
+ cpu_string = demand_copy_C_string (&len);
+ }
+ else
+ {
+ char c;
+ cpu_string = input_line_pointer;
+ c = get_symbol_end ();
+ cpu_string = xstrdup (cpu_string);
+ *input_line_pointer = c;
+ }
+
+ if (cpu_string != NULL)
+ {
+ unsigned long old_cpu = ppc_cpu;
+ char *p;
+
+ for (p = cpu_string; *p != 0; p++)
+ *p = TOLOWER (*p);
+
+ if (strcmp (cpu_string, "push") == 0)
+ {
+ if (cpu_history == NULL)
+ cpu_history = xmalloc (MAX_HISTORY * sizeof (*cpu_history));
+
+ if (curr_hist >= MAX_HISTORY)
+ as_bad (_(".machine stack overflow"));
+ else
+ cpu_history[curr_hist++] = ppc_cpu;
+ }
+ else if (strcmp (cpu_string, "pop") == 0)
+ {
+ if (curr_hist <= 0)
+ as_bad (_(".machine stack underflow"));
+ else
+ ppc_cpu = cpu_history[--curr_hist];
+ }
+ else if (parse_cpu (cpu_string))
+ ;
+ else
+ as_bad (_("invalid machine `%s'"), cpu_string);
+
+ if (ppc_cpu != old_cpu)
+ ppc_setup_opcodes ();
+ }
+
+ demand_empty_rest_of_line ();
}
/* See whether a symbol is in the TOC section. */
table. */
if (! symbol_used_in_reloc_p (sym)
&& ((symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) != 0
- || (! S_IS_EXTERNAL (sym)
+ || (! (S_IS_EXTERNAL (sym) || S_IS_WEAK (sym))
&& ! symbol_get_tc (sym)->output
&& S_GET_STORAGE_CLASS (sym) != C_FILE)))
return 1;
}
}
- if (! S_IS_EXTERNAL (sym)
+ if (! (S_IS_EXTERNAL (sym) || S_IS_WEAK (sym))
&& (symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) == 0
&& S_GET_STORAGE_CLASS (sym) != C_FILE
&& S_GET_STORAGE_CLASS (sym) != C_FCN
ppc_frob_section (sec)
asection *sec;
{
- static bfd_size_type vma = 0;
+ static bfd_vma vma = 0;
+ vma = md_section_align (sec, vma);
bfd_set_section_vma (stdoutput, sec, vma);
vma += bfd_section_size (stdoutput, sec);
}
abort ();
{
unsigned char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
- unsigned long val;
+ unsigned long val, mask;
if (target_big_endian)
- val = bfd_getb16 (where);
+ val = bfd_getb32 (where - 2);
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)) == (56u << 26))
+ mask = 0xfff0;
+ val |= value & mask;
if (target_big_endian)
bfd_putb16 ((bfd_vma) val, where);
else
}
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_8:
if (fixP->fx_pcrel)
- abort ();
-
- md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
- value, 1);
+ {
+ /* This can occur if there is a bug in the input assembler, eg:
+ ".byte <undefined_symbol> - ." */
+ if (fixP->fx_addsy)
+ as_bad (_("Unable to handle reference to symbol %s"),
+ S_GET_NAME (fixP->fx_addsy));
+ else
+ as_bad (_("Unable to resolve expression"));
+ fixP->fx_done = 1;
+ }
+ else
+ md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+ value, 1);
break;
case BFD_RELOC_24_PLT_PCREL:
return reloc;
}
+
+void
+ppc_cfi_frame_initial_instructions ()
+{
+ cfi_add_CFA_def_cfa (1, 0);
+}
+
+int
+tc_ppc_regname_to_dw2regnum (const char *regname)
+{
+ unsigned int regnum = -1;
+ unsigned int i;
+ const char *p;
+ char *q;
+ static struct { char *name; int dw2regnum; } regnames[] =
+ {
+ { "sp", 1 }, { "r.sp", 1 }, { "rtoc", 2 }, { "r.toc", 2 },
+ { "mq", 64 }, { "lr", 65 }, { "ctr", 66 }, { "ap", 67 },
+ { "cr", 70 }, { "xer", 76 }, { "vrsave", 109 }, { "vscr", 110 },
+ { "spe_acc", 111 }, { "spefscr", 112 }
+ };
+
+ for (i = 0; i < ARRAY_SIZE (regnames); ++i)
+ if (strcmp (regnames[i].name, regname) == 0)
+ return regnames[i].dw2regnum;
+
+ if (regname[0] == 'r' || regname[0] == 'f' || regname[0] == 'v')
+ {
+ p = regname + 1 + (regname[1] == '.');
+ regnum = strtoul (p, &q, 10);
+ if (p == q || *q || regnum >= 32)
+ return -1;
+ if (regname[0] == 'f')
+ regnum += 32;
+ else if (regname[0] == 'v')
+ regnum += 77;
+ }
+ else if (regname[0] == 'c' && regname[1] == 'r')
+ {
+ p = regname + 2 + (regname[2] == '.');
+ if (p[0] < '0' || p[0] > '7' || p[1])
+ return -1;
+ regnum = p[0] - '0' + 68;
+ }
+ return regnum;
+}