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>
* 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_ADDR64_LOCAL,
BFD_RELOC_PPC64_ENTRY,
BFD_RELOC_PPC64_REL24_NOTOC,
/* PowerPC and PowerPC64 thread-local storage relocations. */
BFD_RELOC_PPC_TLS,

View File

@ -164,6 +164,8 @@ static bfd_vma opd_entry_value
#define BCTR 0x4e800420 /* bctr */
#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 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 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_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 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 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. */
#define GLINK_PLTRESOLVE_SIZE(htab) \
@ -446,6 +455,21 @@ static reloc_howto_type ppc64_elf_howto_raw[] =
0x03fffffc, /* dst_mask */
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. */
HOWTO (R_PPC64_REL14, /* type */
0, /* rightshift */
@ -2308,6 +2332,8 @@ ppc64_elf_reloc_type_lookup (bfd *abfd,
break;
case BFD_RELOC_PPC_B26: r = R_PPC64_REL24;
break;
case BFD_RELOC_PPC64_REL24_NOTOC: r = R_PPC64_REL24_NOTOC;
break;
case BFD_RELOC_PPC_B16: r = R_PPC64_REL14;
break;
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
the plt entry referenced crosses a 64k boundary, then an extra
"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
. ld %r12,xxx+0@toc@l(%r11)
. mtctr %r12
@ -3979,18 +4005,98 @@ must_be_dyn_reloc (struct bfd_link_info *info,
. mtctr %r12
. bctr
In cases where the "addis" instruction would add zero, the "addis" is
omitted and following instructions modified slightly in some cases.
*/
All of the above stubs are shown as their ELFv1 variants. ELFv2
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 {
ppc_stub_none,
ppc_stub_long_branch,
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_r2off,
ppc_stub_plt_branch_notoc,
ppc_stub_plt_branch_both,
ppc_stub_plt_call,
ppc_stub_plt_call_r2save,
ppc_stub_plt_call_notoc,
ppc_stub_plt_call_both,
ppc_stub_global_entry,
ppc_stub_save_res
};
@ -5478,6 +5584,7 @@ static bfd_boolean
is_branch_reloc (enum elf_ppc64_reloc_type r_type)
{
return (r_type == R_PPC64_REL24
|| r_type == R_PPC64_REL24_NOTOC
|| r_type == R_PPC64_REL14
|| r_type == R_PPC64_REL14_BRTAKEN
|| r_type == R_PPC64_REL14_BRNTAKEN
@ -5848,6 +5955,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
/* Fall through. */
case R_PPC64_REL24:
case R_PPC64_REL24_NOTOC:
rel24:
plt_list = ifunc;
if (h != NULL)
@ -10757,6 +10865,106 @@ ppc_type_of_stub (asection *input_sec,
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
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
@ -10784,8 +10992,17 @@ plt_stub_size (struct ppc_link_hash_table *htab,
struct ppc_stub_hash_entry *stub_entry,
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
|| stub_entry->stub_type == ppc_stub_plt_call_r2save)
size += 4;
@ -11422,6 +11639,78 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
p += 4;
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_r2save:
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;
char *name;
const char *const stub_str[] = { "long_branch",
"long_branch",
"long_branch",
"long_branch",
"plt_branch",
"plt_branch",
"plt_branch",
"plt_branch",
"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;
}
if (stub_entry->stub_type == ppc_stub_plt_call
|| stub_entry->stub_type == ppc_stub_plt_call_r2save)
if (stub_entry->stub_type >= ppc_stub_plt_call
&& stub_entry->stub_type <= ppc_stub_plt_call_both)
{
asection *plt;
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;
off = (elf_gp (info->output_bfd)
+ htab->sec_info[stub_entry->group->link_sec->id].toc_off);
off = targ - off;
if (stub_entry->stub_type >= ppc_stub_plt_call_notoc)
{
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)
{
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->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);
if (stub_entry->h != NULL
&& (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)
if (stub_entry->stub_type < ppc_stub_plt_call_notoc)
{
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;
if (stub_entry->h != NULL
&& (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
+= ((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
@ -11671,82 +11980,102 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
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;
local_off = PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other);
/* 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))
if (stub_entry->stub_type >= ppc_stub_long_branch_notoc)
{
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)
if (off + (1 << 25) >= (bfd_vma) (1 << 26))
{
_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;
}
}
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;
stub_entry->stub_type += (ppc_stub_plt_branch_notoc
- ppc_stub_long_branch_notoc);
size += 4;
}
}
else if (info->emitrelocations)
else
{
stub_entry->group->stub_sec->reloc_count += 1;
stub_entry->group->stub_sec->flags |= SEC_RELOC;
local_off = PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other);
/* 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);
if (r_type != R_PPC64_REL24
&& r_type != R_PPC64_REL24_NOTOC
&& r_type != R_PPC64_REL14
&& r_type != R_PPC64_REL14_BRTAKEN
&& 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. */
if (r_type != R_PPC64_REL24
&& r_type != R_PPC64_REL24_NOTOC
&& r_type != R_PPC64_REL14
&& r_type != R_PPC64_REL14_BRTAKEN
&& r_type != R_PPC64_REL14_BRNTAKEN)
@ -12857,7 +13188,19 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
&plt_ent, destination,
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.
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. */
if (stub_type != ppc_stub_plt_call
&& stub_type != ppc_stub_plt_call_notoc
&& hash != NULL
&& (hash == htab->tls_get_addr
|| hash == htab->tls_get_addr_fd)
@ -12929,9 +13273,71 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
stub_name, FALSE, FALSE);
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);
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;
continue;
}
@ -12952,17 +13358,17 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
}
stub_entry->stub_type = stub_type;
if (stub_type != ppc_stub_plt_call
&& stub_type != ppc_stub_plt_call_r2save)
{
stub_entry->target_value = code_value;
stub_entry->target_section = code_sec;
}
else
if (stub_type >= ppc_stub_plt_call
&& stub_type <= ppc_stub_plt_call_both)
{
stub_entry->target_value = sym_value;
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->plt_ent = plt_ent;
stub_entry->symtype
@ -13841,19 +14247,31 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
"linker stubs in %u groups\n",
stub_sec_count),
stub_sec_count);
sprintf (*stats + len, _(" branch %lu\n"
" toc adjust %lu\n"
" long branch %lu\n"
" long toc adj %lu\n"
" plt call %lu\n"
" plt call toc %lu\n"
" global entry %lu"),
sprintf (*stats + len, _(" branch %lu\n"
" branch toc adj %lu\n"
" branch notoc %lu\n"
" branch both %lu\n"
" long branch %lu\n"
" long toc adj %lu\n"
" 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_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_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_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]);
}
return TRUE;
@ -14685,6 +15103,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
/* Fall through. */
case R_PPC64_REL24:
case R_PPC64_REL24_NOTOC:
case R_PPC64_PLTCALL:
/* Calls to functions with a different TOC, such as calls to
shared objects, need to alter the TOC pointer. This is
@ -14701,15 +15120,18 @@ ppc64_elf_relocate_section (bfd *output_bfd,
htab);
if (r_type == R_PPC64_PLTCALL
&& stub_entry != NULL
&& (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
&& stub_entry->stub_type <= ppc_stub_plt_call_both)
stub_entry = NULL;
if (stub_entry != NULL
&& (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->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;
@ -14721,6 +15143,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
/* The function doesn't use or change r2. */
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
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 (stub_entry->stub_type == ppc_stub_plt_call
|| stub_entry->stub_type == ppc_stub_plt_call_r2save)
if (stub_entry->stub_type >= ppc_stub_plt_call
&& stub_entry->stub_type <= ppc_stub_plt_call_both)
info->callbacks->einfo
/* xgettext:c-format */
(_("%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
&& (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
&& stub_entry->stub_type <= ppc_stub_plt_call_both)
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. */
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)
{
/* 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;
reloc_dest = DEST_STUB;
if ((stub_entry->stub_type == ppc_stub_plt_call
|| stub_entry->stub_type == ppc_stub_plt_call_r2save)
&& (ALWAYS_EMIT_R2SAVE
|| stub_entry->stub_type == ppc_stub_plt_call_r2save)
if (((stub_entry->stub_type == ppc_stub_plt_call
&& ALWAYS_EMIT_R2SAVE)
|| stub_entry->stub_type == ppc_stub_plt_call_r2save
|| stub_entry->stub_type == ppc_stub_plt_call_both)
&& rel + 1 < relend
&& rel[1].r_offset == rel->r_offset + 4
&& ELF64_R_TYPE (rel[1].r_info) == R_PPC64_TOCSAVE)
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)
@ -14923,7 +15377,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
else if (h != NULL
&& h->elf.root.type == bfd_link_hash_undefweak
&& h->elf.dynindx == -1
&& r_type == R_PPC64_REL24
&& (r_type == R_PPC64_REL24
|| r_type == R_PPC64_REL24_NOTOC)
&& relocation == 0
&& addend == 0)
{
@ -15300,6 +15755,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_REL14_BRNTAKEN:
case R_PPC64_REL14_BRTAKEN:
case R_PPC64_REL24:
case R_PPC64_REL24_NOTOC:
break;
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_ADDR64_LOCAL",
"BFD_RELOC_PPC64_ENTRY",
"BFD_RELOC_PPC64_REL24_NOTOC",
"BFD_RELOC_PPC_TLS",
"BFD_RELOC_PPC_TLSGD",
"BFD_RELOC_PPC_TLSLD",

View File

@ -3011,6 +3011,8 @@ ENUMX
BFD_RELOC_PPC64_ADDR64_LOCAL
ENUMX
BFD_RELOC_PPC64_ENTRY
ENUMX
BFD_RELOC_PPC64_REL24_NOTOC
ENUMDOC
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>
* 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@highest", BFD_RELOC_PPC64_TPREL16_HIGHEST),
MAP64 ("tprel@highesta", BFD_RELOC_PPC64_TPREL16_HIGHESTA),
MAP64 ("notoc", BFD_RELOC_PPC64_REL24_NOTOC),
{ (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_B16:
case BFD_RELOC_PPC_BA16:
case BFD_RELOC_PPC64_REL24_NOTOC:
/* All branch fixups targeting a localentry symbol must
force a relocation. */
if (fix->fx_addsy)
@ -6454,6 +6456,7 @@ ppc_fix_adjustable (fixS *fix)
case BFD_RELOC_PPC_B16_BRNTAKEN:
case BFD_RELOC_PPC_BA16_BRTAKEN:
case BFD_RELOC_PPC_BA16_BRNTAKEN:
case BFD_RELOC_PPC64_REL24_NOTOC:
if (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>
* 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 "dotsym3"
run_dump_test "dotsym4"
run_dump_test "ext"
run_dump_test "notoc"
}
run_dump_test "tlsld32"