/* tc-ppc.c -- Assemble for the PowerPC or POWER (RS/6000)
- Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
- 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
- Free Software Foundation, Inc.
+ Copyright (C) 1994-2016 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Cygnus Support.
This file is part of GAS, the GNU Assembler.
#ifdef OBJ_ELF
#include "elf/ppc.h"
+#include "elf/ppc64.h"
#include "dwarf2dbg.h"
#endif
compensating for #lo being treated as a signed number. */
#define PPC_HIGHESTA(v) PPC_HIGHEST ((v) + 0x8000)
-#define SEX16(val) ((((val) & 0xffff) ^ 0x8000) - 0x8000)
+#define SEX16(val) (((val) ^ 0x8000) - 0x8000)
+
+/* For the time being on ppc64, don't report overflow on @h and @ha
+ applied to constants. */
+#define REPORT_OVERFLOW_HI 0
static bfd_boolean reg_names_p = TARGET_REG_NAMES_P;
#endif
#ifdef OBJ_ELF
-static void ppc_elf_cons (int);
static void ppc_elf_rdata (int);
static void ppc_elf_lcomm (int);
+static void ppc_elf_localentry (int);
+static void ppc_elf_abiversion (int);
+static void ppc_elf_gnu_attribute (int);
#endif
#ifdef TE_PE
ppc_cpu_t ppc_cpu = 0;
ppc_cpu_t sticky = 0;
+/* Value for ELF e_flags EF_PPC64_ABI. */
+unsigned int ppc_abiversion = 0;
+
+#ifdef OBJ_ELF
/* Flags set on encountering toc relocs. */
-enum {
+static enum {
has_large_toc_reloc = 1,
has_small_toc_reloc = 2
} toc_reloc_types;
+#endif
+
+/* Warn on emitting data to code sections. */
+int warn_476;
+unsigned long last_insn;
+segT last_seg;
+subsegT last_subseg;
\f
/* The target specific pseudo-ops which we support. */
#endif
#ifdef OBJ_ELF
- { "llong", ppc_elf_cons, 8 },
- { "quad", ppc_elf_cons, 8 },
- { "long", ppc_elf_cons, 4 },
- { "word", ppc_elf_cons, 2 },
- { "short", ppc_elf_cons, 2 },
+ { "llong", cons, 8 },
{ "rdata", ppc_elf_rdata, 0 },
{ "rodata", ppc_elf_rdata, 0 },
{ "lcomm", ppc_elf_lcomm, 0 },
+ { "localentry", ppc_elf_localentry, 0 },
+ { "abiversion", ppc_elf_abiversion, 0 },
+ { "gnu_attribute", ppc_elf_gnu_attribute, 0},
#endif
#ifdef TE_PE
/* Structure to hold information about predefined registers. */
struct pd_reg
{
- char *name;
+ const char *name;
int value;
};
else if (!reg_names_p || !ISALPHA (name[0]))
return FALSE;
- c = get_symbol_end ();
+ c = get_symbol_name (&name);
reg_number = reg_name_search (pre_defined_registers, REG_NAME_CNT, name);
/* Put back the delimiting char. */
#ifdef OBJ_ELF
symbolS *GOT_symbol; /* Pre-defined "_GLOBAL_OFFSET_TABLE" */
-#define PPC_APUINFO_ISEL 0x40
-#define PPC_APUINFO_PMR 0x41
-#define PPC_APUINFO_RFMCI 0x42
-#define PPC_APUINFO_CACHELCK 0x43
-#define PPC_APUINFO_SPE 0x100
-#define PPC_APUINFO_EFS 0x101
-#define PPC_APUINFO_BRLOCK 0x102
-#define PPC_APUINFO_VLE 0x104
-
-/*
- * We keep a list of APUinfo
- */
unsigned long *ppc_apuinfo_list;
unsigned int ppc_apuinfo_num;
unsigned int ppc_apuinfo_num_alloc;
#define OPTION_NOPS (OPTION_MD_BASE + 0)
const struct option md_longopts[] = {
{"nops", required_argument, NULL, OPTION_NOPS},
+ {"ppc476-workaround", no_argument, &warn_476, 1},
+ {"no-ppc476-workaround", no_argument, &warn_476, 0},
{NULL, no_argument, NULL, 0}
};
const size_t md_longopts_size = sizeof (md_longopts);
int
-md_parse_option (int c, char *arg)
+md_parse_option (int c, const char *arg)
{
ppc_cpu_t new_cpu;
}
break;
+ case 0:
+ break;
+
default:
return 0;
}
-m476 generate code for PowerPC 476\n\
-m7400, -m7410, -m7450, -m7455\n\
generate code for PowerPC 7400/7410/7450/7455\n\
--m750cl generate code for PowerPC 750cl\n"));
+-m750cl generate code for PowerPC 750cl\n\
+-m821, -m850, -m860 generate code for PowerPC 821/850/860\n"));
fprintf (stream, _("\
-mppc64, -m620 generate code for PowerPC 620/625/630\n\
-mppc64bridge generate code for PowerPC 64, including bridge insns\n\
-mpower6, -mpwr6 generate code for Power6 architecture\n\
-mpower7, -mpwr7 generate code for Power7 architecture\n\
-mpower8, -mpwr8 generate code for Power8 architecture\n\
+-mpower9, -mpwr9 generate code for Power9 architecture\n\
-mcell generate code for Cell Broadband Engine architecture\n\
-mcom generate code Power/PowerPC common instructions\n\
-many generate code for any architecture (PWR/PWRX/PPC)\n"));
-Qy, -Qn ignored\n"));
#endif
fprintf (stream, _("\
--nops=count when aligning, more than COUNT nops uses a branch\n"));
+-nops=count when aligning, more than COUNT nops uses a branch\n\
+-ppc476-workaround warn if emitting data to code sections\n"));
}
\f
/* Set ppc_cpu if it is not already set. */
return bfd_mach_ppc;
}
-extern char*
+extern const char*
ppc_target_format (void)
{
#ifdef OBJ_COFF
else
{
const struct powerpc_operand *operand = &powerpc_operands[*o];
- if (operand->shift != PPC_OPSHIFT_INV)
+ if (operand->shift != (int) PPC_OPSHIFT_INV)
{
unsigned long mask;
bad_insn = TRUE;
}
}
+ if ((op->flags & PPC_OPCODE_VLE) != 0)
+ {
+ as_bad (_("%s is enabled by vle flag"), op->name);
+ bad_insn = TRUE;
+ }
+ if (PPC_OP (op->opcode) != 4
+ && PPC_OP (op->opcode) != 31
+ && (op->deprecated & PPC_OPCODE_VLE) == 0)
+ {
+ as_bad (_("%s not disabled by vle flag"), op->name);
+ bad_insn = TRUE;
+ }
bad_insn |= insn_validate (op);
}
}
}
- if ((ppc_cpu & PPC_OPCODE_VLE) != 0)
- for (op = vle_opcodes; op < op_end; op++)
- hash_insert (ppc_hash, op->name, (void *) op);
-
/* Insert the macros into a hash table. */
ppc_macro_hash = hash_new ();
unsigned int i;
/* Create the .PPC.EMB.apuinfo section. */
- apuinfo_secp = subseg_new (".PPC.EMB.apuinfo", 0);
+ apuinfo_secp = subseg_new (APUINFO_SECTION_NAME, 0);
bfd_set_section_flags (stdoutput,
apuinfo_secp,
SEC_HAS_CONTENTS | SEC_READONLY);
md_number_to_chars (p, (valueT) 2, 4);
p = frag_more (8);
- strcpy (p, "APUinfo");
+ strcpy (p, APUINFO_LABEL);
for (i = 0; i < ppc_apuinfo_num; i++)
{
const struct powerpc_operand *operand,
offsetT val,
ppc_cpu_t cpu,
- char *file,
+ const char *file,
unsigned int line)
{
long min, max, right;
right = max & -max;
min = 0;
- if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
+ if ((operand->flags & PPC_OPERAND_SIGNOPT) != 0)
{
- if ((operand->flags & PPC_OPERAND_SIGNOPT) == 0)
- max = (max >> 1) & -right;
+ /* Extend the allowed range for addis to [-32768, 65535].
+ Similarly for cmpli and some VLE high part insns. For 64-bit
+ it would be good to disable this for signed fields since the
+ value is sign extended into the high 32 bits of the register.
+ If the value is, say, an address, then we might care about
+ the high bits. However, gcc as of 2014-06 uses unsigned
+ values when loading the high part of 64-bit constants using
+ lis. */
+ min = ~(max >> 1) & -right;
+ }
+ else if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
+ {
+ max = (max >> 1) & -right;
min = ~max & -right;
}
ppc_elf_suffix (char **str_p, expressionS *exp_p)
{
struct map_bfd {
- char *string;
+ const char *string;
unsigned int length : 8;
unsigned int valid32 : 1;
unsigned int valid64 : 1;
MAP32 ("bitfld", BFD_RELOC_PPC_EMB_BIT_FLD),
MAP32 ("relsda", BFD_RELOC_PPC_EMB_RELSDA),
MAP32 ("xgot", BFD_RELOC_PPC_TOC16),
+ MAP64 ("high", BFD_RELOC_PPC64_ADDR16_HIGH),
+ MAP64 ("higha", BFD_RELOC_PPC64_ADDR16_HIGHA),
MAP64 ("higher", BFD_RELOC_PPC64_HIGHER),
MAP64 ("highera", BFD_RELOC_PPC64_HIGHER_S),
MAP64 ("highest", BFD_RELOC_PPC64_HIGHEST),
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@high", BFD_RELOC_PPC64_DTPREL16_HIGH),
+ MAP64 ("dtprel@higha", BFD_RELOC_PPC64_DTPREL16_HIGHA),
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 ("localentry", BFD_RELOC_PPC64_ADDR64_LOCAL),
+ MAP64 ("tprel@high", BFD_RELOC_PPC64_TPREL16_HIGH),
+ MAP64 ("tprel@higha", BFD_RELOC_PPC64_TPREL16_HIGHA),
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 }
+ { (char *) 0, 0, 0, 0, BFD_RELOC_NONE }
};
if (*str++ != '@')
- return BFD_RELOC_UNUSED;
+ return BFD_RELOC_NONE;
for (ch = *str, str2 = ident;
(str2 < ident + sizeof (ident) - 1
return (bfd_reloc_code_real_type) reloc;
}
- return BFD_RELOC_UNUSED;
+ return BFD_RELOC_NONE;
}
-/* Like normal .long/.short/.word, except support @got, etc.
- Clobbers input_line_pointer, checks end-of-line. */
-static void
-ppc_elf_cons (int nbytes /* 1=.byte, 2=.word, 4=.long, 8=.llong */)
-{
- expressionS exp;
- bfd_reloc_code_real_type reloc;
-
- if (is_it_end_of_statement ())
- {
- demand_empty_rest_of_line ();
- return;
- }
+/* Support @got, etc. on constants emitted via .short, .int etc. */
- do
- {
- expression (&exp);
- if (*input_line_pointer == '@'
- && (reloc = ppc_elf_suffix (&input_line_pointer,
- &exp)) != BFD_RELOC_UNUSED)
- {
- reloc_howto_type *reloc_howto;
- int size;
+bfd_reloc_code_real_type
+ppc_elf_parse_cons (expressionS *exp, unsigned int nbytes)
+{
+ expression (exp);
+ if (nbytes >= 2 && *input_line_pointer == '@')
+ return ppc_elf_suffix (&input_line_pointer, exp);
+ return BFD_RELOC_NONE;
+}
- reloc_howto = bfd_reloc_type_lookup (stdoutput, reloc);
- size = bfd_get_reloc_size (reloc_howto);
+/* Warn when emitting data to code sections, unless we are emitting
+ a relocation that ld --ppc476-workaround uses to recognise data
+ *and* there was an unconditional branch prior to the data. */
- if (size > nbytes)
- {
- as_bad (_("%s relocations do not fit in %d bytes\n"),
- reloc_howto->name, nbytes);
- }
- else
- {
- char *p;
- int offset;
-
- p = frag_more (nbytes);
- memset (p, 0, nbytes);
- offset = 0;
- if (target_big_endian)
- offset = nbytes - size;
- fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size,
- &exp, 0, reloc);
- }
- }
- else
- emit_expr (&exp, (unsigned int) nbytes);
+void
+ppc_elf_cons_fix_check (expressionS *exp ATTRIBUTE_UNUSED,
+ unsigned int nbytes, fixS *fix)
+{
+ if (warn_476
+ && (now_seg->flags & SEC_CODE) != 0
+ && (nbytes != 4
+ || fix == NULL
+ || !(fix->fx_r_type == BFD_RELOC_32
+ || fix->fx_r_type == BFD_RELOC_CTOR
+ || fix->fx_r_type == BFD_RELOC_32_PCREL)
+ || !(last_seg == now_seg && last_subseg == now_subseg)
+ || !((last_insn & (0x3f << 26)) == (18u << 26)
+ || ((last_insn & (0x3f << 26)) == (16u << 26)
+ && (last_insn & (0x14 << 21)) == (0x14 << 21))
+ || ((last_insn & (0x3f << 26)) == (19u << 26)
+ && (last_insn & (0x3ff << 1)) == (16u << 1)
+ && (last_insn & (0x14 << 21)) == (0x14 << 21)))))
+ {
+ /* Flag that we've warned. */
+ if (fix != NULL)
+ fix->fx_tcbit = 1;
+
+ as_warn (_("data in executable section"));
}
- while (*input_line_pointer++ == ',');
-
- /* Put terminator back into stream. */
- input_line_pointer--;
- demand_empty_rest_of_line ();
}
/* Solaris pseduo op to change to the .rodata section. */
char *pfrag;
int align2;
- name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&name);
- /* just after name is now '\0'. */
+ /* Just after name is now '\0'. */
p = input_line_pointer;
*p = c;
- SKIP_WHITESPACE ();
+ SKIP_WHITESPACE_AFTER_NAME ();
if (*input_line_pointer != ',')
{
as_bad (_("expected comma after symbol-name: rest of line ignored."));
demand_empty_rest_of_line ();
}
+/* Pseudo op to set symbol local entry point. */
+static void
+ppc_elf_localentry (int ignore ATTRIBUTE_UNUSED)
+{
+ char *name;
+ char c = get_symbol_name (&name);
+ char *p;
+ expressionS exp;
+ symbolS *sym;
+ asymbol *bfdsym;
+ elf_symbol_type *elfsym;
+
+ p = input_line_pointer;
+ *p = c;
+ SKIP_WHITESPACE_AFTER_NAME ();
+ if (*input_line_pointer != ',')
+ {
+ *p = 0;
+ as_bad (_("expected comma after name `%s' in .localentry directive"),
+ name);
+ *p = c;
+ ignore_rest_of_line ();
+ return;
+ }
+ input_line_pointer++;
+ expression (&exp);
+ if (exp.X_op == O_absent)
+ {
+ as_bad (_("missing expression in .localentry directive"));
+ exp.X_op = O_constant;
+ exp.X_add_number = 0;
+ }
+ *p = 0;
+ sym = symbol_find_or_make (name);
+ *p = c;
+
+ if (resolve_expression (&exp)
+ && exp.X_op == O_constant)
+ {
+ unsigned char encoded = PPC64_SET_LOCAL_ENTRY_OFFSET (exp.X_add_number);
+
+ if (exp.X_add_number != (offsetT) PPC64_LOCAL_ENTRY_OFFSET (encoded))
+ as_bad (_(".localentry expression for `%s' "
+ "is not a valid power of 2"), S_GET_NAME (sym));
+ else
+ {
+ bfdsym = symbol_get_bfdsym (sym);
+ elfsym = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym);
+ gas_assert (elfsym);
+ elfsym->internal_elf_sym.st_other &= ~STO_PPC64_LOCAL_MASK;
+ elfsym->internal_elf_sym.st_other |= encoded;
+ if (ppc_abiversion == 0)
+ ppc_abiversion = 2;
+ }
+ }
+ else
+ as_bad (_(".localentry expression for `%s' "
+ "does not evaluate to a constant"), S_GET_NAME (sym));
+
+ demand_empty_rest_of_line ();
+}
+
+/* Pseudo op to set ABI version. */
+static void
+ppc_elf_abiversion (int ignore ATTRIBUTE_UNUSED)
+{
+ expressionS exp;
+
+ expression (&exp);
+ if (exp.X_op == O_absent)
+ {
+ as_bad (_("missing expression in .abiversion directive"));
+ exp.X_op = O_constant;
+ exp.X_add_number = 0;
+ }
+
+ if (resolve_expression (&exp)
+ && exp.X_op == O_constant)
+ ppc_abiversion = exp.X_add_number;
+ else
+ as_bad (_(".abiversion expression does not evaluate to a constant"));
+ demand_empty_rest_of_line ();
+}
+
+/* Parse a .gnu_attribute directive. */
+static void
+ppc_elf_gnu_attribute (int ignored ATTRIBUTE_UNUSED)
+{
+ int tag = obj_elf_vendor_attribute (OBJ_ATTR_GNU);
+
+ /* Check validity of defined powerpc tags. */
+ if (tag == Tag_GNU_Power_ABI_FP
+ || tag == Tag_GNU_Power_ABI_Vector
+ || tag == Tag_GNU_Power_ABI_Struct_Return)
+ {
+ unsigned int val;
+
+ val = bfd_elf_get_obj_attr_int (stdoutput, OBJ_ATTR_GNU, tag);
+
+ if ((tag == Tag_GNU_Power_ABI_FP && val > 15)
+ || (tag == Tag_GNU_Power_ABI_Vector && val > 3)
+ || (tag == Tag_GNU_Power_ABI_Struct_Return && val > 2))
+ as_warn (_("unknown .gnu_attribute value"));
+ }
+}
+
+/* Set ABI version in output file. */
+void
+ppc_elf_end (void)
+{
+ if (ppc_obj64 && ppc_abiversion != 0)
+ {
+ elf_elfheader (stdoutput)->e_flags &= ~EF_PPC64_ABI;
+ elf_elfheader (stdoutput)->e_flags |= ppc_abiversion & EF_PPC64_ABI;
+ }
+}
+
/* Validate any relocations emitted for -mrelocatable, possibly adding
fixups for word relocations in writable segments, so we can adjust
them at runtime. */
return;
case SHLIB_MRELOCATABLE:
- if (fixp->fx_r_type <= BFD_RELOC_UNUSED
- && fixp->fx_r_type != BFD_RELOC_16_GOTOFF
+ if (fixp->fx_r_type != BFD_RELOC_16_GOTOFF
&& fixp->fx_r_type != BFD_RELOC_HI16_GOTOFF
&& fixp->fx_r_type != BFD_RELOC_LO16_GOTOFF
&& fixp->fx_r_type != BFD_RELOC_HI16_S_GOTOFF
const char *name;
char *dotname;
symbolS *dotsym;
- size_t len;
name = S_GET_NAME (symp);
if (name[0] == '.')
|| S_IS_DEFINED (symp))
continue;
- len = strlen (name) + 1;
- dotname = xmalloc (len + 1);
- dotname[0] = '.';
- memcpy (dotname + 1, name, len);
+ dotname = concat (".", name, (char *) NULL);
dotsym = symbol_find_noref (dotname, 1);
free (dotname);
if (dotsym != NULL && (symbol_used_p (dotsym)
SKIP_WHITESPACE ();
/* Find the spelling of the operand. */
- toc_spec = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&toc_spec);
if (strcmp (toc_spec, "toc") == 0)
{
/* Now find the ']'. */
*input_line_pointer = c;
- SKIP_WHITESPACE (); /* leading whitespace could be there. */
+ SKIP_WHITESPACE_AFTER_NAME (); /* leading whitespace could be there. */
c = *input_line_pointer++; /* input_line_pointer->past char in c. */
if (c != ']')
if (ppc_apuinfo_num_alloc == 0)
{
ppc_apuinfo_num_alloc = 4;
- ppc_apuinfo_list = (unsigned long *)
- xmalloc (sizeof (unsigned long) * ppc_apuinfo_num_alloc);
+ ppc_apuinfo_list = XNEWVEC (unsigned long, ppc_apuinfo_num_alloc);
}
else
{
ppc_apuinfo_num_alloc += 4;
- ppc_apuinfo_list = (unsigned long *) xrealloc (ppc_apuinfo_list,
- sizeof (unsigned long) * ppc_apuinfo_num_alloc);
+ ppc_apuinfo_list = XRESIZEVEC (unsigned long, ppc_apuinfo_list,
+ ppc_apuinfo_num_alloc);
}
}
ppc_apuinfo_list[ppc_apuinfo_num++] = APUID (apu, version);
#define MAX_INSN_FIXUPS (5)
-/* Form I16L. */
-#define E_OR2I_INSN 0x7000C000
-#define E_AND2I_DOT_INSN 0x7000C800
-#define E_OR2IS_INSN 0x7000D000
-#define E_LIS_INSN 0x7000E000
-#define E_AND2IS_DOT_INSN 0x7000E800
-
-/* Form I16A. */
-#define E_ADD2I_DOT_INSN 0x70008800
-#define E_ADD2IS_INSN 0x70009000
-#define E_CMP16I_INSN 0x70009800
-#define E_MULL2I_INSN 0x7000A000
-#define E_CMPL16I_INSN 0x7000A800
-#define E_CMPH16I_INSN 0x7000B000
-#define E_CMPHL16I_INSN 0x7000B800
-
/* This routine is called for each instruction to be assembled. */
void
const struct powerpc_operand *operand;
operand = &powerpc_operands[*opindex_ptr];
- if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0)
+ if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
+ && !((operand->flags & PPC_OPERAND_OPTIONAL32) != 0 && ppc_obj64))
{
unsigned int opcount;
unsigned int num_operands_expected;
/* If this is an optional operand, and we are skipping it, just
insert a zero. */
if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
+ && !((operand->flags & PPC_OPERAND_OPTIONAL32) != 0 && ppc_obj64)
&& skip_optional)
{
+ long val = ppc_optional_operand_value (operand);
if (operand->insert)
{
- insn = (*operand->insert) (insn, 0L, ppc_cpu, &errmsg);
+ insn = (*operand->insert) (insn, val, ppc_cpu, &errmsg);
if (errmsg != (const char *) NULL)
as_bad ("%s", errmsg);
}
+ else if (operand->shift >= 0)
+ insn |= ((long) val & operand->bitm) << operand->shift;
+ else
+ insn |= ((long) val & operand->bitm) >> -operand->shift;
+
if ((operand->flags & PPC_OPERAND_NEXT) != 0)
next_opindex = *opindex_ptr + 1;
continue;
/* FIXME: these next two specifically specify 32/64 bit
toc entries. We don't support them today. Is this
the right way to say that? */
- toc_reloc = BFD_RELOC_UNUSED;
+ toc_reloc = BFD_RELOC_NONE;
as_bad (_("unimplemented toc32 expression modifier"));
break;
case must_be_64:
/* FIXME: see above. */
- toc_reloc = BFD_RELOC_UNUSED;
+ toc_reloc = BFD_RELOC_NONE;
as_bad (_("unimplemented toc64 expression modifier"));
break;
default:
bfd_reloc_code_real_type reloc;
char *orig_str = str;
- if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)
+ if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_NONE)
switch (reloc)
{
default:
break;
case BFD_RELOC_LO16:
- /* X_unsigned is the default, so if the user has done
- something which cleared it, we always produce a
- signed value. */
- if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
- ex.X_add_number &= 0xffff;
- else
+ ex.X_add_number &= 0xffff;
+ if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
ex.X_add_number = SEX16 (ex.X_add_number);
break;
case BFD_RELOC_HI16:
- if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
- ex.X_add_number = PPC_HI (ex.X_add_number);
- else
- ex.X_add_number = SEX16 (PPC_HI (ex.X_add_number));
+ if (REPORT_OVERFLOW_HI && ppc_obj64)
+ {
+ /* PowerPC64 @h is tested for overflow. */
+ ex.X_add_number = (addressT) ex.X_add_number >> 16;
+ if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
+ {
+ addressT sign = (((addressT) -1 >> 16) + 1) >> 1;
+ ex.X_add_number
+ = ((addressT) ex.X_add_number ^ sign) - sign;
+ }
+ break;
+ }
+ /* Fall thru */
+
+ case BFD_RELOC_PPC64_ADDR16_HIGH:
+ ex.X_add_number = PPC_HI (ex.X_add_number);
+ if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
+ ex.X_add_number = SEX16 (ex.X_add_number);
break;
case BFD_RELOC_HI16_S:
- if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
- ex.X_add_number = PPC_HA (ex.X_add_number);
- else
- ex.X_add_number = SEX16 (PPC_HA (ex.X_add_number));
+ if (REPORT_OVERFLOW_HI && ppc_obj64)
+ {
+ /* PowerPC64 @ha is tested for overflow. */
+ ex.X_add_number
+ = ((addressT) ex.X_add_number + 0x8000) >> 16;
+ if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
+ {
+ addressT sign = (((addressT) -1 >> 16) + 1) >> 1;
+ ex.X_add_number
+ = ((addressT) ex.X_add_number ^ sign) - sign;
+ }
+ break;
+ }
+ /* Fall thru */
+
+ case BFD_RELOC_PPC64_ADDR16_HIGHA:
+ ex.X_add_number = PPC_HA (ex.X_add_number);
+ if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
+ ex.X_add_number = SEX16 (ex.X_add_number);
break;
case BFD_RELOC_PPC64_HIGHER:
- if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
- ex.X_add_number = PPC_HIGHER (ex.X_add_number);
- else
- ex.X_add_number = SEX16 (PPC_HIGHER (ex.X_add_number));
+ ex.X_add_number = PPC_HIGHER (ex.X_add_number);
+ if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
+ ex.X_add_number = SEX16 (ex.X_add_number);
break;
case BFD_RELOC_PPC64_HIGHER_S:
- if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
- ex.X_add_number = PPC_HIGHERA (ex.X_add_number);
- else
- ex.X_add_number = SEX16 (PPC_HIGHERA (ex.X_add_number));
+ ex.X_add_number = PPC_HIGHERA (ex.X_add_number);
+ if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
+ ex.X_add_number = SEX16 (ex.X_add_number);
break;
case BFD_RELOC_PPC64_HIGHEST:
- if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
- ex.X_add_number = PPC_HIGHEST (ex.X_add_number);
- else
- ex.X_add_number = SEX16 (PPC_HIGHEST (ex.X_add_number));
+ ex.X_add_number = PPC_HIGHEST (ex.X_add_number);
+ if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
+ ex.X_add_number = SEX16 (ex.X_add_number);
break;
case BFD_RELOC_PPC64_HIGHEST_S:
- if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
- ex.X_add_number = PPC_HIGHESTA (ex.X_add_number);
- else
- ex.X_add_number = SEX16 (PPC_HIGHESTA (ex.X_add_number));
+ ex.X_add_number = PPC_HIGHESTA (ex.X_add_number);
+ if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
+ ex.X_add_number = SEX16 (ex.X_add_number);
break;
}
#endif /* OBJ_ELF */
}
else
{
- bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
+ bfd_reloc_code_real_type reloc = BFD_RELOC_NONE;
#ifdef OBJ_ELF
if (ex.X_op == O_symbol && str[0] == '(')
{
expression (&tls_exp);
if (tls_exp.X_op == O_symbol)
{
- reloc = BFD_RELOC_UNUSED;
+ reloc = BFD_RELOC_NONE;
if (strncasecmp (input_line_pointer, "@tlsgd)", 7) == 0)
{
reloc = BFD_RELOC_PPC_TLSGD;
reloc = BFD_RELOC_PPC_TLSLD;
input_line_pointer += 7;
}
- if (reloc != BFD_RELOC_UNUSED)
+ if (reloc != BFD_RELOC_NONE)
{
SKIP_WHITESPACE ();
str = input_line_pointer;
}
}
- if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)
+ if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_NONE)
{
/* Some TLS tweaks. */
switch (reloc)
break;
}
+ /* addpcis. */
+ if (opcode->opcode == (19 << 26) + (2 << 1)
+ && reloc == BFD_RELOC_HI16_S)
+ reloc = BFD_RELOC_PPC_REL16DX_HA;
+
/* If VLE-mode convert LO/HI/HA relocations. */
if (opcode->flags & PPC_OPCODE_VLE)
{
int tmp_insn = insn & opcode->mask;
-
- int use_d_reloc = (tmp_insn == E_OR2I_INSN
+
+ int use_a_reloc = (tmp_insn == E_OR2I_INSN
|| tmp_insn == E_AND2I_DOT_INSN
|| tmp_insn == E_OR2IS_INSN
|| tmp_insn == E_LIS_INSN
|| tmp_insn == E_AND2IS_DOT_INSN);
- int use_a_reloc = (tmp_insn == E_ADD2I_DOT_INSN
+ int use_d_reloc = (tmp_insn == E_ADD2I_DOT_INSN
|| tmp_insn == E_ADD2IS_INSN
|| tmp_insn == E_CMP16I_INSN
|| tmp_insn == E_MULL2I_INSN
else if (use_a_reloc)
reloc = BFD_RELOC_PPC_VLE_HI16A;
break;
-
+
case BFD_RELOC_HI16_S:
if (use_d_reloc)
reloc = BFD_RELOC_PPC_VLE_HA16D;
break;
}
}
-
- /* For the absolute forms of branches, convert the PC
- relative form back into the absolute. */
- if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
- {
- switch (reloc)
- {
- case BFD_RELOC_PPC_B26:
- reloc = BFD_RELOC_PPC_BA26;
- break;
- case BFD_RELOC_PPC_B16:
- reloc = BFD_RELOC_PPC_BA16;
- break;
- case BFD_RELOC_PPC_B16_BRTAKEN:
- reloc = BFD_RELOC_PPC_BA16_BRTAKEN;
- break;
- case BFD_RELOC_PPC_B16_BRNTAKEN:
- reloc = BFD_RELOC_PPC_BA16_BRNTAKEN;
- break;
- default:
- break;
- }
- }
-
- switch (reloc)
- {
- case BFD_RELOC_PPC_TOC16:
- toc_reloc_types |= has_small_toc_reloc;
- break;
- case BFD_RELOC_PPC64_TOC16_LO:
- case BFD_RELOC_PPC64_TOC16_HI:
- case BFD_RELOC_PPC64_TOC16_HA:
- toc_reloc_types |= has_large_toc_reloc;
- break;
- default:
- break;
- }
-
- if ((operand->flags & (PPC_OPERAND_DS | PPC_OPERAND_DQ)) != 0)
- {
- switch (reloc)
- {
- case BFD_RELOC_16:
- reloc = BFD_RELOC_PPC64_ADDR16_DS;
- break;
- case BFD_RELOC_LO16:
- reloc = BFD_RELOC_PPC64_ADDR16_LO_DS;
- break;
- case BFD_RELOC_16_GOTOFF:
- reloc = BFD_RELOC_PPC64_GOT16_DS;
- break;
- case BFD_RELOC_LO16_GOTOFF:
- reloc = BFD_RELOC_PPC64_GOT16_LO_DS;
- break;
- case BFD_RELOC_LO16_PLTOFF:
- reloc = BFD_RELOC_PPC64_PLT16_LO_DS;
- break;
- case BFD_RELOC_16_BASEREL:
- reloc = BFD_RELOC_PPC64_SECTOFF_DS;
- break;
- case BFD_RELOC_LO16_BASEREL:
- reloc = BFD_RELOC_PPC64_SECTOFF_LO_DS;
- break;
- case BFD_RELOC_PPC_TOC16:
- reloc = BFD_RELOC_PPC64_TOC16_DS;
- break;
- case BFD_RELOC_PPC64_TOC16_LO:
- reloc = BFD_RELOC_PPC64_TOC16_LO_DS;
- break;
- case BFD_RELOC_PPC64_PLTGOT16:
- reloc = BFD_RELOC_PPC64_PLTGOT16_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;
- }
- }
}
#endif /* OBJ_ELF */
- if (reloc != BFD_RELOC_UNUSED)
+ if (reloc != BFD_RELOC_NONE)
;
/* Determine a BFD reloc value based on the operand information.
We are only prepared to turn a few of the operands into
relocs. */
- else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
+ else if ((operand->flags & (PPC_OPERAND_RELATIVE
+ | PPC_OPERAND_ABSOLUTE)) != 0
&& operand->bitm == 0x3fffffc
&& operand->shift == 0)
reloc = BFD_RELOC_PPC_B26;
- else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
+ else if ((operand->flags & (PPC_OPERAND_RELATIVE
+ | PPC_OPERAND_ABSOLUTE)) != 0
&& operand->bitm == 0xfffc
&& operand->shift == 0)
reloc = BFD_RELOC_PPC_B16;
&& operand->bitm == 0x1fffffe
&& operand->shift == 0)
reloc = BFD_RELOC_PPC_VLE_REL24;
- else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0
- && operand->bitm == 0x3fffffc
- && operand->shift == 0)
- reloc = BFD_RELOC_PPC_BA26;
- else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0
- && operand->bitm == 0xfffc
- && operand->shift == 0)
- reloc = BFD_RELOC_PPC_BA16;
-#if defined (OBJ_XCOFF) || defined (OBJ_ELF)
- else if ((operand->flags & PPC_OPERAND_PARENS) != 0
+ else if ((operand->flags & PPC_OPERAND_NEGATIVE) == 0
&& (operand->bitm & 0xfff0) == 0xfff0
&& operand->shift == 0)
{
+ reloc = BFD_RELOC_16;
+#if defined OBJ_XCOFF || defined OBJ_ELF
/* Note: the symbol may be not yet defined. */
- if (ppc_is_toc_sym (ex.X_add_symbol))
+ if ((operand->flags & PPC_OPERAND_PARENS) != 0
+ && ppc_is_toc_sym (ex.X_add_symbol))
{
reloc = BFD_RELOC_PPC_TOC16;
#ifdef OBJ_ELF
- if (ppc_obj64
- && (operand->flags & PPC_OPERAND_DS) != 0)
- reloc = BFD_RELOC_PPC64_TOC16_DS;
+ as_warn (_("assuming %s on symbol"),
+ ppc_obj64 ? "@toc" : "@xgot");
#endif
}
- else
+#endif
+ }
+
+ /* For the absolute forms of branches, convert the PC
+ relative form back into the absolute. */
+ if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
+ {
+ switch (reloc)
{
- reloc = BFD_RELOC_16;
+ case BFD_RELOC_PPC_B26:
+ reloc = BFD_RELOC_PPC_BA26;
+ break;
+ case BFD_RELOC_PPC_B16:
+ reloc = BFD_RELOC_PPC_BA16;
+ break;
#ifdef OBJ_ELF
- if (ppc_obj64
- && (operand->flags & PPC_OPERAND_DS) != 0)
- reloc = BFD_RELOC_PPC64_ADDR16_DS;
+ case BFD_RELOC_PPC_B16_BRTAKEN:
+ reloc = BFD_RELOC_PPC_BA16_BRTAKEN;
+ break;
+ case BFD_RELOC_PPC_B16_BRNTAKEN:
+ reloc = BFD_RELOC_PPC_BA16_BRNTAKEN;
+ break;
#endif
+ default:
+ break;
}
}
-#endif /* defined (OBJ_XCOFF) || defined (OBJ_ELF) */
+
+#ifdef OBJ_ELF
+ switch (reloc)
+ {
+ case BFD_RELOC_PPC_TOC16:
+ toc_reloc_types |= has_small_toc_reloc;
+ break;
+ case BFD_RELOC_PPC64_TOC16_LO:
+ case BFD_RELOC_PPC64_TOC16_HI:
+ case BFD_RELOC_PPC64_TOC16_HA:
+ toc_reloc_types |= has_large_toc_reloc;
+ break;
+ default:
+ break;
+ }
+
+ if (ppc_obj64
+ && (operand->flags & (PPC_OPERAND_DS | PPC_OPERAND_DQ)) != 0)
+ {
+ switch (reloc)
+ {
+ case BFD_RELOC_16:
+ reloc = BFD_RELOC_PPC64_ADDR16_DS;
+ break;
+ case BFD_RELOC_LO16:
+ reloc = BFD_RELOC_PPC64_ADDR16_LO_DS;
+ break;
+ case BFD_RELOC_16_GOTOFF:
+ reloc = BFD_RELOC_PPC64_GOT16_DS;
+ break;
+ case BFD_RELOC_LO16_GOTOFF:
+ reloc = BFD_RELOC_PPC64_GOT16_LO_DS;
+ break;
+ case BFD_RELOC_LO16_PLTOFF:
+ reloc = BFD_RELOC_PPC64_PLT16_LO_DS;
+ break;
+ case BFD_RELOC_16_BASEREL:
+ reloc = BFD_RELOC_PPC64_SECTOFF_DS;
+ break;
+ case BFD_RELOC_LO16_BASEREL:
+ reloc = BFD_RELOC_PPC64_SECTOFF_LO_DS;
+ break;
+ case BFD_RELOC_PPC_TOC16:
+ reloc = BFD_RELOC_PPC64_TOC16_DS;
+ break;
+ case BFD_RELOC_PPC64_TOC16_LO:
+ reloc = BFD_RELOC_PPC64_TOC16_LO_DS;
+ break;
+ case BFD_RELOC_PPC64_PLTGOT16:
+ reloc = BFD_RELOC_PPC64_PLTGOT16_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;
+ }
+ }
+#endif
/* We need to generate a fixup for this expression. */
if (fc >= MAX_INSN_FIXUPS)
ppc_apuinfo_section_add (PPC_APUINFO_CACHELCK, 1);
if (opcode->flags & PPC_OPCODE_RFMCI)
ppc_apuinfo_section_add (PPC_APUINFO_RFMCI, 1);
- if (opcode->flags & PPC_OPCODE_VLE)
- ppc_apuinfo_section_add (PPC_APUINFO_VLE, 1);
+ /* Only set the VLE flag if the instruction has been pulled via
+ the VLE instruction set. This way the flag is guaranteed to
+ be set for VLE-only instructions or for VLE-only processors,
+ however it'll remain clear for dual-mode instructions on
+ dual-mode and, more importantly, standard-mode processors. */
+ if ((ppc_cpu & opcode->flags) == PPC_OPCODE_VLE)
+ {
+ ppc_apuinfo_section_add (PPC_APUINFO_VLE, 1);
+ if (elf_section_data (now_seg) != NULL)
+ elf_section_data (now_seg)->this_hdr.sh_flags |= SHF_PPC_VLE;
+ }
}
#endif
/* Write out the instruction. */
/* Differentiate between two and four byte insns. */
- if (ppc_mach () == bfd_mach_ppc_vle)
+ if ((ppc_cpu & PPC_OPCODE_VLE) != 0)
{
if (PPC_OP_SE_VLE (insn))
insn_length = 2;
f = frag_more (insn_length);
if (frag_now->has_code && frag_now->insn_addr != addr_mod)
{
- if (ppc_mach() == bfd_mach_ppc_vle)
+ if ((ppc_cpu & PPC_OPCODE_VLE) != 0)
as_bad (_("instruction address is not a multiple of 2"));
else
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, insn_length);
+ last_insn = insn;
+ last_seg = now_seg;
+ last_subseg = now_subseg;
#ifdef OBJ_ELF
dwarf2_emit_insn (insn_length);
for (i = 0; i < fc; i++)
{
fixS *fixP;
- if (fixups[i].reloc != BFD_RELOC_UNUSED)
+ if (fixups[i].reloc != BFD_RELOC_NONE)
{
reloc_howto_type *reloc_howto;
int size;
size = bfd_get_reloc_size (reloc_howto);
offset = target_big_endian ? (insn_length - size) : 0;
- if (size < 1 || size > 4)
- abort ();
-
fixP = fix_new_exp (frag_now,
f - frag_now->fr_literal + offset,
size,
insn_length,
&fixups[i].exp,
(operand->flags & PPC_OPERAND_RELATIVE) != 0,
- BFD_RELOC_UNUSED);
+ BFD_RELOC_NONE);
}
fixP->fx_pcrel_adjust = fixups[i].opindex;
}
}
/* Put the string together. */
- complete = s = (char *) alloca (len + 1);
+ complete = s = XNEWVEC (char, len + 1);
format = macro->format;
while (*format != '\0')
{
/* Assemble the constructed instruction. */
md_assemble (complete);
+ free (complete);
}
\f
#ifdef OBJ_ELF
static void
ppc_byte (int ignore ATTRIBUTE_UNUSED)
{
+ int count = 0;
+
if (*input_line_pointer != '\"')
{
cons (1);
}
FRAG_APPEND_1_CHAR (c);
+ ++count;
}
+ if (warn_476 && count != 0 && (now_seg->flags & SEC_CODE) != 0)
+ as_warn (_("data in executable section"));
demand_empty_rest_of_line ();
}
\f
symbolS *sym;
char *pfrag;
- name = input_line_pointer;
- endc = get_symbol_end ();
+ endc = get_symbol_name (&name);
end_name = input_line_pointer;
- *end_name = endc;
+ (void) restore_line_pointer (endc);
if (*input_line_pointer != ',')
{
}
++input_line_pointer;
- lcomm_name = input_line_pointer;
- lcomm_endc = get_symbol_end ();
+ lcomm_endc = get_symbol_name (&lcomm_name);
lcomm_sym = symbol_find_or_make (lcomm_name);
- *input_line_pointer = lcomm_endc;
+ (void) restore_line_pointer (lcomm_endc);
/* The fourth argument to .lcomm is the alignment. */
if (*input_line_pointer != ',')
symbolS *sym;
offsetT align;
- name = input_line_pointer;
- endc = get_symbol_end ();
+ endc = get_symbol_name (&name);
sym = symbol_find_or_make (name);
- *input_line_pointer = endc;
+ (void) restore_line_pointer (endc);
if (S_GET_NAME (sym)[0] == '\0')
{
/* Parse opt-label. */
if (*input_line_pointer == ',')
{
- const char *label;
+ char *label;
char c;
++input_line_pointer;
- label = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&label);
opt_label = symbol_find_or_make (label);
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
}
else
opt_label = NULL;
else
{
/* Create a new dw subsection. */
- subseg = (struct dw_subsection *)
- xmalloc (sizeof (struct dw_subsection));
+ subseg = XNEW (struct dw_subsection);
if (opt_label == NULL)
{
char c;
symbolS *sym;
- user_name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&user_name);
if (strcmp (user_name, ".text") == 0)
real_name = ".text[PR]";
else
{
as_bad (_("the XCOFF file format does not support arbitrary sections"));
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
ignore_rest_of_line ();
return;
}
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
sym = symbol_find_or_make (real_name);
char *name;
char endc;
- name = input_line_pointer;
- endc = get_symbol_end ();
+ endc = get_symbol_name (&name);
(void) symbol_find_or_make (name);
- *input_line_pointer = endc;
+ (void) restore_line_pointer (endc);
demand_empty_rest_of_line ();
}
char endc;
symbolS *sym;
- name = input_line_pointer;
- endc = get_symbol_end ();
+ endc = get_symbol_name (&name);
sym = symbol_find_or_make (name);
- *input_line_pointer = endc;
+ (void) restore_line_pointer (endc);
symbol_get_tc (sym)->output = 1;
do
{
- name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&name);
fix_at_start (symbol_get_frag (ppc_current_csect), 0,
symbol_find_or_make (name), 0, FALSE, BFD_RELOC_NONE);
*input_line_pointer = c;
- SKIP_WHITESPACE ();
+ SKIP_WHITESPACE_AFTER_NAME ();
c = *input_line_pointer;
if (c == ',')
{
symbolS *sym;
int len;
- name = input_line_pointer;
- endc = get_symbol_end ();
+ endc = get_symbol_name (&name);
sym = symbol_find_or_make (name);
- *input_line_pointer = endc;
+ (void) restore_line_pointer (endc);
if (*input_line_pointer != ',')
{
symbolS *ext_sym;
symbolS *lab_sym;
- name = input_line_pointer;
- endc = get_symbol_end ();
+ endc = get_symbol_name (&name);
/* Ignore any [PR] suffix. */
name = ppc_canonicalize_symbol_name (name);
ext_sym = symbol_find_or_make (name);
- *input_line_pointer = endc;
+ (void) restore_line_pointer (endc);
if (*input_line_pointer != ',')
{
}
++input_line_pointer;
- name = input_line_pointer;
- endc = get_symbol_end ();
+ endc = get_symbol_name (&name);
lab_sym = symbol_find_or_make (name);
- *input_line_pointer = endc;
+ (void) restore_line_pointer (endc);
if (ext_sym != lab_sym)
{
if (ppc_current_block != NULL)
as_bad (_("nested .bs blocks"));
- name = input_line_pointer;
- endc = get_symbol_end ();
+ endc = get_symbol_name (&name);
csect = symbol_find_or_make (name);
- *input_line_pointer = endc;
+ (void) restore_line_pointer (endc);
sym = symbol_make (".bs");
S_SET_SEGMENT (sym, now_seg);
return;
}
- name = input_line_pointer;
- endc = get_symbol_end ();
+ endc = get_symbol_name (&name);
sym = symbol_find_or_make (name);
- *input_line_pointer = endc;
+ (void) restore_line_pointer (endc);
if (S_IS_DEFINED (sym))
{
static void
ppc_machine (int ignore ATTRIBUTE_UNUSED)
{
+ char c;
char *cpu_string;
#define MAX_HISTORY 100
static ppc_cpu_t *cpu_history;
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;
- }
+ c = get_symbol_name (&cpu_string);
+ cpu_string = xstrdup (cpu_string);
+ (void) restore_line_pointer (c);
if (cpu_string != NULL)
{
if (strcmp (cpu_string, "push") == 0)
{
if (cpu_history == NULL)
- cpu_history = xmalloc (MAX_HISTORY * sizeof (*cpu_history));
+ cpu_history = XNEWVEC (ppc_cpu_t, MAX_HISTORY);
if (curr_hist >= MAX_HISTORY)
as_bad (_(".machine stack overflow"));
char *name;
/* Strip out the symbol name. */
- symbol_name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&symbol_name);
- name = xmalloc (input_line_pointer - symbol_name + 1);
- strcpy (name, symbol_name);
+ name = xstrdup (symbol_name);
sym = symbol_find_or_make (name);
*input_line_pointer = c;
- SKIP_WHITESPACE ();
+ SKIP_WHITESPACE_AFTER_NAME ();
/* Look up the opcode in the hash table. */
opcode = (const struct powerpc_opcode *) hash_find (ppc_hash, "nop");
symbolS *symbolP;
offsetT align;
- name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&name);
/* just after name is now '\0'. */
p = input_line_pointer;
*p = c;
- SKIP_WHITESPACE ();
+ SKIP_WHITESPACE_AFTER_NAME ();
if (*input_line_pointer != ',')
{
as_bad (_("expected comma after symbol-name: rest of line ignored."));
segT sec;
int align;
- section_name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (§ion_name);
- name = xmalloc (input_line_pointer - section_name + 1);
- strcpy (name, section_name);
+ name = xstrdup (section_name);
*input_line_pointer = c;
- SKIP_WHITESPACE ();
+ SKIP_WHITESPACE_AFTER_NAME ();
exp = 0;
flags = SEC_NO_FLAGS;
char endc;
symbolS *ext_sym;
- name = input_line_pointer;
- endc = get_symbol_end ();
+ endc = get_symbol_name (&name);
ext_sym = symbol_find_or_make (name);
- *input_line_pointer = endc;
+ (void) restore_line_pointer (endc);
S_SET_DATA_TYPE (ext_sym, DT_FCN << N_BTSHFT);
SF_SET_FUNCTION (ext_sym);
char *snew;
len = s - name;
- snew = xmalloc (len + 1);
- memcpy (snew, name, len);
- snew[len] = '\0';
+ snew = xstrndup (name, len);
S_SET_NAME (sym, snew);
}
#endif /* OBJ_XCOFF */
\f
-char *
+const char *
md_atof (int type, char *litp, int *sizep)
{
return ieee_md_atof (type, litp, sizep, target_big_endian);
#else
int align = bfd_get_section_alignment (stdoutput, seg);
- return ((addr + (1 << align) - 1) & (-1 << align));
+ return ((addr + (1 << align) - 1) & -(1 << align));
#endif
}
case BFD_RELOC_24_PLT_PCREL:
case BFD_RELOC_PPC64_TOC:
return 1;
+ case BFD_RELOC_PPC_B26:
+ case BFD_RELOC_PPC_BA26:
+ case BFD_RELOC_PPC_B16:
+ case BFD_RELOC_PPC_BA16:
+ /* All branch fixups targeting a localentry symbol must
+ force a relocation. */
+ if (fix->fx_addsy)
+ {
+ asymbol *bfdsym = symbol_get_bfdsym (fix->fx_addsy);
+ elf_symbol_type *elfsym
+ = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym);
+ gas_assert (elfsym);
+ if ((STO_PPC64_LOCAL_MASK & elfsym->internal_elf_sym.st_other) != 0)
+ return 1;
+ }
+ break;
default:
break;
}
int
ppc_fix_adjustable (fixS *fix)
{
+ switch (fix->fx_r_type)
+ {
+ /* All branch fixups targeting a localentry symbol must
+ continue using the symbol. */
+ case BFD_RELOC_PPC_B26:
+ case BFD_RELOC_PPC_BA26:
+ case BFD_RELOC_PPC_B16:
+ case BFD_RELOC_PPC_BA16:
+ case BFD_RELOC_PPC_B16_BRTAKEN:
+ case BFD_RELOC_PPC_B16_BRNTAKEN:
+ case BFD_RELOC_PPC_BA16_BRTAKEN:
+ case BFD_RELOC_PPC_BA16_BRNTAKEN:
+ if (fix->fx_addsy)
+ {
+ asymbol *bfdsym = symbol_get_bfdsym (fix->fx_addsy);
+ elf_symbol_type *elfsym
+ = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym);
+ gas_assert (elfsym);
+ if ((STO_PPC64_LOCAL_MASK & elfsym->internal_elf_sym.st_other) != 0)
+ return 0;
+ }
+ break;
+ default:
+ break;
+ }
+
return (fix->fx_r_type != BFD_RELOC_16_GOTOFF
&& fix->fx_r_type != BFD_RELOC_LO16_GOTOFF
&& fix->fx_r_type != BFD_RELOC_HI16_GOTOFF
if (!fragP->has_code)
return;
- if (ppc_mach() == bfd_mach_ppc_vle)
+ if ((ppc_cpu & PPC_OPCODE_VLE) != 0)
{
if (((fragP->fr_address + fragP->insn_addr) & 1) != 0)
as_bad (_("instruction address is not a multiple of 2"));
valueT count = (fragP->fr_next->fr_address
- (fragP->fr_address + fragP->fr_fix));
- if (ppc_mach() == bfd_mach_ppc_vle && count != 0 && (count & 1) == 0)
+ if ((ppc_cpu & PPC_OPCODE_VLE) != 0 && count != 0 && (count & 1) == 0)
{
char *dest = fragP->fr_literal + fragP->fr_fix;
if ((ppc_cpu & PPC_OPCODE_POWER6) != 0
|| (ppc_cpu & PPC_OPCODE_POWER7) != 0
- || (ppc_cpu & PPC_OPCODE_POWER8) != 0)
+ || (ppc_cpu & PPC_OPCODE_POWER8) != 0
+ || (ppc_cpu & PPC_OPCODE_POWER9) != 0)
{
- /* For power6, power7 and power8, we want the last nop to be a group
- terminating one. Do this by inserting an rs_fill frag immediately
- after this one, with its address set to the last nop location.
- This will automatically reduce the number of nops in the current
- frag by one. */
+ /* For power6, power7, power8 and power9, we want the last nop to be
+ a group terminating one. Do this by inserting an rs_fill frag
+ immediately after this one, with its address set to the last nop
+ location. This will automatically reduce the number of nops in
+ the current frag by one. */
if (count > 4)
{
struct frag *group_nop = xmalloc (SIZEOF_STRUCT_FRAG + 4);
}
if ((ppc_cpu & PPC_OPCODE_POWER7) != 0
- || (ppc_cpu & PPC_OPCODE_POWER8) != 0)
+ || (ppc_cpu & PPC_OPCODE_POWER8) != 0
+ || (ppc_cpu & PPC_OPCODE_POWER9) != 0)
{
if (ppc_cpu & PPC_OPCODE_E500MC)
/* e500mc group terminating nop: "ori 0,0,0". */
md_number_to_chars (dest, 0x60000000, 4);
else
- /* power7/power8 group terminating nop: "ori 2,2,0". */
+ /* power7/power8/power9 group terminating nop: "ori 2,2,0". */
md_number_to_chars (dest, 0x60420000, 4);
}
else
fixups we generated by the calls to fix_new_exp, above. */
void
-md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
+md_apply_fix (fixS *fixP, valueT *valP, segT seg)
{
valueT value = * valP;
offsetT fieldval;
/* Hack around bfd_install_relocation brain damage. */
if (fixP->fx_pcrel)
value += fixP->fx_frag->fr_address + fixP->fx_where;
+
+ if (fixP->fx_addsy == abs_section_sym)
+ fixP->fx_done = 1;
}
else
fixP->fx_done = 1;
fieldval = value & 0xffff;
sign_extend_16:
if (operand != NULL && (operand->flags & PPC_OPERAND_SIGNED) != 0)
- fieldval = (fieldval ^ 0x8000) - 0x8000;
+ fieldval = SEX16 (fieldval);
fixP->fx_no_overflow = 1;
break;
+ case BFD_RELOC_HI16:
+ case BFD_RELOC_HI16_PCREL:
#ifdef OBJ_ELF
+ if (REPORT_OVERFLOW_HI && ppc_obj64)
+ {
+ fieldval = value >> 16;
+ if (operand != NULL && (operand->flags & PPC_OPERAND_SIGNED) != 0)
+ {
+ valueT sign = (((valueT) -1 >> 16) + 1) >> 1;
+ fieldval = ((valueT) fieldval ^ sign) - sign;
+ }
+ break;
+ }
+ /* Fall thru */
+
case BFD_RELOC_PPC_VLE_HI16A:
case BFD_RELOC_PPC_VLE_HI16D:
+ case BFD_RELOC_PPC64_ADDR16_HIGH:
#endif
- case BFD_RELOC_HI16:
- case BFD_RELOC_HI16_PCREL:
fieldval = PPC_HI (value);
goto sign_extend_16;
+ case BFD_RELOC_HI16_S:
+ case BFD_RELOC_HI16_S_PCREL:
+ case BFD_RELOC_PPC_REL16DX_HA:
#ifdef OBJ_ELF
+ if (REPORT_OVERFLOW_HI && ppc_obj64)
+ {
+ fieldval = (value + 0x8000) >> 16;
+ if (operand != NULL && (operand->flags & PPC_OPERAND_SIGNED) != 0)
+ {
+ valueT sign = (((valueT) -1 >> 16) + 1) >> 1;
+ fieldval = ((valueT) fieldval ^ sign) - sign;
+ }
+ break;
+ }
+ /* Fall thru */
+
case BFD_RELOC_PPC_VLE_HA16A:
case BFD_RELOC_PPC_VLE_HA16D:
+ case BFD_RELOC_PPC64_ADDR16_HIGHA:
#endif
- case BFD_RELOC_HI16_S:
- case BFD_RELOC_HI16_S_PCREL:
fieldval = PPC_HA (value);
goto sign_extend_16;
if (operand != NULL)
{
/* Handle relocs in an insn. */
- char *where;
- unsigned long insn;
-
switch (fixP->fx_r_type)
{
#ifdef OBJ_ELF
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_HIGH:
+ case BFD_RELOC_PPC64_TPREL16_HIGHA:
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_HIGH:
+ case BFD_RELOC_PPC64_DTPREL16_HIGHA:
case BFD_RELOC_PPC64_DTPREL16_DS:
case BFD_RELOC_PPC64_DTPREL16_LO_DS:
case BFD_RELOC_PPC64_DTPREL16_HIGHER:
break;
#endif
+ case BFD_RELOC_VTABLE_INHERIT:
+ case BFD_RELOC_VTABLE_ENTRY:
+ case BFD_RELOC_PPC_DTPMOD:
+ case BFD_RELOC_PPC_TPREL:
+ case BFD_RELOC_PPC_DTPREL:
+ case BFD_RELOC_PPC_COPY:
+ case BFD_RELOC_PPC_GLOB_DAT:
+ case BFD_RELOC_32_PLT_PCREL:
+ case BFD_RELOC_PPC_EMB_NADDR32:
+ case BFD_RELOC_PPC64_TOC:
+ case BFD_RELOC_CTOR:
+ case BFD_RELOC_32:
+ case BFD_RELOC_32_PCREL:
+ case BFD_RELOC_RVA:
+ case BFD_RELOC_64:
+ case BFD_RELOC_64_PCREL:
+ case BFD_RELOC_PPC64_ADDR64_LOCAL:
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("%s unsupported as instruction fixup"),
+ bfd_get_reloc_code_name (fixP->fx_r_type));
+ fixP->fx_done = 1;
+ return;
+
default:
break;
}
#endif
if ((fieldval != 0 && APPLY_RELOC) || operand->insert != NULL)
{
+ unsigned long insn;
+ unsigned char *where;
+
/* Fetch the instruction, insert the fully resolved operand
value, and stuff the instruction back again. */
- where = fixP->fx_frag->fr_literal + fixP->fx_where;
+ where = (unsigned char *) fixP->fx_frag->fr_literal + fixP->fx_where;
if (target_big_endian)
{
if (fixP->fx_size == 4)
- insn = bfd_getb32 ((unsigned char *) where);
+ insn = bfd_getb32 (where);
else
- insn = bfd_getb16 ((unsigned char *) where);
+ insn = bfd_getb16 (where);
}
else
{
if (fixP->fx_size == 4)
- insn = bfd_getl32 ((unsigned char *) where);
+ insn = bfd_getl32 (where);
else
- insn = bfd_getl16 ((unsigned char *) where);
+ insn = bfd_getl16 (where);
}
insn = ppc_insert_operand (insn, operand, fieldval,
fixP->tc_fix_data.ppc_cpu,
if (target_big_endian)
{
if (fixP->fx_size == 4)
- bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
+ bfd_putb32 (insn, where);
else
- bfd_putb16 ((bfd_vma) insn, (unsigned char *) where);
+ bfd_putb16 (insn, where);
}
else
{
if (fixP->fx_size == 4)
- bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
+ bfd_putl32 (insn, where);
else
- bfd_putl16 ((bfd_vma) insn, (unsigned char *) where);
+ bfd_putl16 (insn, where);
}
}
return;
gas_assert (fixP->fx_addsy != NULL);
- if (fixP->fx_r_type == BFD_RELOC_UNUSED)
+ if (fixP->fx_r_type == BFD_RELOC_NONE)
{
- char *sfile;
+ const char *sfile;
unsigned int sline;
/* Use expr_symbol_where to see if this is an expression
case BFD_RELOC_PPC64_HIGHER_S:
case BFD_RELOC_PPC64_HIGHEST:
case BFD_RELOC_PPC64_HIGHEST_S:
+ case BFD_RELOC_PPC64_ADDR16_HIGH:
+ case BFD_RELOC_PPC64_ADDR16_HIGHA:
+ case BFD_RELOC_PPC64_ADDR64_LOCAL:
break;
case BFD_RELOC_PPC_DTPMOD:
case BFD_RELOC_PPC64_TOC16_LO:
case BFD_RELOC_PPC64_TOC16_HI:
case BFD_RELOC_PPC64_TOC16_HA:
+ case BFD_RELOC_PPC64_DTPREL16_HIGH:
+ case BFD_RELOC_PPC64_DTPREL16_HIGHA:
case BFD_RELOC_PPC64_DTPREL16_HIGHER:
case BFD_RELOC_PPC64_DTPREL16_HIGHERA:
case BFD_RELOC_PPC64_DTPREL16_HIGHEST:
case BFD_RELOC_PPC64_DTPREL16_HIGHESTA:
+ case BFD_RELOC_PPC64_TPREL16_HIGH:
+ case BFD_RELOC_PPC64_TPREL16_HIGHA:
case BFD_RELOC_PPC64_TPREL16_HIGHER:
case BFD_RELOC_PPC64_TPREL16_HIGHERA:
case BFD_RELOC_PPC64_TPREL16_HIGHEST:
if (fixP->fx_size && APPLY_RELOC)
md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
fieldval, fixP->fx_size);
+ if (warn_476
+ && (seg->flags & SEC_CODE) != 0
+ && fixP->fx_size == 4
+ && fixP->fx_done
+ && !fixP->fx_tcbit
+ && (fixP->fx_r_type == BFD_RELOC_32
+ || fixP->fx_r_type == BFD_RELOC_CTOR
+ || fixP->fx_r_type == BFD_RELOC_32_PCREL))
+ as_warn_where (fixP->fx_file, fixP->fx_line,
+ _("data in executable section"));
}
/* We are only able to convert some relocs to pc-relative. */
case BFD_RELOC_LO16_PCREL:
case BFD_RELOC_HI16_PCREL:
case BFD_RELOC_HI16_S_PCREL:
+ case BFD_RELOC_PPC_REL16DX_HA:
case BFD_RELOC_64_PCREL:
case BFD_RELOC_32_PCREL:
case BFD_RELOC_16_PCREL:
default:
if (fixP->fx_addsy)
{
- char *sfile;
+ const char *sfile;
unsigned int sline;
/* Use expr_symbol_where to see if this is an
{
arelent *reloc;
- reloc = (arelent *) xmalloc (sizeof (arelent));
+ reloc = XNEW (arelent);
- reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ reloc->sym_ptr_ptr = XNEW (asymbol *);
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
unsigned int i;
const char *p;
char *q;
- static struct { char *name; int dw2regnum; } regnames[] =
+ static struct { const char *name; int dw2regnum; } regnames[] =
{
{ "sp", 1 }, { "r.sp", 1 }, { "rtoc", 2 }, { "r.toc", 2 },
{ "mq", 64 }, { "lr", 65 }, { "ctr", 66 }, { "ap", 67 },