R_PPC64_REL24_NOTOC support

R_PPC64_REL24_NOTOC is used on calls like "bl foo@notoc" to tell the
linker that linkage stubs for PLT calls or long branches can't use r2
for pic addressing.  Instead, new stubs that generate pc-relative
addresses are used.  One complication is that pc-relative offsets to
the PLT may need to be 64-bit in large programs, in contrast to the
toc-relative addressing used by older PLT linkage stubs where a 32-bit
offset is sufficient until the PLT itself exceeds 2G in size.

.eh_frame info to cover the _notoc stubs is yet to be implemented.

bfd/
	* elf64-ppc.c (ADDI_R12_R11, ADDI_R12_R12, LIS_R12),
	(ADDIS_R12_R11, ORIS_R12_R12_0, ORI_R12_R12_0),
	(SLDI_R12_R12_32, LDX_R12_R11_R12, ADD_R12_R11_R12): Define.
	(ppc64_elf_howto_raw): Add R_PPC64_REL24_NOTOC entry.
	(ppc64_elf_reloc_type_lookup): Support R_PPC64_REL24_NOTOC.
	(ppc_stub_type): Add ppc_stub_long_branch_notoc,
	ppc_stub_long_branch_both, ppc_stub_plt_branch_notoc,
	ppc_stub_plt_branch_both, ppc_stub_plt_call_notoc, and
	ppc_stub_plt_call_both.
	(is_branch_reloc): Add R_PPC64_REL24_NOTOC.
	(build_offset, size_offset): New functions.
	(plt_stub_size): Support plt_call_notoc and plt_call_both.
	(ppc_build_one_stub, ppc_size_one_stub): Support new stubs.
	(toc_adjusting_stub_needed): Handle R_PPC64_REL24_NOTOC.
	(ppc64_elf_size_stubs): Likewise, and new stubs.
	(ppc64_elf_build_stubs, ppc64_elf_relocate_section): Likewise.
	* reloc.c: Add BFD_RELOC_PPC64_REL24_NOTOC.
	* bfd-in2.h: Regenerate.
	* libbfd.h: Regenerate.
gas/
	* config/tc-ppc.c (ppc_elf_suffix): Support @notoc.
	(ppc_force_relocation, ppc_fix_adjustable): Handle REL24_NOTOC.
ld/
	* testsuite/ld-powerpc/ext.d,
	* testsuite/ld-powerpc/ext.s,
	* testsuite/ld-powerpc/ext.lnk,
	* testsuite/ld-powerpc/notoc.d,
	* testsuite/ld-powerpc/notoc.s: New tests.
	* testsuite/ld-powerpc/powerpc.exp: Run them.
This commit is contained in:
Alan Modra 2018-08-03 16:41:22 +09:30
parent 3f6ff4799b
commit 05d0e962f0
14 changed files with 817 additions and 126 deletions

View File

@ -1,3 +1,25 @@
2018-08-05 Alan Modra <amodra@gmail.com>
* elf64-ppc.c (ADDI_R12_R11, ADDI_R12_R12, LIS_R12),
(ADDIS_R12_R11, ORIS_R12_R12_0, ORI_R12_R12_0),
(SLDI_R12_R12_32, LDX_R12_R11_R12, ADD_R12_R11_R12): Define.
(ppc64_elf_howto_raw): Add R_PPC64_REL24_NOTOC entry.
(ppc64_elf_reloc_type_lookup): Support R_PPC64_REL24_NOTOC.
(ppc_stub_type): Add ppc_stub_long_branch_notoc,
ppc_stub_long_branch_both, ppc_stub_plt_branch_notoc,
ppc_stub_plt_branch_both, ppc_stub_plt_call_notoc, and
ppc_stub_plt_call_both.
(is_branch_reloc): Add R_PPC64_REL24_NOTOC.
(build_offset, size_offset): New functions.
(plt_stub_size): Support plt_call_notoc and plt_call_both.
(ppc_build_one_stub, ppc_size_one_stub): Support new stubs.
(toc_adjusting_stub_needed): Handle R_PPC64_REL24_NOTOC.
(ppc64_elf_size_stubs): Likewise, and new stubs.
(ppc64_elf_build_stubs, ppc64_elf_relocate_section): Likewise.
* reloc.c: Add BFD_RELOC_PPC64_REL24_NOTOC.
* bfd-in2.h: Regenerate.
* libbfd.h: Regenerate.
2018-08-05 Alan Modra <amodra@gmail.com> 2018-08-05 Alan Modra <amodra@gmail.com>
* elf64-ppc.c (ppc_build_one_stub): Lose "_r2off" in stub symbols. * elf64-ppc.c (ppc_build_one_stub): Lose "_r2off" in stub symbols.

View File

@ -3457,6 +3457,7 @@ instruction. */
BFD_RELOC_PPC64_ADDR16_HIGHA, BFD_RELOC_PPC64_ADDR16_HIGHA,
BFD_RELOC_PPC64_ADDR64_LOCAL, BFD_RELOC_PPC64_ADDR64_LOCAL,
BFD_RELOC_PPC64_ENTRY, BFD_RELOC_PPC64_ENTRY,
BFD_RELOC_PPC64_REL24_NOTOC,
/* PowerPC and PowerPC64 thread-local storage relocations. */ /* PowerPC and PowerPC64 thread-local storage relocations. */
BFD_RELOC_PPC_TLS, BFD_RELOC_PPC_TLS,

View File

