+2014-03-08 Alan Modra <amodra@gmail.com>
+
+ * elf64-ppc.c (ppc64_elf_howto_raw): Use complain_overflow_signed
+ for R_PPC64_ADDR14, R_PPC64_ADDR14_BRTAKEN, R_PPC64_ADDR14_BRNTAKEN,
+ R_PPC64_SECTOFF, R_PPC64_ADDR16_DS, R_PPC64_SECTOFF_DS,
+ R_PPC64_REL16 entries. Use complain_overflow_dont for R_PPC64_TOC.
+ (ppc64_elf_relocate_section): Modify overflow test for 16-bit
+ fields in instructions to signed/unsigned according to whether
+ the field takes a signed or unsigned value.
+
2014-03-07 Pedro Alves <palves@redhat.com>
* rs6000-core.c (rs6000coff_core_p): Cast pointers to bfd_vma
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_signed, /* complain_on_overflow */
ppc64_elf_branch_reloc, /* special_function */
"R_PPC64_ADDR14", /* name */
FALSE, /* partial_inplace */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_signed, /* complain_on_overflow */
ppc64_elf_brtaken_reloc, /* special_function */
"R_PPC64_ADDR14_BRTAKEN",/* name */
FALSE, /* partial_inplace */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_signed, /* complain_on_overflow */
ppc64_elf_brtaken_reloc, /* special_function */
"R_PPC64_ADDR14_BRNTAKEN",/* name */
FALSE, /* partial_inplace */
32, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
- /* FIXME: Verify. Was complain_overflow_bitfield. */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC64_REL32", /* name */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_signed, /* complain_on_overflow */
ppc64_elf_sectoff_reloc, /* special_function */
"R_PPC64_SECTOFF", /* name */
FALSE, /* partial_inplace */
64, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
ppc64_elf_toc64_reloc, /* special_function */
"R_PPC64_TOC", /* name */
FALSE, /* partial_inplace */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC64_ADDR16_DS", /* name */
FALSE, /* partial_inplace */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_signed, /* complain_on_overflow */
ppc64_elf_sectoff_reloc, /* special_function */
"R_PPC64_SECTOFF_DS", /* name */
FALSE, /* partial_inplace */
16, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC64_REL16", /* name */
FALSE, /* partial_inplace */
bfd_vma max_br_offset;
bfd_vma from;
const Elf_Internal_Rela orig_rel = *rel;
+ reloc_howto_type *howto;
+ struct reloc_howto_struct alt_howto;
r_type = ELF64_R_TYPE (rel->r_info);
r_symndx = ELF64_R_SYM (rel->r_info);
}
/* Do any further special processing. */
+ howto = ppc64_elf_howto_table[(int) r_type];
switch (r_type)
{
default:
info->callbacks->einfo
(_("%P: %H: error: %s not a multiple of %u\n"),
input_bfd, input_section, rel->r_offset,
- ppc64_elf_howto_table[r_type]->name,
+ howto->name,
mask + 1);
bfd_set_error (bfd_error_bad_value);
ret = FALSE;
info->callbacks->einfo
(_("%P: %H: unresolvable %s against `%T'\n"),
input_bfd, input_section, rel->r_offset,
- ppc64_elf_howto_table[(int) r_type]->name,
+ howto->name,
h->elf.root.root.string);
ret = FALSE;
}
- r = _bfd_final_link_relocate (ppc64_elf_howto_table[(int) r_type],
- input_bfd,
- input_section,
- contents,
- rel->r_offset,
- relocation,
- addend);
+ /* 16-bit fields in insns mostly have signed values, but a
+ few insns have 16-bit unsigned values. Really, we should
+ have different reloc types. */
+ if (howto->complain_on_overflow != complain_overflow_dont
+ && howto->dst_mask == 0xffff
+ && (input_section->flags & SEC_CODE) != 0)
+ {
+ enum complain_overflow complain = complain_overflow_signed;
+
+ insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
+ if (howto->rightshift == 0
+ ? ((insn & (0x3f << 26)) == 28u << 26 /* andi */
+ || (insn & (0x3f << 26)) == 24u << 26 /* ori */
+ || (insn & (0x3f << 26)) == 26u << 26 /* xori */
+ || (insn & (0x3f << 26)) == 10u << 26 /* cmpli */)
+ : ((insn & (0x3f << 26)) == 29u << 26 /* andis */
+ || (insn & (0x3f << 26)) == 25u << 26 /* oris */
+ || (insn & (0x3f << 26)) == 27u << 26 /* xoris */))
+ complain = complain_overflow_unsigned;
+ if (howto->complain_on_overflow != complain)
+ {
+ alt_howto = *howto;
+ alt_howto.complain_on_overflow = complain;
+ howto = &alt_howto;
+ }
+ }
+
+ r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
+ rel->r_offset, relocation, addend);
if (r != bfd_reloc_ok)
{
char *more_info = NULL;
- const char *reloc_name = ppc64_elf_howto_table[r_type]->name;
+ const char *reloc_name = howto->name;
if (reloc_dest != DEST_NORMAL)
{
continue;
if (h != NULL
&& h->elf.root.type == bfd_link_hash_undefweak
- && ppc64_elf_howto_table[r_type]->pc_relative)
+ && howto->pc_relative)
{
/* Assume this is a call protected by other code that
detects the symbol is undefined. If this is the case,
+2014-03-07 Alan Modra <amodra@gmail.com>
+
+ * powerpc.cc (Powerpc_relocate_functions::Overflow_check): Add
+ CHECK_UNSIGNED, CHECK_LOW_INSN, CHECK_HIGH_INSN.
+ (Powerpc_relocate_functions::has_overflow_unsigned): New function.
+ (Powerpc_relocate_functions::has_overflow_bitfield,
+ overflowed): Use the above.
+ (Target_powerpc::Relocate::relocate): Correct overflow checking
+ for a number of relocations. Modify overflow test for 16-bit
+ fields in instructions to signed/unsigned according to whether
+ the field takes a signed or unsigned value.
+
2014-03-05 Alan Modra <amodra@gmail.com>
Update copyright years.
{
CHECK_NONE,
CHECK_SIGNED,
- CHECK_BITFIELD
+ CHECK_UNSIGNED,
+ CHECK_BITFIELD,
+ CHECK_LOW_INSN,
+ CHECK_HIGH_INSN
};
enum Status
template<int valsize>
static inline bool
- has_overflow_bitfield(Address value)
+ has_overflow_unsigned(Address value)
{
Address limit = static_cast<Address>(1) << ((valsize - 1) >> 1);
limit <<= ((valsize - 1) >> 1);
limit <<= ((valsize - 1) - 2 * ((valsize - 1) >> 1));
- return value > (limit << 1) - 1 && value + limit > (limit << 1) - 1;
+ return value > (limit << 1) - 1;
+ }
+
+ template<int valsize>
+ static inline bool
+ has_overflow_bitfield(Address value)
+ {
+ return (has_overflow_unsigned<valsize>(value)
+ && has_overflow_signed<valsize>(value));
}
template<int valsize>
if (has_overflow_signed<valsize>(value))
return STATUS_OVERFLOW;
}
+ else if (overflow == CHECK_UNSIGNED)
+ {
+ if (has_overflow_unsigned<valsize>(value))
+ return STATUS_OVERFLOW;
+ }
else if (overflow == CHECK_BITFIELD)
{
if (has_overflow_bitfield<valsize>(value))
}
typename Reloc::Overflow_check overflow = Reloc::CHECK_NONE;
+ elfcpp::Shdr<size, big_endian> shdr(relinfo->data_shdr);
switch (r_type)
{
case elfcpp::R_POWERPC_ADDR32:
overflow = Reloc::CHECK_SIGNED;
break;
- case elfcpp::R_POWERPC_ADDR24:
- case elfcpp::R_POWERPC_ADDR16:
case elfcpp::R_POWERPC_UADDR16:
- case elfcpp::R_PPC64_ADDR16_DS:
- case elfcpp::R_POWERPC_ADDR14:
- case elfcpp::R_POWERPC_ADDR14_BRTAKEN:
- case elfcpp::R_POWERPC_ADDR14_BRNTAKEN:
overflow = Reloc::CHECK_BITFIELD;
break;
+ case elfcpp::R_POWERPC_ADDR16:
+ // We really should have three separate relocations,
+ // one for 16-bit data, one for insns with 16-bit signed fields,
+ // and one for insns with 16-bit unsigned fields.
+ overflow = Reloc::CHECK_BITFIELD;
+ if ((shdr.get_sh_flags() & elfcpp::SHF_EXECINSTR) != 0)
+ overflow = Reloc::CHECK_LOW_INSN;
+ break;
+
case elfcpp::R_POWERPC_ADDR16_HI:
case elfcpp::R_POWERPC_ADDR16_HA:
case elfcpp::R_POWERPC_GOT16_HI:
case elfcpp::R_POWERPC_GOT_DTPREL16_HA:
case elfcpp::R_POWERPC_REL16_HI:
case elfcpp::R_POWERPC_REL16_HA:
- if (size == 32)
- break;
- case elfcpp::R_POWERPC_REL24:
- case elfcpp::R_PPC_PLTREL24:
- case elfcpp::R_PPC_LOCAL24PC:
+ if (size != 32)
+ overflow = Reloc::CHECK_HIGH_INSN;
+ break;
+
case elfcpp::R_POWERPC_REL16:
case elfcpp::R_PPC64_TOC16:
case elfcpp::R_POWERPC_GOT16:
case elfcpp::R_POWERPC_SECTOFF:
case elfcpp::R_POWERPC_TPREL16:
case elfcpp::R_POWERPC_DTPREL16:
+ case elfcpp::R_POWERPC_GOT_TLSGD16:
+ case elfcpp::R_POWERPC_GOT_TLSLD16:
+ case elfcpp::R_POWERPC_GOT_TPREL16:
+ case elfcpp::R_POWERPC_GOT_DTPREL16:
+ overflow = Reloc::CHECK_LOW_INSN;
+ break;
+
+ case elfcpp::R_POWERPC_ADDR24:
+ case elfcpp::R_POWERPC_ADDR14:
+ case elfcpp::R_POWERPC_ADDR14_BRTAKEN:
+ case elfcpp::R_POWERPC_ADDR14_BRNTAKEN:
+ case elfcpp::R_PPC64_ADDR16_DS:
+ case elfcpp::R_POWERPC_REL24:
+ case elfcpp::R_PPC_PLTREL24:
+ case elfcpp::R_PPC_LOCAL24PC:
case elfcpp::R_PPC64_TPREL16_DS:
case elfcpp::R_PPC64_DTPREL16_DS:
case elfcpp::R_PPC64_TOC16_DS:
case elfcpp::R_POWERPC_REL14:
case elfcpp::R_POWERPC_REL14_BRTAKEN:
case elfcpp::R_POWERPC_REL14_BRNTAKEN:
- case elfcpp::R_POWERPC_GOT_TLSGD16:
- case elfcpp::R_POWERPC_GOT_TLSLD16:
- case elfcpp::R_POWERPC_GOT_TPREL16:
- case elfcpp::R_POWERPC_GOT_DTPREL16:
overflow = Reloc::CHECK_SIGNED;
break;
}
+ if (overflow == Reloc::CHECK_LOW_INSN
+ || overflow == Reloc::CHECK_HIGH_INSN)
+ {
+ Insn* iview = reinterpret_cast<Insn*>(view - 2 * big_endian);
+ Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
+
+ overflow = Reloc::CHECK_SIGNED;
+ if (overflow == Reloc::CHECK_LOW_INSN
+ ? ((insn & (0x3f << 26)) == 28u << 26 /* andi */
+ || (insn & (0x3f << 26)) == 24u << 26 /* ori */
+ || (insn & (0x3f << 26)) == 26u << 26 /* xori */
+ || (insn & (0x3f << 26)) == 10u << 26 /* cmpli */)
+ : ((insn & (0x3f << 26)) == 29u << 26 /* andis */
+ || (insn & (0x3f << 26)) == 25u << 26 /* oris */
+ || (insn & (0x3f << 26)) == 27u << 26 /* xoris */))
+ overflow = Reloc::CHECK_UNSIGNED;
+ }
+
typename Powerpc_relocate_functions<size, big_endian>::Status status
= Powerpc_relocate_functions<size, big_endian>::STATUS_OK;
switch (r_type)