PowerPC addpcis fix

This came up because I was looking at ld/tmpdir/addpcis.o and noticed
the odd addends on REL16DX_HA.  They ought to both be -4.  The error
crept in due REL16DX_HA howto being pc-relative (as indeed it should
be), and code at gas/write.c:1001 after this comment
	      /* Make it pc-relative.  If the back-end code has not
		 selected a pc-relative reloc, cancel the adjustment
		 we do later on all pc-relative relocs.  */
*not* cancelling the pc-relative adjustment.  So I've made a dummy
non-relative split reloc so that the generic code handles this, rather
than attempting to add hacks later in md_apply_fix which would not be
very robust.  Having the new internal reloc also makes it easy to
support

 addpcis rx,sym@ha

as an equivalent to

 addpcis rx,(sym-0f)@ha
0:

The patch also fixes overflow checking, which must test whether the
addi will overflow too since @l relocs don't have any overflow check.

Lastly, since I was poking at md_apply_fix, I arranged to have the
generic gas/write.c code emit errors for subtraction expressions where
we lack reloc support.

include/
	* elf/ppc64.h (R_PPC64_16DX_HA): New.  Expand fake reloc comment.
	* elf/ppc.h (R_PPC_16DX_HA): Likewise.
bfd/
	* reloc.c (BFD_RELOC_PPC_16DX_HA): New.
	* elf64-ppc.c (ppc64_elf_howto_raw <R_PPC64_16DX_HA>): New howto.
	(ppc64_elf_reloc_type_lookup): Translate new bfd reloc.
	(ppc64_elf_ha_reloc): Correct overflow test on REL16DX_HA.
	(ppc64_elf_relocate_section): Likewise.
	* elf32-ppc.c (ppc_elf_howto_raw <R_PPC_16DX_HA>): New howto.
	(ppc_elf_reloc_type_lookup): Translate new bfd reloc.
	(ppc_elf_check_relocs): Handle R_PPC_16DX_HA to pacify gcc.
	* libbfd.h: Regenerate.
	* bfd-in2.h: Regenerate.
gas/
	* config/tc-ppc.c (md_assemble): Use BFD_RELOC_PPC_16DX_HA for addpcis.
	(md_apply_fix): Remove fx_subsy check.  Move code converting to
	pcrel reloc earlier and handle BFD_RELOC_PPC_16DX_HA.  Remove code
	emiiting errors on seeing fx_pcrel set on unexpected relocs, as
	that is done now by the generic code via..
	* config/tc-ppc.h (TC_FORCE_RELOCATION_SUB_LOCAL): ..this. Define.
	(TC_VALIDATE_FIX_SUB): Define.
ld/
	* testsuite/ld-powerpc/addpcis.d: Define ext1 and ext2 at
	limits of addpcis range.
This commit is contained in:
Alan Modra 2017-02-28 08:32:36 +10:30
parent afbf7e8e3a
commit 7ba71655a4
14 changed files with 155 additions and 94 deletions

View File

@ -1,3 +1,16 @@
2017-02-28 Alan Modra <amodra@gmail.com>
* reloc.c (BFD_RELOC_PPC_16DX_HA): New.
* elf64-ppc.c (ppc64_elf_howto_raw <R_PPC64_16DX_HA>): New howto.
(ppc64_elf_reloc_type_lookup): Translate new bfd reloc.
(ppc64_elf_ha_reloc): Correct overflow test on REL16DX_HA.
(ppc64_elf_relocate_section): Likewise.
* elf32-ppc.c (ppc_elf_howto_raw <R_PPC_16DX_HA>): New howto.
(ppc_elf_reloc_type_lookup): Translate new bfd reloc.
(ppc_elf_check_relocs): Handle R_PPC_16DX_HA to pacify gcc.
* libbfd.h: Regenerate.
* bfd-in2.h: Regenerate.
2017-02-28 Alan Modra <amodra@gmail.com>
* elflink.c (_bfd_elf_create_dynamic_sections): Don't make

View File

