/* 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)
+ {
+ /* 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)
{
- if ((operand->flags & PPC_OPERAND_SIGNOPT) == 0)
- max = (max >> 1) & -right;
+ 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;
+/* Support @got, etc. on constants emitted via .short, .int etc. */
- if (is_it_end_of_statement ())
- {
- demand_empty_rest_of_line ();
- return;
- }
-
- do
- {
- expression (&exp);
- if (exp.X_op == O_symbol
- && *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."));
align2 = 0;
record_alignment (bss_section, align2);
- subseg_set (bss_section, 0);
+ subseg_set (bss_section, 1);
if (align2)
frag_align (align2, 0, 0);
if (S_GET_SEGMENT (symbolP) == bss_section)
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)
{
- if (ppc_is_toc_sym (ex.X_add_symbol))
+ reloc = BFD_RELOC_16;
+#if defined OBJ_XCOFF || defined OBJ_ELF
+ /* Note: the symbol may be not yet defined. */
+ 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 != ',')
{
char *lcomm_name;
char lcomm_endc;
- if (size <= 4)
- align = 2;
- else
- align = 3;
-
/* The third argument to .lcomm appears to be the real local
common symbol to create. References to the symbol named in
the first argument are turned into references to the third
}
++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 != ',')
+ {
+ if (size <= 4)
+ align = 2;
+ else
+ align = 3;
+ }
+ else
+ {
+ ++input_line_pointer;
+ align = get_absolute_expression ();
+ if (align <= 0)
+ {
+ as_warn (_("ignoring bad alignment"));
+ align = 2;
+ }
+ }
}
*end_name = '\0';
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;
value = fixP->fx_offset;
fixP->fx_done = 1;
}
+
+ /* During parsing of instructions, a TOC16 reloc is generated for
+ instructions such as 'lwz RT,SYM(RB)' if SYM is a symbol defined
+ in the toc. But at parse time, SYM may be not yet defined, so
+ check again here. */
+ if (fixP->fx_r_type == BFD_RELOC_16
+ && fixP->fx_addsy != NULL
+ && ppc_is_toc_sym (fixP->fx_addsy))
+ fixP->fx_r_type = BFD_RELOC_PPC_TOC16;
#endif
}
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
fixP->fx_addnumber =
- bfd_get_section_vma (stdoutput, S_GET_SEGMENT (fixP->fx_addsy))
- S_GET_VALUE (ppc_toc_csect);
+ /* Set *valP to avoid errors. */
+ *valP = value;
#endif
}
#endif
{
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 },