X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-ppc.c;h=7d6459aa269288fc6d0bebe55efc3672c18ee5d6;hb=df3a023bd614133fe69afb02cd0e8f3e590a36a9;hp=cebbd4298c7f30a23499d223828b105dc37f4d61;hpb=bb6bf75e7a1f9aaf0283895705710f415b81b6b1;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c index cebbd4298c..7d6459aa26 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-2019 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")); } @@ -1673,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++) { @@ -1943,8 +2057,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) @@ -1953,6 +2069,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) @@ -2104,6 +2221,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 } }; @@ -2484,6 +2613,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 @@ -2740,6 +2875,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 @@ -2800,6 +3019,10 @@ fixup_size (bfd_reloc_code_real_type reloc, bfd_boolean *pc_relative) 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: @@ -2887,9 +3110,13 @@ fixup_size (bfd_reloc_code_real_type reloc, bfd_boolean *pc_relative) 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 @@ -2933,6 +3160,7 @@ fixup_size (bfd_reloc_code_real_type reloc, bfd_boolean *pc_relative) 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; @@ -2969,12 +3197,27 @@ fixup_size (bfd_reloc_code_real_type reloc, bfd_boolean *pc_relative) 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; @@ -2999,6 +3242,45 @@ fixup_size (bfd_reloc_code_real_type reloc, bfd_boolean *pc_relative) 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 (strcasecmp (sym_name, "__tls_get_addr") == 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 @@ -3035,6 +3317,7 @@ md_assemble (char *str) else ppc_macro (s, macro); + ppc_clear_labels (); return; } @@ -3388,47 +3671,12 @@ 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) @@ -3508,6 +3756,7 @@ md_assemble (char *str) 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); @@ -3520,33 +3769,66 @@ md_assemble (char *str) break; /* We'll only use the 32 (or 64) bit form of these relocations - in constants. Instructions get the 16 bit form. */ + in constants. Instructions get the 16 or 34 bit form. */ case BFD_RELOC_PPC_DTPREL: - reloc = BFD_RELOC_PPC_DTPREL16; + if (operand->bitm == 0x3ffffffffULL) + reloc = BFD_RELOC_PPC64_DTPREL34; + else + reloc = BFD_RELOC_PPC_DTPREL16; break; case BFD_RELOC_PPC_TPREL: - reloc = BFD_RELOC_PPC_TPREL16; + if (operand->bitm == 0x3ffffffffULL) + reloc = BFD_RELOC_PPC64_TPREL34; + else + reloc = BFD_RELOC_PPC_TPREL16; break; - case BFD_RELOC_LO16: - if ((operand->bitm | 0xf) != 0xffff - || operand->shift != 0 + 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 != 0xffff - || operand->shift != 0 - || (operand->flags & PPC_OPERAND_NEGATIVE) != 0) + 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 == 0xffff - && operand->shift == (int) PPC_OPSHIFT_INV - && opcode->opcode == (19 << 26) + (2 << 1)) + 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 @@ -3602,6 +3884,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. */ @@ -3651,58 +3937,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. */ @@ -3814,14 +4126,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; @@ -5243,6 +5591,7 @@ ppc_xcoff_end (void) symbol_set_value_now (dwss->end_exp.X_add_symbol); } } + ppc_cpu = 0; } #endif /* OBJ_XCOFF */ @@ -6104,30 +6453,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. */ @@ -6659,14 +6984,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 @@ -6709,7 +7026,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); @@ -6751,11 +7068,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 @@ -6768,26 +7107,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) @@ -6816,8 +7187,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 @@ -6837,18 +7207,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); } } } @@ -6950,10 +7314,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; } @@ -7138,6 +7526,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; @@ -7200,12 +7594,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 @@ -7251,9 +7648,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 @@ -7261,34 +7661,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); + } } } @@ -7434,6 +7856,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 @@ -7526,6 +7949,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) {