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
/* 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;
{ "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
#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;
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++)
{
if ((operand->flags & PPC_OPERAND_SIGNOPT) != 0)
{
- /* Extend the allowed range for addis to [-65536, 65535].
- Similarly for some VLE high part insns. For 64-bit it
- would be good to disable this for signed fields since the
+ /* 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.
- Use the same extended range for cmpli, to allow at least
- [-32768, 65535]. */
- min = ~max & -right;
+ lis. */
+ min = ~(max >> 1) & -right;
}
else if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
{
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)
#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);
{
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
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);
+ {
+ 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"));
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;