@ -3362,6 +3362,7 @@ instruction. */
BFD_RELOC_PPC_VLE_SDAREL_HI16D,
BFD_RELOC_PPC_VLE_SDAREL_HA16A,
BFD_RELOC_PPC_VLE_SDAREL_HA16D,
BFD_RELOC_PPC_16DX_HA,
BFD_RELOC_PPC_REL16DX_HA,
BFD_RELOC_PPC64_HIGHER,
BFD_RELOC_PPC64_HIGHER_S,

View File

@ -1746,6 +1746,21 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
0x1fffc1, /* dst_mask */
TRUE), /* pcrel_offset */
/* A split-field reloc for addpcis, non-relative (gas internal use only). */
HOWTO (R_PPC_16DX_HA, /* type */
16, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
ppc_elf_addr16_ha_reloc, /* special_function */
"R_PPC_16DX_HA", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0x1fffc1, /* dst_mask */
FALSE), /* pcrel_offset */
/* GNU extension to record C++ vtable hierarchy. */
HOWTO (R_PPC_GNU_VTINHERIT, /* type */
0, /* rightshift */
@ -2002,6 +2017,7 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
case BFD_RELOC_LO16_PCREL: r = R_PPC_REL16_LO; break;
case BFD_RELOC_HI16_PCREL: r = R_PPC_REL16_HI; break;
case BFD_RELOC_HI16_S_PCREL: r = R_PPC_REL16_HA; break;
case BFD_RELOC_PPC_16DX_HA: r = R_PPC_16DX_HA; break;
case BFD_RELOC_PPC_REL16DX_HA: r = R_PPC_REL16DX_HA; break;
case BFD_RELOC_VTABLE_INHERIT: r = R_PPC_GNU_VTINHERIT; break;
case BFD_RELOC_VTABLE_ENTRY: r = R_PPC_GNU_VTENTRY; break;
@ -4351,6 +4367,7 @@ ppc_elf_check_relocs (bfd *abfd,
case R_PPC_RELAX:
case R_PPC_RELAX_PLT:
case R_PPC_RELAX_PLTREL24:
case R_PPC_16DX_HA:
break;
/* These should only appear in dynamic objects. */

View File

@ -2045,6 +2045,21 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
0x1fffc1, /* dst_mask */
TRUE), /* pcrel_offset */
/* A split-field reloc for addpcis, non-relative (gas internal use only). */
HOWTO (R_PPC64_16DX_HA, /* type */
16, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
ppc64_elf_ha_reloc, /* special_function */
"R_PPC64_16DX_HA", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0x1fffc1, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like R_PPC64_ADDR16_HI, but no overflow. */
HOWTO (R_PPC64_ADDR16_HIGH, /* type */
16, /* rightshift */
@ -2450,6 +2465,8 @@ ppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
break;
case BFD_RELOC_HI16_S_PCREL: r = R_PPC64_REL16_HA;
break;
case BFD_RELOC_PPC_16DX_HA: r = R_PPC64_16DX_HA;
break;
case BFD_RELOC_PPC_REL16DX_HA: r = R_PPC64_REL16DX_HA;
break;
case BFD_RELOC_PPC64_ENTRY: r = R_PPC64_ENTRY;
@ -2512,7 +2529,7 @@ ppc64_elf_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
enum elf_ppc64_reloc_type r_type;
long insn;
bfd_size_type octets;
bfd_vma value;
bfd_vma value, field;
/* If this is a relocatable link (output_bfd test tells us), just
call the generic function. Any adjustment will be done at final
@ -2538,14 +2555,14 @@ ppc64_elf_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
value -= (reloc_entry->address
+ input_section->output_offset
+ input_section->output_section->vma);
value = (bfd_signed_vma) value >> 16;
field = (bfd_signed_vma) value >> 16;
octets = reloc_entry->address * bfd_octets_per_byte (abfd);
insn = bfd_get_32 (abfd, (bfd_byte *) data + octets);
insn &= ~0x1fffc1;
insn |= (value & 0xffc1) | ((value & 0x3e) << 15);
insn |= (field & 0xffc1) | ((field & 0x3e) << 15);
bfd_put_32 (abfd, insn, (bfd_byte *) data + octets);
if (value + 0x8000 > 0xffff)
if (value + 0x80000000 > 0xffffffff)
return bfd_reloc_overflow;
return bfd_reloc_ok;
}
@ -15238,17 +15255,19 @@ ppc64_elf_relocate_section (bfd *output_bfd,
r = bfd_reloc_outofrange;
else
{
bfd_signed_vma field;
relocation += addend;
relocation -= (rel->r_offset
+ input_section->output_offset
+ input_section->output_section->vma);
relocation = (bfd_signed_vma) relocation >> 16;
field = (bfd_signed_vma) relocation >> 16;
insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
insn &= ~0x1fffc1;
insn |= (relocation & 0xffc1) | ((relocation & 0x3e) << 15);
insn |= (field & 0xffc1) | ((field & 0x3e) << 15);
bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
r = bfd_reloc_ok;
if (relocation + 0x8000 > 0xffff)
if (relocation + 0x80000000 > 0xffffffff)
r = bfd_reloc_overflow;
}
}

View File

@ -1397,6 +1397,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_RELOC_PPC_VLE_SDAREL_HI16D",
"BFD_RELOC_PPC_VLE_SDAREL_HA16A",
"BFD_RELOC_PPC_VLE_SDAREL_HA16D",
"BFD_RELOC_PPC_16DX_HA",
"BFD_RELOC_PPC_REL16DX_HA",
"BFD_RELOC_PPC64_HIGHER",
"BFD_RELOC_PPC64_HIGHER_S",

View File

@ -2900,6 +2900,8 @@ ENUMX
BFD_RELOC_PPC_VLE_SDAREL_HA16A
ENUMX
BFD_RELOC_PPC_VLE_SDAREL_HA16D
ENUMX
BFD_RELOC_PPC_16DX_HA
ENUMX
BFD_RELOC_PPC_REL16DX_HA
ENUMX

View File

@ -1,3 +1,13 @@
2017-02-28 Alan Modra <amodra@gmail.com>
* config/tc-ppc.c (md_assemble): Use BFD_RELOC_PPC_16DX_HA for addpcis.
(md_apply_fix): Remove fx_subsy check. Move code converting to
pcrel reloc earlier and handle BFD_RELOC_PPC_16DX_HA. Remove code
emiiting errors on seeing fx_pcrel set on unexpected relocs, as
that is done now by the generic code via..
* config/tc-ppc.h (TC_FORCE_RELOCATION_SUB_LOCAL): ..this. Define.
(TC_VALIDATE_FIX_SUB): Define.
2017-02-28 Maciej W. Rozycki <macro@imgtec.com>
* testsuite/gas/mips/jalr4.s: Add `jalr $0, $25' instructions.

View File

@ -3151,7 +3151,7 @@ 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)
@ -6566,10 +6566,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 +6691,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 +7119,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;

View File

@ -257,6 +257,22 @@ extern void ppc_elf_end (void);
extern int ppc_force_relocation (struct fix *);
#endif
#ifdef OBJ_ELF
/* Don't allow the generic code to convert fixups involving the
subtraction of a label in the current section to pc-relative if we
don't have the necessary pc-relative relocation. */
#define TC_FORCE_RELOCATION_SUB_LOCAL(FIX, SEG) \
(!((FIX)->fx_r_type == BFD_RELOC_LO16 \
|| (FIX)->fx_r_type == BFD_RELOC_HI16 \
|| (FIX)->fx_r_type == BFD_RELOC_HI16_S \
|| (FIX)->fx_r_type == BFD_RELOC_64 \
|| (FIX)->fx_r_type == BFD_RELOC_32 \
|| (FIX)->fx_r_type == BFD_RELOC_16 \
|| (FIX)->fx_r_type == BFD_RELOC_PPC_16DX_HA))
#endif
#define TC_VALIDATE_FIX_SUB(FIX, SEG) 0
/* call md_pcrel_from_section, not md_pcrel_from */
#define MD_PCREL_FROM_SECTION(FIX, SEC) md_pcrel_from_section(FIX, SEC)
extern long md_pcrel_from_section (struct fix *, segT);

View File

@ -1,3 +1,8 @@
2017-02-28 Alan Modra <amodra@gmail.com>
* elf/ppc64.h (R_PPC64_16DX_HA): New. Expand fake reloc comment.
* elf/ppc.h (R_PPC_16DX_HA): Likewise.
2017-02-24 Richard Sandiford <richard.sandiford@arm.com>
* opcode/aarch64.h (AARCH64_OPND_SVE_ADDR_RI_S4x16)

View File

@ -73,10 +73,14 @@ START_RELOC_NUMBERS (elf_ppc_reloc_type)
RELOC_NUMBER (R_PPC_ADDR30, 37)
#ifndef RELOC_MACROS_GEN_FUNC
/* Fake relocations for branch stubs, only used internally by ld. */
/* Relocations only used internally by ld. If you need to use these
reloc numbers, you can change them to some other unused value
without affecting the ABI. They will never appear in object files. */
RELOC_NUMBER (R_PPC_RELAX, 48)
RELOC_NUMBER (R_PPC_RELAX_PLT, 49)
RELOC_NUMBER (R_PPC_RELAX_PLTREL24, 50)
/* Reloc only used internally by gas. As above, value is unimportant. */
RELOC_NUMBER (R_PPC_16DX_HA, 51)
#endif
/* Relocs added to support TLS. */

View File

@ -155,8 +155,12 @@ START_RELOC_NUMBERS (elf_ppc64_reloc_type)
RELOC_NUMBER (R_PPC64_ENTRY, 118)
#ifndef RELOC_MACROS_GEN_FUNC
/* Fake relocation only used internally by ld. */
/* Relocation only used internally by ld. If you need to use these
reloc numbers, you can change them to some other unused value
without affecting the ABI. They will never appear in object files. */
RELOC_NUMBER (R_PPC64_LO_DS_OPT, 128)
/* Reloc only used internally by gas. As above, value is unimportant. */
RELOC_NUMBER (R_PPC64_16DX_HA, 129)
#endif
/* Power9 split rel16 for addpcis. */

View File

@ -1,3 +1,8 @@
2017-02-28 Alan Modra <amodra@gmail.com>
* testsuite/ld-powerpc/addpcis.d: Define ext1 and ext2 at
limits of addpcis range.
2017-02-28 Maciej W. Rozycki <macro@imgtec.com>
* testsuite/ld-mips-elf/jalr4.dd: Adjust for `jalr $0, $25'

View File

@ -1,6 +1,6 @@
#source: addpcis.s
#as: -a64 -mpower9
#ld: -melf64ppc -Ttext=0x10000000 --defsym ext1=0 --defsym ext2=0x8fff0000
#ld: -melf64ppc -Ttext=0x10000000 --defsym ext1=-0x70007ffc --defsym ext2=0x8fff800b
#objdump: -d -Mpower9
.*: file format .*
@ -8,10 +8,10 @@
Disassembly of section \.text:
0+10000000 <_start>:
10000000: (4c 60 f0 04|04 f0 60 4c) addpcis r3,-4096
10000004: (38 63 ff fc|fc ff 63 38) addi r3,r3,-4
10000000: (4c 60 80 04|04 80 60 4c) addpcis r3,-32768
10000004: (38 63 80 00|00 80 63 38) addi r3,r3,-32768
10000008: (4c 9f 7f c5|c5 7f 9f 4c) addpcis r4,32767
1000000c: (38 84 ff f4|f4 ff 84 38) addi r4,r4,-12
1000000c: (38 84 7f ff|ff 7f 84 38) addi r4,r4,32767
10000010: (4c a0 00 05|05 00 a0 4c) addpcis r5,1
10000014: (38 a5 80 00|00 80 a5 38) addi r5,r5,-32768
\.\.\.