|
|
a094f6 |
commit b80eed39e2e813c37cffcb873dc4fdd03381383c
|
|
|
a094f6 |
Author: Alan Modra <amodra@gmail.com>
|
|
|
a094f6 |
Date: Fri Mar 7 10:14:30 2014 +1030
|
|
|
a094f6 |
|
|
|
a094f6 |
Better overflow checking for powerpc64 relocations
|
|
|
a094f6 |
|
|
|
a094f6 |
R_PPC64_ADDR16 is used in three contexts:
|
|
|
a094f6 |
- .short data relocation
|
|
|
a094f6 |
- 16-bit signed insn fields, eg. addi
|
|
|
a094f6 |
- 16-bit unsigned insn fields, eg. ori
|
|
|
a094f6 |
In the first case we want to allow both signed and unsigned 16-bit
|
|
|
a094f6 |
values, the latter two ought to error if the field exceeds the range
|
|
|
a094f6 |
of values allowed for 16-bit signed and unsigned integers
|
|
|
a094f6 |
respectively. These conflicting requirements meant that ld had to
|
|
|
a094f6 |
choose the least restrictive overflow checks, and thus it is possible
|
|
|
a094f6 |
to construct testcases where an addi field overflows but is not
|
|
|
a094f6 |
reported by ld. Many relocations dealing with 16-bit insn fields have
|
|
|
a094f6 |
this problem. What's more, some relocations that are only ever used
|
|
|
a094f6 |
for signed fields of instructions woodenly copied the lax overflow
|
|
|
a094f6 |
checking of R_PPC64_ADDR16.
|
|
|
a094f6 |
|
|
|
a094f6 |
bfd/
|
|
|
a094f6 |
* elf64-ppc.c (ppc64_elf_howto_raw): Use complain_overflow_signed
|
|
|
a094f6 |
for R_PPC64_ADDR14, R_PPC64_ADDR14_BRTAKEN, R_PPC64_ADDR14_BRNTAKEN,
|
|
|
a094f6 |
R_PPC64_SECTOFF, R_PPC64_ADDR16_DS, R_PPC64_SECTOFF_DS,
|
|
|
a094f6 |
R_PPC64_REL16 entries. Use complain_overflow_dont for R_PPC64_TOC.
|
|
|
a094f6 |
(ppc64_elf_relocate_section): Modify overflow test for 16-bit
|
|
|
a094f6 |
fields in instructions to signed/unsigned according to whether
|
|
|
a094f6 |
the field takes a signed or unsigned value.
|
|
|
a094f6 |
gold/
|
|
|
a094f6 |
* powerpc.cc (Powerpc_relocate_functions::Overflow_check): Add
|
|
|
a094f6 |
CHECK_UNSIGNED, CHECK_LOW_INSN, CHECK_HIGH_INSN.
|
|
|
a094f6 |
(Powerpc_relocate_functions::has_overflow_unsigned): New function.
|
|
|
a094f6 |
(Powerpc_relocate_functions::has_overflow_bitfield,
|
|
|
a094f6 |
overflowed): Use the above.
|
|
|
a094f6 |
(Target_powerpc::Relocate::relocate): Correct overflow checking
|
|
|
a094f6 |
for a number of relocations. Modify overflow test for 16-bit
|
|
|
a094f6 |
fields in instructions to signed/unsigned according to whether
|
|
|
a094f6 |
the field takes a signed or unsigned value.
|
|
|
a094f6 |
|
|
|
a094f6 |
### a/bfd/ChangeLog
|
|
|
a094f6 |
### b/bfd/ChangeLog
|
|
|
a094f6 |
## -1,3 +1,13 @@
|
|
|
a094f6 |
+2014-03-08 Alan Modra <amodra@gmail.com>
|
|
|
a094f6 |
+
|
|
|
a094f6 |
+ * elf64-ppc.c (ppc64_elf_howto_raw): Use complain_overflow_signed
|
|
|
a094f6 |
+ for R_PPC64_ADDR14, R_PPC64_ADDR14_BRTAKEN, R_PPC64_ADDR14_BRNTAKEN,
|
|
|
a094f6 |
+ R_PPC64_SECTOFF, R_PPC64_ADDR16_DS, R_PPC64_SECTOFF_DS,
|
|
|
a094f6 |
+ R_PPC64_REL16 entries. Use complain_overflow_dont for R_PPC64_TOC.
|
|
|
a094f6 |
+ (ppc64_elf_relocate_section): Modify overflow test for 16-bit
|
|
|
a094f6 |
+ fields in instructions to signed/unsigned according to whether
|
|
|
a094f6 |
+ the field takes a signed or unsigned value.
|
|
|
a094f6 |
+
|
|
|
a094f6 |
2014-03-07 Pedro Alves <palves@redhat.com>
|
|
|
a094f6 |
|
|
|
a094f6 |
* rs6000-core.c (rs6000coff_core_p): Cast pointers to bfd_vma
|
|
|
a094f6 |
--- a/bfd/elf64-ppc.c
|
|
|
a094f6 |
+++ b/bfd/elf64-ppc.c
|
|
|
a094f6 |
@@ -357,7 +357,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
|
|
|
a094f6 |
16, /* bitsize */
|
|
|
a094f6 |
FALSE, /* pc_relative */
|
|
|
a094f6 |
0, /* bitpos */
|
|
|
a094f6 |
- complain_overflow_bitfield, /* complain_on_overflow */
|
|
|
a094f6 |
+ complain_overflow_signed, /* complain_on_overflow */
|
|
|
a094f6 |
ppc64_elf_branch_reloc, /* special_function */
|
|
|
a094f6 |
"R_PPC64_ADDR14", /* name */
|
|
|
a094f6 |
FALSE, /* partial_inplace */
|
|
|
a094f6 |
@@ -374,7 +374,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
|
|
|
a094f6 |
16, /* bitsize */
|
|
|
a094f6 |
FALSE, /* pc_relative */
|
|
|
a094f6 |
0, /* bitpos */
|
|
|
a094f6 |
- complain_overflow_bitfield, /* complain_on_overflow */
|
|
|
a094f6 |
+ complain_overflow_signed, /* complain_on_overflow */
|
|
|
a094f6 |
ppc64_elf_brtaken_reloc, /* special_function */
|
|
|
a094f6 |
"R_PPC64_ADDR14_BRTAKEN",/* name */
|
|
|
a094f6 |
FALSE, /* partial_inplace */
|
|
|
a094f6 |
@@ -391,7 +391,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
|
|
|
a094f6 |
16, /* bitsize */
|
|
|
a094f6 |
FALSE, /* pc_relative */
|
|
|
a094f6 |
0, /* bitpos */
|
|
|
a094f6 |
- complain_overflow_bitfield, /* complain_on_overflow */
|
|
|
a094f6 |
+ complain_overflow_signed, /* complain_on_overflow */
|
|
|
a094f6 |
ppc64_elf_brtaken_reloc, /* special_function */
|
|
|
a094f6 |
"R_PPC64_ADDR14_BRNTAKEN",/* name */
|
|
|
a094f6 |
FALSE, /* partial_inplace */
|
|
|
a094f6 |
@@ -632,7 +632,6 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
|
|
|
a094f6 |
32, /* bitsize */
|
|
|
a094f6 |
TRUE, /* pc_relative */
|
|
|
a094f6 |
0, /* bitpos */
|
|
|
a094f6 |
- /* FIXME: Verify. Was complain_overflow_bitfield. */
|
|
|
a094f6 |
complain_overflow_signed, /* complain_on_overflow */
|
|
|
a094f6 |
bfd_elf_generic_reloc, /* special_function */
|
|
|
a094f6 |
"R_PPC64_REL32", /* name */
|
|
|
a094f6 |
@@ -727,7 +726,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
|
|
|
a094f6 |
16, /* bitsize */
|
|
|
a094f6 |
FALSE, /* pc_relative */
|
|
|
a094f6 |
0, /* bitpos */
|
|
|
a094f6 |
- complain_overflow_bitfield, /* complain_on_overflow */
|
|
|
a094f6 |
+ complain_overflow_signed, /* complain_on_overflow */
|
|
|
a094f6 |
ppc64_elf_sectoff_reloc, /* special_function */
|
|
|
a094f6 |
"R_PPC64_SECTOFF", /* name */
|
|
|
a094f6 |
FALSE, /* partial_inplace */
|
|
|
a094f6 |
@@ -1015,7 +1014,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
|
|
|
a094f6 |
64, /* bitsize */
|
|
|
a094f6 |
FALSE, /* pc_relative */
|
|
|
a094f6 |
0, /* bitpos */
|
|
|
a094f6 |
- complain_overflow_bitfield, /* complain_on_overflow */
|
|
|
a094f6 |
+ complain_overflow_dont, /* complain_on_overflow */
|
|
|
a094f6 |
ppc64_elf_toc64_reloc, /* special_function */
|
|
|
a094f6 |
"R_PPC64_TOC", /* name */
|
|
|
a094f6 |
FALSE, /* partial_inplace */
|
|
|
a094f6 |
@@ -1103,7 +1102,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
|
|
|
a094f6 |
16, /* bitsize */
|
|
|
a094f6 |
FALSE, /* pc_relative */
|
|
|
a094f6 |
0, /* bitpos */
|
|
|
a094f6 |
- complain_overflow_bitfield, /* complain_on_overflow */
|
|
|
a094f6 |
+ complain_overflow_signed, /* complain_on_overflow */
|
|
|
a094f6 |
bfd_elf_generic_reloc, /* special_function */
|
|
|
a094f6 |
"R_PPC64_ADDR16_DS", /* name */
|
|
|
a094f6 |
FALSE, /* partial_inplace */
|
|
|
a094f6 |
@@ -1178,7 +1177,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
|
|
|
a094f6 |
16, /* bitsize */
|
|
|
a094f6 |
FALSE, /* pc_relative */
|
|
|
a094f6 |
0, /* bitpos */
|
|
|
a094f6 |
- complain_overflow_bitfield, /* complain_on_overflow */
|
|
|
a094f6 |
+ complain_overflow_signed, /* complain_on_overflow */
|
|
|
a094f6 |
ppc64_elf_sectoff_reloc, /* special_function */
|
|
|
a094f6 |
"R_PPC64_SECTOFF_DS", /* name */
|
|
|
a094f6 |
FALSE, /* partial_inplace */
|
|
|
a094f6 |
@@ -1950,7 +1949,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
|
|
|
a094f6 |
16, /* bitsize */
|
|
|
a094f6 |
TRUE, /* pc_relative */
|
|
|
a094f6 |
0, /* bitpos */
|
|
|
a094f6 |
- complain_overflow_bitfield, /* complain_on_overflow */
|
|
|
a094f6 |
+ complain_overflow_signed, /* complain_on_overflow */
|
|
|
a094f6 |
bfd_elf_generic_reloc, /* special_function */
|
|
|
a094f6 |
"R_PPC64_REL16", /* name */
|
|
|
a094f6 |
FALSE, /* partial_inplace */
|
|
|
a094f6 |
@@ -12943,6 +12942,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
|
|
a094f6 |
bfd_vma max_br_offset;
|
|
|
a094f6 |
bfd_vma from;
|
|
|
a094f6 |
const Elf_Internal_Rela orig_rel = *rel;
|
|
|
a094f6 |
+ reloc_howto_type *howto;
|
|
|
a094f6 |
+ struct reloc_howto_struct alt_howto;
|
|
|
a094f6 |
|
|
|
a094f6 |
r_type = ELF64_R_TYPE (rel->r_info);
|
|
|
a094f6 |
r_symndx = ELF64_R_SYM (rel->r_info);
|
|
|
a094f6 |
@@ -14507,6 +14508,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
|
|
a094f6 |
}
|
|
|
a094f6 |
|
|
|
a094f6 |
/* Do any further special processing. */
|
|
|
a094f6 |
+ howto = ppc64_elf_howto_table[(int) r_type];
|
|
|
a094f6 |
switch (r_type)
|
|
|
a094f6 |
{
|
|
|
a094f6 |
default:
|
|
|
a094f6 |
@@ -14581,7 +14583,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
|
|
a094f6 |
info->callbacks->einfo
|
|
|
a094f6 |
(_("%P: %H: error: %s not a multiple of %u\n"),
|
|
|
a094f6 |
input_bfd, input_section, rel->r_offset,
|
|
|
a094f6 |
- ppc64_elf_howto_table[r_type]->name,
|
|
|
a094f6 |
+ howto->name,
|
|
|
a094f6 |
mask + 1);
|
|
|
a094f6 |
bfd_set_error (bfd_error_bad_value);
|
|
|
a094f6 |
ret = FALSE;
|
|
|
a094f6 |
@@ -14602,23 +14604,45 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
|
|
a094f6 |
info->callbacks->einfo
|
|
|
a094f6 |
(_("%P: %H: unresolvable %s against `%T'\n"),
|
|
|
a094f6 |
input_bfd, input_section, rel->r_offset,
|
|
|
a094f6 |
- ppc64_elf_howto_table[(int) r_type]->name,
|
|
|
a094f6 |
+ howto->name,
|
|
|
a094f6 |
h->elf.root.root.string);
|
|
|
a094f6 |
ret = FALSE;
|
|
|
a094f6 |
}
|
|
|
a094f6 |
|
|
|
a094f6 |
- r = _bfd_final_link_relocate (ppc64_elf_howto_table[(int) r_type],
|
|
|
a094f6 |
- input_bfd,
|
|
|
a094f6 |
- input_section,
|
|
|
a094f6 |
- contents,
|
|
|
a094f6 |
- rel->r_offset,
|
|
|
a094f6 |
- relocation,
|
|
|
a094f6 |
- addend);
|
|
|
a094f6 |
+ /* 16-bit fields in insns mostly have signed values, but a
|
|
|
a094f6 |
+ few insns have 16-bit unsigned values. Really, we should
|
|
|
a094f6 |
+ have different reloc types. */
|
|
|
a094f6 |
+ if (howto->complain_on_overflow != complain_overflow_dont
|
|
|
a094f6 |
+ && howto->dst_mask == 0xffff
|
|
|
a094f6 |
+ && (input_section->flags & SEC_CODE) != 0)
|
|
|
a094f6 |
+ {
|
|
|
a094f6 |
+ enum complain_overflow complain = complain_overflow_signed;
|
|
|
a094f6 |
+
|
|
|
a094f6 |
+ insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
|
|
|
a094f6 |
+ if (howto->rightshift == 0
|
|
|
a094f6 |
+ ? ((insn & (0x3f << 26)) == 28u << 26 /* andi */
|
|
|
a094f6 |
+ || (insn & (0x3f << 26)) == 24u << 26 /* ori */
|
|
|
a094f6 |
+ || (insn & (0x3f << 26)) == 26u << 26 /* xori */
|
|
|
a094f6 |
+ || (insn & (0x3f << 26)) == 10u << 26 /* cmpli */)
|
|
|
a094f6 |
+ : ((insn & (0x3f << 26)) == 29u << 26 /* andis */
|
|
|
a094f6 |
+ || (insn & (0x3f << 26)) == 25u << 26 /* oris */
|
|
|
a094f6 |
+ || (insn & (0x3f << 26)) == 27u << 26 /* xoris */))
|
|
|
a094f6 |
+ complain = complain_overflow_unsigned;
|
|
|
a094f6 |
+ if (howto->complain_on_overflow != complain)
|
|
|
a094f6 |
+ {
|
|
|
a094f6 |
+ alt_howto = *howto;
|
|
|
a094f6 |
+ alt_howto.complain_on_overflow = complain;
|
|
|
a094f6 |
+ howto = &alt_howto;
|
|
|
a094f6 |
+ }
|
|
|
a094f6 |
+ }
|
|
|
a094f6 |
+
|
|
|
a094f6 |
+ r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
|
|
|
a094f6 |
+ rel->r_offset, relocation, addend);
|
|
|
a094f6 |
|
|
|
a094f6 |
if (r != bfd_reloc_ok)
|
|
|
a094f6 |
{
|
|
|
a094f6 |
char *more_info = NULL;
|
|
|
a094f6 |
- const char *reloc_name = ppc64_elf_howto_table[r_type]->name;
|
|
|
a094f6 |
+ const char *reloc_name = howto->name;
|
|
|
a094f6 |
|
|
|
a094f6 |
if (reloc_dest != DEST_NORMAL)
|
|
|
a094f6 |
{
|
|
|
a094f6 |
@@ -14638,7 +14662,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
|
|
a094f6 |
continue;
|
|
|
a094f6 |
if (h != NULL
|
|
|
a094f6 |
&& h->elf.root.type == bfd_link_hash_undefweak
|
|
|
a094f6 |
- && ppc64_elf_howto_table[r_type]->pc_relative)
|
|
|
a094f6 |
+ && howto->pc_relative)
|
|
|
a094f6 |
{
|
|
|
a094f6 |
/* Assume this is a call protected by other code that
|
|
|
a094f6 |
detects the symbol is undefined. If this is the case,
|