@ -164,6 +164,8 @@ static bfd_vma opd_entry_value
#define BCTR 0x4e800420 /* bctr */ #define BCTR 0x4e800420 /* bctr */
#define ADDI_R11_R11 0x396b0000 /* addi %r11,%r11,off@l */ #define ADDI_R11_R11 0x396b0000 /* addi %r11,%r11,off@l */
#define ADDI_R12_R11 0x398b0000 /* addi %r12,%r11,off@l */
#define ADDI_R12_R12 0x398c0000 /* addi %r12,%r12,off@l */
#define ADDIS_R2_R2 0x3c420000 /* addis %r2,%r2,off@ha */ #define ADDIS_R2_R2 0x3c420000 /* addis %r2,%r2,off@ha */
#define ADDI_R2_R2 0x38420000 /* addi %r2,%r2,off@l */ #define ADDI_R2_R2 0x38420000 /* addi %r2,%r2,off@l */
@ -184,10 +186,17 @@ static bfd_vma opd_entry_value
#define ADD_R2_R2_R12 0x7c426214 /* add %r2,%r2,%r12 */ #define ADD_R2_R2_R12 0x7c426214 /* add %r2,%r2,%r12 */
#define LIS_R2 0x3c400000 /* lis %r2,xxx@ha */ #define LIS_R2 0x3c400000 /* lis %r2,xxx@ha */
#define LIS_R12 0x3d800000 /* lis %r12,xxx@ha */
#define ADDIS_R2_R12 0x3c4c0000 /* addis %r2,%r12,xxx@ha */ #define ADDIS_R2_R12 0x3c4c0000 /* addis %r2,%r12,xxx@ha */
#define ADDIS_R12_R2 0x3d820000 /* addis %r12,%r2,xxx@ha */ #define ADDIS_R12_R2 0x3d820000 /* addis %r12,%r2,xxx@ha */
#define ADDIS_R12_R11 0x3d8b0000 /* addis %r12,%r11,xxx@ha */
#define ADDIS_R12_R12 0x3d8c0000 /* addis %r12,%r12,xxx@ha */ #define ADDIS_R12_R12 0x3d8c0000 /* addis %r12,%r12,xxx@ha */
#define ORIS_R12_R12_0 0x658c0000 /* oris %r12,%r12,xxx@hi */
#define ORI_R12_R12_0 0x618c0000 /* ori %r12,%r12,xxx@l */
#define LD_R12_0R12 0xe98c0000 /* ld %r12,xxx@l(%r12) */ #define LD_R12_0R12 0xe98c0000 /* ld %r12,xxx@l(%r12) */
#define SLDI_R12_R12_32 0x799c07c6 /* sldi %r12,%r12,32 */
#define LDX_R12_R11_R12 0x7d8b602a /* ldx %r12,%r11,%r12 */
#define ADD_R12_R11_R12 0x7d8b6214 /* add %r12,%r11,%r12 */
/* __glink_PLTresolve stub instructions. We enter with the index in R0. */ /* __glink_PLTresolve stub instructions. We enter with the index in R0. */
#define GLINK_PLTRESOLVE_SIZE(htab) \ #define GLINK_PLTRESOLVE_SIZE(htab) \
@ -446,6 +455,21 @@ static reloc_howto_type ppc64_elf_howto_raw[] =
0x03fffffc, /* dst_mask */ 0x03fffffc, /* dst_mask */
TRUE), /* pcrel_offset */ TRUE), /* pcrel_offset */
/* A variant of R_PPC64_REL24, used when r2 is not the toc pointer. */
HOWTO (R_PPC64_REL24_NOTOC, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
26, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
ppc64_elf_branch_reloc, /* special_function */
"R_PPC64_REL24_NOTOC", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0x03fffffc, /* dst_mask */
TRUE), /* pcrel_offset */
/* A relative 16 bit branch; the lower two bits must be zero. */ /* A relative 16 bit branch; the lower two bits must be zero. */
HOWTO (R_PPC64_REL14, /* type */ HOWTO (R_PPC64_REL14, /* type */
0, /* rightshift */ 0, /* rightshift */
@ -2308,6 +2332,8 @@ ppc64_elf_reloc_type_lookup (bfd *abfd,
break; break;
case BFD_RELOC_PPC_B26: r = R_PPC64_REL24; case BFD_RELOC_PPC_B26: r = R_PPC64_REL24;
break; break;
case BFD_RELOC_PPC64_REL24_NOTOC: r = R_PPC64_REL24_NOTOC;
break;
case BFD_RELOC_PPC_B16: r = R_PPC64_REL14; case BFD_RELOC_PPC_B16: r = R_PPC64_REL14;
break; break;
case BFD_RELOC_PPC_B16_BRTAKEN: r = R_PPC64_REL14_BRTAKEN; case BFD_RELOC_PPC_B16_BRTAKEN: r = R_PPC64_REL14_BRTAKEN;
@ -3954,7 +3980,7 @@ must_be_dyn_reloc (struct bfd_link_info *info,
Used to call a function in a shared library. If it so happens that Used to call a function in a shared library. If it so happens that
the plt entry referenced crosses a 64k boundary, then an extra the plt entry referenced crosses a 64k boundary, then an extra
"addi %r11,%r11,xxx@toc@l" will be inserted before the "mtctr". "addi %r11,%r11,xxx@toc@l" will be inserted before the "mtctr".
. std %r2,40(%r1) ppc_stub_plt_call_r2save starts with "std %r2,40(%r1)".
. addis %r11,%r2,xxx@toc@ha . addis %r11,%r2,xxx@toc@ha
. ld %r12,xxx+0@toc@l(%r11) . ld %r12,xxx+0@toc@l(%r11)
. mtctr %r12 . mtctr %r12
@ -3979,18 +4005,98 @@ must_be_dyn_reloc (struct bfd_link_info *info,
. mtctr %r12 . mtctr %r12
. bctr . bctr
In cases where the "addis" instruction would add zero, the "addis" is All of the above stubs are shown as their ELFv1 variants. ELFv2
omitted and following instructions modified slightly in some cases. variants exist too, simpler for plt calls since a new toc pointer
*/ and static chain are not loaded by the stub. In addition, ELFv2
has some more complex stubs to handle calls marked with NOTOC
relocs from functions where r2 is not a valid toc pointer. These
come in two flavours, the ones shown below, and _both variants that
start with "std %r2,24(%r1)" to save r2 in the unlikely event that
one call is from a function where r2 is used as the toc pointer but
needs a toc adjusting stub for small-model multi-toc, and another
call is from a function where r2 is not valid.
ppc_stub_long_branch_notoc:
. mflr %r12
. bcl 20,31,1f
. 1:
. mflr %r11
. mtlr %r12
. lis %r12,xxx-1b@highest
. ori %r12,xxx-1b@higher
. sldi %r12,%r12,32
. oris %r12,%r12,xxx-1b@hi
. ori %r12,%r12,xxx-1b@l
. add %r12,%r11,%r12
. b dest
ppc_stub_plt_branch_notoc:
. mflr %r12
. bcl 20,31,1f
. 1:
. mflr %r11
. mtlr %r12
. lis %r12,xxx-1b@highest
. ori %r12,xxx-1b@higher
. sldi %r12,%r12,32
. oris %r12,%r12,xxx-1b@hi
. ori %r12,%r12,xxx-1b@l
. add %r12,%r11,%r12
. mtctr %r12
. bctr
ppc_stub_plt_call_notoc:
. mflr %r12
. bcl 20,31,1f
. 1:
. mflr %r11
. mtlr %r12
. lis %r12,xxx-1b@highest
. ori %r12,xxx-1b@higher
. sldi %r12,%r12,32
. oris %r12,%r12,xxx-1b@hi
. ori %r12,%r12,xxx-1b@l
. ldx %r12,%r11,%r12
. mtctr %r12
. bctr
In cases where the high instructions would add zero, they are
omitted and following instructions modified in some cases.
For a given stub group (a set of sections all using the same toc
pointer value) there will be just one stub type used for any
particular function symbol. For example, if printf is called from
code with the tocsave optimization (ie. r2 saved in function
prologue) and therefore calls use a ppc_stub_plt_call linkage stub,
and from other code without the tocsave optimization requiring a
ppc_stub_plt_call_r2save linkage stub, a single stub of the latter
type will be created. Calls with the tocsave optimization will
enter this stub after the instruction saving r2. A similar
situation exists when calls are marked with R_PPC64_REL24_NOTOC
relocations. These require a ppc_stub_plt_call_notoc linkage stub
to call an external function like printf. If other calls to printf
require a ppc_stub_plt_call linkage stub then a single
ppc_stub_plt_call_notoc linkage stub will be used for both types of
call. If other calls to printf require a ppc_stub_plt_call_r2save
linkage stub then a single ppc_stub_plt_call_both linkage stub will
be created and calls not requiring r2 to be saved will enter the
stub after the r2 save instruction. There is an analogous
hierarchy of long branch and plt branch stubs for local call
linkage. */
enum ppc_stub_type { enum ppc_stub_type {
ppc_stub_none, ppc_stub_none,
ppc_stub_long_branch, ppc_stub_long_branch,
ppc_stub_long_branch_r2off, ppc_stub_long_branch_r2off,
ppc_stub_long_branch_notoc,
ppc_stub_long_branch_both, /* r2off and notoc variants both needed. */
ppc_stub_plt_branch, ppc_stub_plt_branch,
ppc_stub_plt_branch_r2off, ppc_stub_plt_branch_r2off,
ppc_stub_plt_branch_notoc,
ppc_stub_plt_branch_both,
ppc_stub_plt_call, ppc_stub_plt_call,
ppc_stub_plt_call_r2save, ppc_stub_plt_call_r2save,
ppc_stub_plt_call_notoc,
ppc_stub_plt_call_both,
ppc_stub_global_entry, ppc_stub_global_entry,
ppc_stub_save_res ppc_stub_save_res
}; };
@ -5478,6 +5584,7 @@ static bfd_boolean
is_branch_reloc (enum elf_ppc64_reloc_type r_type) is_branch_reloc (enum elf_ppc64_reloc_type r_type)
{ {
return (r_type == R_PPC64_REL24 return (r_type == R_PPC64_REL24
|| r_type == R_PPC64_REL24_NOTOC
|| r_type == R_PPC64_REL14 || r_type == R_PPC64_REL14
|| r_type == R_PPC64_REL14_BRTAKEN || r_type == R_PPC64_REL14_BRTAKEN
|| r_type == R_PPC64_REL14_BRNTAKEN || r_type == R_PPC64_REL14_BRNTAKEN
@ -5848,6 +5955,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
/* Fall through. */ /* Fall through. */
case R_PPC64_REL24: case R_PPC64_REL24:
case R_PPC64_REL24_NOTOC:
rel24: rel24:
plt_list = ifunc; plt_list = ifunc;
if (h != NULL) if (h != NULL)
@ -10757,6 +10865,106 @@ ppc_type_of_stub (asection *input_sec,
return ppc_stub_none; return ppc_stub_none;
} }
/* Builds a 64-bit offset in r12 then adds it to r11 (LOAD false) or
loads r12 from r11+r12 (LOAD true).
. lis %r12,xxx-1b@highest
. ori %r12,xxx-1b@higher
. sldi %r12,%r12,32
. oris %r12,%r12,xxx-1b@hi
. ori %r12,%r12,xxx-1b@l
. add %r12,%r11,%r12 */
static bfd_byte *
build_offset (bfd *abfd, bfd_byte *p, bfd_vma off, bfd_boolean load)
{
if (off + 0x8000 < 0x10000)
{
if (load)
bfd_put_32 (abfd, LD_R12_0R11 + PPC_LO (off), p);
else
bfd_put_32 (abfd, ADDI_R12_R11 + PPC_LO (off), p);
p += 4;
}
else if (off + 0x80008000ULL < 0x100000000ULL)
{
bfd_put_32 (abfd, ADDIS_R12_R11 + PPC_HA (off), p);
p += 4;
if (load)
bfd_put_32 (abfd, LD_R12_0R12 + PPC_LO (off), p);
else
bfd_put_32 (abfd, ADDI_R12_R12 + PPC_LO (off), p);
p += 4;
}
else
{
if (off + 0x800000000000ULL < 0x1000000000000ULL)
{
bfd_put_32 (abfd, LI_R12_0 + ((off >> 32) & 0xffff), p);
p += 4;
}
else
{
bfd_put_32 (abfd, LIS_R12 + ((off >> 48) & 0xffff), p);
p += 4;
if (((off >> 32) & 0xffff) != 0)
{
bfd_put_32 (abfd, ORI_R12_R12_0 + ((off >> 32) & 0xffff), p);
p += 4;
}
}
if (((off >> 32) & 0xffffffffULL) != 0)
{
bfd_put_32 (abfd, SLDI_R12_R12_32, p);
p += 4;
}
if (PPC_HI (off) != 0)
{
bfd_put_32 (abfd, ORIS_R12_R12_0 + PPC_HI (off), p);
p += 4;
}
if (PPC_LO (off) != 0)
{
bfd_put_32 (abfd, ORI_R12_R12_0 + PPC_LO (off), p);
p += 4;
}
if (load)
bfd_put_32 (abfd, LDX_R12_R11_R12, p);
else
bfd_put_32 (abfd, ADD_R12_R11_R12, p);
p += 4;
}
return p;
}
static unsigned int
size_offset (bfd_vma off)
{
unsigned int size;
if (off + 0x8000 < 0x10000)
size = 4;
else if (off + 0x80008000ULL < 0x100000000ULL)
size = 8;
else
{
if (off + 0x800000000000ULL < 0x1000000000000ULL)
size = 4;
else
{
size = 4;
if (((off >> 32) & 0xffff) != 0)
size += 4;
}
if (((off >> 32) & 0xffffffffULL) != 0)
size += 4;
if (PPC_HI (off) != 0)
size += 4;
if (PPC_LO (off) != 0)
size += 4;
size += 4;
}
return size;
}
/* With power7 weakly ordered memory model, it is possible for ld.so /* With power7 weakly ordered memory model, it is possible for ld.so
to update a plt entry in one thread and have another thread see a to update a plt entry in one thread and have another thread see a
stale zero toc entry. To avoid this we need some sort of acquire stale zero toc entry. To avoid this we need some sort of acquire
@ -10784,8 +10992,17 @@ plt_stub_size (struct ppc_link_hash_table *htab,
struct ppc_stub_hash_entry *stub_entry, struct ppc_stub_hash_entry *stub_entry,
bfd_vma off) bfd_vma off)
{ {
unsigned size = 12; unsigned size;
if (stub_entry->stub_type >= ppc_stub_plt_call_notoc)
{
size = 24 + size_offset (off);
if (stub_entry->stub_type > ppc_stub_plt_call_notoc)
size += 4;
return size;
}
size = 12;
if (ALWAYS_EMIT_R2SAVE if (ALWAYS_EMIT_R2SAVE
|| stub_entry->stub_type == ppc_stub_plt_call_r2save) || stub_entry->stub_type == ppc_stub_plt_call_r2save)
size += 4; size += 4;
@ -11422,6 +11639,78 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
p += 4; p += 4;
break; break;
case ppc_stub_long_branch_notoc:
case ppc_stub_long_branch_both:
case ppc_stub_plt_branch_notoc:
case ppc_stub_plt_branch_both:
case ppc_stub_plt_call_notoc:
case ppc_stub_plt_call_both:
p = loc;
off = (8 + stub_entry->stub_offset
+ stub_entry->group->stub_sec->output_offset
+ stub_entry->group->stub_sec->output_section->vma);
if (stub_entry->stub_type == ppc_stub_long_branch_both
|| stub_entry->stub_type == ppc_stub_plt_branch_both
|| stub_entry->stub_type == ppc_stub_plt_call_both)
{
off += 4;
bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), p);
p += 4;
}
if (stub_entry->stub_type >= ppc_stub_plt_call_notoc)
{
targ = stub_entry->plt_ent->plt.offset & ~1;
if (targ >= (bfd_vma) -2)
abort ();
plt = htab->elf.splt;
if (!htab->elf.dynamic_sections_created
|| stub_entry->h == NULL
|| stub_entry->h->elf.dynindx == -1)
{
if (stub_entry->symtype == STT_GNU_IFUNC)
plt = htab->elf.iplt;
else
plt = htab->pltlocal;
}
targ += plt->output_offset + plt->output_section->vma;
}
else
targ = (stub_entry->target_value
+ stub_entry->target_section->output_offset
+ stub_entry->target_section->output_section->vma);
off = targ - off;
bfd_put_32 (htab->params->stub_bfd, MFLR_R12, p);
p += 4;
bfd_put_32 (htab->params->stub_bfd, BCL_20_31, p);
p += 4;
bfd_put_32 (htab->params->stub_bfd, MFLR_R11, p);
p += 4;
bfd_put_32 (htab->params->stub_bfd, MTLR_R12, p);
p += 4;
p = build_offset (htab->params->stub_bfd, p, off,
stub_entry->stub_type >= ppc_stub_plt_call_notoc);
if (stub_entry->stub_type == ppc_stub_long_branch_notoc)
{
off += 8;
bfd_put_32 (htab->params->stub_bfd,
B_DOT | ((off - (p - loc)) & 0x3fffffc), p);
}
else if (stub_entry->stub_type == ppc_stub_long_branch_both)
{
off += 12;
bfd_put_32 (htab->params->stub_bfd,
B_DOT | ((off - (p - loc)) & 0x3fffffc), p);
}
else
{
bfd_put_32 (htab->params->stub_bfd, MTCTR_R12, p);
p += 4;
bfd_put_32 (htab->params->stub_bfd, BCTR, p);
}
p += 4;
break;
case ppc_stub_plt_call: case ppc_stub_plt_call:
case ppc_stub_plt_call_r2save: case ppc_stub_plt_call_r2save:
if (stub_entry->h != NULL if (stub_entry->h != NULL
@ -11513,9 +11802,15 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
size_t len1, len2; size_t len1, len2;
char *name; char *name;
const char *const stub_str[] = { "long_branch", const char *const stub_str[] = { "long_branch",
"long_branch",
"long_branch",
"long_branch", "long_branch",
"plt_branch", "plt_branch",
"plt_branch", "plt_branch",
"plt_branch",
"plt_branch",
"plt_call",
"plt_call",
"plt_call", "plt_call",
"plt_call" }; "plt_call" };
@ -11583,8 +11878,8 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
return TRUE; return TRUE;
} }
if (stub_entry->stub_type == ppc_stub_plt_call if (stub_entry->stub_type >= ppc_stub_plt_call
|| stub_entry->stub_type == ppc_stub_plt_call_r2save) && stub_entry->stub_type <= ppc_stub_plt_call_both)
{ {
asection *plt; asection *plt;
targ = stub_entry->plt_ent->plt.offset & ~(bfd_vma) 1; targ = stub_entry->plt_ent->plt.offset & ~(bfd_vma) 1;
@ -11602,38 +11897,52 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
} }
targ += plt->output_offset + plt->output_section->vma; targ += plt->output_offset + plt->output_section->vma;
off = (elf_gp (info->output_bfd) if (stub_entry->stub_type >= ppc_stub_plt_call_notoc)
+ htab->sec_info[stub_entry->group->link_sec->id].toc_off); {
off = targ - off; off = (8 + stub_entry->stub_offset
+ stub_entry->group->stub_sec->output_offset
+ stub_entry->group->stub_sec->output_section->vma);
if (stub_entry->stub_type > ppc_stub_plt_call_notoc)
off += 4;
}
else
off = (elf_gp (info->output_bfd)
+ htab->sec_info[stub_entry->group->link_sec->id].toc_off);
if (htab->params->plt_stub_align != 0) if (htab->params->plt_stub_align != 0)
{ {
unsigned pad = plt_stub_pad (htab, stub_entry, off); unsigned pad = plt_stub_pad (htab, stub_entry, targ - off);
stub_entry->group->stub_sec->size += pad; stub_entry->group->stub_sec->size += pad;
stub_entry->stub_offset = stub_entry->group->stub_sec->size; stub_entry->stub_offset = stub_entry->group->stub_sec->size;
if (stub_entry->stub_type >= ppc_stub_plt_call_notoc)
off += pad;
} }
off = targ - off;
size = plt_stub_size (htab, stub_entry, off); size = plt_stub_size (htab, stub_entry, off);
if (stub_entry->h != NULL if (stub_entry->stub_type < ppc_stub_plt_call_notoc)
&& (stub_entry->h == htab->tls_get_addr_fd
|| stub_entry->h == htab->tls_get_addr)
&& htab->params->tls_get_addr_opt
&& (ALWAYS_EMIT_R2SAVE
|| stub_entry->stub_type == ppc_stub_plt_call_r2save))
stub_entry->group->tls_get_addr_opt_bctrl
= stub_entry->stub_offset + size - 5 * 4;
if (info->emitrelocations)
{ {
stub_entry->group->stub_sec->reloc_count if (stub_entry->h != NULL
+= ((PPC_HA (off) != 0) && (stub_entry->h == htab->tls_get_addr_fd
+ (htab->opd_abi || stub_entry->h == htab->tls_get_addr)
? 2 + (htab->params->plt_static_chain && htab->params->tls_get_addr_opt
&& PPC_HA (off + 16) == PPC_HA (off)) && (ALWAYS_EMIT_R2SAVE
: 1)); || stub_entry->stub_type == ppc_stub_plt_call_r2save))
stub_entry->group->stub_sec->flags |= SEC_RELOC; stub_entry->group->tls_get_addr_opt_bctrl
= stub_entry->stub_offset + size - 5 * 4;
if (info->emitrelocations)
{
stub_entry->group->stub_sec->reloc_count
+= ((PPC_HA (off) != 0)
+ (htab->opd_abi
? 2 + (htab->params->plt_static_chain
&& PPC_HA (off + 16) == PPC_HA (off))
: 1));
stub_entry->group->stub_sec->flags |= SEC_RELOC;
}
} }
} }
else else
@ -11671,82 +11980,102 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
size += 4; size += 4;
off += size - 4; off += size - 4;
} }
else if (stub_entry->stub_type >= ppc_stub_long_branch_notoc)
{
size = 20 + size_offset (targ - (off + 8));
if (stub_entry->stub_type > ppc_stub_long_branch_notoc)
size += 4;
off += size - 4;
}
off = targ - off; off = targ - off;
local_off = PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other); if (stub_entry->stub_type >= ppc_stub_long_branch_notoc)
/* If the branch offset is too big, use a ppc_stub_plt_branch.
Do the same for -R objects without function descriptors. */
if (off + (1 << 25) >= (bfd_vma) (1 << 26) - local_off
|| (stub_entry->stub_type == ppc_stub_long_branch_r2off
&& r2off == 0
&& htab->sec_info[stub_entry->target_section->id].toc_off == 0))
{ {
struct ppc_branch_hash_entry *br_entry; if (off + (1 << 25) >= (bfd_vma) (1 << 26))
br_entry = ppc_branch_hash_lookup (&htab->branch_hash_table,
stub_entry->root.string + 9,
TRUE, FALSE);
if (br_entry == NULL)
{ {
_bfd_error_handler (_("can't build branch stub `%s'"), stub_entry->stub_type += (ppc_stub_plt_branch_notoc
stub_entry->root.string); - ppc_stub_long_branch_notoc);
htab->stub_error = TRUE; size += 4;
return FALSE;
}
if (br_entry->iter != htab->stub_iteration)
{
br_entry->iter = htab->stub_iteration;
br_entry->offset = htab->brlt->size;
htab->brlt->size += 8;
if (htab->relbrlt != NULL)
htab->relbrlt->size += sizeof (Elf64_External_Rela);
else if (info->emitrelocations)
{
htab->brlt->reloc_count += 1;
htab->brlt->flags |= SEC_RELOC;
}
}
stub_entry->stub_type += ppc_stub_plt_branch - ppc_stub_long_branch;
targ = (br_entry->offset
+ htab->brlt->output_offset
+ htab->brlt->output_section->vma);
off = (elf_gp (info->output_bfd)
+ htab->sec_info[stub_entry->group->link_sec->id].toc_off);
off = targ - off;
if (info->emitrelocations)
{
stub_entry->group->stub_sec->reloc_count
+= 1 + (PPC_HA (off) != 0);
stub_entry->group->stub_sec->flags |= SEC_RELOC;
}
if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
{
size = 12;
if (PPC_HA (off) != 0)
size = 16;
}
else
{
size = 16;
if (PPC_HA (off) != 0)
size += 4;
if (PPC_HA (r2off) != 0)
size += 4;
if (PPC_LO (r2off) != 0)
size += 4;
} }
} }
else if (info->emitrelocations) else
{ {
stub_entry->group->stub_sec->reloc_count += 1; local_off = PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other);
stub_entry->group->stub_sec->flags |= SEC_RELOC;
/* If the branch offset is too big, use a ppc_stub_plt_branch.
Do the same for -R objects without function descriptors. */
if ((stub_entry->stub_type == ppc_stub_long_branch_r2off
&& r2off == 0
&& htab->sec_info[stub_entry->target_section->id].toc_off == 0)
|| off + (1 << 25) >= (bfd_vma) (1 << 26) - local_off)
{
struct ppc_branch_hash_entry *br_entry;
br_entry = ppc_branch_hash_lookup (&htab->branch_hash_table,
stub_entry->root.string + 9,
TRUE, FALSE);
if (br_entry == NULL)
{
_bfd_error_handler (_("can't build branch stub `%s'"),
stub_entry->root.string);
htab->stub_error = TRUE;
return FALSE;
}
if (br_entry->iter != htab->stub_iteration)
{
br_entry->iter = htab->stub_iteration;
br_entry->offset = htab->brlt->size;
htab->brlt->size += 8;
if (htab->relbrlt != NULL)
htab->relbrlt->size += sizeof (Elf64_External_Rela);
else if (info->emitrelocations)
{
htab->brlt->reloc_count += 1;
htab->brlt->flags |= SEC_RELOC;
}
}
targ = (br_entry->offset
+ htab->brlt->output_offset
+ htab->brlt->output_section->vma);
off = (elf_gp (info->output_bfd)
+ htab->sec_info[stub_entry->group->link_sec->id].toc_off);
off = targ - off;
if (info->emitrelocations)
{
stub_entry->group->stub_sec->reloc_count
+= 1 + (PPC_HA (off) != 0);
stub_entry->group->stub_sec->flags |= SEC_RELOC;
}
stub_entry->stub_type
+= ppc_stub_plt_branch - ppc_stub_long_branch;
if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
{
size = 12;
if (PPC_HA (off) != 0)
size = 16;
}
else
{
size = 16;
if (PPC_HA (off) != 0)
size += 4;
if (PPC_HA (r2off) != 0)
size += 4;
if (PPC_LO (r2off) != 0)
size += 4;
}
}
else if (info->emitrelocations)
{
stub_entry->group->stub_sec->reloc_count += 1;
stub_entry->group->stub_sec->flags |= SEC_RELOC;
}
} }
} }
@ -12154,6 +12483,7 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
r_type = ELF64_R_TYPE (rel->r_info); r_type = ELF64_R_TYPE (rel->r_info);
if (r_type != R_PPC64_REL24 if (r_type != R_PPC64_REL24
&& r_type != R_PPC64_REL24_NOTOC
&& r_type != R_PPC64_REL14 && r_type != R_PPC64_REL14
&& r_type != R_PPC64_REL14_BRTAKEN && r_type != R_PPC64_REL14_BRTAKEN
&& r_type != R_PPC64_REL14_BRNTAKEN && r_type != R_PPC64_REL14_BRNTAKEN
@ -12750,6 +13080,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
/* Only look for stubs on branch instructions. */ /* Only look for stubs on branch instructions. */
if (r_type != R_PPC64_REL24 if (r_type != R_PPC64_REL24
&& r_type != R_PPC64_REL24_NOTOC
&& r_type != R_PPC64_REL14 && r_type != R_PPC64_REL14
&& r_type != R_PPC64_REL14_BRTAKEN && r_type != R_PPC64_REL14_BRTAKEN
&& r_type != R_PPC64_REL14_BRNTAKEN) && r_type != R_PPC64_REL14_BRNTAKEN)
@ -12857,7 +13188,19 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
&plt_ent, destination, &plt_ent, destination,
local_off); local_off);
if (stub_type != ppc_stub_plt_call) if (r_type == R_PPC64_REL24_NOTOC)
{
if (stub_type == ppc_stub_plt_call)
stub_type = ppc_stub_plt_call_notoc;
else if (stub_type == ppc_stub_long_branch
|| (code_sec != NULL
&& code_sec->output_section != NULL
&& (((hash ? hash->elf.other : sym->st_other)
& STO_PPC64_LOCAL_MASK)
!= 1 << STO_PPC64_LOCAL_BIT)))
stub_type = ppc_stub_long_branch_notoc;
}
else if (stub_type != ppc_stub_plt_call)
{ {
/* Check whether we need a TOC adjusting stub. /* Check whether we need a TOC adjusting stub.
Since the linker pastes together pieces from Since the linker pastes together pieces from
@ -12882,6 +13225,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
/* __tls_get_addr calls might be eliminated. */ /* __tls_get_addr calls might be eliminated. */
if (stub_type != ppc_stub_plt_call if (stub_type != ppc_stub_plt_call
&& stub_type != ppc_stub_plt_call_notoc
&& hash != NULL && hash != NULL
&& (hash == htab->tls_get_addr && (hash == htab->tls_get_addr
|| hash == htab->tls_get_addr_fd) || hash == htab->tls_get_addr_fd)
@ -12929,9 +13273,71 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
stub_name, FALSE, FALSE); stub_name, FALSE, FALSE);
if (stub_entry != NULL) if (stub_entry != NULL)
{ {
/* The proper stub has already been created. */ enum ppc_stub_type old_type;
/* A stub has already been created, but it may
not be the required type. We shouldn't be
transitioning from plt_call to long_branch
stubs or vice versa, but we might be
upgrading from plt_call to plt_call_r2save or
from long_branch to long_branch_r2off. */
free (stub_name); free (stub_name);
if (stub_type == ppc_stub_plt_call_r2save) old_type = stub_entry->stub_type;
switch (old_type)
{
default:
abort ();
case ppc_stub_save_res:
continue;
case ppc_stub_plt_call:
case ppc_stub_plt_call_r2save:
case ppc_stub_plt_call_notoc:
case ppc_stub_plt_call_both:
if (stub_type == ppc_stub_plt_call)
continue;
else if (stub_type == ppc_stub_plt_call_r2save)
{
if (old_type == ppc_stub_plt_call_notoc)
stub_type = ppc_stub_plt_call_both;
}
else if (stub_type == ppc_stub_plt_call_notoc)
{
if (old_type == ppc_stub_plt_call_r2save)
stub_type = ppc_stub_plt_call_both;
}
else
abort ();
break;
case ppc_stub_plt_branch:
case ppc_stub_plt_branch_r2off:
case ppc_stub_plt_branch_notoc:
case ppc_stub_plt_branch_both:
old_type += (ppc_stub_long_branch
- ppc_stub_plt_branch);
/* Fall through. */
case ppc_stub_long_branch:
case ppc_stub_long_branch_r2off:
case ppc_stub_long_branch_notoc:
case ppc_stub_long_branch_both:
if (stub_type == ppc_stub_long_branch)
continue;
else if (stub_type == ppc_stub_long_branch_r2off)
{
if (old_type == ppc_stub_long_branch_notoc)
stub_type = ppc_stub_long_branch_both;
}
else if (stub_type == ppc_stub_long_branch_notoc)
{
if (old_type == ppc_stub_long_branch_r2off)
stub_type = ppc_stub_long_branch_both;
}
else
abort ();
break;
}
if (old_type < stub_type)
stub_entry->stub_type = stub_type; stub_entry->stub_type = stub_type;
continue; continue;
} }
@ -12952,17 +13358,17 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
} }
stub_entry->stub_type = stub_type; stub_entry->stub_type = stub_type;
if (stub_type != ppc_stub_plt_call if (stub_type >= ppc_stub_plt_call
&& stub_type != ppc_stub_plt_call_r2save) && stub_type <= ppc_stub_plt_call_both)
{
stub_entry->target_value = code_value;
stub_entry->target_section = code_sec;
}
else
{ {
stub_entry->target_value = sym_value; stub_entry->target_value = sym_value;
stub_entry->target_section = sym_sec; stub_entry->target_section = sym_sec;
} }
else
{
stub_entry->target_value = code_value;
stub_entry->target_section = code_sec;
}
stub_entry->h = hash; stub_entry->h = hash;
stub_entry->plt_ent = plt_ent; stub_entry->plt_ent = plt_ent;
stub_entry->symtype stub_entry->symtype
@ -13841,19 +14247,31 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
"linker stubs in %u groups\n", "linker stubs in %u groups\n",
stub_sec_count), stub_sec_count),
stub_sec_count); stub_sec_count);
sprintf (*stats + len, _(" branch %lu\n" sprintf (*stats + len, _(" branch %lu\n"
" toc adjust %lu\n" " branch toc adj %lu\n"
" long branch %lu\n" " branch notoc %lu\n"
" long toc adj %lu\n" " branch both %lu\n"
" plt call %lu\n" " long branch %lu\n"
" plt call toc %lu\n" " long toc adj %lu\n"
" global entry %lu"), " long notoc %lu\n"
" long both %lu\n"
" plt call %lu\n"
" plt call save %lu\n"
" plt call notoc %lu\n"
" plt call both %lu\n"
" global entry %lu"),
htab->stub_count[ppc_stub_long_branch - 1], htab->stub_count[ppc_stub_long_branch - 1],
htab->stub_count[ppc_stub_long_branch_r2off - 1], htab->stub_count[ppc_stub_long_branch_r2off - 1],
htab->stub_count[ppc_stub_long_branch_notoc - 1],
htab->stub_count[ppc_stub_long_branch_both - 1],
htab->stub_count[ppc_stub_plt_branch - 1], htab->stub_count[ppc_stub_plt_branch - 1],
htab->stub_count[ppc_stub_plt_branch_r2off - 1], htab->stub_count[ppc_stub_plt_branch_r2off - 1],
htab->stub_count[ppc_stub_plt_branch_notoc - 1],
htab->stub_count[ppc_stub_plt_branch_both - 1],
htab->stub_count[ppc_stub_plt_call - 1], htab->stub_count[ppc_stub_plt_call - 1],
htab->stub_count[ppc_stub_plt_call_r2save - 1], htab->stub_count[ppc_stub_plt_call_r2save - 1],
htab->stub_count[ppc_stub_plt_call_notoc - 1],
htab->stub_count[ppc_stub_plt_call_both - 1],
htab->stub_count[ppc_stub_global_entry - 1]); htab->stub_count[ppc_stub_global_entry - 1]);
} }
return TRUE; return TRUE;
@ -14685,6 +15103,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
/* Fall through. */ /* Fall through. */
case R_PPC64_REL24: case R_PPC64_REL24:
case R_PPC64_REL24_NOTOC:
case R_PPC64_PLTCALL: case R_PPC64_PLTCALL:
/* Calls to functions with a different TOC, such as calls to /* Calls to functions with a different TOC, such as calls to
shared objects, need to alter the TOC pointer. This is shared objects, need to alter the TOC pointer. This is
@ -14701,15 +15120,18 @@ ppc64_elf_relocate_section (bfd *output_bfd,
htab); htab);
if (r_type == R_PPC64_PLTCALL if (r_type == R_PPC64_PLTCALL
&& stub_entry != NULL && stub_entry != NULL
&& (stub_entry->stub_type == ppc_stub_plt_call && stub_entry->stub_type >= ppc_stub_plt_call
|| stub_entry->stub_type == ppc_stub_plt_call_r2save)) && stub_entry->stub_type <= ppc_stub_plt_call_both)
stub_entry = NULL; stub_entry = NULL;
if (stub_entry != NULL if (stub_entry != NULL
&& (stub_entry->stub_type == ppc_stub_plt_call && (stub_entry->stub_type == ppc_stub_plt_call
|| stub_entry->stub_type == ppc_stub_plt_call_r2save || stub_entry->stub_type == ppc_stub_plt_call_r2save
|| stub_entry->stub_type == ppc_stub_plt_call_both
|| stub_entry->stub_type == ppc_stub_plt_branch_r2off || stub_entry->stub_type == ppc_stub_plt_branch_r2off
|| stub_entry->stub_type == ppc_stub_long_branch_r2off)) || stub_entry->stub_type == ppc_stub_plt_branch_both
|| stub_entry->stub_type == ppc_stub_long_branch_r2off
|| stub_entry->stub_type == ppc_stub_long_branch_both))
{ {
bfd_boolean can_plt_call = FALSE; bfd_boolean can_plt_call = FALSE;
@ -14721,6 +15143,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
/* The function doesn't use or change r2. */ /* The function doesn't use or change r2. */
can_plt_call = TRUE; can_plt_call = TRUE;
} }
else if (r_type == R_PPC64_REL24_NOTOC)
{
/* NOTOC calls don't need to restore r2. */
can_plt_call = TRUE;
}
/* All of these stubs may modify r2, so there must be a /* All of these stubs may modify r2, so there must be a
branch and link followed by a nop. The nop is branch and link followed by a nop. The nop is
@ -14802,8 +15229,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
if (!can_plt_call) if (!can_plt_call)
{ {
if (stub_entry->stub_type == ppc_stub_plt_call if (stub_entry->stub_type >= ppc_stub_plt_call
|| stub_entry->stub_type == ppc_stub_plt_call_r2save) && stub_entry->stub_type <= ppc_stub_plt_call_both)
info->callbacks->einfo info->callbacks->einfo
/* xgettext:c-format */ /* xgettext:c-format */
(_("%H: call to `%pT' lacks nop, can't restore toc; " (_("%H: call to `%pT' lacks nop, can't restore toc; "
@ -14821,8 +15248,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
} }
if (can_plt_call if (can_plt_call
&& (stub_entry->stub_type == ppc_stub_plt_call && stub_entry->stub_type >= ppc_stub_plt_call
|| stub_entry->stub_type == ppc_stub_plt_call_r2save)) && stub_entry->stub_type <= ppc_stub_plt_call_both)
unresolved_reloc = FALSE; unresolved_reloc = FALSE;
} }
@ -14864,6 +15291,28 @@ ppc64_elf_relocate_section (bfd *output_bfd,
/* Don't use the stub if this branch is in range. */ /* Don't use the stub if this branch is in range. */
stub_entry = NULL; stub_entry = NULL;
if (stub_entry != NULL
&& (stub_entry->stub_type == ppc_stub_long_branch_notoc
|| stub_entry->stub_type == ppc_stub_long_branch_both
|| stub_entry->stub_type == ppc_stub_plt_branch_notoc
|| stub_entry->stub_type == ppc_stub_plt_branch_both)
&& (r_type != R_PPC64_REL24_NOTOC
|| ((fdh ? fdh->elf.other : sym->st_other)
& STO_PPC64_LOCAL_MASK) == 1 << STO_PPC64_LOCAL_BIT)
&& (relocation + addend - from + max_br_offset
< 2 * max_br_offset))
stub_entry = NULL;
if (stub_entry != NULL
&& (stub_entry->stub_type == ppc_stub_long_branch_r2off
|| stub_entry->stub_type == ppc_stub_long_branch_both
|| stub_entry->stub_type == ppc_stub_plt_branch_r2off
|| stub_entry->stub_type == ppc_stub_plt_branch_both)
&& r_type == R_PPC64_REL24_NOTOC
&& (relocation + addend - from + max_br_offset
< 2 * max_br_offset))
stub_entry = NULL;
if (stub_entry != NULL) if (stub_entry != NULL)
{ {
/* Munge up the value and addend so that we call the stub /* Munge up the value and addend so that we call the stub
@ -14883,14 +15332,19 @@ ppc64_elf_relocate_section (bfd *output_bfd,
addend = 0; addend = 0;
reloc_dest = DEST_STUB; reloc_dest = DEST_STUB;
if ((stub_entry->stub_type == ppc_stub_plt_call if (((stub_entry->stub_type == ppc_stub_plt_call
|| stub_entry->stub_type == ppc_stub_plt_call_r2save) && ALWAYS_EMIT_R2SAVE)
&& (ALWAYS_EMIT_R2SAVE || stub_entry->stub_type == ppc_stub_plt_call_r2save
|| stub_entry->stub_type == ppc_stub_plt_call_r2save) || stub_entry->stub_type == ppc_stub_plt_call_both)
&& rel + 1 < relend && rel + 1 < relend
&& rel[1].r_offset == rel->r_offset + 4 && rel[1].r_offset == rel->r_offset + 4
&& ELF64_R_TYPE (rel[1].r_info) == R_PPC64_TOCSAVE) && ELF64_R_TYPE (rel[1].r_info) == R_PPC64_TOCSAVE)
relocation += 4; relocation += 4;
else if ((stub_entry->stub_type == ppc_stub_long_branch_both
|| stub_entry->stub_type == ppc_stub_plt_branch_both
|| stub_entry->stub_type == ppc_stub_plt_call_both)
&& r_type == R_PPC64_REL24_NOTOC)
relocation += 4;
} }
if (insn != 0) if (insn != 0)
@ -14923,7 +15377,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
else if (h != NULL else if (h != NULL
&& h->elf.root.type == bfd_link_hash_undefweak && h->elf.root.type == bfd_link_hash_undefweak
&& h->elf.dynindx == -1 && h->elf.dynindx == -1
&& r_type == R_PPC64_REL24 && (r_type == R_PPC64_REL24
|| r_type == R_PPC64_REL24_NOTOC)
&& relocation == 0 && relocation == 0
&& addend == 0) && addend == 0)
{ {
@ -15300,6 +15755,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_REL14_BRNTAKEN: case R_PPC64_REL14_BRNTAKEN:
case R_PPC64_REL14_BRTAKEN: case R_PPC64_REL14_BRTAKEN:
case R_PPC64_REL24: case R_PPC64_REL24:
case R_PPC64_REL24_NOTOC:
break; break;
case R_PPC64_TPREL16: case R_PPC64_TPREL16:

View File

@ -1469,6 +1469,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_RELOC_PPC64_ADDR16_HIGHA", "BFD_RELOC_PPC64_ADDR16_HIGHA",
"BFD_RELOC_PPC64_ADDR64_LOCAL", "BFD_RELOC_PPC64_ADDR64_LOCAL",
"BFD_RELOC_PPC64_ENTRY", "BFD_RELOC_PPC64_ENTRY",
"BFD_RELOC_PPC64_REL24_NOTOC",
"BFD_RELOC_PPC_TLS", "BFD_RELOC_PPC_TLS",
"BFD_RELOC_PPC_TLSGD", "BFD_RELOC_PPC_TLSGD",
"BFD_RELOC_PPC_TLSLD", "BFD_RELOC_PPC_TLSLD",

View File

@ -3011,6 +3011,8 @@ ENUMX
BFD_RELOC_PPC64_ADDR64_LOCAL BFD_RELOC_PPC64_ADDR64_LOCAL
ENUMX ENUMX
BFD_RELOC_PPC64_ENTRY BFD_RELOC_PPC64_ENTRY
ENUMX
BFD_RELOC_PPC64_REL24_NOTOC
ENUMDOC ENUMDOC
Power(rs6000) and PowerPC relocations. Power(rs6000) and PowerPC relocations.

View File

@ -1,3 +1,8 @@
2018-08-05 Alan Modra <amodra@gmail.com>
* config/tc-ppc.c (ppc_elf_suffix): Support @notoc.
(ppc_force_relocation, ppc_fix_adjustable): Handle REL24_NOTOC.
2018-08-03 Dimitar Dimitrov <dimitar@dinux.eu> 2018-08-03 Dimitar Dimitrov <dimitar@dinux.eu>
* config/tc-pru.c (pru_regname_to_dw2regnum): Return the starting HW * config/tc-pru.c (pru_regname_to_dw2regnum): Return the starting HW

View File

@ -2085,6 +2085,7 @@ ppc_elf_suffix (char **str_p, expressionS *exp_p)
MAP64 ("tprel@highera", BFD_RELOC_PPC64_TPREL16_HIGHERA), MAP64 ("tprel@highera", BFD_RELOC_PPC64_TPREL16_HIGHERA),
MAP64 ("tprel@highest", BFD_RELOC_PPC64_TPREL16_HIGHEST), MAP64 ("tprel@highest", BFD_RELOC_PPC64_TPREL16_HIGHEST),
MAP64 ("tprel@highesta", BFD_RELOC_PPC64_TPREL16_HIGHESTA), MAP64 ("tprel@highesta", BFD_RELOC_PPC64_TPREL16_HIGHESTA),
MAP64 ("notoc", BFD_RELOC_PPC64_REL24_NOTOC),
{ (char *) 0, 0, 0, 0, BFD_RELOC_NONE } { (char *) 0, 0, 0, 0, BFD_RELOC_NONE }
}; };
@ -6416,6 +6417,7 @@ ppc_force_relocation (fixS *fix)
case BFD_RELOC_PPC_BA26: case BFD_RELOC_PPC_BA26:
case BFD_RELOC_PPC_B16: case BFD_RELOC_PPC_B16:
case BFD_RELOC_PPC_BA16: case BFD_RELOC_PPC_BA16:
case BFD_RELOC_PPC64_REL24_NOTOC:
/* All branch fixups targeting a localentry symbol must /* All branch fixups targeting a localentry symbol must
force a relocation. */ force a relocation. */
if (fix->fx_addsy) if (fix->fx_addsy)
@ -6454,6 +6456,7 @@ ppc_fix_adjustable (fixS *fix)
case BFD_RELOC_PPC_B16_BRNTAKEN: case BFD_RELOC_PPC_B16_BRNTAKEN:
case BFD_RELOC_PPC_BA16_BRTAKEN: case BFD_RELOC_PPC_BA16_BRTAKEN:
case BFD_RELOC_PPC_BA16_BRNTAKEN: case BFD_RELOC_PPC_BA16_BRNTAKEN:
case BFD_RELOC_PPC64_REL24_NOTOC:
if (fix->fx_addsy) if (fix->fx_addsy)
{ {
asymbol *bfdsym = symbol_get_bfdsym (fix->fx_addsy); asymbol *bfdsym = symbol_get_bfdsym (fix->fx_addsy);

View File

@ -1,3 +1,12 @@
2018-08-05 Alan Modra <amodra@gmail.com>
* testsuite/ld-powerpc/ext.d,
* testsuite/ld-powerpc/ext.s,
* testsuite/ld-powerpc/ext.lnk,
* testsuite/ld-powerpc/notoc.d,
* testsuite/ld-powerpc/notoc.s: New tests.
* testsuite/ld-powerpc/powerpc.exp: Run them.
2018-08-05 Alan Modra <amodra@gmail.com> 2018-08-05 Alan Modra <amodra@gmail.com>
* testsuite/ld-powerpc/elfv2exe.d: Adjust for stub symbol change. * testsuite/ld-powerpc/elfv2exe.d: Adjust for stub symbol change.

View File

@ -0,0 +1,17 @@
#source: ext.s
#as: -a64
#objdump: -dr
#target: powerpc64*-*-*
# Just assembles an object for notoc.d
.*
Disassembly of section \.text:
0+ <ext>:
0: (00 00 4c 3c|3c 4c 00 00) addis r2,r12,0
(0|2): R_PPC64_REL16_HA \.TOC\.(|\+0x2)
4: (00 00 42 38|38 42 00 00) addi r2,r2,0
(4|6): R_PPC64_REL16_LO \.TOC\.\+0x(4|6)
8: (00 00 00 60|60 00 00 00) nop
c: (20 00 80 4e|4e 80 00 20) blr

View File

@ -0,0 +1,6 @@
SECTIONS
{
. = 0x8000000000000000;
.text.ext : { tmpdir/ext.o(.text) }
}
INSERT BEFORE .stab;

View File

@ -0,0 +1,9 @@
.text
.globl ext
ext:
0:
addis 2,12,.TOC.-0b@ha
addi 2,2,.TOC.-0b@l
.localentry ext,.-0b
nop
blr

View File

@ -0,0 +1,102 @@
#source: notoc.s
#as: -a64
#ld: --no-plt-localentry -T ext.lnk
#objdump: -dr
#target: powerpc64*-*-*
.*
Disassembly of section \.text:
.* <.*\.long_branch\.f1>:
.*: (18 00 41 f8|f8 41 00 18) std r2,24\(r1\)
.*: (7c 00 00 48|48 00 00 7c) b .* <f1>
.* <.*\.long_branch\.g1>:
.*: (18 00 41 f8|f8 41 00 18) std r2,24\(r1\)
.*: (8c 00 00 48|48 00 00 8c) b .* <g1>
.* <.*\.plt_branch\.ext>:
.*: (a6 02 88 7d|7d 88 02 a6) mflr r12
.*: (05 00 9f 42|42 9f 00 05) bcl .*
.*: (a6 02 68 7d|7d 68 02 a6) mflr r11
.*: (a6 03 88 7d|7d 88 03 a6) mtlr r12
.*: (ff 7f 80 3d|3d 80 7f ff) lis r12,32767
.*: (ff ff 8c 61|61 8c ff ff) ori r12,r12,65535
.*: (c6 07 9c 79|79 9c 07 c6) rldicr r28,r12,32,31
.*: (ff ef 8c 65|65 8c ef ff) oris r12,r12,61439
.*: (28 ff 8c 61|61 8c ff 28) ori r12,r12,65320
.*: (14 62 8b 7d|7d 8b 62 14) add r12,r11,r12
.*: (a6 03 89 7d|7d 89 03 a6) mtctr r12
.*: (20 04 80 4e|4e 80 04 20) bctr
.* <.*\.long_branch\.f2>:
.*: (a6 02 88 7d|7d 88 02 a6) mflr r12
.*: (05 00 9f 42|42 9f 00 05) bcl .*
.*: (a6 02 68 7d|7d 68 02 a6) mflr r11
.*: (a6 03 88 7d|7d 88 03 a6) mtlr r12
.*: (64 00 8b 39|39 8b 00 64) addi r12,r11,100
.*: (58 00 00 48|48 00 00 58) b .* <f2>
.* <.*\.long_branch\.g2>:
.*: (a6 02 88 7d|7d 88 02 a6) mflr r12
.*: (05 00 9f 42|42 9f 00 05) bcl .*
.*: (a6 02 68 7d|7d 68 02 a6) mflr r11
.*: (a6 03 88 7d|7d 88 03 a6) mtlr r12
.*: (80 00 8b 39|39 8b 00 80) addi r12,r11,128
.*: (74 00 00 48|48 00 00 74) b .* <g2>
\.\.\.
.* <f1>:
.*: (01 00 00 48|48 00 00 01) bl .* <f1>
.*: (bd ff ff 4b|4b ff ff bd) bl .* <.*\.long_branch\.f2>
.*: (11 00 00 48|48 00 00 11) bl .* <g1>
.*: (cd ff ff 4b|4b ff ff cd) bl .* <.*\.long_branch\.g2>
.*: (81 ff ff 4b|4b ff ff 81) bl .* <.*\.plt_branch\.ext>
.*: (20 00 80 4e|4e 80 00 20) blr
.* <g1>:
.*: (a9 ff ff 4b|4b ff ff a9) bl .* <.*\.long_branch\.f2>
.*: (e5 ff ff 4b|4b ff ff e5) bl .* <f1>
.*: (b9 ff ff 4b|4b ff ff b9) bl .* <.*\.long_branch\.g2>
.*: (f5 ff ff 4b|4b ff ff f5) bl .* <g1>
.*: (20 00 80 4e|4e 80 00 20) blr
.* <f2>:
.*: (02 10 40 3c|3c 40 10 02) lis r2,4098
.*: (00 90 42 38|38 42 90 00) addi r2,r2,-28672
.*: (4d ff ff 4b|4b ff ff 4d) bl .* <.*\.long_branch\.f1>
.*: (18 00 41 e8|e8 41 00 18) ld r2,24\(r1\)
.*: (f9 ff ff 4b|4b ff ff f9) bl .* <f2\+0x8>
.*: (00 00 00 60|60 00 00 00) nop
.*: (45 ff ff 4b|4b ff ff 45) bl .* <.*\.long_branch\.g1>
.*: (18 00 41 e8|e8 41 00 18) ld r2,24\(r1\)
.*: (1d 00 00 48|48 00 00 1d) bl .* <g2\+0x8>
.*: (00 00 00 60|60 00 00 00) nop
.*: (3d ff ff 4b|4b ff ff 3d) bl .* <.*\.plt_branch\.ext>
.*: (00 00 00 60|60 00 00 00) nop
.*: (20 00 80 4e|4e 80 00 20) blr
.* <g2>:
.*: (02 10 40 3c|3c 40 10 02) lis r2,4098
.*: (00 90 42 38|38 42 90 00) addi r2,r2,-28672
.*: (cd ff ff 4b|4b ff ff cd) bl .* <f2\+0x8>
.*: (00 00 00 60|60 00 00 00) nop
.*: (11 ff ff 4b|4b ff ff 11) bl .* <.*\.long_branch\.f1>
.*: (18 00 41 e8|e8 41 00 18) ld r2,24\(r1\)
.*: (f1 ff ff 4b|4b ff ff f1) bl .* <g2\+0x8>
.*: (00 00 00 60|60 00 00 00) nop
.*: (09 ff ff 4b|4b ff ff 09) bl .* <.*\.long_branch\.g1>
.*: (18 00 41 e8|e8 41 00 18) ld r2,24\(r1\)
.*: (20 00 80 4e|4e 80 00 20) blr
.* <_start>:
.*: (00 00 00 48|48 00 00 00) b .* <_start>
Disassembly of section \.text\.ext:
8000000000000000 <ext>:
8000000000000000: (02 10 40 3c|3c 40 10 02) lis r2,4098
8000000000000004: (00 90 42 38|38 42 90 00) addi r2,r2,-28672
8000000000000008: (00 00 00 60|60 00 00 00) nop
800000000000000c: (20 00 80 4e|4e 80 00 20) blr

View File

@ -0,0 +1,56 @@
.text
.globl f1, f2, g1, g2, _start
.weak ext
.abiversion 2
f1:
.localentry f1,1
bl f1@notoc
bl f2@notoc
bl g1@notoc
bl g2@notoc
bl ext@notoc
blr
g1:
.localentry g1,1
bl f2@notoc
bl f1@notoc
bl g2@notoc
bl g1@notoc
blr
f2:
0:
addis 2,12,.TOC.-0b@ha
addi 2,2,.TOC.-0b@l
.localentry f2,.-0b
bl f1
nop
bl f2
nop
bl g1
nop
bl g2
nop
bl ext
nop
blr
g2:
0:
addis 2,12,.TOC.-0b@ha
addi 2,2,.TOC.-0b@l
.localentry g2,.-0b
bl f2
nop
bl f1
nop
bl g2
nop
bl g1
nop
blr
_start:
b _start

View File

@ -331,6 +331,8 @@ if [ supports_ppc64 ] then {
run_dump_test "dotsym2" run_dump_test "dotsym2"
run_dump_test "dotsym3" run_dump_test "dotsym3"
run_dump_test "dotsym4" run_dump_test "dotsym4"
run_dump_test "ext"
run_dump_test "notoc"
} }
run_dump_test "tlsld32" run_dump_test "tlsld32"