X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-ppc.c;h=6135cb40f93d9b5f5f52477befdca623e958a4d1;hb=05d0e962f08af24f18cc79b890a68176b42bcb78;hp=fd5cc35cd26ec47e29b22394c7f5c3d8d996d4e1;hpb=7e0de605cbacbbbb2531bb70506c0843aea13111;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c index fd5cc35cd2..6135cb40f9 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-2017 Free Software Foundation, Inc. + Copyright (C) 1994-2018 Free Software Foundation, Inc. Written by Ian Lance Taylor, Cygnus Support. This file is part of GAS, the GNU Assembler. @@ -217,7 +217,7 @@ static enum { /* Warn on emitting data to code sections. */ int warn_476; -unsigned long last_insn; +uint64_t last_insn; segT last_seg; subsegT last_subseg; @@ -974,7 +974,7 @@ ppc_optimize_expr (expressionS *left, operatorT op, expressionS *right) /* Accept reg +/- constant. */ if (left->X_op == O_register && !((op == O_add || op == O_subtract) && right->X_op == O_constant)) - as_bad (_("invalid register expression")); + as_warn (_("invalid register expression")); /* Accept constant + reg. */ if (right->X_op == O_register) @@ -982,7 +982,7 @@ ppc_optimize_expr (expressionS *left, operatorT op, expressionS *right) if (op == O_add && left->X_op == O_constant) left->X_md = right->X_md; else - as_bad (_("invalid register expression")); + as_warn (_("invalid register expression")); } return 0; @@ -1193,7 +1193,8 @@ md_parse_option (int c, const char *arg) case 'm': new_cpu = ppc_parse_cpu (ppc_cpu, &sticky, arg); - if (new_cpu != 0) + /* "raw" is only valid for the disassembler. */ + if (new_cpu != 0 && (new_cpu & PPC_OPCODE_RAW) == 0) { ppc_cpu = new_cpu; if (strcmp (arg, "vle") == 0) @@ -1205,6 +1206,16 @@ md_parse_option (int c, const char *arg) } } + else if (strcmp (arg, "no-vle") == 0) + { + sticky &= ~PPC_OPCODE_VLE; + + new_cpu = ppc_parse_cpu (ppc_cpu, &sticky, "booke"); + new_cpu &= ~PPC_OPCODE_VLE; + + ppc_cpu = new_cpu; + } + else if (strcmp (arg, "regnames") == 0) reg_names_p = TRUE; @@ -1257,6 +1268,10 @@ md_parse_option (int c, const char *arg) msolaris = FALSE; ppc_comment_chars = ppc_eabi_comment_chars; } + else if (strcmp (arg, "spe2") == 0) + { + ppc_cpu |= PPC_OPCODE_SPE2; + } #endif else { @@ -1325,7 +1340,8 @@ PowerPC options:\n\ -m476 generate code for PowerPC 476\n\ -m7400, -m7410, -m7450, -m7455\n\ generate code for PowerPC 7400/7410/7450/7455\n\ --m750cl generate code for PowerPC 750cl\n\ +-m750cl, -mgekko, -mbroadway\n\ + generate code for PowerPC 750cl/Gekko/Broadway\n\ -m821, -m850, -m860 generate code for PowerPC 821/850/860\n")); fprintf (stream, _("\ -mppc64, -m620 generate code for PowerPC 620/625/630\n\ @@ -1345,7 +1361,6 @@ PowerPC options:\n\ fprintf (stream, _("\ -maltivec generate code for AltiVec\n\ -mvsx generate code for Vector-Scalar (VSX) instructions\n\ --mhtm generate code for Hardware Transactional Memory\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\ @@ -1353,6 +1368,7 @@ PowerPC options:\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\ @@ -1388,7 +1404,11 @@ ppc_set_cpu (void) if ((ppc_cpu & ~(ppc_cpu_t) PPC_OPCODE_ANY) == 0) { if (ppc_obj64) - ppc_cpu |= PPC_OPCODE_PPC | PPC_OPCODE_64; + if (target_big_endian) + ppc_cpu |= PPC_OPCODE_PPC | PPC_OPCODE_64; + else + /* The minimum supported cpu for 64-bit little-endian is power8. */ + ppc_cpu |= ppc_parse_cpu (ppc_cpu, &sticky, "power8"); else if (strncmp (default_os, "aix", 3) == 0 && default_os[3] >= '4' && default_os[3] <= '9') ppc_cpu |= PPC_OPCODE_COMMON; @@ -1482,7 +1502,7 @@ static bfd_boolean insn_validate (const struct powerpc_opcode *op) { const unsigned char *o; - unsigned long omask = op->mask; + uint64_t omask = op->mask; /* The mask had better not trim off opcode bits. */ if ((op->opcode & omask) != op->opcode) @@ -1504,7 +1524,7 @@ insn_validate (const struct powerpc_opcode *op) const struct powerpc_operand *operand = &powerpc_operands[*o]; if (operand->shift != (int) PPC_OPSHIFT_INV) { - unsigned long mask; + uint64_t mask; if (operand->shift >= 0) mask = operand->bitm << operand->shift; @@ -1555,8 +1575,8 @@ ppc_setup_opcodes (void) all the 1's in the mask are contiguous. */ for (i = 0; i < num_powerpc_operands; ++i) { - unsigned long mask = powerpc_operands[i].bitm; - unsigned long right_bit; + uint64_t mask = powerpc_operands[i].bitm; + uint64_t right_bit; unsigned int j; right_bit = mask & -mask; @@ -1583,28 +1603,24 @@ ppc_setup_opcodes (void) { if (ENABLE_CHECKING) { - if (op != powerpc_opcodes) - { - int old_opcode = PPC_OP (op[-1].opcode); - int new_opcode = PPC_OP (op[0].opcode); + unsigned int new_opcode = PPC_OP (op[0].opcode); #ifdef PRINT_OPCODE_TABLE - printf ("%-14s\t#%04u\tmajor op: 0x%x\top: 0x%x\tmask: 0x%x\tflags: 0x%llx\n", - op->name, (unsigned int) (op - powerpc_opcodes), - (unsigned int) new_opcode, (unsigned int) op->opcode, - (unsigned int) op->mask, (unsigned long long) op->flags); + printf ("%-14s\t#%04u\tmajor op: 0x%x\top: 0x%llx\tmask: 0x%llx\tflags: 0x%llx\n", + op->name, (unsigned int) (op - powerpc_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 (new_opcode < old_opcode) - { - as_bad (_("major opcode is not sorted for %s"), - op->name); - bad_insn = TRUE; - } + /* The major opcodes had better be sorted. Code in the disassembler + assumes the insns are sorted according to major opcode. */ + if (op != powerpc_opcodes + && new_opcode < PPC_OP (op[-1].opcode)) + { + as_bad (_("major opcode is not sorted for %s"), op->name); + bad_insn = TRUE; } + if ((op->flags & PPC_OPCODE_VLE) != 0) { as_bad (_("%s is enabled by vle flag"), op->name); @@ -1644,30 +1660,22 @@ ppc_setup_opcodes (void) { if (ENABLE_CHECKING) { - if (op != vle_opcodes) - { - unsigned old_seg, new_seg; - - old_seg = VLE_OP (op[-1].opcode, op[-1].mask); - old_seg = VLE_OP_TO_SEG (old_seg); - new_seg = VLE_OP (op[0].opcode, op[0].mask); - new_seg = VLE_OP_TO_SEG (new_seg); + unsigned new_seg = VLE_OP_TO_SEG (VLE_OP (op[0].opcode, op[0].mask)); #ifdef PRINT_OPCODE_TABLE - printf ("%-14s\t#%04u\tmajor op: 0x%x\top: 0x%x\tmask: 0x%x\tflags: 0x%llx\n", - op->name, (unsigned int) (op - powerpc_opcodes), - (unsigned int) new_seg, (unsigned int) op->opcode, - (unsigned int) op->mask, (unsigned long long) op->flags); + printf ("%-14s\t#%04u\tmajor op: 0x%x\top: 0x%llx\tmask: 0x%llx\tflags: 0x%llx\n", + op->name, (unsigned int) (op - vle_opcodes), + (unsigned int) new_seg, (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 (new_seg < old_seg) - { - as_bad (_("major opcode is not sorted for %s"), - op->name); - bad_insn = TRUE; - } + + /* The major opcodes had better be sorted. Code in the disassembler + assumes the insns are sorted according to major opcode. */ + if (op != vle_opcodes + && new_seg < VLE_OP_TO_SEG (VLE_OP (op[-1].opcode, op[-1].mask))) + { + as_bad (_("major opcode is not sorted for %s"), op->name); + bad_insn = TRUE; } bad_insn |= insn_validate (op); @@ -1688,6 +1696,54 @@ ppc_setup_opcodes (void) } } + /* SPE2 instructions */ + if ((ppc_cpu & PPC_OPCODE_SPE2) == PPC_OPCODE_SPE2) + { + op_end = spe2_opcodes + spe2_num_opcodes; + for (op = spe2_opcodes; op < op_end; op++) + { + if (ENABLE_CHECKING) + { + if (op != spe2_opcodes) + { + unsigned old_seg, new_seg; + + old_seg = VLE_OP (op[-1].opcode, op[-1].mask); + old_seg = VLE_OP_TO_SEG (old_seg); + new_seg = VLE_OP (op[0].opcode, op[0].mask); + new_seg = VLE_OP_TO_SEG (new_seg); + + /* The major opcodes had better be sorted. Code in the + disassembler assumes the insns are sorted according to + major opcode. */ + if (new_seg < old_seg) + { + 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; + } + } + } + + for (op = spe2_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 (); @@ -1821,15 +1877,15 @@ ppc_cleanup (void) /* Insert an operand value into an instruction. */ -static unsigned long -ppc_insert_operand (unsigned long insn, +static uint64_t +ppc_insert_operand (uint64_t insn, const struct powerpc_operand *operand, - offsetT val, + int64_t val, ppc_cpu_t cpu, const char *file, unsigned int line) { - long min, max, right; + int64_t min, max, right; max = operand->bitm; right = max & -max; @@ -1858,7 +1914,7 @@ ppc_insert_operand (unsigned long insn, if ((operand->flags & PPC_OPERAND_NEGATIVE) != 0) { - long tmp = min; + int64_t tmp = min; min = -max; max = -tmp; } @@ -1871,18 +1927,18 @@ ppc_insert_operand (unsigned long insn, sign extend the 32-bit value to 64 bits if so doing makes the value valid. */ if (val > max - && (offsetT) (val - 0x80000000 - 0x80000000) >= min - && (offsetT) (val - 0x80000000 - 0x80000000) <= max - && ((val - 0x80000000 - 0x80000000) & (right - 1)) == 0) - val = val - 0x80000000 - 0x80000000; + && (val - (1LL << 32)) >= min + && (val - (1LL << 32)) <= max + && ((val - (1LL << 32)) & (right - 1)) == 0) + val = val - (1LL << 32); /* Similarly, people write expressions like ~(1<<15), and expect this to be OK for a 32-bit unsigned value. */ else if (val < min - && (offsetT) (val + 0x80000000 + 0x80000000) >= min - && (offsetT) (val + 0x80000000 + 0x80000000) <= max - && ((val + 0x80000000 + 0x80000000) & (right - 1)) == 0) - val = val + 0x80000000 + 0x80000000; + && (val + (1LL << 32)) >= min + && (val + (1LL << 32)) <= max + && ((val + (1LL << 32)) & (right - 1)) == 0) + val = val + (1LL << 32); else if (val < min || val > max @@ -1895,14 +1951,14 @@ ppc_insert_operand (unsigned long insn, const char *errmsg; errmsg = NULL; - insn = (*operand->insert) (insn, (long) val, cpu, &errmsg); + insn = (*operand->insert) (insn, val, cpu, &errmsg); if (errmsg != (const char *) NULL) as_bad_where (file, line, "%s", errmsg); } else if (operand->shift >= 0) - insn |= ((long) val & operand->bitm) << operand->shift; + insn |= (val & operand->bitm) << operand->shift; else - insn |= ((long) val & operand->bitm) >> -operand->shift; + insn |= (val & operand->bitm) >> -operand->shift; return insn; } @@ -2029,6 +2085,7 @@ ppc_elf_suffix (char **str_p, expressionS *exp_p) MAP64 ("tprel@highera", BFD_RELOC_PPC64_TPREL16_HIGHERA), MAP64 ("tprel@highest", BFD_RELOC_PPC64_TPREL16_HIGHEST), MAP64 ("tprel@highesta", BFD_RELOC_PPC64_TPREL16_HIGHESTA), + MAP64 ("notoc", BFD_RELOC_PPC64_REL24_NOTOC), { (char *) 0, 0, 0, 0, BFD_RELOC_NONE } }; @@ -2323,12 +2380,22 @@ ppc_elf_localentry (int ignore ATTRIBUTE_UNUSED) if (resolve_expression (&exp) && exp.X_op == O_constant) { - unsigned char encoded = PPC64_SET_LOCAL_ENTRY_OFFSET (exp.X_add_number); + unsigned int encoded, ok; - if (exp.X_add_number != (offsetT) PPC64_LOCAL_ENTRY_OFFSET (encoded)) - as_bad (_(".localentry expression for `%s' " - "is not a valid power of 2"), S_GET_NAME (sym)); + ok = 1; + if (exp.X_add_number == 1 || exp.X_add_number == 7) + encoded = exp.X_add_number << STO_PPC64_LOCAL_BIT; else + { + encoded = PPC64_SET_LOCAL_ENTRY_OFFSET (exp.X_add_number); + if (exp.X_add_number != (offsetT) PPC64_LOCAL_ENTRY_OFFSET (encoded)) + { + as_bad (_(".localentry expression for `%s' " + "is not a valid power of 2"), S_GET_NAME (sym)); + ok = 0; + } + } + if (ok) { bfdsym = symbol_get_bfdsym (sym); elfsym = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym); @@ -2676,7 +2743,7 @@ md_assemble (char *str) { char *s; const struct powerpc_opcode *opcode; - unsigned long insn; + uint64_t insn; const unsigned char *opindex_ptr; int skip_optional; int need_paren; @@ -2684,7 +2751,7 @@ md_assemble (char *str) struct ppc_fixup fixups[MAX_INSN_FIXUPS]; int fc; char *f; - int addr_mod; + int addr_mask; int i; unsigned int insn_length; @@ -2752,11 +2819,9 @@ md_assemble (char *str) } } - /* Compute the number of expected operands. - Do not count fake operands. */ + /* Compute the number of expected operands. */ for (num_operands_expected = 0, i = 0; opcode->operands[i]; i ++) - if ((powerpc_operands [opcode->operands[i]].flags & PPC_OPERAND_FAKE) == 0) - ++ num_operands_expected; + ++ num_operands_expected; /* If there are fewer operands in the line then are called for by the instruction, we want to skip the optional @@ -2789,23 +2854,13 @@ md_assemble (char *str) } errmsg = NULL; - /* If this is a fake operand, then we do not expect anything - from the input. */ - if ((operand->flags & PPC_OPERAND_FAKE) != 0) - { - insn = (*operand->insert) (insn, 0L, ppc_cpu, &errmsg); - if (errmsg != (const char *) NULL) - as_bad ("%s", errmsg); - continue; - } - /* 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); + int64_t val = ppc_optional_operand_value (operand); if (operand->insert) { insn = (*operand->insert) (insn, val, ppc_cpu, &errmsg); @@ -2813,9 +2868,9 @@ md_assemble (char *str) as_bad ("%s", errmsg); } else if (operand->shift >= 0) - insn |= ((long) val & operand->bitm) << operand->shift; + insn |= (val & operand->bitm) << operand->shift; else - insn |= ((long) val & operand->bitm) >> -operand->shift; + insn |= (val & operand->bitm) >> -operand->shift; if ((operand->flags & PPC_OPERAND_NEXT) != 0) next_opindex = *opindex_ptr + 1; @@ -2976,8 +3031,8 @@ md_assemble (char *str) && !((ex.X_md & PPC_OPERAND_GPR) != 0 && ex.X_add_number != 0 && (operand->flags & PPC_OPERAND_GPR_0) != 0)) - as_bad (_("invalid register expression")); - insn = ppc_insert_operand (insn, operand, ex.X_add_number & 0xff, + as_warn (_("invalid register expression")); + insn = ppc_insert_operand (insn, operand, ex.X_add_number, ppc_cpu, (char *) NULL, 0); } else if (ex.X_op == O_constant) @@ -3151,12 +3206,12 @@ md_assemble (char *str) /* addpcis. */ if (opcode->opcode == (19 << 26) + (2 << 1) && reloc == BFD_RELOC_HI16_S) - reloc = BFD_RELOC_PPC_REL16DX_HA; + reloc = BFD_RELOC_PPC_16DX_HA; /* If VLE-mode convert LO/HI/HA relocations. */ if (opcode->flags & PPC_OPCODE_VLE) { - int tmp_insn = insn & opcode->mask; + uint64_t tmp_insn = insn & opcode->mask; int use_a_reloc = (tmp_insn == E_OR2I_INSN || tmp_insn == E_AND2I_DOT_INSN @@ -3457,31 +3512,34 @@ md_assemble (char *str) #endif /* Write out the instruction. */ - /* Differentiate between two and four byte insns. */ + + addr_mask = 3; if ((ppc_cpu & PPC_OPCODE_VLE) != 0) + /* All instructions can start on a 2 byte boundary for VLE. */ + addr_mask = 1; + + if (frag_now->insn_addr != addr_mask) { - if (PPC_OP_SE_VLE (insn)) - insn_length = 2; - else - insn_length = 4; - addr_mod = frag_now_fix () & 1; - } - else - { - insn_length = 4; - addr_mod = frag_now_fix () & 3; + /* Don't emit instructions to a frag started for data, or for a + CPU differing in VLE mode. Data is allowed to be misaligned, + and it's possible to start a new frag in the middle of + misaligned data. */ + frag_wane (frag_now); + frag_new (0); } - /* All instructions can start on a 2 byte boundary for VLE. */ + + /* Check that insns within the frag are aligned. ppc_frag_check + will ensure that the frag start address is aligned. */ + 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. */ + insn_length = 4; + if ((ppc_cpu & PPC_OPCODE_VLE) != 0 && 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_cpu & PPC_OPCODE_VLE) != 0) - as_bad (_("instruction address is not a multiple of 2")); - else - as_bad (_("instruction address is not a multiple of 4")); - } - frag_now->insn_addr = addr_mod; - frag_now->has_code = 1; + frag_now->insn_addr = addr_mask; md_number_to_chars (f, insn, insn_length); last_insn = insn; last_seg = now_seg; @@ -3630,6 +3688,16 @@ ppc_section_flags (flagword flags, bfd_vma attr ATTRIBUTE_UNUSED, int type) return flags; } + +bfd_vma +ppc_elf_section_letter (int letter, const char **ptrmsg) +{ + if (letter == 'v') + return SHF_PPC_VLE; + + *ptrmsg = _("bad .section directive: want a,e,v,w,x,M,S,G,T in string"); + return -1; +} #endif /* OBJ_ELF */ @@ -6349,6 +6417,7 @@ ppc_force_relocation (fixS *fix) case BFD_RELOC_PPC_BA26: case BFD_RELOC_PPC_B16: case BFD_RELOC_PPC_BA16: + case BFD_RELOC_PPC64_REL24_NOTOC: /* All branch fixups targeting a localentry symbol must force a relocation. */ if (fix->fx_addsy) @@ -6387,6 +6456,7 @@ ppc_fix_adjustable (fixS *fix) case BFD_RELOC_PPC_B16_BRNTAKEN: case BFD_RELOC_PPC_BA16_BRTAKEN: case BFD_RELOC_PPC_BA16_BRNTAKEN: + case BFD_RELOC_PPC64_REL24_NOTOC: if (fix->fx_addsy) { asymbol *bfdsym = symbol_get_bfdsym (fix->fx_addsy); @@ -6418,19 +6488,10 @@ ppc_fix_adjustable (fixS *fix) void ppc_frag_check (struct frag *fragP) { - if (!fragP->has_code) - return; - - 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")); - } - else - { - if (((fragP->fr_address + fragP->insn_addr) & 3) != 0) - as_bad (_("instruction address is not a multiple of 4")); - } + if ((fragP->fr_address & fragP->insn_addr) != 0) + as_bad_where (fragP->fr_file, fragP->fr_line, + _("instruction address is not a multiple of %d"), + fragP->insn_addr + 1); } /* Implement HANDLE_ALIGN. This writes the NOP pattern into an @@ -6482,15 +6543,13 @@ ppc_handle_align (struct frag *fragP) md_number_to_chars (dest, 0x60000000, 4); if ((ppc_cpu & PPC_OPCODE_POWER6) != 0 - || (ppc_cpu & PPC_OPCODE_POWER7) != 0 - || (ppc_cpu & PPC_OPCODE_POWER8) != 0 - || (ppc_cpu & PPC_OPCODE_POWER9) != 0) + && (ppc_cpu & PPC_OPCODE_POWER9) == 0) { - /* For power6, power7, power8 and power9, we want the last nop to be - a group terminating one. Do this by inserting an rs_fill frag - immediately after this one, with its address set to the last nop - location. This will automatically reduce the number of nops in - the current frag by one. */ + /* For power6, power7, and power8, we want the last nop to + be a group terminating one. Do this by inserting an + rs_fill frag immediately after this one, with its address + set to the last nop location. This will automatically + reduce the number of nops in the current frag by one. */ if (count > 4) { struct frag *group_nop = xmalloc (SIZEOF_STRUCT_FRAG + 4); @@ -6504,15 +6563,13 @@ ppc_handle_align (struct frag *fragP) dest = group_nop->fr_literal; } - if ((ppc_cpu & PPC_OPCODE_POWER7) != 0 - || (ppc_cpu & PPC_OPCODE_POWER8) != 0 - || (ppc_cpu & PPC_OPCODE_POWER9) != 0) + 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/power9 group terminating nop: "ori 2,2,0". */ + /* power7/power8 group terminating nop: "ori 2,2,0". */ md_number_to_chars (dest, 0x60420000, 4); } else @@ -6566,10 +6623,50 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg) } #endif - if (fixP->fx_subsy != (symbolS *) NULL) + /* We are only able to convert some relocs to pc-relative. */ + if (fixP->fx_pcrel) { - /* We can't actually support subtracting a symbol. */ - as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex")); + switch (fixP->fx_r_type) + { + case BFD_RELOC_LO16: + fixP->fx_r_type = BFD_RELOC_LO16_PCREL; + break; + + case BFD_RELOC_HI16: + fixP->fx_r_type = BFD_RELOC_HI16_PCREL; + break; + + case BFD_RELOC_HI16_S: + fixP->fx_r_type = BFD_RELOC_HI16_S_PCREL; + break; + + case BFD_RELOC_64: + fixP->fx_r_type = BFD_RELOC_64_PCREL; + break; + + case BFD_RELOC_32: + fixP->fx_r_type = BFD_RELOC_32_PCREL; + break; + + case BFD_RELOC_16: + fixP->fx_r_type = BFD_RELOC_16_PCREL; + break; + + case BFD_RELOC_PPC_16DX_HA: + fixP->fx_r_type = BFD_RELOC_PPC_REL16DX_HA; + break; + + default: + break; + } + } + else if (!fixP->fx_done + && fixP->fx_r_type == BFD_RELOC_PPC_16DX_HA) + { + /* addpcis is relative to next insn address. */ + value -= 4; + fixP->fx_r_type = BFD_RELOC_PPC_REL16DX_HA; + fixP->fx_pcrel = 1; } operand = NULL; @@ -6651,6 +6748,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg) case BFD_RELOC_HI16_S: case BFD_RELOC_HI16_S_PCREL: + case BFD_RELOC_PPC_16DX_HA: case BFD_RELOC_PPC_REL16DX_HA: #ifdef OBJ_ELF if (REPORT_OVERFLOW_HI && ppc_obj64) @@ -7078,83 +7176,6 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg) _("data in executable section")); } - /* We are only able to convert some relocs to pc-relative. */ - if (!fixP->fx_done && fixP->fx_pcrel) - { - switch (fixP->fx_r_type) - { - case BFD_RELOC_LO16: - fixP->fx_r_type = BFD_RELOC_LO16_PCREL; - break; - - case BFD_RELOC_HI16: - fixP->fx_r_type = BFD_RELOC_HI16_PCREL; - break; - - case BFD_RELOC_HI16_S: - fixP->fx_r_type = BFD_RELOC_HI16_S_PCREL; - break; - - case BFD_RELOC_64: - fixP->fx_r_type = BFD_RELOC_64_PCREL; - break; - - case BFD_RELOC_32: - fixP->fx_r_type = BFD_RELOC_32_PCREL; - break; - - case BFD_RELOC_16: - fixP->fx_r_type = BFD_RELOC_16_PCREL; - break; - - /* Some of course are already pc-relative. */ - case BFD_RELOC_LO16_PCREL: - case BFD_RELOC_HI16_PCREL: - case BFD_RELOC_HI16_S_PCREL: - case BFD_RELOC_PPC_REL16DX_HA: - case BFD_RELOC_64_PCREL: - case BFD_RELOC_32_PCREL: - case BFD_RELOC_16_PCREL: - case BFD_RELOC_PPC_B16: - case BFD_RELOC_PPC_B16_BRTAKEN: - case BFD_RELOC_PPC_B16_BRNTAKEN: - case BFD_RELOC_PPC_B26: - case BFD_RELOC_PPC_LOCAL24PC: - case BFD_RELOC_24_PLT_PCREL: - case BFD_RELOC_32_PLT_PCREL: - case BFD_RELOC_64_PLT_PCREL: - case BFD_RELOC_PPC_VLE_REL8: - case BFD_RELOC_PPC_VLE_REL15: - case BFD_RELOC_PPC_VLE_REL24: - break; - - default: - if (fixP->fx_addsy) - { - const char *sfile; - unsigned int sline; - - /* Use expr_symbol_where to see if this is an - expression symbol. */ - if (expr_symbol_where (fixP->fx_addsy, &sfile, &sline)) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("unresolved expression that must" - " be resolved")); - else - as_bad_where (fixP->fx_file, fixP->fx_line, - _("cannot emit PC relative %s relocation" - " against %s"), - bfd_get_reloc_code_name (fixP->fx_r_type), - S_GET_NAME (fixP->fx_addsy)); - } - else - as_bad_where (fixP->fx_file, fixP->fx_line, - _("unable to resolve expression")); - fixP->fx_done = 1; - break; - } - } - #ifdef OBJ_ELF ppc_elf_validate_fix (fixP, seg); fixP->fx_addnumber = value;