X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-ppc.c;h=0b24298c2bbdce7e6cb6f8f97851d1bd8b2fe409;hb=a8c4d40b578378be3b12575d127d4c7bd9972f32;hp=d587a50ca7b5a95afb06cf47188ad3db834aefba;hpb=16de26a611b78bd353af5b86ce67ace81ec1bfec;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c index d587a50ca7..0b24298c2b 100644 --- a/gas/config/tc-ppc.c +++ b/gas/config/tc-ppc.c @@ -1,5 +1,5 @@ /* tc-ppc.c -- Assemble for the PowerPC or POWER (RS/6000) - Copyright (C) 1994-2018 Free Software Foundation, Inc. + Copyright (C) 1994-2020 Free Software Foundation, Inc. Written by Ian Lance Taylor, Cygnus Support. This file is part of GAS, the GNU Assembler. @@ -1320,76 +1320,146 @@ md_parse_option (int c, const char *arg) return 1; } +static int +is_ppc64_target (const bfd_target *targ, void *data ATTRIBUTE_UNUSED) +{ + switch (targ->flavour) + { +#ifdef OBJ_ELF + case bfd_target_elf_flavour: + return strncmp (targ->name, "elf64-powerpc", 13) == 0; +#endif +#ifdef OBJ_XCOFF + case bfd_target_xcoff_flavour: + return (strcmp (targ->name, "aixcoff64-rs6000") == 0 + || strcmp (targ->name, "aix5coff64-rs6000") == 0); +#endif + default: + return 0; + } +} + void md_show_usage (FILE *stream) { fprintf (stream, _("\ -PowerPC options:\n\ --a32 generate ELF32/XCOFF32\n\ --a64 generate ELF64/XCOFF64\n\ --u ignored\n\ --mpwrx, -mpwr2 generate code for POWER/2 (RIOS2)\n\ --mpwr generate code for POWER (RIOS1)\n\ --m601 generate code for PowerPC 601\n\ +PowerPC options:\n")); + fprintf (stream, _("\ +-a32 generate ELF32/XCOFF32\n")); + if (bfd_iterate_over_targets (is_ppc64_target, NULL)) + fprintf (stream, _("\ +-a64 generate ELF64/XCOFF64\n")); + fprintf (stream, _("\ +-u ignored\n")); + fprintf (stream, _("\ +-mpwrx, -mpwr2 generate code for POWER/2 (RIOS2)\n")); + fprintf (stream, _("\ +-mpwr generate code for POWER (RIOS1)\n")); + fprintf (stream, _("\ +-m601 generate code for PowerPC 601\n")); + fprintf (stream, _("\ -mppc, -mppc32, -m603, -m604\n\ - generate code for PowerPC 603/604\n\ --m403 generate code for PowerPC 403\n\ --m405 generate code for PowerPC 405\n\ --m440 generate code for PowerPC 440\n\ --m464 generate code for PowerPC 464\n\ --m476 generate code for PowerPC 476\n\ + generate code for PowerPC 603/604\n")); + fprintf (stream, _("\ +-m403 generate code for PowerPC 403\n")); + fprintf (stream, _("\ +-m405 generate code for PowerPC 405\n")); + fprintf (stream, _("\ +-m440 generate code for PowerPC 440\n")); + fprintf (stream, _("\ +-m464 generate code for PowerPC 464\n")); + fprintf (stream, _("\ +-m476 generate code for PowerPC 476\n")); + fprintf (stream, _("\ -m7400, -m7410, -m7450, -m7455\n\ - generate code for PowerPC 7400/7410/7450/7455\n\ + generate code for PowerPC 7400/7410/7450/7455\n")); + fprintf (stream, _("\ -m750cl, -mgekko, -mbroadway\n\ - generate code for PowerPC 750cl/Gekko/Broadway\n\ + generate code for PowerPC 750cl/Gekko/Broadway\n")); + fprintf (stream, _("\ -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\ --mbooke generate code for 32-bit PowerPC BookE\n\ --ma2 generate code for A2 architecture\n\ --mpower4, -mpwr4 generate code for Power4 architecture\n\ +-mppc64, -m620 generate code for PowerPC 620/625/630\n")); + fprintf (stream, _("\ +-mppc64bridge generate code for PowerPC 64, including bridge insns\n")); + fprintf (stream, _("\ +-mbooke generate code for 32-bit PowerPC BookE\n")); + fprintf (stream, _("\ +-ma2 generate code for A2 architecture\n")); + fprintf (stream, _("\ +-mpower4, -mpwr4 generate code for Power4 architecture\n")); + fprintf (stream, _("\ -mpower5, -mpwr5, -mpwr5x\n\ - generate code for Power5 architecture\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 for Power/PowerPC common instructions\n\ + generate code for Power5 architecture\n")); + fprintf (stream, _("\ +-mpower6, -mpwr6 generate code for Power6 architecture\n")); + fprintf (stream, _("\ +-mpower7, -mpwr7 generate code for Power7 architecture\n")); + fprintf (stream, _("\ +-mpower8, -mpwr8 generate code for Power8 architecture\n")); + fprintf (stream, _("\ +-mpower9, -mpwr9 generate code for Power9 architecture\n")); + fprintf (stream, _("\ +-mcell generate code for Cell Broadband Engine architecture\n")); + fprintf (stream, _("\ +-mcom generate code for Power/PowerPC common instructions\n")); + fprintf (stream, _("\ -many generate code for any architecture (PWR/PWRX/PPC)\n")); fprintf (stream, _("\ --maltivec generate code for AltiVec\n\ --mvsx generate code for Vector-Scalar (VSX) instructions\n\ --me300 generate code for PowerPC e300 family\n\ --me500, -me500x2 generate code for Motorola e500 core complex\n\ --me500mc, generate code for Freescale e500mc core complex\n\ --me500mc64, generate code for Freescale e500mc64 core complex\n\ --me5500, generate code for Freescale e5500 core complex\n\ --me6500, generate code for Freescale e6500 core complex\n\ --mspe generate code for Motorola SPE instructions\n\ --mspe2 generate code for Freescale SPE2 instructions\n\ --mvle generate code for Freescale VLE instructions\n\ --mtitan generate code for AppliedMicro Titan core complex\n\ --mregnames Allow symbolic names for registers\n\ +-maltivec generate code for AltiVec\n")); + fprintf (stream, _("\ +-mvsx generate code for Vector-Scalar (VSX) instructions\n")); + fprintf (stream, _("\ +-me300 generate code for PowerPC e300 family\n")); + fprintf (stream, _("\ +-me500, -me500x2 generate code for Motorola e500 core complex\n")); + fprintf (stream, _("\ +-me500mc, generate code for Freescale e500mc core complex\n")); + fprintf (stream, _("\ +-me500mc64, generate code for Freescale e500mc64 core complex\n")); + fprintf (stream, _("\ +-me5500, generate code for Freescale e5500 core complex\n")); + fprintf (stream, _("\ +-me6500, generate code for Freescale e6500 core complex\n")); + fprintf (stream, _("\ +-mspe generate code for Motorola SPE instructions\n")); + fprintf (stream, _("\ +-mspe2 generate code for Freescale SPE2 instructions\n")); + fprintf (stream, _("\ +-mvle generate code for Freescale VLE instructions\n")); + fprintf (stream, _("\ +-mtitan generate code for AppliedMicro Titan core complex\n")); + fprintf (stream, _("\ +-mregnames Allow symbolic names for registers\n")); + fprintf (stream, _("\ -mno-regnames Do not allow symbolic names for registers\n")); #ifdef OBJ_ELF fprintf (stream, _("\ --mrelocatable support for GCC's -mrelocatble option\n\ --mrelocatable-lib support for GCC's -mrelocatble-lib option\n\ --memb set PPC_EMB bit in ELF flags\n\ +-mrelocatable support for GCC's -mrelocatble option\n")); + fprintf (stream, _("\ +-mrelocatable-lib support for GCC's -mrelocatble-lib option\n")); + fprintf (stream, _("\ +-memb set PPC_EMB bit in ELF flags\n")); + fprintf (stream, _("\ -mlittle, -mlittle-endian, -le\n\ - generate code for a little endian machine\n\ + generate code for a little endian machine\n")); + fprintf (stream, _("\ -mbig, -mbig-endian, -be\n\ - generate code for a big endian machine\n\ --msolaris generate code for Solaris\n\ --mno-solaris do not generate code for Solaris\n\ --K PIC set EF_PPC_RELOCATABLE_LIB in ELF flags\n\ --V print assembler version number\n\ + generate code for a big endian machine\n")); + fprintf (stream, _("\ +-msolaris generate code for Solaris\n")); + fprintf (stream, _("\ +-mno-solaris do not generate code for Solaris\n")); + fprintf (stream, _("\ +-K PIC set EF_PPC_RELOCATABLE_LIB in ELF flags\n")); + fprintf (stream, _("\ +-V print assembler version number\n")); + fprintf (stream, _("\ -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")); + fprintf (stream, _("\ -ppc476-workaround warn if emitting data to code sections\n")); } @@ -1514,6 +1584,7 @@ insn_validate (const struct powerpc_opcode *op) /* The operands must not overlap the opcode or each other. */ for (o = op->operands; *o; ++o) { + bfd_boolean optional = FALSE; if (*o >= num_powerpc_operands) { as_bad (_("operand index error for %s"), op->name); @@ -1521,22 +1592,39 @@ insn_validate (const struct powerpc_opcode *op) } else { + uint64_t mask; const struct powerpc_operand *operand = &powerpc_operands[*o]; - if (operand->shift != (int) PPC_OPSHIFT_INV) + if (operand->shift == (int) PPC_OPSHIFT_INV) { - uint64_t mask; - - if (operand->shift >= 0) - mask = operand->bitm << operand->shift; - else - mask = operand->bitm >> -operand->shift; - if (omask & mask) - { - as_bad (_("operand %d overlap in %s"), - (int) (o - op->operands), op->name); - return TRUE; - } - omask |= mask; + const char *errmsg; + int64_t val; + + errmsg = NULL; + val = -1; + if ((operand->flags & PPC_OPERAND_NEGATIVE) != 0) + val = -val; + else if ((operand->flags & PPC_OPERAND_PLUS1) != 0) + val += 1; + mask = (*operand->insert) (0, val, ppc_cpu, &errmsg); + } + else if (operand->shift >= 0) + mask = operand->bitm << operand->shift; + else + mask = operand->bitm >> -operand->shift; + if (omask & mask) + { + as_bad (_("operand %d overlap in %s"), + (int) (o - op->operands), op->name); + return TRUE; + } + omask |= mask; + if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0) + optional = TRUE; + else if (optional) + { + as_bad (_("non-optional operand %d follows optional operand in %s"), + (int) (o - op->operands), op->name); + return TRUE; } } } @@ -1655,6 +1743,50 @@ ppc_setup_opcodes (void) for (op = powerpc_opcodes; op < op_end; op++) hash_insert (ppc_hash, op->name, (void *) op); + op_end = prefix_opcodes + prefix_num_opcodes; + for (op = prefix_opcodes; op < op_end; op++) + { + if (ENABLE_CHECKING) + { + unsigned int new_opcode = PPC_PREFIX_SEG (op[0].opcode); + +#ifdef PRINT_OPCODE_TABLE + printf ("%-14s\t#%04u\tmajor op/2: 0x%x\top: 0x%llx\tmask: 0x%llx\tflags: 0x%llx\n", + op->name, (unsigned int) (op - prefix_opcodes), + new_opcode, (unsigned long long) op->opcode, + (unsigned long long) op->mask, (unsigned long long) op->flags); +#endif + + /* The major opcodes had better be sorted. Code in the disassembler + assumes the insns are sorted according to major opcode. */ + if (op != prefix_opcodes + && new_opcode < PPC_PREFIX_SEG (op[-1].opcode)) + { + as_bad (_("major opcode is not sorted for %s"), op->name); + bad_insn = TRUE; + } + bad_insn |= insn_validate (op); + } + + if ((ppc_cpu & op->flags) != 0 + && !(ppc_cpu & op->deprecated)) + { + const char *retval; + + retval = hash_insert (ppc_hash, op->name, (void *) op); + if (retval != NULL) + { + as_bad (_("duplicate instruction %s"), + op->name); + bad_insn = TRUE; + } + } + } + + if ((ppc_cpu & PPC_OPCODE_ANY) != 0) + for (op = prefix_opcodes; op < op_end; op++) + hash_insert (ppc_hash, op->name, (void *) op); + op_end = vle_opcodes + vle_num_opcodes; for (op = vle_opcodes; op < op_end; op++) { @@ -1843,9 +1975,7 @@ ppc_cleanup (void) /* Create the .PPC.EMB.apuinfo section. */ apuinfo_secp = subseg_new (APUINFO_SECTION_NAME, 0); - bfd_set_section_flags (stdoutput, - apuinfo_secp, - SEC_HAS_CONTENTS | SEC_READONLY); + bfd_set_section_flags (apuinfo_secp, SEC_HAS_CONTENTS | SEC_READONLY); p = frag_more (4); md_number_to_chars (p, (valueT) 8, 4); @@ -1925,8 +2055,10 @@ ppc_insert_operand (uint64_t insn, hand but only up to 32 bits. This shouldn't really be valid, but, to permit this code to assemble on a 64-bit host, we sign extend the 32-bit value to 64 bits if so doing makes the - value valid. */ + value valid. We only do this for operands that are 32-bits or + smaller. */ if (val > max + && (operand->bitm & ~0xffffffffULL) == 0 && (val - (1LL << 32)) >= min && (val - (1LL << 32)) <= max && ((val - (1LL << 32)) & (right - 1)) == 0) @@ -1935,6 +2067,7 @@ ppc_insert_operand (uint64_t insn, /* Similarly, people write expressions like ~(1<<15), and expect this to be OK for a 32-bit unsigned value. */ else if (val < min + && (operand->bitm & ~0xffffffffULL) == 0 && (val + (1LL << 32)) >= min && (val + (1LL << 32)) <= max && ((val + (1LL << 32)) & (right - 1)) == 0) @@ -2086,6 +2219,18 @@ ppc_elf_suffix (char **str_p, expressionS *exp_p) MAP64 ("tprel@highest", BFD_RELOC_PPC64_TPREL16_HIGHEST), MAP64 ("tprel@highesta", BFD_RELOC_PPC64_TPREL16_HIGHESTA), MAP64 ("notoc", BFD_RELOC_PPC64_REL24_NOTOC), + MAP64 ("pcrel", BFD_RELOC_PPC64_PCREL34), + MAP64 ("got@pcrel", BFD_RELOC_PPC64_GOT_PCREL34), + MAP64 ("plt@pcrel", BFD_RELOC_PPC64_PLT_PCREL34), + MAP64 ("tls@pcrel", BFD_RELOC_PPC64_TLS_PCREL), + MAP64 ("got@tlsgd@pcrel", BFD_RELOC_PPC64_GOT_TLSGD34), + MAP64 ("got@tlsld@pcrel", BFD_RELOC_PPC64_GOT_TLSLD34), + MAP64 ("got@tprel@pcrel", BFD_RELOC_PPC64_GOT_TPREL34), + MAP64 ("got@dtprel@pcrel", BFD_RELOC_PPC64_GOT_DTPREL34), + MAP64 ("higher34", BFD_RELOC_PPC64_ADDR16_HIGHER34), + MAP64 ("highera34", BFD_RELOC_PPC64_ADDR16_HIGHERA34), + MAP64 ("highest34", BFD_RELOC_PPC64_ADDR16_HIGHEST34), + MAP64 ("highesta34", BFD_RELOC_PPC64_ADDR16_HIGHESTA34), { (char *) 0, 0, 0, 0, BFD_RELOC_NONE } }; @@ -2120,8 +2265,8 @@ ppc_elf_suffix (char **str_p, expressionS *exp_p) case BFD_RELOC_LO16_GOTOFF: case BFD_RELOC_HI16_GOTOFF: case BFD_RELOC_HI16_S_GOTOFF: - as_warn (_("identifier+constant@got means " - "identifier@got+constant")); + as_warn (_("symbol+offset@%s means symbol@%s+offset"), + ptr->string, ptr->string); break; case BFD_RELOC_PPC_GOT_TLSGD16: @@ -2140,7 +2285,7 @@ ppc_elf_suffix (char **str_p, expressionS *exp_p) case BFD_RELOC_PPC_GOT_TPREL16_LO: case BFD_RELOC_PPC_GOT_TPREL16_HI: case BFD_RELOC_PPC_GOT_TPREL16_HA: - as_bad (_("symbol+offset not supported for got tls")); + as_bad (_("symbol+offset@%s not supported"), ptr->string); break; } } @@ -2466,6 +2611,12 @@ ppc_elf_end (void) elf_elfheader (stdoutput)->e_flags &= ~EF_PPC64_ABI; elf_elfheader (stdoutput)->e_flags |= ppc_abiversion & EF_PPC64_ABI; } + /* Any selection of opcodes based on ppc_cpu after gas has finished + parsing the file is invalid. md_apply_fix and ppc_handle_align + must select opcodes based on the machine in force at the point + where the fixup or alignment frag was created, not the machine in + force at the end of file. */ + ppc_cpu = 0; } /* Validate any relocations emitted for -mrelocatable, possibly adding @@ -2550,7 +2701,7 @@ ppc_frob_file_before_adjust (void) toc = bfd_get_section_by_name (stdoutput, ".toc"); if (toc != NULL && toc_reloc_types != has_large_toc_reloc - && bfd_section_size (stdoutput, toc) > 0x10000) + && bfd_section_size (toc) > 0x10000) as_warn (_("TOC section size exceeds 64k")); } @@ -2722,6 +2873,90 @@ ppc_apuinfo_section_add (unsigned int apu, unsigned int version) #undef APUID #endif +/* Various frobbings of labels and their addresses. */ + +/* Symbols labelling the current insn. */ +struct insn_label_list +{ + struct insn_label_list *next; + symbolS *label; +}; + +static struct insn_label_list *insn_labels; +static struct insn_label_list *free_insn_labels; + +static void +ppc_record_label (symbolS *sym) +{ + struct insn_label_list *l; + + if (free_insn_labels == NULL) + l = XNEW (struct insn_label_list); + else + { + l = free_insn_labels; + free_insn_labels = l->next; + } + + l->label = sym; + l->next = insn_labels; + insn_labels = l; +} + +static void +ppc_clear_labels (void) +{ + while (insn_labels != NULL) + { + struct insn_label_list *l = insn_labels; + insn_labels = l->next; + l->next = free_insn_labels; + free_insn_labels = l; + } +} + +void +ppc_start_line_hook (void) +{ + ppc_clear_labels (); +} + +void +ppc_new_dot_label (symbolS *sym) +{ + ppc_record_label (sym); +#ifdef OBJ_XCOFF + /* Anchor this label to the current csect for relocations. */ + symbol_get_tc (sym)->within = ppc_current_csect; +#endif +} + +void +ppc_frob_label (symbolS *sym) +{ + ppc_record_label (sym); + +#ifdef OBJ_XCOFF + /* Set the class of a label based on where it is defined. This handles + symbols without suffixes. Also, move the symbol so that it follows + the csect symbol. */ + if (ppc_current_csect != (symbolS *) NULL) + { + if (symbol_get_tc (sym)->symbol_class == -1) + symbol_get_tc (sym)->symbol_class = symbol_get_tc (ppc_current_csect)->symbol_class; + + symbol_remove (sym, &symbol_rootP, &symbol_lastP); + symbol_append (sym, symbol_get_tc (ppc_current_csect)->within, + &symbol_rootP, &symbol_lastP); + symbol_get_tc (ppc_current_csect)->within = sym; + symbol_get_tc (sym)->within = ppc_current_csect; + } +#endif + +#ifdef OBJ_ELF + dwarf2_emit_label (sym); +#endif +} /* We need to keep a list of fixups. We can't simply generate them as we go, because that would require us to first create the frag, and @@ -2736,6 +2971,317 @@ struct ppc_fixup #define MAX_INSN_FIXUPS (5) +/* Return the field size operated on by RELOC, and whether it is + pc-relative in PC_RELATIVE. */ + +static unsigned int +fixup_size (bfd_reloc_code_real_type reloc, bfd_boolean *pc_relative) +{ + unsigned int size = 0; + bfd_boolean pcrel = FALSE; + + switch (reloc) + { + /* This switch statement must handle all BFD_RELOC values + possible in instruction fixups. As is, it handles all + BFD_RELOC values used in bfd/elf64-ppc.c, bfd/elf32-ppc.c, + bfd/coff-ppc, bfd/coff-rs6000.c and bfd/coff64-rs6000.c. + Overkill since data and marker relocs need not be handled + here, but this way we can be sure a needed fixup reloc isn't + accidentally omitted. */ + case BFD_RELOC_PPC_EMB_MRKREF: + case BFD_RELOC_VTABLE_ENTRY: + case BFD_RELOC_VTABLE_INHERIT: + break; + + case BFD_RELOC_8: + size = 1; + break; + + case BFD_RELOC_16: + case BFD_RELOC_16_BASEREL: + case BFD_RELOC_16_GOTOFF: + case BFD_RELOC_GPREL16: + case BFD_RELOC_HI16: + case BFD_RELOC_HI16_BASEREL: + case BFD_RELOC_HI16_GOTOFF: + case BFD_RELOC_HI16_PLTOFF: + case BFD_RELOC_HI16_S: + case BFD_RELOC_HI16_S_BASEREL: + case BFD_RELOC_HI16_S_GOTOFF: + case BFD_RELOC_HI16_S_PLTOFF: + case BFD_RELOC_LO16: + case BFD_RELOC_LO16_BASEREL: + case BFD_RELOC_LO16_GOTOFF: + case BFD_RELOC_LO16_PLTOFF: + case BFD_RELOC_PPC64_ADDR16_DS: + case BFD_RELOC_PPC64_ADDR16_HIGH: + case BFD_RELOC_PPC64_ADDR16_HIGHA: + case BFD_RELOC_PPC64_ADDR16_HIGHER34: + case BFD_RELOC_PPC64_ADDR16_HIGHERA34: + case BFD_RELOC_PPC64_ADDR16_HIGHEST34: + case BFD_RELOC_PPC64_ADDR16_HIGHESTA34: + case BFD_RELOC_PPC64_ADDR16_LO_DS: + case BFD_RELOC_PPC64_DTPREL16_DS: + 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_DTPREL16_LO_DS: + case BFD_RELOC_PPC64_GOT16_DS: + case BFD_RELOC_PPC64_GOT16_LO_DS: + case BFD_RELOC_PPC64_HIGHER: + case BFD_RELOC_PPC64_HIGHER_S: + case BFD_RELOC_PPC64_HIGHEST: + case BFD_RELOC_PPC64_HIGHEST_S: + case BFD_RELOC_PPC64_PLT16_LO_DS: + case BFD_RELOC_PPC64_PLTGOT16: + case BFD_RELOC_PPC64_PLTGOT16_DS: + case BFD_RELOC_PPC64_PLTGOT16_HA: + case BFD_RELOC_PPC64_PLTGOT16_HI: + case BFD_RELOC_PPC64_PLTGOT16_LO: + case BFD_RELOC_PPC64_PLTGOT16_LO_DS: + case BFD_RELOC_PPC64_SECTOFF_DS: + case BFD_RELOC_PPC64_SECTOFF_LO_DS: + case BFD_RELOC_PPC64_TOC16_DS: + case BFD_RELOC_PPC64_TOC16_HA: + case BFD_RELOC_PPC64_TOC16_HI: + case BFD_RELOC_PPC64_TOC16_LO: + case BFD_RELOC_PPC64_TOC16_LO_DS: + case BFD_RELOC_PPC64_TPREL16_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_TPREL16_LO_DS: +#ifdef OBJ_XCOFF + case BFD_RELOC_PPC_BA16: +#endif + case BFD_RELOC_PPC_DTPREL16: + case BFD_RELOC_PPC_DTPREL16_HA: + case BFD_RELOC_PPC_DTPREL16_HI: + case BFD_RELOC_PPC_DTPREL16_LO: + case BFD_RELOC_PPC_EMB_NADDR16: + case BFD_RELOC_PPC_EMB_NADDR16_HA: + case BFD_RELOC_PPC_EMB_NADDR16_HI: + case BFD_RELOC_PPC_EMB_NADDR16_LO: + case BFD_RELOC_PPC_EMB_RELSDA: + case BFD_RELOC_PPC_EMB_RELSEC16: + case BFD_RELOC_PPC_EMB_RELST_LO: + case BFD_RELOC_PPC_EMB_RELST_HI: + case BFD_RELOC_PPC_EMB_RELST_HA: + case BFD_RELOC_PPC_EMB_SDA2I16: + case BFD_RELOC_PPC_EMB_SDA2REL: + case BFD_RELOC_PPC_EMB_SDAI16: + case BFD_RELOC_PPC_GOT_DTPREL16: + case BFD_RELOC_PPC_GOT_DTPREL16_HA: + case BFD_RELOC_PPC_GOT_DTPREL16_HI: + case BFD_RELOC_PPC_GOT_DTPREL16_LO: + case BFD_RELOC_PPC_GOT_TLSGD16: + case BFD_RELOC_PPC_GOT_TLSGD16_HA: + case BFD_RELOC_PPC_GOT_TLSGD16_HI: + case BFD_RELOC_PPC_GOT_TLSGD16_LO: + case BFD_RELOC_PPC_GOT_TLSLD16: + case BFD_RELOC_PPC_GOT_TLSLD16_HA: + case BFD_RELOC_PPC_GOT_TLSLD16_HI: + case BFD_RELOC_PPC_GOT_TLSLD16_LO: + case BFD_RELOC_PPC_GOT_TPREL16: + case BFD_RELOC_PPC_GOT_TPREL16_HA: + case BFD_RELOC_PPC_GOT_TPREL16_HI: + case BFD_RELOC_PPC_GOT_TPREL16_LO: + case BFD_RELOC_PPC_TOC16: + case BFD_RELOC_PPC_TPREL16: + case BFD_RELOC_PPC_TPREL16_HA: + case BFD_RELOC_PPC_TPREL16_HI: + case BFD_RELOC_PPC_TPREL16_LO: + size = 2; + break; + + case BFD_RELOC_16_PCREL: + case BFD_RELOC_HI16_PCREL: + case BFD_RELOC_HI16_S_PCREL: + case BFD_RELOC_LO16_PCREL: + case BFD_RELOC_PPC64_REL16_HIGH: + case BFD_RELOC_PPC64_REL16_HIGHA: + case BFD_RELOC_PPC64_REL16_HIGHER: + case BFD_RELOC_PPC64_REL16_HIGHER34: + case BFD_RELOC_PPC64_REL16_HIGHERA: + case BFD_RELOC_PPC64_REL16_HIGHERA34: + case BFD_RELOC_PPC64_REL16_HIGHEST: + case BFD_RELOC_PPC64_REL16_HIGHEST34: + case BFD_RELOC_PPC64_REL16_HIGHESTA: + case BFD_RELOC_PPC64_REL16_HIGHESTA34: +#ifdef OBJ_XCOFF + case BFD_RELOC_PPC_B16: +#endif + case BFD_RELOC_PPC_VLE_REL8: + size = 2; + pcrel = TRUE; + break; + + case BFD_RELOC_16_GOT_PCREL: /* coff reloc, bad name re size. */ + case BFD_RELOC_32: + case BFD_RELOC_32_GOTOFF: + case BFD_RELOC_32_PLTOFF: +#ifdef OBJ_XCOFF + case BFD_RELOC_CTOR: +#endif + case BFD_RELOC_PPC64_ENTRY: + case BFD_RELOC_PPC_16DX_HA: +#ifndef OBJ_XCOFF + case BFD_RELOC_PPC_BA16: +#endif + case BFD_RELOC_PPC_BA16_BRNTAKEN: + case BFD_RELOC_PPC_BA16_BRTAKEN: + case BFD_RELOC_PPC_BA26: + case BFD_RELOC_PPC_EMB_BIT_FLD: + case BFD_RELOC_PPC_EMB_NADDR32: + case BFD_RELOC_PPC_EMB_SDA21: + case BFD_RELOC_PPC_TLS: + case BFD_RELOC_PPC_TLSGD: + case BFD_RELOC_PPC_TLSLD: + case BFD_RELOC_PPC_VLE_HA16A: + case BFD_RELOC_PPC_VLE_HA16D: + case BFD_RELOC_PPC_VLE_HI16A: + case BFD_RELOC_PPC_VLE_HI16D: + case BFD_RELOC_PPC_VLE_LO16A: + case BFD_RELOC_PPC_VLE_LO16D: + case BFD_RELOC_PPC_VLE_SDA21: + case BFD_RELOC_PPC_VLE_SDA21_LO: + case BFD_RELOC_PPC_VLE_SDAREL_HA16A: + case BFD_RELOC_PPC_VLE_SDAREL_HA16D: + case BFD_RELOC_PPC_VLE_SDAREL_HI16A: + case BFD_RELOC_PPC_VLE_SDAREL_HI16D: + case BFD_RELOC_PPC_VLE_SDAREL_LO16A: + case BFD_RELOC_PPC_VLE_SDAREL_LO16D: + case BFD_RELOC_PPC64_TLS_PCREL: + case BFD_RELOC_RVA: + size = 4; + break; + + case BFD_RELOC_24_PLT_PCREL: + case BFD_RELOC_32_PCREL: + case BFD_RELOC_32_PLT_PCREL: + case BFD_RELOC_PPC64_REL24_NOTOC: +#ifndef OBJ_XCOFF + case BFD_RELOC_PPC_B16: +#endif + case BFD_RELOC_PPC_B16_BRNTAKEN: + case BFD_RELOC_PPC_B16_BRTAKEN: + case BFD_RELOC_PPC_B26: + case BFD_RELOC_PPC_LOCAL24PC: + case BFD_RELOC_PPC_REL16DX_HA: + case BFD_RELOC_PPC_VLE_REL15: + case BFD_RELOC_PPC_VLE_REL24: + size = 4; + pcrel = TRUE; + break; + +#ifndef OBJ_XCOFF + case BFD_RELOC_CTOR: +#endif + case BFD_RELOC_PPC_COPY: + case BFD_RELOC_PPC_DTPMOD: + case BFD_RELOC_PPC_DTPREL: + case BFD_RELOC_PPC_GLOB_DAT: + case BFD_RELOC_PPC_TPREL: + size = ppc_obj64 ? 8 : 4; + break; + + case BFD_RELOC_64: + case BFD_RELOC_64_PLTOFF: + case BFD_RELOC_PPC64_ADDR64_LOCAL: + case BFD_RELOC_PPC64_D28: + case BFD_RELOC_PPC64_D34: + case BFD_RELOC_PPC64_D34_LO: + case BFD_RELOC_PPC64_D34_HI30: + case BFD_RELOC_PPC64_D34_HA30: + case BFD_RELOC_PPC64_TPREL34: + case BFD_RELOC_PPC64_DTPREL34: + case BFD_RELOC_PPC64_TOC: + size = 8; + break; + + case BFD_RELOC_64_PCREL: + case BFD_RELOC_64_PLT_PCREL: + case BFD_RELOC_PPC64_GOT_PCREL34: + case BFD_RELOC_PPC64_GOT_TLSGD34: + case BFD_RELOC_PPC64_GOT_TLSLD34: + case BFD_RELOC_PPC64_GOT_TPREL34: + case BFD_RELOC_PPC64_GOT_DTPREL34: + case BFD_RELOC_PPC64_PCREL28: + case BFD_RELOC_PPC64_PCREL34: + case BFD_RELOC_PPC64_PLT_PCREL34: + size = 8; + pcrel = TRUE; + break; + + default: + abort (); + } + + if (ENABLE_CHECKING) + { + reloc_howto_type *reloc_howto = bfd_reloc_type_lookup (stdoutput, reloc); + if (reloc_howto != NULL + && (size != bfd_get_reloc_size (reloc_howto) + || pcrel != reloc_howto->pc_relative)) + { + as_bad (_("%s howto doesn't match size/pcrel in gas"), + reloc_howto->name); + abort (); + } + } + *pc_relative = pcrel; + return size; +} + +#ifdef OBJ_ELF +/* If we have parsed a call to __tls_get_addr, parse an argument like + (gd0@tlsgd). *STR is the leading parenthesis on entry. If an arg + is successfully parsed, *STR is updated past the trailing + parenthesis and trailing white space, and *TLS_FIX contains the + reloc and arg expression. */ + +static int +parse_tls_arg (char **str, const expressionS *exp, struct ppc_fixup *tls_fix) +{ + const char *sym_name = S_GET_NAME (exp->X_add_symbol); + if (sym_name[0] == '.') + ++sym_name; + + tls_fix->reloc = BFD_RELOC_NONE; + if (strncasecmp (sym_name, "__tls_get_addr", 14) == 0 + && (sym_name[14] == 0 + || strcasecmp (sym_name + 14, "_desc") == 0 + || strcasecmp (sym_name + 14, "_opt") == 0)) + { + char *hold = input_line_pointer; + input_line_pointer = *str + 1; + expression (&tls_fix->exp); + if (tls_fix->exp.X_op == O_symbol) + { + if (strncasecmp (input_line_pointer, "@tlsgd)", 7) == 0) + tls_fix->reloc = BFD_RELOC_PPC_TLSGD; + else if (strncasecmp (input_line_pointer, "@tlsld)", 7) == 0) + tls_fix->reloc = BFD_RELOC_PPC_TLSLD; + if (tls_fix->reloc != BFD_RELOC_NONE) + { + input_line_pointer += 7; + SKIP_WHITESPACE (); + *str = input_line_pointer; + } + } + input_line_pointer = hold; + } + return tls_fix->reloc != BFD_RELOC_NONE; +} +#endif + /* This routine is called for each instruction to be assembled. */ void @@ -2772,6 +3318,7 @@ md_assemble (char *str) else ppc_macro (s, macro); + ppc_clear_labels (); return; } @@ -3125,84 +3672,16 @@ md_assemble (char *str) { bfd_reloc_code_real_type reloc = BFD_RELOC_NONE; #ifdef OBJ_ELF - if (ex.X_op == O_symbol && str[0] == '(') + /* Look for a __tls_get_addr arg using the insane old syntax. */ + if (ex.X_op == O_symbol && *str == '(' && fc < MAX_INSN_FIXUPS + && parse_tls_arg (&str, &ex, &fixups[fc])) { - const char *sym_name = S_GET_NAME (ex.X_add_symbol); - if (sym_name[0] == '.') - ++sym_name; - - if (strcasecmp (sym_name, "__tls_get_addr") == 0) - { - expressionS tls_exp; - - hold = input_line_pointer; - input_line_pointer = str + 1; - expression (&tls_exp); - if (tls_exp.X_op == O_symbol) - { - reloc = BFD_RELOC_NONE; - if (strncasecmp (input_line_pointer, "@tlsgd)", 7) == 0) - { - reloc = BFD_RELOC_PPC_TLSGD; - input_line_pointer += 7; - } - else if (strncasecmp (input_line_pointer, "@tlsld)", 7) == 0) - { - reloc = BFD_RELOC_PPC_TLSLD; - input_line_pointer += 7; - } - if (reloc != BFD_RELOC_NONE) - { - SKIP_WHITESPACE (); - str = input_line_pointer; - - if (fc >= MAX_INSN_FIXUPS) - as_fatal (_("too many fixups")); - fixups[fc].exp = tls_exp; - fixups[fc].opindex = *opindex_ptr; - fixups[fc].reloc = reloc; - ++fc; - } - } - input_line_pointer = hold; - } + fixups[fc].opindex = *opindex_ptr; + ++fc; } if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_NONE) { - /* Some TLS tweaks. */ - switch (reloc) - { - default: - break; - - case BFD_RELOC_PPC_TLS: - if (!_bfd_elf_ppc_at_tls_transform (opcode->opcode, 0)) - as_bad (_("@tls may not be used with \"%s\" operands"), - opcode->name); - else if (operand->shift != 11) - as_bad (_("@tls may only be used in last operand")); - else - insn = ppc_insert_operand (insn, operand, - ppc_obj64 ? 13 : 2, - ppc_cpu, (char *) NULL, 0); - break; - - /* We'll only use the 32 (or 64) bit form of these relocations - in constants. Instructions get the 16 bit form. */ - case BFD_RELOC_PPC_DTPREL: - reloc = BFD_RELOC_PPC_DTPREL16; - break; - case BFD_RELOC_PPC_TPREL: - reloc = BFD_RELOC_PPC_TPREL16; - break; - } - - /* addpcis. */ - if (opcode->opcode == (19 << 26) + (2 << 1) - && reloc == BFD_RELOC_HI16_S) - reloc = BFD_RELOC_PPC_16DX_HA; - /* If VLE-mode convert LO/HI/HA relocations. */ if (opcode->flags & PPC_OPCODE_VLE) { @@ -3211,6 +3690,7 @@ md_assemble (char *str) int use_a_reloc = (tmp_insn == E_OR2I_INSN || tmp_insn == E_AND2I_DOT_INSN || tmp_insn == E_OR2IS_INSN + || tmp_insn == E_LI_INSN || tmp_insn == E_LIS_INSN || tmp_insn == E_AND2IS_DOT_INSN); @@ -3269,6 +3749,94 @@ md_assemble (char *str) break; } } + + /* TLS and other tweaks. */ + switch (reloc) + { + default: + break; + + case BFD_RELOC_PPC_TLS: + case BFD_RELOC_PPC64_TLS_PCREL: + if (!_bfd_elf_ppc_at_tls_transform (opcode->opcode, 0)) + as_bad (_("@tls may not be used with \"%s\" operands"), + opcode->name); + else if (operand->shift != 11) + as_bad (_("@tls may only be used in last operand")); + else + insn = ppc_insert_operand (insn, operand, + ppc_obj64 ? 13 : 2, + ppc_cpu, (char *) NULL, 0); + break; + + /* We'll only use the 32 (or 64) bit form of these relocations + in constants. Instructions get the 16 or 34 bit form. */ + case BFD_RELOC_PPC_DTPREL: + if (operand->bitm == 0x3ffffffffULL) + reloc = BFD_RELOC_PPC64_DTPREL34; + else + reloc = BFD_RELOC_PPC_DTPREL16; + break; + + case BFD_RELOC_PPC_TPREL: + if (operand->bitm == 0x3ffffffffULL) + reloc = BFD_RELOC_PPC64_TPREL34; + else + reloc = BFD_RELOC_PPC_TPREL16; + break; + + case BFD_RELOC_PPC64_PCREL34: + if (operand->bitm == 0xfffffffULL) + { + reloc = BFD_RELOC_PPC64_PCREL28; + break; + } + /* Fall through. */ + case BFD_RELOC_PPC64_GOT_PCREL34: + case BFD_RELOC_PPC64_PLT_PCREL34: + case BFD_RELOC_PPC64_GOT_TLSGD34: + case BFD_RELOC_PPC64_GOT_TLSLD34: + case BFD_RELOC_PPC64_GOT_TPREL34: + case BFD_RELOC_PPC64_GOT_DTPREL34: + if (operand->bitm != 0x3ffffffffULL + || (operand->flags & PPC_OPERAND_NEGATIVE) != 0) + as_warn (_("%s unsupported on this instruction"), "@pcrel"); + break; + + case BFD_RELOC_LO16: + if (operand->bitm == 0x3ffffffffULL + && (operand->flags & PPC_OPERAND_NEGATIVE) == 0) + reloc = BFD_RELOC_PPC64_D34_LO; + else if ((operand->bitm | 0xf) != 0xffff + || operand->shift != 0 + || (operand->flags & PPC_OPERAND_NEGATIVE) != 0) + as_warn (_("%s unsupported on this instruction"), "@l"); + break; + + case BFD_RELOC_HI16: + if (operand->bitm == 0x3ffffffffULL + && (operand->flags & PPC_OPERAND_NEGATIVE) == 0) + reloc = BFD_RELOC_PPC64_D34_HI30; + else if (operand->bitm != 0xffff + || operand->shift != 0 + || (operand->flags & PPC_OPERAND_NEGATIVE) != 0) + as_warn (_("%s unsupported on this instruction"), "@h"); + break; + + case BFD_RELOC_HI16_S: + if (operand->bitm == 0x3ffffffffULL + && (operand->flags & PPC_OPERAND_NEGATIVE) == 0) + reloc = BFD_RELOC_PPC64_D34_HA30; + else if (operand->bitm == 0xffff + && operand->shift == (int) PPC_OPSHIFT_INV + && opcode->opcode == (19 << 26) + (2 << 1)) + /* addpcis. */ + reloc = BFD_RELOC_PPC_16DX_HA; + else if (operand->bitm != 0xffff + || operand->shift != 0 + || (operand->flags & PPC_OPERAND_NEGATIVE) != 0) + as_warn (_("%s unsupported on this instruction"), "@ha"); + } } #endif /* OBJ_ELF */ @@ -3317,6 +3885,10 @@ md_assemble (char *str) } #endif } + else if (operand->bitm == 0x3ffffffffULL) + reloc = BFD_RELOC_PPC64_D34; + else if (operand->bitm == 0xfffffffULL) + reloc = BFD_RELOC_PPC64_D28; /* For the absolute forms of branches, convert the PC relative form back into the absolute. */ @@ -3366,58 +3938,84 @@ md_assemble (char *str) 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; } } + + /* Look for a __tls_get_addr arg after any __tls_get_addr + modifiers like @plt. This fixup must be emitted before + the usual call fixup. */ + if (ex.X_op == O_symbol && *str == '(' && fc < MAX_INSN_FIXUPS + && parse_tls_arg (&str, &ex, &fixups[fc])) + { + fixups[fc].opindex = *opindex_ptr; + ++fc; + } #endif /* We need to generate a fixup for this expression. */ @@ -3529,14 +4127,50 @@ md_assemble (char *str) if ((frag_now_fix () & addr_mask) != 0) as_bad (_("instruction address is not a multiple of %d"), addr_mask + 1); - /* Differentiate between two and four byte insns. */ + /* Differentiate between two, four, and eight byte insns. */ insn_length = 4; if ((ppc_cpu & PPC_OPCODE_VLE) != 0 && PPC_OP_SE_VLE (insn)) insn_length = 2; + else if ((opcode->flags & PPC_OPCODE_POWERXX) != 0 + && PPC_PREFIX_P (insn)) + { + struct insn_label_list *l; + + insn_length = 8; + + /* 8-byte prefix instructions are not allowed to cross 64-byte + boundaries. */ + frag_align_code (6, 4); + record_alignment (now_seg, 6); + + /* Update "dot" in any expressions used by this instruction, and + a label attached to the instruction. By "attached" we mean + on the same source line as the instruction and without any + intervening semicolons. */ + dot_value = frag_now_fix (); + dot_frag = frag_now; + for (l = insn_labels; l != NULL; l = l->next) + { + symbol_set_frag (l->label, dot_frag); + S_SET_VALUE (l->label, dot_value); + } + } + + ppc_clear_labels (); f = frag_more (insn_length); frag_now->insn_addr = addr_mask; - md_number_to_chars (f, insn, insn_length); + + /* The prefix part of an 8-byte instruction always occupies the lower + addressed word in a doubleword, regardless of endianness. */ + if (!target_big_endian && insn_length == 8) + { + md_number_to_chars (f, PPC_GET_PREFIX (insn), 4); + md_number_to_chars (f + 4, PPC_GET_SUFFIX (insn), 4); + } + else + md_number_to_chars (f, insn, insn_length); + last_insn = insn; last_seg = now_seg; last_subseg = now_subseg; @@ -3551,22 +4185,15 @@ md_assemble (char *str) fixS *fixP; if (fixups[i].reloc != BFD_RELOC_NONE) { - reloc_howto_type *reloc_howto; - int size; - int offset; - - reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc); - if (!reloc_howto) - abort (); - - size = bfd_get_reloc_size (reloc_howto); - offset = target_big_endian ? (insn_length - size) : 0; + bfd_boolean pcrel; + unsigned int size = fixup_size (fixups[i].reloc, &pcrel); + int offset = target_big_endian ? (insn_length - size) : 0; fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset, size, &fixups[i].exp, - reloc_howto->pc_relative, + pcrel, fixups[i].reloc); } else @@ -4055,14 +4682,14 @@ ppc_change_debug_section (unsigned int idx, subsegT subseg) const struct xcoff_dwsect_name *dw = &xcoff_dwsect_names[idx]; sec = subseg_new (dw->name, subseg); - oldflags = bfd_get_section_flags (stdoutput, sec); + oldflags = bfd_section_flags (sec); if (oldflags == SEC_NO_FLAGS) { /* Just created section. */ gas_assert (dw_sections[idx].sect == NULL); - bfd_set_section_flags (stdoutput, sec, SEC_DEBUGGING); - bfd_set_section_alignment (stdoutput, sec, 0); + bfd_set_section_flags (sec, SEC_DEBUGGING); + bfd_set_section_alignment (sec, 0); dw_sections[idx].sect = sec; } @@ -4965,6 +5592,7 @@ ppc_xcoff_end (void) symbol_set_value_now (dwss->end_exp.X_add_symbol); } } + ppc_cpu = 0; } #endif /* OBJ_XCOFF */ @@ -5177,11 +5805,10 @@ ppc_pdata (int ignore ATTRIBUTE_UNUSED) { pdata_section = subseg_new (".pdata", 0); - bfd_set_section_flags (stdoutput, pdata_section, - (SEC_ALLOC | SEC_LOAD | SEC_RELOC - | SEC_READONLY | SEC_DATA )); + bfd_set_section_flags (pdata_section, (SEC_ALLOC | SEC_LOAD | SEC_RELOC + | SEC_READONLY | SEC_DATA)); - bfd_set_section_alignment (stdoutput, pdata_section, 2); + bfd_set_section_alignment (pdata_section, 2); } else { @@ -5210,11 +5837,10 @@ ppc_ydata (int ignore ATTRIBUTE_UNUSED) if (ydata_section == 0) { ydata_section = subseg_new (".ydata", 0); - bfd_set_section_flags (stdoutput, ydata_section, - (SEC_ALLOC | SEC_LOAD | SEC_RELOC - | SEC_READONLY | SEC_DATA )); + bfd_set_section_flags (ydata_section, (SEC_ALLOC | SEC_LOAD | SEC_RELOC + | SEC_READONLY | SEC_DATA )); - bfd_set_section_alignment (stdoutput, ydata_section, 3); + bfd_set_section_alignment (ydata_section, 3); } else { @@ -5247,11 +5873,10 @@ ppc_reldata (int ignore ATTRIBUTE_UNUSED) { reldata_section = subseg_new (".reldata", 0); - bfd_set_section_flags (stdoutput, reldata_section, - (SEC_ALLOC | SEC_LOAD | SEC_RELOC - | SEC_DATA)); + bfd_set_section_flags (reldata_section, (SEC_ALLOC | SEC_LOAD | SEC_RELOC + | SEC_DATA)); - bfd_set_section_alignment (stdoutput, reldata_section, 2); + bfd_set_section_alignment (reldata_section, 2); } else { @@ -5276,11 +5901,10 @@ ppc_rdata (int ignore ATTRIBUTE_UNUSED) if (rdata_section == 0) { rdata_section = subseg_new (".rdata", 0); - bfd_set_section_flags (stdoutput, rdata_section, - (SEC_ALLOC | SEC_LOAD | SEC_RELOC - | SEC_READONLY | SEC_DATA )); + bfd_set_section_flags (rdata_section, (SEC_ALLOC | SEC_LOAD | SEC_RELOC + | SEC_READONLY | SEC_DATA )); - bfd_set_section_alignment (stdoutput, rdata_section, 2); + bfd_set_section_alignment (rdata_section, 2); } else { @@ -5634,13 +6258,13 @@ ppc_pe_section (int ignore ATTRIBUTE_UNUSED) if (flags != SEC_NO_FLAGS) { - if (! bfd_set_section_flags (stdoutput, sec, flags)) + if (!bfd_set_section_flags (sec, flags)) as_bad (_("error setting flags for \"%s\": %s"), - bfd_section_name (stdoutput, sec), + bfd_section_name (sec), bfd_errmsg (bfd_get_error ())); } - bfd_set_section_alignment (stdoutput, sec, align); + bfd_set_section_alignment (sec, align); } static void @@ -5671,11 +6295,10 @@ ppc_pe_tocd (int ignore ATTRIBUTE_UNUSED) { tocdata_section = subseg_new (".tocd", 0); /* FIXME: section flags won't work. */ - bfd_set_section_flags (stdoutput, tocdata_section, - (SEC_ALLOC | SEC_LOAD | SEC_RELOC - | SEC_READONLY | SEC_DATA)); + bfd_set_section_flags (tocdata_section, (SEC_ALLOC | SEC_LOAD | SEC_RELOC + | SEC_READONLY | SEC_DATA)); - bfd_set_section_alignment (stdoutput, tocdata_section, 2); + bfd_set_section_alignment (tocdata_section, 2); } else { @@ -5826,30 +6449,6 @@ ppc_symbol_new_hook (symbolS *sym) as_bad (_("unrecognized symbol suffix")); } -/* Set the class of a label based on where it is defined. This - handles symbols without suffixes. Also, move the symbol so that it - follows the csect symbol. */ - -void -ppc_frob_label (symbolS *sym) -{ - if (ppc_current_csect != (symbolS *) NULL) - { - if (symbol_get_tc (sym)->symbol_class == -1) - symbol_get_tc (sym)->symbol_class = symbol_get_tc (ppc_current_csect)->symbol_class; - - symbol_remove (sym, &symbol_rootP, &symbol_lastP); - symbol_append (sym, symbol_get_tc (ppc_current_csect)->within, - &symbol_rootP, &symbol_lastP); - symbol_get_tc (ppc_current_csect)->within = sym; - symbol_get_tc (sym)->within = ppc_current_csect; - } - -#ifdef OBJ_ELF - dwarf2_emit_label (sym); -#endif -} - /* This variable is set by ppc_frob_symbol if any absolute symbols are seen. It tells ppc_adjust_symtab whether it needs to look through the symbols. */ @@ -5970,8 +6569,7 @@ ppc_frob_symbol (symbolS *sym) /* This is a csect symbol. x_scnlen is the size of the csect. */ if (symbol_get_tc (sym)->next == (symbolS *) NULL) - a->x_csect.x_scnlen.l = (bfd_section_size (stdoutput, - S_GET_SEGMENT (sym)) + a->x_csect.x_scnlen.l = (bfd_section_size (S_GET_SEGMENT (sym)) - S_GET_VALUE (sym)); else { @@ -6019,8 +6617,7 @@ ppc_frob_symbol (symbolS *sym) || symbol_get_tc (next)->symbol_class != XMC_TC) { if (ppc_after_toc_frag == (fragS *) NULL) - a->x_csect.x_scnlen.l = (bfd_section_size (stdoutput, - data_section) + a->x_csect.x_scnlen.l = (bfd_section_size (data_section) - S_GET_VALUE (sym)); else a->x_csect.x_scnlen.l = (ppc_after_toc_frag->fr_address @@ -6184,12 +6781,12 @@ ppc_frob_section (asection *sec) static bfd_vma vma = 0; /* Dwarf sections start at 0. */ - if (bfd_get_section_flags (NULL, sec) & SEC_DEBUGGING) + if (bfd_section_flags (sec) & SEC_DEBUGGING) return; vma = md_section_align (sec, vma); - bfd_set_section_vma (stdoutput, sec, vma); - vma += bfd_section_size (stdoutput, sec); + bfd_set_section_vma (sec, vma); + vma += bfd_section_size (sec); } #endif /* OBJ_XCOFF */ @@ -6220,7 +6817,7 @@ md_section_align (asection *seg ATTRIBUTE_UNUSED, valueT addr) #ifdef OBJ_ELF return addr; #else - int align = bfd_get_section_alignment (stdoutput, seg); + int align = bfd_section_alignment (seg); return ((addr + (1 << align) - 1) & -(1 << align)); #endif @@ -6283,7 +6880,7 @@ ppc_fix_adjustable (fixS *fix) return 0; /* Always adjust symbols in debugging sections. */ - if (bfd_get_section_flags (stdoutput, symseg) & SEC_DEBUGGING) + if (bfd_section_flags (symseg) & SEC_DEBUGGING) return 1; if (ppc_toc_csect != (symbolS *) NULL @@ -6381,14 +6978,6 @@ ppc_force_relocation (fixS *fix) return generic_force_reloc (fix); } - -void -ppc_new_dot_label (symbolS *sym) -{ - /* Anchor this label to the current csect for relocations. */ - symbol_get_tc (sym)->within = ppc_current_csect; -} - #endif /* OBJ_XCOFF */ #ifdef OBJ_ELF @@ -6431,7 +7020,7 @@ ppc_force_relocation (fixS *fix) } if (fix->fx_r_type >= BFD_RELOC_PPC_TLS - && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA) + && fix->fx_r_type <= BFD_RELOC_PPC64_TLS_PCREL) return 1; return generic_force_reloc (fix); @@ -6473,11 +7062,33 @@ ppc_fix_adjustable (fixS *fix) && fix->fx_r_type != BFD_RELOC_HI16_S_GOTOFF && fix->fx_r_type != BFD_RELOC_PPC64_GOT16_DS && fix->fx_r_type != BFD_RELOC_PPC64_GOT16_LO_DS + && fix->fx_r_type != BFD_RELOC_16_GOT_PCREL + && fix->fx_r_type != BFD_RELOC_32_GOTOFF + && fix->fx_r_type != BFD_RELOC_PPC64_GOT_PCREL34 + && fix->fx_r_type != BFD_RELOC_24_PLT_PCREL + && fix->fx_r_type != BFD_RELOC_32_PLTOFF + && fix->fx_r_type != BFD_RELOC_32_PLT_PCREL + && fix->fx_r_type != BFD_RELOC_LO16_PLTOFF + && fix->fx_r_type != BFD_RELOC_HI16_PLTOFF + && fix->fx_r_type != BFD_RELOC_HI16_S_PLTOFF + && fix->fx_r_type != BFD_RELOC_64_PLTOFF + && fix->fx_r_type != BFD_RELOC_64_PLT_PCREL + && fix->fx_r_type != BFD_RELOC_PPC64_PLT16_LO_DS + && fix->fx_r_type != BFD_RELOC_PPC64_PLT_PCREL34 + && fix->fx_r_type != BFD_RELOC_PPC64_PLTGOT16 + && fix->fx_r_type != BFD_RELOC_PPC64_PLTGOT16_LO + && fix->fx_r_type != BFD_RELOC_PPC64_PLTGOT16_HI + && fix->fx_r_type != BFD_RELOC_PPC64_PLTGOT16_HA + && fix->fx_r_type != BFD_RELOC_PPC64_PLTGOT16_DS + && fix->fx_r_type != BFD_RELOC_PPC64_PLTGOT16_LO_DS && fix->fx_r_type != BFD_RELOC_GPREL16 + && fix->fx_r_type != BFD_RELOC_PPC_VLE_SDAREL_LO16A + && fix->fx_r_type != BFD_RELOC_PPC_VLE_SDAREL_HI16A + && fix->fx_r_type != BFD_RELOC_PPC_VLE_SDAREL_HA16A && fix->fx_r_type != BFD_RELOC_VTABLE_INHERIT && fix->fx_r_type != BFD_RELOC_VTABLE_ENTRY && !(fix->fx_r_type >= BFD_RELOC_PPC_TLS - && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA)); + && fix->fx_r_type <= BFD_RELOC_PPC64_TLS_PCREL)); } #endif @@ -6490,26 +7101,58 @@ ppc_frag_check (struct frag *fragP) fragP->insn_addr + 1); } -/* Implement HANDLE_ALIGN. This writes the NOP pattern into an - rs_align_code frag. */ +/* rs_align_code frag handling. */ + +enum ppc_nop_encoding_for_rs_align_code +{ + PPC_NOP_VANILLA, + PPC_NOP_VLE, + PPC_NOP_GROUP_P6, + PPC_NOP_GROUP_P7 +}; + +unsigned int +ppc_nop_select (void) +{ + if ((ppc_cpu & PPC_OPCODE_VLE) != 0) + return PPC_NOP_VLE; + if ((ppc_cpu & (PPC_OPCODE_POWER9 | PPC_OPCODE_E500MC)) == 0) + { + if ((ppc_cpu & PPC_OPCODE_POWER7) != 0) + return PPC_NOP_GROUP_P7; + if ((ppc_cpu & PPC_OPCODE_POWER6) != 0) + return PPC_NOP_GROUP_P6; + } + return PPC_NOP_VANILLA; +} void ppc_handle_align (struct frag *fragP) { valueT count = (fragP->fr_next->fr_address - (fragP->fr_address + fragP->fr_fix)); + char *dest = fragP->fr_literal + fragP->fr_fix; + enum ppc_nop_encoding_for_rs_align_code nop_select = *dest & 0xff; - if ((ppc_cpu & PPC_OPCODE_VLE) != 0 && count != 0 && (count & 1) == 0) + /* Pad with zeros if not inserting a whole number of instructions. + We could pad with zeros up to an instruction boundary then follow + with nops but odd counts indicate data in an executable section + so padding with zeros is most appropriate. */ + if (count == 0 + || (nop_select == PPC_NOP_VLE ? (count & 1) != 0 : (count & 3) != 0)) + { + *dest = 0; + return; + } + + if (nop_select == PPC_NOP_VLE) { - char *dest = fragP->fr_literal + fragP->fr_fix; fragP->fr_var = 2; md_number_to_chars (dest, 0x4400, 2); } - else if (count != 0 && (count & 3) == 0) + else { - char *dest = fragP->fr_literal + fragP->fr_fix; - fragP->fr_var = 4; if (count > 4 * nop_limit && count < 0x2000000) @@ -6538,8 +7181,7 @@ ppc_handle_align (struct frag *fragP) md_number_to_chars (dest, 0x60000000, 4); - if ((ppc_cpu & PPC_OPCODE_POWER6) != 0 - && (ppc_cpu & PPC_OPCODE_POWER9) == 0) + if (nop_select >= PPC_NOP_GROUP_P6) { /* For power6, power7, and power8, we want the last nop to be a group terminating one. Do this by inserting an @@ -6559,18 +7201,12 @@ ppc_handle_align (struct frag *fragP) dest = group_nop->fr_literal; } - if ((ppc_cpu & PPC_OPCODE_POWER7) != 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". */ - md_number_to_chars (dest, 0x60420000, 4); - } - else + if (nop_select == PPC_NOP_GROUP_P6) /* power6 group terminating nop: "ori 1,1,0". */ md_number_to_chars (dest, 0x60210000, 4); + else + /* power7/power8 group terminating nop: "ori 2,2,0". */ + md_number_to_chars (dest, 0x60420000, 4); } } } @@ -6672,10 +7308,34 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg) fixP->fx_r_type = BFD_RELOC_PPC64_REL16_HIGHESTA; break; + case BFD_RELOC_PPC64_ADDR16_HIGHER34: + fixP->fx_r_type = BFD_RELOC_PPC64_REL16_HIGHER34; + break; + + case BFD_RELOC_PPC64_ADDR16_HIGHERA34: + fixP->fx_r_type = BFD_RELOC_PPC64_REL16_HIGHERA34; + break; + + case BFD_RELOC_PPC64_ADDR16_HIGHEST34: + fixP->fx_r_type = BFD_RELOC_PPC64_REL16_HIGHEST34; + break; + + case BFD_RELOC_PPC64_ADDR16_HIGHESTA34: + fixP->fx_r_type = BFD_RELOC_PPC64_REL16_HIGHESTA34; + break; + case BFD_RELOC_PPC_16DX_HA: fixP->fx_r_type = BFD_RELOC_PPC_REL16DX_HA; break; + case BFD_RELOC_PPC64_D34: + fixP->fx_r_type = BFD_RELOC_PPC64_PCREL34; + break; + + case BFD_RELOC_PPC64_D28: + fixP->fx_r_type = BFD_RELOC_PPC64_PCREL28; + break; + default: break; } @@ -6860,6 +7520,12 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg) case BFD_RELOC_PPC64_DTPREL16_HIGHERA: case BFD_RELOC_PPC64_DTPREL16_HIGHEST: case BFD_RELOC_PPC64_DTPREL16_HIGHESTA: + case BFD_RELOC_PPC64_TPREL34: + case BFD_RELOC_PPC64_DTPREL34: + case BFD_RELOC_PPC64_GOT_TLSGD34: + case BFD_RELOC_PPC64_GOT_TLSLD34: + case BFD_RELOC_PPC64_GOT_TPREL34: + case BFD_RELOC_PPC64_GOT_DTPREL34: gas_assert (fixP->fx_addsy != NULL); S_SET_THREAD_LOCAL (fixP->fx_addsy); fieldval = 0; @@ -6922,12 +7588,15 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg) case BFD_RELOC_PPC_VLE_SDAREL_HI16D: case BFD_RELOC_PPC_VLE_SDAREL_HA16A: case BFD_RELOC_PPC_VLE_SDAREL_HA16D: + case BFD_RELOC_PPC64_GOT_PCREL34: + case BFD_RELOC_PPC64_PLT_PCREL34: gas_assert (fixP->fx_addsy != NULL); /* Fallthru */ case BFD_RELOC_PPC_TLS: case BFD_RELOC_PPC_TLSGD: case BFD_RELOC_PPC_TLSLD: + case BFD_RELOC_PPC64_TLS_PCREL: fieldval = 0; break; #endif @@ -6973,9 +7642,12 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg) #else #define APPLY_RELOC 1 #endif + /* We need to call the insert function even when fieldval is + zero if the insert function would translate that zero to a + bit pattern other than all zeros. */ if ((fieldval != 0 && APPLY_RELOC) || operand->insert != NULL) { - unsigned long insn; + uint64_t insn; unsigned char *where; /* Fetch the instruction, insert the fully resolved operand @@ -6983,34 +7655,56 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg) where = (unsigned char *) fixP->fx_frag->fr_literal + fixP->fx_where; if (target_big_endian) { - if (fixP->fx_size == 4) - insn = bfd_getb32 (where); - else + if (fixP->fx_size < 4) insn = bfd_getb16 (where); + else + { + insn = bfd_getb32 (where); + if (fixP->fx_size > 4) + insn = insn << 32 | bfd_getb32 (where + 4); + } } else { - if (fixP->fx_size == 4) - insn = bfd_getl32 (where); - else + if (fixP->fx_size < 4) insn = bfd_getl16 (where); + else + { + insn = bfd_getl32 (where); + if (fixP->fx_size > 4) + insn = insn << 32 | bfd_getl32 (where + 4); + } } insn = ppc_insert_operand (insn, operand, fieldval, fixP->tc_fix_data.ppc_cpu, fixP->fx_file, fixP->fx_line); if (target_big_endian) { - if (fixP->fx_size == 4) - bfd_putb32 (insn, where); - else + if (fixP->fx_size < 4) bfd_putb16 (insn, where); + else + { + if (fixP->fx_size > 4) + { + bfd_putb32 (insn, where + 4); + insn >>= 32; + } + bfd_putb32 (insn, where); + } } else { - if (fixP->fx_size == 4) - bfd_putl32 (insn, where); - else + if (fixP->fx_size < 4) bfd_putl16 (insn, where); + else + { + if (fixP->fx_size > 4) + { + bfd_putl32 (insn, where + 4); + insn >>= 32; + } + bfd_putl32 (insn, where); + } } } @@ -7156,6 +7850,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg) case BFD_RELOC_PPC64_TPREL16_HIGHERA: case BFD_RELOC_PPC64_TPREL16_HIGHEST: case BFD_RELOC_PPC64_TPREL16_HIGHESTA: + case BFD_RELOC_PPC64_TLS_PCREL: fixP->fx_done = 0; break; #endif @@ -7226,9 +7921,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg) #else /* We want to use the offset within the toc, not the actual VMA of the symbol. */ - fixP->fx_addnumber = - - bfd_get_section_vma (stdoutput, S_GET_SEGMENT (fixP->fx_addsy)) - - S_GET_VALUE (ppc_toc_csect); + fixP->fx_addnumber = (- bfd_section_vma (S_GET_SEGMENT (fixP->fx_addsy)) + - S_GET_VALUE (ppc_toc_csect)); /* Set *valP to avoid errors. */ *valP = value; #endif @@ -7248,6 +7942,9 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp) 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; + /* BFD_RELOC_PPC64_TLS_PCREL generates R_PPC64_TLS with an odd r_offset. */ + if (fixp->fx_r_type == BFD_RELOC_PPC64_TLS_PCREL) + reloc->address++; reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); if (reloc->howto == (reloc_howto_type *) NULL) {