From 3b8b57a9495016b2b02fbc2612dd1607d4b6f9ba Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Mon, 5 Nov 2012 10:00:12 +0000 Subject: [PATCH] * config/tc-ppc.c (md_chars_to_number): Delete. (ppc_setup_opcodes): Assert num_powerpc_operands fit. (ppc_is_toc_sym): Move earlier in file. (md_assemble): Move code setting reloc from md_apply_fix. Combine non-ELF code setting fixup with ELF code. Stash opindex in fx_pcrel_adjust. Adjust fixup offset for VLE. Don't set fx_no_overflow here. (md_apply_fix): Rewrite to use ppc_insert_operand for all resolved instruction fields. Leave insn field zero when emitting an ELF reloc in most cases. --- gas/ChangeLog | 11 + gas/config/tc-ppc.c | 1021 ++++++++++++++++++++----------------------- 2 files changed, 476 insertions(+), 556 deletions(-) diff --git a/gas/ChangeLog b/gas/ChangeLog index 082dfd60164..17045c73394 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,5 +1,16 @@ 2012-11-05 Alan Modra + * config/tc-ppc.c (md_chars_to_number): Delete. + (ppc_setup_opcodes): Assert num_powerpc_operands fit. + (ppc_is_toc_sym): Move earlier in file. + (md_assemble): Move code setting reloc from md_apply_fix. Combine + non-ELF code setting fixup with ELF code. Stash opindex in + fx_pcrel_adjust. Adjust fixup offset for VLE. Don't set + fx_no_overflow here. + (md_apply_fix): Rewrite to use ppc_insert_operand for all + resolved instruction fields. Leave insn field zero when + emitting an ELF reloc in most cases. + * write.h (struct fix ): Make it a signed char. * config/tc-m68k.c (tc_gen_reloc, md_pcrel_from): Remove explicit sign extendion of fx_pxrel_adjust. diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c index 0f8da736d80..2dc2f59af54 100644 --- a/gas/config/tc-ppc.c +++ b/gas/config/tc-ppc.c @@ -1089,35 +1089,6 @@ const struct option md_longopts[] = { }; const size_t md_longopts_size = sizeof (md_longopts); -/* Convert the target integer stored in N bytes in BUF to a host - integer, returning that value. */ - -static valueT -md_chars_to_number (char *buf, int n) -{ - valueT result = 0; - unsigned char *p = (unsigned char *) buf; - - if (target_big_endian) - { - while (n--) - { - result <<= 8; - result |= (*p++ & 0xff); - } - } - else - { - while (n--) - { - result <<= 8; - result |= (p[n] & 0xff); - } - } - - return result; -} - int md_parse_option (int c, char *arg) { @@ -1536,6 +1507,10 @@ ppc_setup_opcodes (void) { unsigned int i; + /* An index into powerpc_operands is stored in struct fix + fx_pcrel_adjust which is 8 bits wide. */ + gas_assert (num_powerpc_operands < 256); + /* Check operand masks. Code here and in the disassembler assumes all the 1's in the mask are contiguous. */ for (i = 0; i < num_powerpc_operands; ++i) @@ -2451,6 +2426,25 @@ parse_toc_entry (enum toc_size_qualifier *toc_kind) return 1; } #endif + +#if defined (OBJ_XCOFF) || defined (OBJ_ELF) +/* See whether a symbol is in the TOC section. */ + +static int +ppc_is_toc_sym (symbolS *sym) +{ +#ifdef OBJ_XCOFF + return symbol_get_tc (sym)->symbol_class == XMC_TC; +#endif +#ifdef OBJ_ELF + const char *sname = segment_name (S_GET_SEGMENT (sym)); + if (ppc_obj64) + return strcmp (sname, ".toc") == 0; + else + return strcmp (sname, ".got") == 0; +#endif +} +#endif /* defined (OBJ_XCOFF) || defined (OBJ_ELF) */ #ifdef OBJ_ELF @@ -2533,9 +2527,6 @@ md_assemble (char *str) int addr_mod; int i; unsigned int insn_length; -#ifdef OBJ_ELF - bfd_reloc_code_real_type reloc; -#endif /* Get the opcode. */ for (s = str; *s != '\0' && ! ISSPACE (*s); s++) @@ -2817,6 +2808,7 @@ md_assemble (char *str) { #ifdef OBJ_ELF /* Allow @HA, @L, @H on constants. */ + bfd_reloc_code_real_type reloc; char *orig_str = str; if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED) @@ -2882,9 +2874,10 @@ md_assemble (char *str) insn = ppc_insert_operand (insn, operand, ex.X_add_number, ppc_cpu, (char *) NULL, 0); } -#ifdef OBJ_ELF else { + bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED; +#ifdef OBJ_ELF if (ex.X_op == O_symbol && str[0] == '(') { const char *sym_name = S_GET_NAME (ex.X_add_symbol); @@ -3122,6 +3115,66 @@ md_assemble (char *str) } } } +#endif /* OBJ_ELF */ + + if (reloc != BFD_RELOC_UNUSED) + ; + /* Determine a BFD reloc value based on the operand information. + We are only prepared to turn a few of the operands into + relocs. */ + else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 + && operand->bitm == 0x3fffffc + && operand->shift == 0) + reloc = BFD_RELOC_PPC_B26; + else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 + && operand->bitm == 0xfffc + && operand->shift == 0) + reloc = BFD_RELOC_PPC_B16; + else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 + && operand->bitm == 0x1fe + && operand->shift == -1) + reloc = BFD_RELOC_PPC_VLE_REL8; + else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 + && operand->bitm == 0xfffe + && operand->shift == 0) + reloc = BFD_RELOC_PPC_VLE_REL15; + else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 + && operand->bitm == 0x1fffffe + && operand->shift == 0) + reloc = BFD_RELOC_PPC_VLE_REL24; + else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0 + && operand->bitm == 0x3fffffc + && operand->shift == 0) + reloc = BFD_RELOC_PPC_BA26; + else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0 + && operand->bitm == 0xfffc + && operand->shift == 0) + reloc = BFD_RELOC_PPC_BA16; +#if defined (OBJ_XCOFF) || defined (OBJ_ELF) + else if ((operand->flags & PPC_OPERAND_PARENS) != 0 + && (operand->bitm & 0xfff0) == 0xfff0 + && operand->shift == 0) + { + if (ppc_is_toc_sym (ex.X_add_symbol)) + { + reloc = BFD_RELOC_PPC_TOC16; +#ifdef OBJ_ELF + if (ppc_obj64 + && (operand->flags & PPC_OPERAND_DS) != 0) + reloc = BFD_RELOC_PPC64_TOC16_DS; +#endif + } + else + { + reloc = BFD_RELOC_16; +#ifdef OBJ_ELF + if (ppc_obj64 + && (operand->flags & PPC_OPERAND_DS) != 0) + reloc = BFD_RELOC_PPC64_ADDR16_DS; +#endif + } + } +#endif /* defined (OBJ_XCOFF) || defined (OBJ_ELF) */ /* We need to generate a fixup for this expression. */ if (fc >= MAX_INSN_FIXUPS) @@ -3131,18 +3184,6 @@ md_assemble (char *str) fixups[fc].reloc = reloc; ++fc; } -#else /* OBJ_ELF */ - else - { - /* We need to generate a fixup for this expression. */ - if (fc >= MAX_INSN_FIXUPS) - as_fatal (_("too many fixups")); - fixups[fc].exp = ex; - fixups[fc].opindex = *opindex_ptr; - fixups[fc].reloc = BFD_RELOC_UNUSED; - ++fc; - } -#endif /* OBJ_ELF */ if (need_paren) { @@ -3243,27 +3284,22 @@ md_assemble (char *str) dwarf2_emit_insn (insn_length); #endif - /* Create any fixups. At this point we do not use a - bfd_reloc_code_real_type, but instead just use the - BFD_RELOC_UNUSED plus the operand index. This lets us easily - handle fixups for any operand type, although that is admittedly - not a very exciting feature. We pick a BFD reloc type in - md_apply_fix. */ + /* Create any fixups. */ for (i = 0; i < fc; i++) { + fixS *fixP; if (fixups[i].reloc != BFD_RELOC_UNUSED) { reloc_howto_type *reloc_howto; int size; int offset; - fixS *fixP; 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 ? (4 - size) : 0; + offset = target_big_endian ? (insn_length - size) : 0; if (size < 1 || size > 4) abort (); @@ -3274,47 +3310,20 @@ md_assemble (char *str) &fixups[i].exp, reloc_howto->pc_relative, fixups[i].reloc); - - /* Turn off complaints that the addend is too large for things like - foo+100000@ha. */ - switch (fixups[i].reloc) - { - case BFD_RELOC_16_GOTOFF: - case BFD_RELOC_PPC_TOC16: - case BFD_RELOC_LO16: - case BFD_RELOC_HI16: - case BFD_RELOC_HI16_S: - case BFD_RELOC_PPC_VLE_LO16A: - case BFD_RELOC_PPC_VLE_LO16D: - case BFD_RELOC_PPC_VLE_HI16A: - case BFD_RELOC_PPC_VLE_HI16D: - case BFD_RELOC_PPC_VLE_HA16A: - case BFD_RELOC_PPC_VLE_HA16D: -#ifdef OBJ_ELF - case BFD_RELOC_PPC64_HIGHER: - case BFD_RELOC_PPC64_HIGHER_S: - case BFD_RELOC_PPC64_HIGHEST: - case BFD_RELOC_PPC64_HIGHEST_S: -#endif - fixP->fx_no_overflow = 1; - break; - default: - break; - } } else { const struct powerpc_operand *operand; operand = &powerpc_operands[fixups[i].opindex]; - fix_new_exp (frag_now, - f - frag_now->fr_literal, - insn_length, - &fixups[i].exp, - (operand->flags & PPC_OPERAND_RELATIVE) != 0, - ((bfd_reloc_code_real_type) - (fixups[i].opindex + (int) BFD_RELOC_UNUSED))); + fixP = fix_new_exp (frag_now, + f - frag_now->fr_literal, + insn_length, + &fixups[i].exp, + (operand->flags & PPC_OPERAND_RELATIVE) != 0, + BFD_RELOC_UNUSED); } + fixP->fx_pcrel_adjust = fixups[i].opindex; } } @@ -4848,23 +4857,6 @@ ppc_machine (int ignore ATTRIBUTE_UNUSED) demand_empty_rest_of_line (); } - -/* See whether a symbol is in the TOC section. */ - -static int -ppc_is_toc_sym (symbolS *sym) -{ -#ifdef OBJ_XCOFF - return symbol_get_tc (sym)->symbol_class == XMC_TC; -#endif -#ifdef OBJ_ELF - const char *sname = segment_name (S_GET_SEGMENT (sym)); - if (ppc_obj64) - return strcmp (sname, ".toc") == 0; - else - return strcmp (sname, ".got") == 0; -#endif -} #endif /* defined (OBJ_XCOFF) || defined (OBJ_ELF) */ #ifdef TE_PE @@ -6292,13 +6284,7 @@ ppc_handle_align (struct frag *fragP) } /* Apply a fixup to the object code. This is called for all the - fixups we generated by the call to fix_new_exp, above. In the call - above we used a reloc code which was the largest legal reloc code - plus the operand index. Here we undo that to recover the operand - index. At this point all symbol values should be fully resolved, - and we attempt to completely resolve the reloc. If we can not do - that, we determine the correct reloc code and put it back in the - fixup. */ + fixups we generated by the calls to fix_new_exp, above. */ void md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) @@ -6342,16 +6328,15 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex")); } - if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED) + if (fixP->fx_pcrel_adjust != 0) { - int opindex; - const struct powerpc_operand *operand; + /* Handle relocs in an insn. */ + + int opindex = fixP->fx_pcrel_adjust & 0xff; + const struct powerpc_operand *operand = &powerpc_operands[opindex]; char *where; unsigned long insn; - - opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED; - - operand = &powerpc_operands[opindex]; + offsetT fieldval; #ifdef OBJ_XCOFF /* An instruction like `lwz 9,sym(30)' when `sym' is not a TOC symbol @@ -6372,437 +6357,72 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) fixP->fx_done = 1; } #endif - - /* Fetch the instruction, insert the fully resolved operand - value, and stuff the instruction back again. */ - where = fixP->fx_frag->fr_literal + fixP->fx_where; - if (target_big_endian) - { - if (fixP->fx_size == 4) - insn = bfd_getb32 ((unsigned char *) where); - else - insn = bfd_getb16 ((unsigned char *) where); - } - else - { - if (fixP->fx_size == 4) - insn = bfd_getl32 ((unsigned char *) where); - else - insn = bfd_getl16 ((unsigned char *) where); - } - insn = ppc_insert_operand (insn, operand, (offsetT) value, - fixP->tc_fix_data.ppc_cpu, - fixP->fx_file, fixP->fx_line); - if (target_big_endian) - { - if (fixP->fx_size == 4) - bfd_putb32 ((bfd_vma) insn, (unsigned char *) where); - else - bfd_putb16 ((bfd_vma) insn, (unsigned char *) where); - } - else - { - if (fixP->fx_size == 4) - bfd_putl32 ((bfd_vma) insn, (unsigned char *) where); - else - bfd_putl16 ((bfd_vma) insn, (unsigned char *) where); - } - - if (fixP->fx_done) - /* Nothing else to do here. */ - return; - - gas_assert (fixP->fx_addsy != NULL); - - /* Determine a BFD reloc value based on the operand information. - We are only prepared to turn a few of the operands into - relocs. */ - if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 - && operand->bitm == 0x3fffffc - && operand->shift == 0) - fixP->fx_r_type = BFD_RELOC_PPC_B26; - else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 - && operand->bitm == 0xfffc - && operand->shift == 0) - { - fixP->fx_r_type = BFD_RELOC_PPC_B16; -#ifdef OBJ_XCOFF - fixP->fx_size = 2; - if (target_big_endian) - fixP->fx_where += 2; -#endif - } - else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 - && operand->bitm == 0x1fe - && operand->shift == -1) - fixP->fx_r_type = BFD_RELOC_PPC_VLE_REL8; - else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 - && operand->bitm == 0xfffe - && operand->shift == 0) - fixP->fx_r_type = BFD_RELOC_PPC_VLE_REL15; - else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 - && operand->bitm == 0x1fffffe - && operand->shift == 0) - fixP->fx_r_type = BFD_RELOC_PPC_VLE_REL24; - else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0 - && operand->bitm == 0x3fffffc - && operand->shift == 0) - fixP->fx_r_type = BFD_RELOC_PPC_BA26; - else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0 - && operand->bitm == 0xfffc - && operand->shift == 0) - { - fixP->fx_r_type = BFD_RELOC_PPC_BA16; -#ifdef OBJ_XCOFF - fixP->fx_size = 2; - if (target_big_endian) - fixP->fx_where += 2; -#endif - } -#if defined (OBJ_XCOFF) || defined (OBJ_ELF) - else if ((operand->flags & PPC_OPERAND_PARENS) != 0 - && (operand->bitm & 0xfff0) == 0xfff0 - && operand->shift == 0) - { - if (ppc_is_toc_sym (fixP->fx_addsy)) - { - fixP->fx_r_type = BFD_RELOC_PPC_TOC16; -#ifdef OBJ_ELF - if (ppc_obj64 - && (operand->flags & PPC_OPERAND_DS) != 0) - fixP->fx_r_type = BFD_RELOC_PPC64_TOC16_DS; -#endif - } - else - { - fixP->fx_r_type = BFD_RELOC_16; -#ifdef OBJ_ELF - if (ppc_obj64 - && (operand->flags & PPC_OPERAND_DS) != 0) - fixP->fx_r_type = BFD_RELOC_PPC64_ADDR16_DS; -#endif - } - fixP->fx_size = 2; - if (target_big_endian) - fixP->fx_where += 2; - } -#endif /* defined (OBJ_XCOFF) || defined (OBJ_ELF) */ - else - { - 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, - _("unsupported relocation against %s"), - S_GET_NAME (fixP->fx_addsy)); - fixP->fx_done = 1; - return; - } - } - else - { -#ifdef OBJ_ELF - ppc_elf_validate_fix (fixP, seg); -#endif + fieldval = value; switch (fixP->fx_r_type) { - case BFD_RELOC_CTOR: - if (ppc_obj64) - goto ctor64; - /* fall through */ - - case BFD_RELOC_32: - if (fixP->fx_pcrel) - fixP->fx_r_type = BFD_RELOC_32_PCREL; - /* fall through */ - - case BFD_RELOC_RVA: - case BFD_RELOC_32_PCREL: - case BFD_RELOC_PPC_EMB_NADDR32: - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - value, 4); - break; - - case BFD_RELOC_64: - ctor64: - if (fixP->fx_pcrel) - fixP->fx_r_type = BFD_RELOC_64_PCREL; - /* fall through */ - - case BFD_RELOC_64_PCREL: - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - value, 8); - break; - - case BFD_RELOC_GPREL16: - case BFD_RELOC_16_GOT_PCREL: - case BFD_RELOC_16_GOTOFF: - case BFD_RELOC_LO16_GOTOFF: - case BFD_RELOC_HI16_GOTOFF: - case BFD_RELOC_HI16_S_GOTOFF: - case BFD_RELOC_16_BASEREL: - case BFD_RELOC_LO16_BASEREL: - case BFD_RELOC_HI16_BASEREL: - case BFD_RELOC_HI16_S_BASEREL: - case BFD_RELOC_PPC_EMB_NADDR16: - case BFD_RELOC_PPC_EMB_NADDR16_LO: - case BFD_RELOC_PPC_EMB_NADDR16_HI: - case BFD_RELOC_PPC_EMB_NADDR16_HA: - case BFD_RELOC_PPC_EMB_SDAI16: - case BFD_RELOC_PPC_EMB_SDA2REL: - case BFD_RELOC_PPC_EMB_SDA2I16: - 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_RELSDA: - case BFD_RELOC_PPC_TOC16: -#ifdef OBJ_ELF - case BFD_RELOC_PPC64_TOC16_LO: - case BFD_RELOC_PPC64_TOC16_HI: - case BFD_RELOC_PPC64_TOC16_HA: -#endif - if (fixP->fx_pcrel) - { - if (fixP->fx_addsy != NULL) - 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, - _("cannot emit PC relative %s relocation"), - bfd_get_reloc_code_name (fixP->fx_r_type)); - } - - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - value, 2); - break; - - case BFD_RELOC_16: + case BFD_RELOC_PPC64_ADDR16_LO_DS: if (fixP->fx_pcrel) - fixP->fx_r_type = BFD_RELOC_16_PCREL; + goto bad_pcrel; /* fall through */ - - case BFD_RELOC_16_PCREL: - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - value, 2); - break; - case BFD_RELOC_LO16: if (fixP->fx_pcrel) fixP->fx_r_type = BFD_RELOC_LO16_PCREL; /* fall through */ - case BFD_RELOC_LO16_PCREL: - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - value, 2); + fieldval = SEX16 (value); break; - /* This case happens when you write, for example, - lis %r3,(L1-L2)@ha - where L1 and L2 are defined later. */ case BFD_RELOC_HI16: if (fixP->fx_pcrel) fixP->fx_r_type = BFD_RELOC_HI16_PCREL; /* fall through */ - case BFD_RELOC_HI16_PCREL: - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - PPC_HI (value), 2); + fieldval = SEX16 (PPC_HI (value)); break; case BFD_RELOC_HI16_S: if (fixP->fx_pcrel) fixP->fx_r_type = BFD_RELOC_HI16_S_PCREL; /* fall through */ - case BFD_RELOC_HI16_S_PCREL: - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - PPC_HA (value), 2); + fieldval = SEX16 (PPC_HA (value)); break; - case BFD_RELOC_PPC_VLE_SDAREL_LO16A: - case BFD_RELOC_PPC_VLE_LO16A: - { - int tval = PPC_VLE_LO16A (value); - valueT oldval = md_chars_to_number ( - fixP->fx_frag->fr_literal + fixP->fx_where, 4); - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - (oldval | tval), 4); - } - break; - - case BFD_RELOC_PPC_VLE_SDAREL_LO16D: - case BFD_RELOC_PPC_VLE_LO16D: - { - int tval = PPC_VLE_LO16D (value); - valueT oldval = md_chars_to_number ( - fixP->fx_frag->fr_literal + fixP->fx_where, 4); - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - (oldval | tval), 4); - } - break; - - case BFD_RELOC_PPC_VLE_SDAREL_HI16A: - case BFD_RELOC_PPC_VLE_HI16A: - { - int tval = PPC_VLE_HI16A (value); - valueT oldval = md_chars_to_number ( - fixP->fx_frag->fr_literal + fixP->fx_where, 4); - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - (oldval | tval), 4); - } - break; - - case BFD_RELOC_PPC_VLE_SDAREL_HI16D: - case BFD_RELOC_PPC_VLE_HI16D: - { - int tval = PPC_VLE_HI16D (value); - valueT oldval = md_chars_to_number ( - fixP->fx_frag->fr_literal + fixP->fx_where, 4); - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - (oldval | tval), 4); - } - break; - - case BFD_RELOC_PPC_VLE_SDAREL_HA16A: - case BFD_RELOC_PPC_VLE_HA16A: - { - int tval = PPC_VLE_HA16A (value); - valueT oldval = md_chars_to_number ( - fixP->fx_frag->fr_literal + fixP->fx_where, 4); - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - (oldval | tval), 4); - } - break; - - case BFD_RELOC_PPC_VLE_SDAREL_HA16D: - case BFD_RELOC_PPC_VLE_HA16D: - { - int tval = PPC_VLE_HA16D (value); - valueT oldval = md_chars_to_number ( - fixP->fx_frag->fr_literal + fixP->fx_where, 4); - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - (oldval | tval), 4); - } - break; - - case BFD_RELOC_PPC_VLE_SDA21_LO: - { - int tval = PPC_LO (value); - valueT oldval = md_chars_to_number ( - fixP->fx_frag->fr_literal + fixP->fx_where, 4); - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - (oldval | tval), 4); - } - break; - - case BFD_RELOC_PPC_VLE_SDA21: - { - valueT oldval = md_chars_to_number ( - fixP->fx_frag->fr_literal + fixP->fx_where, 4); - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - (oldval | value), 4); - } - break; - -#ifdef OBJ_XCOFF - case BFD_RELOC_NONE: - break; -#endif - -#ifdef OBJ_ELF - case BFD_RELOC_PPC64_HIGHER: - if (fixP->fx_pcrel) - abort (); - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - PPC_HIGHER (value), 2); +#ifdef OBJ_ELF + case BFD_RELOC_PPC64_HIGHER: + if (fixP->fx_pcrel) + goto bad_pcrel; + fieldval = SEX16 (PPC_HIGHER (value)); break; case BFD_RELOC_PPC64_HIGHER_S: if (fixP->fx_pcrel) - abort (); - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - PPC_HIGHERA (value), 2); + goto bad_pcrel; + fieldval = SEX16 (PPC_HIGHERA (value)); break; case BFD_RELOC_PPC64_HIGHEST: if (fixP->fx_pcrel) - abort (); - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - PPC_HIGHEST (value), 2); + goto bad_pcrel; + fieldval = SEX16 (PPC_HIGHEST (value)); break; case BFD_RELOC_PPC64_HIGHEST_S: if (fixP->fx_pcrel) - abort (); - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - PPC_HIGHESTA (value), 2); + goto bad_pcrel; + fieldval = SEX16 (PPC_HIGHESTA (value)); break; - case BFD_RELOC_PPC64_ADDR16_DS: - case BFD_RELOC_PPC64_ADDR16_LO_DS: - case BFD_RELOC_PPC64_GOT16_DS: - case BFD_RELOC_PPC64_GOT16_LO_DS: - case BFD_RELOC_PPC64_PLT16_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_LO_DS: - case BFD_RELOC_PPC64_PLTGOT16_DS: - case BFD_RELOC_PPC64_PLTGOT16_LO_DS: - if (fixP->fx_pcrel) - abort (); - { - char *where = fixP->fx_frag->fr_literal + fixP->fx_where; - unsigned long val, mask; - - if (target_big_endian) - val = bfd_getb32 (where - 2); - else - val = bfd_getl32 (where); - mask = 0xfffc; - /* lq insns reserve the four lsbs. */ - if ((ppc_cpu & PPC_OPCODE_POWER4) != 0 - && (val & (0x3f << 26)) == (56u << 26)) - mask = 0xfff0; - val |= value & mask; - if (target_big_endian) - bfd_putb16 ((bfd_vma) val, where); - else - bfd_putl16 ((bfd_vma) val, where); - } - break; - - case BFD_RELOC_PPC_B16_BRTAKEN: - case BFD_RELOC_PPC_B16_BRNTAKEN: - case BFD_RELOC_PPC_BA16_BRTAKEN: - case BFD_RELOC_PPC_BA16_BRNTAKEN: - break; - - case BFD_RELOC_PPC_TLS: - case BFD_RELOC_PPC_TLSGD: - case BFD_RELOC_PPC_TLSLD: - break; - - case BFD_RELOC_PPC_DTPMOD: + /* The following relocs can't be calculated by the assembler. + Leave the field zero. */ case BFD_RELOC_PPC_TPREL16: case BFD_RELOC_PPC_TPREL16_LO: case BFD_RELOC_PPC_TPREL16_HI: case BFD_RELOC_PPC_TPREL16_HA: - case BFD_RELOC_PPC_TPREL: case BFD_RELOC_PPC_DTPREL16: case BFD_RELOC_PPC_DTPREL16_LO: case BFD_RELOC_PPC_DTPREL16_HI: case BFD_RELOC_PPC_DTPREL16_HA: - case BFD_RELOC_PPC_DTPREL: case BFD_RELOC_PPC_GOT_TLSGD16: case BFD_RELOC_PPC_GOT_TLSGD16_LO: case BFD_RELOC_PPC_GOT_TLSGD16_HI: @@ -6831,98 +6451,386 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) case BFD_RELOC_PPC64_DTPREL16_HIGHERA: case BFD_RELOC_PPC64_DTPREL16_HIGHEST: case BFD_RELOC_PPC64_DTPREL16_HIGHESTA: + gas_assert (fixP->fx_addsy != NULL); S_SET_THREAD_LOCAL (fixP->fx_addsy); + fieldval = 0; + if (fixP->fx_pcrel) + goto bad_pcrel; break; -#endif - /* Because SDA21 modifies the register field, the size is set to 4 - bytes, rather than 2, so offset it here appropriately. */ + + /* These also should leave the field zero for the same + reason. Note that older versions of gas wrote values + here. If we want to go back to the old behaviour, then + all _LO and _LO_DS cases will need to be treated like + BFD_RELOC_LO16_PCREL above. Similarly for _HI etc. */ + case BFD_RELOC_16_GOTOFF: + case BFD_RELOC_LO16_GOTOFF: + case BFD_RELOC_HI16_GOTOFF: + case BFD_RELOC_HI16_S_GOTOFF: + case BFD_RELOC_LO16_PLTOFF: + case BFD_RELOC_HI16_PLTOFF: + case BFD_RELOC_HI16_S_PLTOFF: + case BFD_RELOC_GPREL16: + case BFD_RELOC_16_BASEREL: + case BFD_RELOC_LO16_BASEREL: + case BFD_RELOC_HI16_BASEREL: + case BFD_RELOC_HI16_S_BASEREL: + case BFD_RELOC_PPC_TOC16: + case BFD_RELOC_PPC64_TOC16_LO: + case BFD_RELOC_PPC64_TOC16_HI: + case BFD_RELOC_PPC64_TOC16_HA: + case BFD_RELOC_PPC64_PLTGOT16: + case BFD_RELOC_PPC64_PLTGOT16_LO: + case BFD_RELOC_PPC64_PLTGOT16_HI: + case BFD_RELOC_PPC64_PLTGOT16_HA: + case BFD_RELOC_PPC64_GOT16_DS: + case BFD_RELOC_PPC64_GOT16_LO_DS: + case BFD_RELOC_PPC64_PLT16_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_LO_DS: + case BFD_RELOC_PPC64_PLTGOT16_DS: + case BFD_RELOC_PPC64_PLTGOT16_LO_DS: + case BFD_RELOC_PPC_EMB_NADDR16: + case BFD_RELOC_PPC_EMB_NADDR16_LO: + case BFD_RELOC_PPC_EMB_NADDR16_HI: + case BFD_RELOC_PPC_EMB_NADDR16_HA: + case BFD_RELOC_PPC_EMB_SDAI16: + case BFD_RELOC_PPC_EMB_SDA2I16: + case BFD_RELOC_PPC_EMB_SDA2REL: case BFD_RELOC_PPC_EMB_SDA21: + case BFD_RELOC_PPC_EMB_MRKREF: + 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_BIT_FLD: + case BFD_RELOC_PPC_EMB_RELSDA: + case BFD_RELOC_PPC_VLE_SDA21: + case BFD_RELOC_PPC_VLE_SDA21_LO: + case BFD_RELOC_PPC_VLE_SDAREL_LO16A: + case BFD_RELOC_PPC_VLE_SDAREL_LO16D: + case BFD_RELOC_PPC_VLE_SDAREL_HI16A: + case BFD_RELOC_PPC_VLE_SDAREL_HI16D: + case BFD_RELOC_PPC_VLE_SDAREL_HA16A: + case BFD_RELOC_PPC_VLE_SDAREL_HA16D: + gas_assert (fixP->fx_addsy != NULL); + /* Fall thru */ + + case BFD_RELOC_PPC_TLS: + case BFD_RELOC_PPC_TLSGD: + case BFD_RELOC_PPC_TLSLD: + fieldval = 0; if (fixP->fx_pcrel) - abort (); + goto bad_pcrel; + break; +#endif - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where - + ((target_big_endian) ? 2 : 0), - value, 2); + default: break; + } - case BFD_RELOC_8: - if (fixP->fx_pcrel) +#ifdef OBJ_ELF +/* powerpc uses RELA style relocs, so if emitting a reloc the field + contents can stay at zero. */ +#define APPLY_RELOC fixP->fx_done +#else +#define APPLY_RELOC 1 +#endif + if ((fieldval != 0 && APPLY_RELOC) || operand->insert != NULL) + { + /* Fetch the instruction, insert the fully resolved operand + value, and stuff the instruction back again. */ + where = fixP->fx_frag->fr_literal + fixP->fx_where; + if (target_big_endian) { - /* This can occur if there is a bug in the input assembler, eg: - ".byte - ." */ - if (fixP->fx_addsy) - as_bad (_("unable to handle reference to symbol %s"), - S_GET_NAME (fixP->fx_addsy)); + if (fixP->fx_size == 4) + insn = bfd_getb32 ((unsigned char *) where); else - as_bad (_("unable to resolve expression")); - fixP->fx_done = 1; + insn = bfd_getb16 ((unsigned char *) where); } else - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - value, 1); + { + if (fixP->fx_size == 4) + insn = bfd_getl32 ((unsigned char *) where); + else + insn = bfd_getl16 ((unsigned char *) where); + } + 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 ((bfd_vma) insn, (unsigned char *) where); + else + bfd_putb16 ((bfd_vma) insn, (unsigned char *) where); + } + else + { + if (fixP->fx_size == 4) + bfd_putl32 ((bfd_vma) insn, (unsigned char *) where); + else + bfd_putl16 ((bfd_vma) insn, (unsigned char *) where); + } + } + + if (fixP->fx_done) + /* Nothing else to do here. */ + return; + + gas_assert (fixP->fx_addsy != NULL); + if (fixP->fx_r_type == BFD_RELOC_UNUSED) + { + 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, + _("unsupported relocation against %s"), + S_GET_NAME (fixP->fx_addsy)); + fixP->fx_done = 1; + return; + } + } + else + { + /* Handle relocs in data. */ + switch (fixP->fx_r_type) + { + case BFD_RELOC_CTOR: + if (ppc_obj64) + goto ctor64; + /* fall through */ + + case BFD_RELOC_32: + if (fixP->fx_pcrel) + fixP->fx_r_type = BFD_RELOC_32_PCREL; + /* fall through */ + + case BFD_RELOC_32_PCREL: + case BFD_RELOC_RVA: + md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, + value, 4); break; - case BFD_RELOC_24_PLT_PCREL: - case BFD_RELOC_PPC_LOCAL24PC: - if (!fixP->fx_pcrel && !fixP->fx_done) - abort (); + case BFD_RELOC_64: + ctor64: + if (fixP->fx_pcrel) + fixP->fx_r_type = BFD_RELOC_64_PCREL; + /* fall through */ - if (fixP->fx_done) - { - char *where; - unsigned long insn; + case BFD_RELOC_64_PCREL: + md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, + value, 8); + break; - /* Fetch the instruction, insert the fully resolved operand - value, and stuff the instruction back again. */ - where = fixP->fx_frag->fr_literal + fixP->fx_where; - if (target_big_endian) - insn = bfd_getb32 ((unsigned char *) where); - else - insn = bfd_getl32 ((unsigned char *) where); - if (ppc_mach() == bfd_mach_ppc_vle) + case BFD_RELOC_16: + if (fixP->fx_pcrel) + fixP->fx_r_type = BFD_RELOC_16_PCREL; + /* fall through */ + + case BFD_RELOC_16_PCREL: + md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, + value, 2); + break; + + case BFD_RELOC_8: + if (fixP->fx_pcrel) + { +#ifdef OBJ_ELF + bad_pcrel: +#endif + if (fixP->fx_addsy) { - if ((value & 1) != 0) + 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, - _("branch address must be a multiple of 2")); - } - else - { - if ((value & 3) != 0) + _("unresolved expression that must" + " be resolved")); + else as_bad_where (fixP->fx_file, fixP->fx_line, - _("branch address must be a multiple of 4")); + _("cannot emit PC relative %s relocation" + " against %s"), + bfd_get_reloc_code_name (fixP->fx_r_type), + S_GET_NAME (fixP->fx_addsy)); } - if ((offsetT) value < -0x40000000 - || (offsetT) value >= 0x40000000) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("@local or @plt branch destination is too far away, %ld bytes"), - (long) value); - insn = insn | (value & 0x03fffffc); - if (target_big_endian) - bfd_putb32 ((bfd_vma) insn, (unsigned char *) where); else - bfd_putl32 ((bfd_vma) insn, (unsigned char *) where); + as_bad_where (fixP->fx_file, fixP->fx_line, + _("unable to resolve expression")); + fixP->fx_done = 1; } + else + md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, + value, 1); break; case BFD_RELOC_VTABLE_INHERIT: - fixP->fx_done = 0; if (fixP->fx_addsy && !S_IS_DEFINED (fixP->fx_addsy) && !S_IS_WEAK (fixP->fx_addsy)) S_SET_WEAK (fixP->fx_addsy); - break; + /* Fall thru */ case BFD_RELOC_VTABLE_ENTRY: fixP->fx_done = 0; break; #ifdef OBJ_ELF - /* Generated by reference to `sym@tocbase'. The sym is - ignored by the linker. */ + /* These can appear with @l etc. in data. */ + case BFD_RELOC_LO16: + if (fixP->fx_pcrel) + fixP->fx_r_type = BFD_RELOC_LO16_PCREL; + case BFD_RELOC_LO16_PCREL: + md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, + value, 2); + break; + + case BFD_RELOC_HI16: + if (fixP->fx_pcrel) + fixP->fx_r_type = BFD_RELOC_HI16_PCREL; + case BFD_RELOC_HI16_PCREL: + md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, + PPC_HI (value), 2); + break; + + case BFD_RELOC_HI16_S: + if (fixP->fx_pcrel) + fixP->fx_r_type = BFD_RELOC_HI16_S_PCREL; + case BFD_RELOC_HI16_S_PCREL: + md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, + PPC_HA (value), 2); + break; + + case BFD_RELOC_PPC64_HIGHER: + if (fixP->fx_pcrel) + goto bad_pcrel; + md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, + PPC_HIGHER (value), 2); + break; + + case BFD_RELOC_PPC64_HIGHER_S: + if (fixP->fx_pcrel) + goto bad_pcrel; + md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, + PPC_HIGHERA (value), 2); + break; + + case BFD_RELOC_PPC64_HIGHEST: + if (fixP->fx_pcrel) + goto bad_pcrel; + md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, + PPC_HIGHEST (value), 2); + break; + + case BFD_RELOC_PPC64_HIGHEST_S: + if (fixP->fx_pcrel) + goto bad_pcrel; + md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, + PPC_HIGHESTA (value), 2); + break; + + case BFD_RELOC_PPC_DTPMOD: + case BFD_RELOC_PPC_TPREL: + case BFD_RELOC_PPC_DTPREL: + S_SET_THREAD_LOCAL (fixP->fx_addsy); + break; + + /* Just punt all of these to the linker. */ + case BFD_RELOC_PPC_B16_BRTAKEN: + case BFD_RELOC_PPC_B16_BRNTAKEN: + case BFD_RELOC_16_GOTOFF: + case BFD_RELOC_LO16_GOTOFF: + case BFD_RELOC_HI16_GOTOFF: + case BFD_RELOC_HI16_S_GOTOFF: + case BFD_RELOC_LO16_PLTOFF: + case BFD_RELOC_HI16_PLTOFF: + case BFD_RELOC_HI16_S_PLTOFF: + case BFD_RELOC_PPC_COPY: + case BFD_RELOC_PPC_GLOB_DAT: + case BFD_RELOC_16_BASEREL: + case BFD_RELOC_LO16_BASEREL: + case BFD_RELOC_HI16_BASEREL: + case BFD_RELOC_HI16_S_BASEREL: + case BFD_RELOC_PPC_TLS: + case BFD_RELOC_PPC_DTPREL16_LO: + case BFD_RELOC_PPC_DTPREL16_HI: + case BFD_RELOC_PPC_DTPREL16_HA: + case BFD_RELOC_PPC_TPREL16_LO: + case BFD_RELOC_PPC_TPREL16_HI: + case BFD_RELOC_PPC_TPREL16_HA: + case BFD_RELOC_PPC_GOT_TLSGD16: + case BFD_RELOC_PPC_GOT_TLSGD16_LO: + case BFD_RELOC_PPC_GOT_TLSGD16_HI: + case BFD_RELOC_PPC_GOT_TLSGD16_HA: + case BFD_RELOC_PPC_GOT_TLSLD16: + case BFD_RELOC_PPC_GOT_TLSLD16_LO: + case BFD_RELOC_PPC_GOT_TLSLD16_HI: + case BFD_RELOC_PPC_GOT_TLSLD16_HA: + case BFD_RELOC_PPC_GOT_DTPREL16: + case BFD_RELOC_PPC_GOT_DTPREL16_LO: + case BFD_RELOC_PPC_GOT_DTPREL16_HI: + case BFD_RELOC_PPC_GOT_DTPREL16_HA: + case BFD_RELOC_PPC_GOT_TPREL16: + case BFD_RELOC_PPC_GOT_TPREL16_LO: + case BFD_RELOC_PPC_GOT_TPREL16_HI: + case BFD_RELOC_PPC_GOT_TPREL16_HA: + case BFD_RELOC_24_PLT_PCREL: + case BFD_RELOC_PPC_LOCAL24PC: + case BFD_RELOC_32_PLT_PCREL: + case BFD_RELOC_GPREL16: + case BFD_RELOC_PPC_VLE_SDAREL_LO16A: + case BFD_RELOC_PPC_VLE_SDAREL_HI16A: + case BFD_RELOC_PPC_VLE_SDAREL_HA16A: + case BFD_RELOC_PPC_EMB_NADDR32: + case BFD_RELOC_PPC_EMB_NADDR16: + case BFD_RELOC_PPC_EMB_NADDR16_LO: + case BFD_RELOC_PPC_EMB_NADDR16_HI: + case BFD_RELOC_PPC_EMB_NADDR16_HA: + case BFD_RELOC_PPC_EMB_SDAI16: + case BFD_RELOC_PPC_EMB_SDA2REL: + case BFD_RELOC_PPC_EMB_SDA2I16: + case BFD_RELOC_PPC_EMB_SDA21: + case BFD_RELOC_PPC_VLE_SDA21_LO: + case BFD_RELOC_PPC_EMB_MRKREF: + 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_BIT_FLD: + case BFD_RELOC_PPC_EMB_RELSDA: case BFD_RELOC_PPC64_TOC: + case BFD_RELOC_PPC_TOC16: + case BFD_RELOC_PPC64_TOC16_LO: + case BFD_RELOC_PPC64_TOC16_HI: + case BFD_RELOC_PPC64_TOC16_HA: + case BFD_RELOC_PPC64_DTPREL16_HIGHER: + case BFD_RELOC_PPC64_DTPREL16_HIGHERA: + case BFD_RELOC_PPC64_DTPREL16_HIGHEST: + case BFD_RELOC_PPC64_DTPREL16_HIGHESTA: + case BFD_RELOC_PPC64_TPREL16_HIGHER: + case BFD_RELOC_PPC64_TPREL16_HIGHERA: + case BFD_RELOC_PPC64_TPREL16_HIGHEST: + case BFD_RELOC_PPC64_TPREL16_HIGHESTA: fixP->fx_done = 0; break; #endif + +#ifdef OBJ_XCOFF + case BFD_RELOC_NONE: + break; +#endif + default: fprintf (stderr, _("Gas failure, reloc value %d\n"), fixP->fx_r_type); @@ -6932,6 +6840,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) } #ifdef OBJ_ELF + ppc_elf_validate_fix (fixP, seg); fixP->fx_addnumber = value; /* PowerPC uses RELA relocs, ie. the reloc addend is stored separately -- 2.30.2