summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>2017-08-21 11:34:06 -0300
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>2017-08-21 11:34:06 -0300
commitf3ae7dbacf5aeb9df207f5dacd778a2f6eab24fc (patch)
tree007fb5f9f137a4cb155cbf457fcd3ae320c2e6f4
parent1d72c7445857652f3eb423f2702bc5981580fb63 (diff)
parentb5d3ac25628b1a16409a9816623c34a45377d400 (diff)
downloadbinutils-gdb-users/linaro/binutils-2_27-branch.tar.gz
Merge with binutils-2_27-branch rev b5d3ac20users/linaro/binutils-2_27-branch
Change-Id: Iaa5f379bb904c3eb5b6e041c62c24076d2838063
-rw-r--r--bfd/ChangeLog50
-rw-r--r--bfd/elf-bfd.h2
-rw-r--r--bfd/elf32-i386.c12
-rw-r--r--bfd/elf32-microblaze.c4
-rw-r--r--bfd/elf32-ppc.c201
-rw-r--r--bfd/elf64-ppc.c42
-rw-r--r--bfd/elfxx-mips.c3
-rw-r--r--bfd/version.h2
-rw-r--r--binutils/ChangeLog9
-rw-r--r--binutils/readelf.c102
-rw-r--r--gas/ChangeLog26
-rw-r--r--gas/config/tc-ppc.c24
-rw-r--r--gas/testsuite/gas/ppc/altivec2.d4
-rw-r--r--gas/testsuite/gas/ppc/power9.d8
-rw-r--r--gas/testsuite/gas/ppc/power9.s4
-rw-r--r--gold/ChangeLog131
-rw-r--r--gold/aarch64.cc8
-rw-r--r--gold/arm.cc8
-rw-r--r--gold/debug.h8
-rw-r--r--gold/object.h7
-rw-r--r--gold/options.h12
-rw-r--r--gold/powerpc.cc922
-rw-r--r--gold/reloc.cc73
-rw-r--r--include/ChangeLog6
-rw-r--r--include/elf/ppc.h17
-rw-r--r--ld/ChangeLog40
-rw-r--r--ld/testsuite/ld-i386/i386.exp22
-rw-r--r--ld/testsuite/ld-i386/pr21168a.c14
-rw-r--r--ld/testsuite/ld-i386/pr21168b.S29
-rw-r--r--ld/testsuite/ld-powerpc/attr-gnu-4-01.d2
-rw-r--r--ld/testsuite/ld-powerpc/attr-gnu-4-02.d2
-rw-r--r--ld/testsuite/ld-powerpc/attr-gnu-4-03.d2
-rw-r--r--ld/testsuite/ld-powerpc/attr-gnu-4-10.d2
-rw-r--r--ld/testsuite/ld-powerpc/attr-gnu-4-11.d2
-rw-r--r--ld/testsuite/ld-powerpc/attr-gnu-4-14.d6
-rw-r--r--ld/testsuite/ld-powerpc/attr-gnu-4-20.d2
-rw-r--r--ld/testsuite/ld-powerpc/attr-gnu-4-22.d2
-rw-r--r--ld/testsuite/ld-powerpc/attr-gnu-4-24.d6
-rw-r--r--ld/testsuite/ld-powerpc/attr-gnu-4-32.d2
-rw-r--r--ld/testsuite/ld-powerpc/attr-gnu-4-33.d2
-rw-r--r--ld/testsuite/ld-powerpc/attr-gnu-4-34.d6
-rw-r--r--ld/testsuite/ld-powerpc/attr-gnu-4-4.s1
-rw-r--r--ld/testsuite/ld-powerpc/attr-gnu-4-41.d6
-rw-r--r--ld/testsuite/ld-powerpc/attr-gnu-8-11.d2
-rw-r--r--ld/testsuite/ld-powerpc/attr-gnu-8-23.d2
-rw-r--r--ld/testsuite/ld-powerpc/powerpc.exp8
-rw-r--r--ld/testsuite/ld-powerpc/tocopt7.d54
-rw-r--r--ld/testsuite/ld-powerpc/tocopt7.out26
-rw-r--r--ld/testsuite/ld-powerpc/tocopt7.s216
-rw-r--r--ld/testsuite/ld-powerpc/tocopt8.d46
-rw-r--r--ld/testsuite/ld-powerpc/tocopt8.s188
-rw-r--r--opcodes/ChangeLog18
-rw-r--r--opcodes/ppc-dis.c4
-rw-r--r--opcodes/ppc-opc.c7
54 files changed, 2014 insertions, 390 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 035353b60a2..b161a20e922 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,53 @@
+2017-03-09 Alan Modra <amodra@gmail.com>
+
+ Apply from master
+ 2016-09-26 Alan Modra <amodra@gmail.com>
+ * elf-bfd.h (_bfd_elf_ppc_merge_fp_attributes): Declare.
+ * elf32-ppc.c (_bfd_elf_ppc_merge_fp_attributes): New function.
+ (ppc_elf_merge_obj_attributes): Use it. Don't copy first file
+ attributes, merge them. Don't warn about undefined tag bits,
+ or copy unknown values to output.
+ * elf64-ppc.c (ppc64_elf_merge_private_bfd_data): Call
+ _bfd_elf_ppc_merge_fp_attributes.
+
+2017-02-22 Alan Modra <amodra@gmail.com>
+
+ * elf64-ppc.c (ppc64_elf_finish_dynamic_sections): Don't segfault
+ on .got or .plt output section being discarded by script.
+ * elf32-ppc.c (ppc_elf_finish_dynamic_sections): Likewise. Move
+ vxworks splt temp.
+
+2017-02-21 Alan Modra <amodra@gmail.com>
+
+ Apply from master
+ 2016-12-06 Alan Modra <amodra@gmail.com>
+ * elf64-ppc.c (ok_lo_toc_insn): Add r_type param. Recognize
+ lq,lfq,lxv,lxsd,lxssp,lfdp,stq,stfq,stxv,stxsd,stxssp,stfdp.
+ Don't match lmd and stmd.
+
+2017-02-15 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR ld/21168
+ * elf32-i386.c (elf_i386_relocate_section): Allow
+ "lea foo@GOT, %reg" in PIC.
+
+2016-12-23 Maciej W. Rozycki <macro@imgtec.com>
+
+ * bfd/elfxx-mips.c (_bfd_mips_post_process_headers): Revert
+ 2016-02-23 change and remove EI_ABIVERSION 5 support.
+
+2016-11-30 Alan Modra <amodra@gmail.com>
+
+ PR ld/20886
+ * elf64-ppc.c (ppc64_elf_size_stubs): Make rawsize max size seen
+ on any pass past STUB_SHRINK_ITER.
+
+2016-10-31 Alan Modra <amodra@gmail.com>
+
+ PR 20748
+ * elf32-microblaze.c (microblaze_elf_finish_dynamic_sections): Revert
+ 2016-05-13 change.
+
2016-10-10 Christophe Lyon <christophe.lyon@linaro.org>
Backport from mainline
2016-09-28 Christophe Lyon <christophe.lyon@linaro.org>
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 163ef35fadc..9b870372f2d 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -2376,6 +2376,8 @@ extern unsigned int _bfd_elf_ppc_at_tprel_transform
(unsigned int, unsigned int);
/* PowerPC elf_object_p tweak. */
extern bfd_boolean _bfd_elf_ppc_set_arch (bfd *);
+/* PowerPC .gnu.attributes handling common to both 32-bit and 64-bit. */
+extern void _bfd_elf_ppc_merge_fp_attributes (bfd *, bfd *);
/* Exported interface for writing elf corefile notes. */
extern char *elfcore_write_note
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index 417957214db..d549ffee716 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -3993,7 +3993,9 @@ elf_i386_relocate_section (bfd *output_bfd,
- gotplt->output_section->vma
- gotplt->output_offset);
- if ((*(contents + rel->r_offset - 1) & 0xc7) == 0x5)
+ if (rel->r_offset > 1
+ && (*(contents + rel->r_offset - 1) & 0xc7) == 0x5
+ && *(contents + rel->r_offset - 2) != 0x8d)
{
if (bfd_link_pic (info))
goto disallow_got32;
@@ -4263,13 +4265,15 @@ r_386_got32:
relocation = (htab->elf.sgot->output_section->vma
+ htab->elf.sgot->output_offset + off);
- if ((*(contents + rel->r_offset - 1) & 0xc7) == 0x5)
+ if (rel->r_offset > 1
+ && (*(contents + rel->r_offset - 1) & 0xc7) == 0x5
+ && *(contents + rel->r_offset - 2) != 0x8d)
{
if (bfd_link_pic (info))
{
/* For PIC, disallow R_386_GOT32 without a base
- register since we don't know what the GOT base
- is. */
+ register, except for "lea foo@GOT, %reg", since
+ we don't know what the GOT base is. */
const char *name;
disallow_got32:
diff --git a/bfd/elf32-microblaze.c b/bfd/elf32-microblaze.c
index 5496d1613aa..d964e17c162 100644
--- a/bfd/elf32-microblaze.c
+++ b/bfd/elf32-microblaze.c
@@ -3400,13 +3400,13 @@ microblaze_elf_finish_dynamic_sections (bfd *output_bfd,
{
asection *s;
- s = bfd_get_linker_section (dynobj, name);
+ s = bfd_get_section_by_name (output_bfd, name);
if (s == NULL)
dyn.d_un.d_val = 0;
else
{
if (! size)
- dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
+ dyn.d_un.d_ptr = s->vma;
else
dyn.d_un.d_val = s->size;
}
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index e42ef1cc885..d42e2cda5ba 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -4647,68 +4647,87 @@ ppc_elf_check_relocs (bfd *abfd,
return TRUE;
}
-
-/* Merge object attributes from IBFD into OBFD. Raise an error if
- there are conflicting attributes. */
-static bfd_boolean
-ppc_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
+/* Warn for conflicting Tag_GNU_Power_ABI_FP attributes between IBFD
+ and OBFD, and merge non-conflicting ones. */
+void
+_bfd_elf_ppc_merge_fp_attributes (bfd *ibfd, bfd *obfd)
{
obj_attribute *in_attr, *in_attrs;
obj_attribute *out_attr, *out_attrs;
- if (!elf_known_obj_attributes_proc (obfd)[0].i)
- {
- /* This is the first object. Copy the attributes. */
- _bfd_elf_copy_obj_attributes (ibfd, obfd);
-
- /* Use the Tag_null value to indicate the attributes have been
- initialized. */
- elf_known_obj_attributes_proc (obfd)[0].i = 1;
-
- return TRUE;
- }
-
in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
- /* Check for conflicting Tag_GNU_Power_ABI_FP attributes and merge
- non-conflicting ones. */
in_attr = &in_attrs[Tag_GNU_Power_ABI_FP];
out_attr = &out_attrs[Tag_GNU_Power_ABI_FP];
+
if (in_attr->i != out_attr->i)
{
- out_attr->type = 1;
- if (out_attr->i == 0)
- out_attr->i = in_attr->i;
- else if (in_attr->i == 0)
+ int in_fp = in_attr->i & 3;
+ int out_fp = out_attr->i & 3;
+
+ if (in_fp == 0)
;
- else if (out_attr->i == 1 && in_attr->i == 2)
+ else if (out_fp == 0)
+ {
+ out_attr->type = 1;
+ out_attr->i ^= in_fp;
+ }
+ else if (out_fp != 2 && in_fp == 2)
_bfd_error_handler
(_("Warning: %B uses hard float, %B uses soft float"), obfd, ibfd);
- else if (out_attr->i == 1 && in_attr->i == 3)
+ else if (out_fp == 2 && in_fp != 2)
_bfd_error_handler
- (_("Warning: %B uses double-precision hard float, %B uses single-precision hard float"),
- obfd, ibfd);
- else if (out_attr->i == 3 && in_attr->i == 1)
+ (_("Warning: %B uses hard float, %B uses soft float"), ibfd, obfd);
+ else if (out_fp == 1 && in_fp == 3)
_bfd_error_handler
- (_("Warning: %B uses double-precision hard float, %B uses single-precision hard float"),
- ibfd, obfd);
- else if (out_attr->i == 3 && in_attr->i == 2)
+ (_("Warning: %B uses double-precision hard float, "
+ "%B uses single-precision hard float"), obfd, ibfd);
+ else if (out_fp == 3 && in_fp == 1)
_bfd_error_handler
- (_("Warning: %B uses soft float, %B uses single-precision hard float"),
- ibfd, obfd);
- else if (out_attr->i == 2 && (in_attr->i == 1 || in_attr->i == 3))
+ (_("Warning: %B uses double-precision hard float, "
+ "%B uses single-precision hard float"), ibfd, obfd);
+
+ in_fp = in_attr->i & 0xc;
+ out_fp = out_attr->i & 0xc;
+ if (in_fp == 0)
+ ;
+ else if (out_fp == 0)
+ {
+ out_attr->type = 1;
+ out_attr->i ^= in_fp;
+ }
+ else if (out_fp != 2 * 4 && in_fp == 2 * 4)
_bfd_error_handler
- (_("Warning: %B uses hard float, %B uses soft float"), ibfd, obfd);
- else if (in_attr->i > 3)
+ (_("Warning: %B uses 64-bit long double, "
+ "%B uses 128-bit long double"), ibfd, obfd);
+ else if (in_fp != 2 * 4 && out_fp == 2 * 4)
_bfd_error_handler
- (_("Warning: %B uses unknown floating point ABI %d"), ibfd,
- in_attr->i);
- else
+ (_("Warning: %B uses 64-bit long double, "
+ "%B uses 128-bit long double"), obfd, ibfd);
+ else if (out_fp == 1 * 4 && in_fp == 3 * 4)
_bfd_error_handler
- (_("Warning: %B uses unknown floating point ABI %d"), obfd,
- out_attr->i);
+ (_("Warning: %B uses IBM long double, "
+ "%B uses IEEE long double"), ibfd, obfd);
+ else if (out_fp == 3 * 4 && in_fp == 1 * 4)
+ _bfd_error_handler
+ (_("Warning: %B uses IBM long double, "
+ "%B uses IEEE long double"), obfd, ibfd);
}
+}
+
+/* Merge object attributes from IBFD into OBFD. Warn if
+ there are conflicting attributes. */
+static bfd_boolean
+ppc_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
+{
+ obj_attribute *in_attr, *in_attrs;
+ obj_attribute *out_attr, *out_attrs;
+
+ _bfd_elf_ppc_merge_fp_attributes (ibfd, obfd);
+
+ in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
+ out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
/* Check for conflicting Tag_GNU_Power_ABI_Vector attributes and
merge non-conflicting ones. */
@@ -4716,48 +4735,36 @@ ppc_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
out_attr = &out_attrs[Tag_GNU_Power_ABI_Vector];
if (in_attr->i != out_attr->i)
{
- const char *in_abi = NULL, *out_abi = NULL;
-
- switch (in_attr->i)
- {
- case 1: in_abi = "generic"; break;
- case 2: in_abi = "AltiVec"; break;
- case 3: in_abi = "SPE"; break;
- }
+ int in_vec = in_attr->i & 3;
+ int out_vec = out_attr->i & 3;
- switch (out_attr->i)
+ if (in_vec == 0)
+ ;
+ else if (out_vec == 0)
{
- case 1: out_abi = "generic"; break;
- case 2: out_abi = "AltiVec"; break;
- case 3: out_abi = "SPE"; break;
+ out_attr->type = 1;
+ out_attr->i = in_vec;
}
-
- out_attr->type = 1;
- if (out_attr->i == 0)
- out_attr->i = in_attr->i;
- else if (in_attr->i == 0)
- ;
/* For now, allow generic to transition to AltiVec or SPE
without a warning. If GCC marked files with their stack
alignment and used don't-care markings for files which are
not affected by the vector ABI, we could warn about this
case too. */
- else if (out_attr->i == 1)
- out_attr->i = in_attr->i;
- else if (in_attr->i == 1)
+ else if (in_vec == 1)
;
- else if (in_abi == NULL)
- _bfd_error_handler
- (_("Warning: %B uses unknown vector ABI %d"), ibfd,
- in_attr->i);
- else if (out_abi == NULL)
+ else if (out_vec == 1)
+ {
+ out_attr->type = 1;
+ out_attr->i = in_vec;
+ }
+ else if (out_vec < in_vec)
_bfd_error_handler
- (_("Warning: %B uses unknown vector ABI %d"), obfd,
- in_attr->i);
- else
+ (_("Warning: %B uses AltiVec vector ABI, %B uses SPE vector ABI"),
+ obfd, ibfd);
+ else if (out_vec > in_vec)
_bfd_error_handler
- (_("Warning: %B uses vector ABI \"%s\", %B uses \"%s\""),
- ibfd, obfd, in_abi, out_abi);
+ (_("Warning: %B uses AltiVec vector ABI, %B uses SPE vector ABI"),
+ ibfd, obfd);
}
/* Check for conflicting Tag_GNU_Power_ABI_Struct_Return attributes
@@ -4766,25 +4773,24 @@ ppc_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
out_attr = &out_attrs[Tag_GNU_Power_ABI_Struct_Return];
if (in_attr->i != out_attr->i)
{
- out_attr->type = 1;
- if (out_attr->i == 0)
- out_attr->i = in_attr->i;
- else if (in_attr->i == 0)
+ int in_struct = in_attr->i & 3;
+ int out_struct = out_attr->i & 3;
+
+ if (in_struct == 0 || in_struct == 3)
;
- else if (out_attr->i == 1 && in_attr->i == 2)
- _bfd_error_handler
- (_("Warning: %B uses r3/r4 for small structure returns, %B uses memory"), obfd, ibfd);
- else if (out_attr->i == 2 && in_attr->i == 1)
- _bfd_error_handler
- (_("Warning: %B uses r3/r4 for small structure returns, %B uses memory"), ibfd, obfd);
- else if (in_attr->i > 2)
- _bfd_error_handler
- (_("Warning: %B uses unknown small structure return convention %d"), ibfd,
- in_attr->i);
- else
- _bfd_error_handler
- (_("Warning: %B uses unknown small structure return convention %d"), obfd,
- out_attr->i);
+ else if (out_struct == 0)
+ {
+ out_attr->type = 1;
+ out_attr->i = in_struct;
+ }
+ else if (out_struct < in_struct)
+ _bfd_error_handler
+ (_("Warning: %B uses r3/r4 for small structure returns, "
+ "%B uses memory"), obfd, ibfd);
+ else if (out_struct > in_struct)
+ _bfd_error_handler
+ (_("Warning: %B uses r3/r4 for small structure returns, "
+ "%B uses memory"), ibfd, obfd);
}
/* Merge Tag_compatibility attributes and any common GNU ones. */
@@ -10303,11 +10309,6 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
htab = ppc_elf_hash_table (info);
dynobj = elf_hash_table (info)->dynobj;
sdyn = bfd_get_linker_section (dynobj, ".dynamic");
- if (htab->is_vxworks)
- splt = bfd_get_linker_section (dynobj, ".plt");
- else
- splt = NULL;
-
got = 0;
if (htab->elf.hgot != NULL)
got = SYM_VAL (htab->elf.hgot);
@@ -10370,7 +10371,8 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
}
}
- if (htab->got != NULL)
+ if (htab->got != NULL
+ && htab->got->output_section != bfd_abs_section_ptr)
{
if (htab->elf.hgot->root.u.def.section == htab->got
|| htab->elf.hgot->root.u.def.section == htab->sgotplt)
@@ -10410,7 +10412,12 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
}
/* Fill in the first entry in the VxWorks procedure linkage table. */
- if (splt && splt->size > 0)
+ splt = NULL;
+ if (htab->is_vxworks)
+ splt = bfd_get_linker_section (dynobj, ".plt");
+ if (splt != NULL
+ && splt->size != 0
+ && splt->output_section != bfd_abs_section_ptr)
{
/* Use the right PLT. */
const bfd_vma *plt_entry = (bfd_link_pic (info)
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index d2367327f0e..ee3c3b2c5f7 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -5998,6 +5998,8 @@ ppc64_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
return FALSE;
}
+ _bfd_elf_ppc_merge_fp_attributes (ibfd, obfd);
+
/* Merge Tag_compatibility attributes and any common GNU ones. */
_bfd_elf_merge_object_attributes (ibfd, obfd);
@@ -8803,12 +8805,14 @@ adjust_toc_syms (struct elf_link_hash_entry *h, void *inf)
return TRUE;
}
-/* Return TRUE iff INSN is one we expect on a _LO variety toc/got reloc. */
+/* Return TRUE iff INSN with a relocation of R_TYPE is one we expect
+ on a _LO variety toc/got reloc. */
static bfd_boolean
-ok_lo_toc_insn (unsigned int insn)
+ok_lo_toc_insn (unsigned int insn, enum elf_ppc64_reloc_type r_type)
{
- return ((insn & (0x3f << 26)) == 14u << 26 /* addi */
+ return ((insn & (0x3f << 26)) == 12u << 26 /* addic */
+ || (insn & (0x3f << 26)) == 14u << 26 /* addi */
|| (insn & (0x3f << 26)) == 32u << 26 /* lwz */
|| (insn & (0x3f << 26)) == 34u << 26 /* lbz */
|| (insn & (0x3f << 26)) == 36u << 26 /* stw */
@@ -8822,11 +8826,20 @@ ok_lo_toc_insn (unsigned int insn)
|| (insn & (0x3f << 26)) == 50u << 26 /* lfd */
|| (insn & (0x3f << 26)) == 52u << 26 /* stfs */
|| (insn & (0x3f << 26)) == 54u << 26 /* stfd */
- || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */
- && (insn & 3) != 1)
- || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */
- && ((insn & 3) == 0 || (insn & 3) == 3))
- || (insn & (0x3f << 26)) == 12u << 26 /* addic */);
+ || (insn & (0x3f << 26)) == 56u << 26 /* lq,lfq */
+ || ((insn & (0x3f << 26)) == 57u << 26 /* lxsd,lxssp,lfdp */
+ /* Exclude lfqu by testing reloc. If relocs are ever
+ defined for the reduced D field in psq_lu then those
+ will need testing too. */
+ && r_type != R_PPC64_TOC16_LO && r_type != R_PPC64_GOT16_LO)
+ || ((insn & (0x3f << 26)) == 58u << 26 /* ld,lwa */
+ && (insn & 1) == 0)
+ || (insn & (0x3f << 26)) == 60u << 26 /* stfq */
+ || ((insn & (0x3f << 26)) == 61u << 26 /* lxv,stx{v,sd,ssp},stfdp */
+ /* Exclude stfqu. psq_stu as above for psq_lu. */
+ && r_type != R_PPC64_TOC16_LO && r_type != R_PPC64_GOT16_LO)
+ || ((insn & (0x3f << 26)) == 62u << 26 /* std,stq */
+ && (insn & 1) == 0));
}
/* Examine all relocs referencing .toc sections in order to remove
@@ -9131,7 +9144,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
}
insn = bfd_get_32 (ibfd, buf);
if (insn_check == check_lo
- ? !ok_lo_toc_insn (insn)
+ ? !ok_lo_toc_insn (insn, r_type)
: ((insn & ((0x3f << 26) | 0x1f << 16))
!= ((15u << 26) | (2 << 16)) /* addis rt,2,imm */))
{
@@ -12540,7 +12553,10 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
stub_sec = stub_sec->next)
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
{
- stub_sec->rawsize = stub_sec->size;
+ if (htab->stub_iteration <= STUB_SHRINK_ITER
+ || stub_sec->rawsize < stub_sec->size)
+ /* Past STUB_SHRINK_ITER, rawsize is the max size seen. */
+ stub_sec->rawsize = stub_sec->size;
stub_sec->size = 0;
stub_sec->reloc_count = 0;
stub_sec->flags &= ~SEC_RELOC;
@@ -15518,7 +15534,8 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
}
}
- if (htab->elf.sgot != NULL && htab->elf.sgot->size != 0)
+ if (htab->elf.sgot != NULL && htab->elf.sgot->size != 0
+ && htab->elf.sgot->output_section != bfd_abs_section_ptr)
{
/* Fill in the first entry in the global offset table.
We use it to hold the link-time TOCbase. */
@@ -15530,7 +15547,8 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize = 8;
}
- if (htab->elf.splt != NULL && htab->elf.splt->size != 0)
+ if (htab->elf.splt != NULL && htab->elf.splt->size != 0
+ && htab->elf.splt->output_section != bfd_abs_section_ptr)
{
/* Set .plt entry size. */
elf_section_data (htab->elf.splt->output_section)->this_hdr.sh_entsize
diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
index e47276bc61c..80e171dd9ab 100644
--- a/bfd/elfxx-mips.c
+++ b/bfd/elfxx-mips.c
@@ -16187,9 +16187,6 @@ _bfd_mips_post_process_headers (bfd *abfd, struct bfd_link_info *link_info)
if (mips_elf_tdata (abfd)->abiflags.fp_abi == Val_GNU_MIPS_ABI_FP_64
|| mips_elf_tdata (abfd)->abiflags.fp_abi == Val_GNU_MIPS_ABI_FP_64A)
i_ehdrp->e_ident[EI_ABIVERSION] = 3;
-
- if (elf_stack_flags (abfd) && !(elf_stack_flags (abfd) & PF_X))
- i_ehdrp->e_ident[EI_ABIVERSION] = 5;
}
int
diff --git a/bfd/version.h b/bfd/version.h
index b959b378a68..28e03591e29 100644
--- a/bfd/version.h
+++ b/bfd/version.h
@@ -1,4 +1,4 @@
-#define BFD_VERSION_DATE 20161019
+#define BFD_VERSION_DATE 20161229
#define BFD_VERSION @bfd_version@
#define BFD_VERSION_STRING @bfd_version_package@ @bfd_version_string@
#define REPORT_BUGS_TO @report_bugs_to@
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index a70bdb7a7b6..c9b81307273 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,12 @@
+2017-03-09 Alan Modra <amodra@gmail.com>
+
+ Apply from master
+ 2016-09-26 Alan Modra <amodra@gmail.com>
+ * readelf.c (display_power_gnu_attribute): Catch truncated section
+ for all powerpc attributes. Display long double ABI. Don't
+ capitalize words, except for names. Show known bits of tag values
+ when some unknown bits are present. Whitespace fixes.
+
2016-08-03 Tristan Gingold <gingold@adacore.com>
* configure: Regenerate.
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 274ddd17266..98fc1961edf 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -13237,47 +13237,77 @@ display_power_gnu_attribute (unsigned char * p,
const unsigned char * const end)
{
unsigned int len;
- int val;
+ unsigned int val;
if (tag == Tag_GNU_Power_ABI_FP)
{
val = read_uleb128 (p, &len, end);
p += len;
printf (" Tag_GNU_Power_ABI_FP: ");
+ if (len == 0)
+ {
+ printf (_("<corrupt>\n"));
+ return p;
+ }
- switch (val)
+ if (val > 15)
+ printf ("(%#x), ", val);
+
+ switch (val & 3)
{
case 0:
- printf (_("Hard or soft float\n"));
+ printf (_("unspecified hard/soft float, "));
break;
case 1:
- printf (_("Hard float\n"));
+ printf (_("hard float, "));
break;
case 2:
- printf (_("Soft float\n"));
+ printf (_("soft float, "));
break;
case 3:
- printf (_("Single-precision hard float\n"));
+ printf (_("single-precision hard float, "));
break;
- default:
- printf ("??? (%d)\n", val);
+ }
+
+ switch (val & 0xC)
+ {
+ case 0:
+ printf (_("unspecified long double\n"));
+ break;
+ case 4:
+ printf (_("128-bit IBM long double\n"));
+ break;
+ case 8:
+ printf (_("64-bit long double\n"));
+ break;
+ case 12:
+ printf (_("128-bit IEEE long double\n"));
break;
}
return p;
- }
+ }
if (tag == Tag_GNU_Power_ABI_Vector)
{
val = read_uleb128 (p, &len, end);
p += len;
printf (" Tag_GNU_Power_ABI_Vector: ");
- switch (val)
+ if (len == 0)
+ {
+ printf (_("<corrupt>\n"));
+ return p;
+ }
+
+ if (val > 3)
+ printf ("(%#x), ", val);
+
+ switch (val & 3)
{
case 0:
- printf (_("Any\n"));
+ printf (_("unspecified\n"));
break;
case 1:
- printf (_("Generic\n"));
+ printf (_("generic\n"));
break;
case 2:
printf ("AltiVec\n");
@@ -13285,39 +13315,39 @@ display_power_gnu_attribute (unsigned char * p,
case 3:
printf ("SPE\n");
break;
- default:
- printf ("??? (%d)\n", val);
- break;
}
return p;
- }
+ }
if (tag == Tag_GNU_Power_ABI_Struct_Return)
{
- if (p == end)
+ val = read_uleb128 (p, &len, end);
+ p += len;
+ printf (" Tag_GNU_Power_ABI_Struct_Return: ");
+ if (len == 0)
{
- warn (_("corrupt Tag_GNU_Power_ABI_Struct_Return\n"));
+ printf (_("<corrupt>\n"));
return p;
}
- val = read_uleb128 (p, &len, end);
- p += len;
- printf (" Tag_GNU_Power_ABI_Struct_Return: ");
- switch (val)
- {
- case 0:
- printf (_("Any\n"));
- break;
- case 1:
- printf ("r3/r4\n");
- break;
- case 2:
- printf (_("Memory\n"));
- break;
- default:
- printf ("??? (%d)\n", val);
- break;
- }
+ if (val > 2)
+ printf ("(%#x), ", val);
+
+ switch (val & 3)
+ {
+ case 0:
+ printf (_("unspecified\n"));
+ break;
+ case 1:
+ printf ("r3/r4\n");
+ break;
+ case 2:
+ printf (_("memory\n"));
+ break;
+ case 3:
+ printf ("???\n");
+ break;
+ }
return p;
}
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 50fcf527a17..a786f299902 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,29 @@
+2017-03-08 Peter Bergner <bergner@vnet.ibm.com>
+
+ * testsuite/gas/ppc/altivec2.d (as): Use the -mpower8 option.
+ (objdump): Use the -Mpower8 option.
+
+2017-03-09 Alan Modra <amodra@gmail.com>
+
+ Apply from master
+ 2016-09-26 Alan Modra <amodra@gmail.com>
+ * config/tc-ppc.c (ppc_elf_gnu_attribute): New function.
+ (md_pseudo_table <ELF>): Handle "gnu_attribute".
+
+2017-03-08 Peter Bergner <bergner@vnet.ibm.com>
+
+ Apply from master.
+ 2017-03-08 Peter Bergner <bergner@vnet.ibm.com>
+ * testsuite/gas/ppc/power9.d <lnia> New test.
+ * testsuite/gas/ppc/power9.s: Likewise.
+
+2017-22-16 Peter Bergner <bergner@vnet.ibm.com>
+
+ Apply from master.
+ 2017-02-10 Nicholas Piggin <npiggin@gmail.com>
+
+ * testsuite/gas/ppc/power9.d <scv, rfscv>: New tests.
+
2016-09-16 Peter Bergner <bergner@vnet.ibm.com>
Apply from master.
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index fc2a0458288..975e8eb5974 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -133,6 +133,7 @@ static void ppc_elf_rdata (int);
static void ppc_elf_lcomm (int);
static void ppc_elf_localentry (int);
static void ppc_elf_abiversion (int);
+static void ppc_elf_gnu_attribute (int);
#endif
#ifdef TE_PE
@@ -270,6 +271,7 @@ const pseudo_typeS md_pseudo_table[] =
{ "lcomm", ppc_elf_lcomm, 0 },
{ "localentry", ppc_elf_localentry, 0 },
{ "abiversion", ppc_elf_abiversion, 0 },
+ { "gnu_attribute", ppc_elf_gnu_attribute, 0},
#endif
#ifdef TE_PE
@@ -2314,6 +2316,28 @@ ppc_elf_abiversion (int ignore ATTRIBUTE_UNUSED)
demand_empty_rest_of_line ();
}
+/* Parse a .gnu_attribute directive. */
+static void
+ppc_elf_gnu_attribute (int ignored ATTRIBUTE_UNUSED)
+{
+ int tag = obj_elf_vendor_attribute (OBJ_ATTR_GNU);
+
+ /* Check validity of defined powerpc tags. */
+ if (tag == Tag_GNU_Power_ABI_FP
+ || tag == Tag_GNU_Power_ABI_Vector
+ || tag == Tag_GNU_Power_ABI_Struct_Return)
+ {
+ unsigned int val;
+
+ val = bfd_elf_get_obj_attr_int (stdoutput, OBJ_ATTR_GNU, tag);
+
+ if ((tag == Tag_GNU_Power_ABI_FP && val > 15)
+ || (tag == Tag_GNU_Power_ABI_Vector && val > 3)
+ || (tag == Tag_GNU_Power_ABI_Struct_Return && val > 2))
+ as_warn (_("unknown .gnu_attribute value"));
+ }
+}
+
/* Set ABI version in output file. */
void
ppc_elf_end (void)
diff --git a/gas/testsuite/gas/ppc/altivec2.d b/gas/testsuite/gas/ppc/altivec2.d
index fc10fb5a2e4..26f9afa9a8c 100644
--- a/gas/testsuite/gas/ppc/altivec2.d
+++ b/gas/testsuite/gas/ppc/altivec2.d
@@ -1,5 +1,5 @@
-#as: -maltivec
-#objdump: -dr -Maltivec
+#as: -mpower8
+#objdump: -dr -Mpower8
#name: Altivec ISA 2.07 instructions
.*
diff --git a/gas/testsuite/gas/ppc/power9.d b/gas/testsuite/gas/ppc/power9.d
index 31e45304a14..3585387c122 100644
--- a/gas/testsuite/gas/ppc/power9.d
+++ b/gas/testsuite/gas/ppc/power9.d
@@ -312,8 +312,9 @@ Disassembly of section \.text:
.*: (f1 31 9d 6f|6f 9d 31 f1) xscvdphp vs41,vs51
.*: (f1 58 a7 6f|6f a7 58 f1) xvcvhpsp vs42,vs52
.*: (f1 79 af 6f|6f af 79 f1) xvcvsphp vs43,vs53
-.*: (4c 60 00 04|04 00 60 4c) addpcis r3,0
-.*: (4c 60 00 04|04 00 60 4c) addpcis r3,0
+.*: (4c 60 00 04|04 00 60 4c) lnia r3
+.*: (4c 60 00 04|04 00 60 4c) lnia r3
+.*: (4c 60 00 04|04 00 60 4c) lnia r3
.*: (4c 80 00 05|05 00 80 4c) addpcis r4,1
.*: (4c 80 00 05|05 00 80 4c) addpcis r4,1
.*: (4c bf ff c4|c4 ff bf 4c) addpcis r5,-2
@@ -391,4 +392,7 @@ Disassembly of section \.text:
.*: (ff d7 04 8e|8e 04 d7 ff) mffscrni f30,0
.*: (ff d7 1c 8e|8e 1c d7 ff) mffscrni f30,3
.*: (ff f8 04 8e|8e 04 f8 ff) mffsl f31
+.*: (01 00 00 44|44 00 00 01) scv 0
+.*: (e1 0f 00 44|44 00 0f e1) scv 127
+.*: (a4 00 00 4c|4c 00 00 a4) rfscv
#pass
diff --git a/gas/testsuite/gas/ppc/power9.s b/gas/testsuite/gas/ppc/power9.s
index 469435d9346..4e3530fba9e 100644
--- a/gas/testsuite/gas/ppc/power9.s
+++ b/gas/testsuite/gas/ppc/power9.s
@@ -303,6 +303,7 @@ power9:
xscvdphp 41,51
xvcvhpsp 42,52
xvcvsphp 43,53
+ lnia 3
addpcis 3,0
subpcis 3,0
addpcis 4,1
@@ -382,3 +383,6 @@ power9:
mffscrni 30,0
mffscrni 30,3
mffsl 31
+ scv 0
+ scv 127
+ rfscv
diff --git a/gold/ChangeLog b/gold/ChangeLog
index f5005ef96a3..59c60e7929c 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,3 +1,134 @@
+2017-02-22 Alan Modra <amodra@gmail.com>
+
+ Apply from master
+ * powerpc.cc (Target_powerpc::make_iplt_section): Check that
+ output_section exists before attempting add_output_section_data.
+ (Target_powerpc::make_brlt_section): Likewise.
+
+ 2017-02-03 Alan Modra <amodra@gmail.com>
+ * powerpc.cc (Powerpc_relobj::make_toc_relative): Don't crash
+ when no .toc section exists.
+
+ 2017-01-13 H.J. Lu <hongjiu.lu@intel.com>
+ PR gold/21040
+ * powerpc.cc (Powerpc_relobj<size, big_endian>::make_toc_relative):
+ Cast 0x80008000 to uint64_t.
+
+ 2017-01-11 Alan Modra <amodra@gmail.com>
+ * powerpc.cc (class Powerpc_copy_relocs): New.
+ (Powerpc_copy_relocs::emit): New function.
+ (Powerpc_relobj::relatoc_, toc_, no_toc_opt_): New variables.
+ (Powerpc_relobj::toc_shndx, set_no_toc_opt, no_toc_opt): New inlines.
+ (Powerpc_relobj::do_relocate_sections): New function.
+ (Powerpc_relobj::make_toc_relative): Likewise.
+ (Powerpc_relobj::do_find_special_sections): Stash away .rela.toc
+ and .toc too.
+ (ok_lo_toc_insn): Move earlier, and handle more insns.
+ (Target_powerpc::Scan::local): If optimizing toc accesses, set
+ no_toc_opt for entries we can't edit. Check insn validity.
+ Emit "toc optimization is not supported" warning, downgraded
+ from error.
+ (Target_powerpc::Scan::global): Likewise.
+ (Target_powerpc::Relocate::relocate): Edit TOC indirect code
+ to TOC relative. Don't emit "toc optimization is not supported"
+ error here.
+
+ 2017-01-10 Cary Coutant <ccoutant@gmail.com>
+ * aarch64.cc (AArch64_relobj::do_relocate_sections): Call
+ Sized_relobj_file::relocate_section_range().
+ * arm.cc (Arm_relobj::do_relocate_sections): Likewise.
+ * object.h (Sized_relobj_file::relocate_section_range): New method.
+ * reloc.cc (Sized_relobj_file::do_relocate_sections): Move
+ implementation...
+ (Sized_relobj_file::relocate_section_range): ...to new method.
+
+ 2017-01-10 Alan Modra <amodra@gmail.com>
+ * options.h: Add --secure-plt option.
+ * powerpc.cc (Target_powerpc::Scan::local): Detect and error
+ on -fPIC -mbss-plt code.
+ (Target_powerpc::Scan::global): Likewise.
+
+ 2017-01-09 Alan Modra <amodra@gmail.com>
+ * powerpc.cc (Target_powerpc::make_plt_section): Point sh_info of
+ ".rela.plt" at ".plt".
+
+ 2017-01-07 Alan Modra <amodra@gmail.com>
+ * powerpc.cc: Use shorter equivalent elfcpp typedef for
+ Reltype and reloc_size throughout.
+ (Target_powerpc::symval_for_branch): Exclude dynamic symbols.
+ (Target_powerpc::Scan::local): Use local var r_sym.
+ (Target_powerpc::Scan::global: Likewise.
+ (Target_powerpc::Relocate::relocate): Delete shadowing r_sym.
+
+ 2016-12-08 Alan Modra <amodra@gmail.com>
+ * powerpc.cc (Powerpc_relobj::stub_table): Return NULL rather
+ then asserting.
+
+ 2016-12-08 Alan Modra <amodra@gmail.com>
+ * options.h (--stub-group-multi): Fix typo.
+
+ 2016-12-07 Alan Modra <amodra@gmail.com>
+ * options.h (--stub-group-multi): New PowerPC option.
+ * powerpc.cc (Stub_control): Add multi_os_ var and param
+ to constructor. Sort start_ var later. Comment State.
+ (Stub_control::can_add_to_stub_group): Heed multi_os_.
+ (Target_powerpc::group_sections): Update.
+
+ 2016-12-07 Alan Modra <amodra@gmail.com>
+ PR gold/20878
+ * powerpc.cc (Stub_control): Replace stubs_always_before_branch_
+ with stubs_always_after_branch_, group_end_addr_ with
+ group_start_addr_.
+ (Stub_control::can_add_to_stub_group): Rewrite to suit scanning
+ sections by increasing address.
+ (Target_powerpc::group_sections): Scan that way. Delete corner
+ case.
+ * options.h (--stub-group-size): Update help string.
+
+ 2016-12-07 Alan Modra <amodra@gmail.com>
+ * powerpc.cc (Stub_table_owner): Provide constructor.
+ (Powerpc_relobj::set_stub_table): Resize fill with -1.
+ (Target_powerpc::Branch_info::make_stub): Provide target debug
+ output on returning false.
+
+ 2016-12-01 Cary Coutant <ccoutant@gmail.com>
+ PR gold/20807
+ * aarch64.cc (Target_aarch64::scan_reloc_section_for_stubs): Handle
+ section symbols correctly.
+ * arm.cc (Target_arm): Likewise.
+ * powerpc.cc (Target_powerpc): Likewise.
+
+ 2016-08-31 Alan Modra <amodra@gmail.com>
+ * powerpc.cc (class Stub_control): Delete stub14_group_size_
+ and has14_. Add group_size_.
+ (Stub_control::can_add_to_stub_group): Adjust to suit. Print
+ debug info when switching to adding sections before stubs.
+
+ 2016-08-31 Alan Modra <amodra@gmail.com>
+ * debug.h (DEBUG_TARGET): New.
+ (DEBUG_ALL): Add DEBUG_TARGET.
+ (gold_debug): Delete FORMAT param.
+ * powerpc.cc (Stub_control::can_add_to_stub_group): Print debug ourput.
+
+ 2016-08-30 Alan Modra <amodra@gmail.com>
+ PR 20523
+ * powerpc.cc (class Stub_control): Add has14_. Comment owner_.
+ (Stub_control::can_add_to_stub_group): Correct grouping of
+ sections containing 14-bit external branches. When returning
+ false, set state_ to reflect the fact that we have one section
+ for the next group. Rewrite most of function for clarity.
+ Add and expand comments.
+ (Target_powerpc::do_relax): Print stub group size retry in hex.
+
+ 2016-08-26 Han Shen <shenhan@google.com>
+ PR gold/20529 - relaxing loop never ends.
+ * powerpc.cc (Stub_table::min_size_threshold_): New member to
+ limit size.
+ (Stub_table::set_min_size_threshold): New member function.
+ (Stub_table::set_address_and_size): Add code to only allow size
+ increase.
+ (Target_powerpc::do_relax): Add code to record last size.
+
2016-09-26 Cary Coutant <ccoutant@gmail.com>
PR gold/20238
diff --git a/gold/aarch64.cc b/gold/aarch64.cc
index db9f06c1c67..96ed66e3ef7 100644
--- a/gold/aarch64.cc
+++ b/gold/aarch64.cc
@@ -2044,9 +2044,9 @@ AArch64_relobj<size, big_endian>::do_relocate_sections(
const unsigned char* pshdrs, Output_file* of,
typename Sized_relobj_file<size, big_endian>::Views* pviews)
{
- // Call parent to relocate sections.
- Sized_relobj_file<size, big_endian>::do_relocate_sections(symtab, layout,
- pshdrs, of, pviews);
+ // Relocate the section data.
+ this->relocate_section_range(symtab, layout, pshdrs, of, pviews,
+ 1, this->shnum() - 1);
// We do not generate stubs if doing a relocatable link.
if (parameters->options().relocatable())
@@ -3865,6 +3865,8 @@ Target_aarch64<size, big_endian>::scan_reloc_section_for_stubs(
if (!is_defined_in_discarded_section)
{
typedef Sized_relobj_file<size, big_endian> ObjType;
+ if (psymval->is_section_symbol())
+ symval.set_is_section_symbol();
typename ObjType::Compute_final_local_value_status status =
object->compute_final_local_value(r_sym, psymval, &symval,
relinfo->symtab);
diff --git a/gold/arm.cc b/gold/arm.cc
index c47b00224cc..d9c0a2b20de 100644
--- a/gold/arm.cc
+++ b/gold/arm.cc
@@ -6555,9 +6555,9 @@ Arm_relobj<big_endian>::do_relocate_sections(
Output_file* of,
typename Sized_relobj_file<32, big_endian>::Views* pviews)
{
- // Call parent to relocate sections.
- Sized_relobj_file<32, big_endian>::do_relocate_sections(symtab, layout,
- pshdrs, of, pviews);
+ // Relocate the section data.
+ this->relocate_section_range(symtab, layout, pshdrs, of, pviews,
+ 1, this->shnum() - 1);
// We do not generate stubs if doing a relocatable link.
if (parameters->options().relocatable())
@@ -11998,6 +11998,8 @@ Target_arm<big_endian>::scan_reloc_section_for_stubs(
if (!is_defined_in_discarded_section)
{
typedef Sized_relobj_file<32, big_endian> ObjType;
+ if (psymval->is_section_symbol())
+ symval.set_is_section_symbol();
typename ObjType::Compute_final_local_value_status status =
arm_object->compute_final_local_value(r_sym, psymval, &symval,
relinfo->symtab);
diff --git a/gold/debug.h b/gold/debug.h
index e95408ffd9e..6fd72c2c1c8 100644
--- a/gold/debug.h
+++ b/gold/debug.h
@@ -39,10 +39,11 @@ const int DEBUG_FILES = 0x4;
const int DEBUG_RELAXATION = 0x8;
const int DEBUG_INCREMENTAL = 0x10;
const int DEBUG_LOCATION = 0x20;
+const int DEBUG_TARGET = 0x40;
const int DEBUG_ALL = (DEBUG_TASK | DEBUG_SCRIPT | DEBUG_FILES
| DEBUG_RELAXATION | DEBUG_INCREMENTAL
- | DEBUG_LOCATION);
+ | DEBUG_LOCATION | DEBUG_TARGET);
// Convert a debug string to the appropriate enum.
inline int
@@ -57,6 +58,7 @@ debug_string_to_enum(const char* arg)
{ "relaxation", DEBUG_RELAXATION },
{ "incremental", DEBUG_INCREMENTAL },
{ "location", DEBUG_LOCATION },
+ { "target", DEBUG_TARGET },
{ "all", DEBUG_ALL }
};
@@ -70,11 +72,11 @@ debug_string_to_enum(const char* arg)
// Print a debug message if TYPE is enabled. This is a macro so that
// we only evaluate the arguments if necessary.
-#define gold_debug(TYPE, FORMAT, ...) \
+#define gold_debug(TYPE, ...) \
do \
{ \
if (is_debugging_enabled(TYPE)) \
- parameters->errors()->debug(FORMAT, __VA_ARGS__); \
+ parameters->errors()->debug(__VA_ARGS__); \
} \
while (0)
diff --git a/gold/object.h b/gold/object.h
index 95f6d56e086..aa1a815f031 100644
--- a/gold/object.h
+++ b/gold/object.h
@@ -2562,6 +2562,13 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
const unsigned char* pshdrs, Output_file* of,
Views* pviews);
+ // Relocate section data for a range of sections.
+ void
+ relocate_section_range(const Symbol_table* symtab, const Layout* layout,
+ const unsigned char* pshdrs, Output_file* of,
+ Views* pviews, unsigned int start_shndx,
+ unsigned int end_shndx);
+
// Adjust this local symbol value. Return false if the symbol
// should be discarded from the output file.
virtual bool
diff --git a/gold/options.h b/gold/options.h
index 4c5b2aea122..6786e9378e9 100644
--- a/gold/options.h
+++ b/gold/options.h
@@ -1069,6 +1069,9 @@ class General_options
DEFINE_special(section_start, options::TWO_DASHES, '\0',
N_("Set address of section"), N_("SECTION=ADDRESS"));
+ DEFINE_bool(secure_plt, options::TWO_DASHES , '\0', true,
+ N_("(PowerPC only) Use new-style PLT"), NULL);
+
DEFINE_optional_string(sort_common, options::TWO_DASHES, '\0', NULL,
N_("Sort common symbols by alignment"),
N_("[={ascending,descending}]"));
@@ -1097,11 +1100,14 @@ class General_options
DEFINE_int(stub_group_size, options::TWO_DASHES , '\0', 1,
N_("(ARM, PowerPC only) The maximum distance from instructions "
- "in a group of sections to their stubs. Negative values mean "
- "stubs are always after (PowerPC before) the group. 1 means "
- "use default size.\n"),
+ "in a group of sections to their stubs. Negative values mean "
+ "stubs are always after the group. 1 means use default size"),
N_("SIZE"));
+ DEFINE_bool(stub_group_multi, options::TWO_DASHES, '\0', false,
+ N_("(PowerPC only) Allow a group of stubs to serve multiple "
+ "output sections"), NULL);
+
DEFINE_bool(no_keep_memory, options::TWO_DASHES, '\0', false,
N_("Use less memory and more disk I/O "
"(included only for compatibility with GNU ld)"), NULL);
diff --git a/gold/powerpc.cc b/gold/powerpc.cc
index 60530bab984..2c70f9f8e4c 100644
--- a/gold/powerpc.cc
+++ b/gold/powerpc.cc
@@ -70,6 +70,10 @@ class Target_powerpc;
struct Stub_table_owner
{
+ Stub_table_owner()
+ : output_section(NULL), owner(NULL)
+ { }
+
Output_section* output_section;
const Output_section::Input_section* owner;
};
@@ -88,8 +92,9 @@ public:
Powerpc_relobj(const std::string& name, Input_file* input_file, off_t offset,
const typename elfcpp::Ehdr<size, big_endian>& ehdr)
: Sized_relobj_file<size, big_endian>(name, input_file, offset, ehdr),
- special_(0), has_small_toc_reloc_(false), opd_valid_(false),
- opd_ent_(), access_from_map_(), has14_(), stub_table_index_(),
+ special_(0), relatoc_(0), toc_(0), no_toc_opt_(),
+ has_small_toc_reloc_(false), opd_valid_(false), opd_ent_(),
+ access_from_map_(), has14_(), stub_table_index_(),
e_flags_(ehdr.get_e_flags()), st_other_()
{
this->set_abiversion(0);
@@ -102,6 +107,52 @@ public:
void
do_read_symbols(Read_symbols_data*);
+ // Arrange to always relocate .toc first.
+ virtual void
+ do_relocate_sections(
+ const Symbol_table* symtab, const Layout* layout,
+ const unsigned char* pshdrs, Output_file* of,
+ typename Sized_relobj_file<size, big_endian>::Views* pviews);
+
+ // The .toc section index.
+ unsigned int
+ toc_shndx() const
+ {
+ return this->toc_;
+ }
+
+ // Mark .toc entry at OFF as not optimizable.
+ void
+ set_no_toc_opt(Address off)
+ {
+ if (this->no_toc_opt_.empty())
+ this->no_toc_opt_.resize(this->section_size(this->toc_shndx())
+ / (size / 8));
+ off /= size / 8;
+ if (off < this->no_toc_opt_.size())
+ this->no_toc_opt_[off] = true;
+ }
+
+ // Mark the entire .toc as not optimizable.
+ void
+ set_no_toc_opt()
+ {
+ this->no_toc_opt_.resize(1);
+ this->no_toc_opt_[0] = true;
+ }
+
+ // Return true if code using the .toc entry at OFF should not be edited.
+ bool
+ no_toc_opt(Address off) const
+ {
+ if (this->no_toc_opt_.empty())
+ return false;
+ off /= size / 8;
+ if (off >= this->no_toc_opt_.size())
+ return true;
+ return this->no_toc_opt_[off];
+ }
+
// The .got2 section shndx.
unsigned int
got2_shndx() const
@@ -184,6 +235,12 @@ public:
const unsigned char* prelocs,
const unsigned char* plocal_syms);
+ // Returns true if a code sequence loading a TOC entry can be
+ // converted into code calculating a TOC pointer relative offset.
+ bool
+ make_toc_relative(Target_powerpc<size, big_endian>* target,
+ Address* value);
+
// Perform the Sized_relobj_file method, then set up opd info from
// .opd relocs.
void
@@ -275,7 +332,7 @@ public:
set_stub_table(unsigned int shndx, unsigned int stub_index)
{
if (shndx >= this->stub_table_index_.size())
- this->stub_table_index_.resize(shndx + 1);
+ this->stub_table_index_.resize(shndx + 1, -1);
this->stub_table_index_[shndx] = stub_index;
}
@@ -288,8 +345,8 @@ public:
= static_cast<Target_powerpc<size, big_endian>*>(
parameters->sized_target<size, big_endian>());
unsigned int indx = this->stub_table_index_[shndx];
- gold_assert(indx < target->stub_tables().size());
- return target->stub_tables()[indx];
+ if (indx < target->stub_tables().size())
+ return target->stub_tables()[indx];
}
return NULL;
}
@@ -342,6 +399,14 @@ private:
// For 32-bit the .got2 section shdnx, for 64-bit the .opd section shndx.
unsigned int special_;
+ // For 64-bit the .rela.toc and .toc section shdnx.
+ unsigned int relatoc_;
+ unsigned int toc_;
+
+ // For 64-bit, an array with one entry per 64-bit word in the .toc
+ // section, set if accesses using that word cannot be optimised.
+ std::vector<bool> no_toc_opt_;
+
// For 64-bit, whether this object uses small model relocs to access
// the toc.
bool has_small_toc_reloc_;
@@ -493,6 +558,23 @@ private:
elfcpp::Elf_Word e_flags_;
};
+// Powerpc_copy_relocs class. Needed to peek at dynamic relocs the
+// base class will emit.
+
+template<int sh_type, int size, bool big_endian>
+class Powerpc_copy_relocs : public Copy_relocs<sh_type, size, big_endian>
+{
+ public:
+ Powerpc_copy_relocs()
+ : Copy_relocs<sh_type, size, big_endian>(elfcpp::R_POWERPC_COPY)
+ { }
+
+ // Emit any saved relocations which turn out to be needed. This is
+ // called after all the relocs have been scanned.
+ void
+ emit(Output_data_reloc<sh_type, true, size, big_endian>*);
+};
+
template<int size, bool big_endian>
class Target_powerpc : public Sized_target<size, big_endian>
{
@@ -509,7 +591,7 @@ class Target_powerpc : public Sized_target<size, big_endian>
Target_powerpc()
: Sized_target<size, big_endian>(&powerpc_info),
got_(NULL), plt_(NULL), iplt_(NULL), brlt_section_(NULL),
- glink_(NULL), rela_dyn_(NULL), copy_relocs_(elfcpp::R_POWERPC_COPY),
+ glink_(NULL), rela_dyn_(NULL), copy_relocs_(),
tlsld_got_offset_(-1U),
stub_tables_(), branch_lookup_table_(), branch_info_(),
plt_thread_safe_(false), relax_failed_(false), relax_fail_count_(0),
@@ -1310,7 +1392,7 @@ class Target_powerpc : public Sized_target<size, big_endian>
// The dynamic reloc section.
Reloc_section* rela_dyn_;
// Relocs saved to avoid a COPY reloc.
- Copy_relocs<elfcpp::SHT_RELA, size, big_endian> copy_relocs_;
+ Powerpc_copy_relocs<elfcpp::SHT_RELA, size, big_endian> copy_relocs_;
// Offset of the GOT entry for local dynamic __tls_get_addr calls.
unsigned int tlsld_got_offset_;
@@ -1768,8 +1850,8 @@ Powerpc_relobj<size, big_endian>::set_abiversion(int ver)
}
}
-// Stash away the index of .got2 or .opd in a relocatable object, if
-// such a section exists.
+// Stash away the index of .got2, .opd, .rela.toc, and .toc in a
+// relocatable object, if such sections exists.
template<int size, bool big_endian>
bool
@@ -1798,6 +1880,18 @@ Powerpc_relobj<size, big_endian>::do_find_special_sections(
this->name().c_str(), this->abiversion());
}
}
+ if (size == 64)
+ {
+ s = this->template find_shdr<size, big_endian>(pshdrs, ".rela.toc",
+ names, names_size, NULL);
+ if (s != NULL)
+ {
+ unsigned int ndx = (s - pshdrs) / elfcpp::Elf_sizes<size>::shdr_size;
+ this->relatoc_ = ndx;
+ typename elfcpp::Shdr<size, big_endian> shdr(s);
+ this->toc_ = this->adjust_shndx(shdr.get_sh_info());
+ }
+ }
return Sized_relobj_file<size, big_endian>::do_find_special_sections(sd);
}
@@ -1812,10 +1906,8 @@ Powerpc_relobj<size, big_endian>::scan_opd_relocs(
{
if (size == 64)
{
- typedef typename Reloc_types<elfcpp::SHT_RELA, size, big_endian>::Reloc
- Reltype;
- const int reloc_size
- = Reloc_types<elfcpp::SHT_RELA, size, big_endian>::reloc_size;
+ typedef typename elfcpp::Rela<size, big_endian> Reltype;
+ const int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
Address expected_off = 0;
bool regular = true;
@@ -1880,6 +1972,60 @@ Powerpc_relobj<size, big_endian>::scan_opd_relocs(
}
}
+// Returns true if a code sequence loading the TOC entry at VALUE
+// relative to the TOC pointer can be converted into code calculating
+// a TOC pointer relative offset.
+// If so, the TOC pointer relative offset is stored to VALUE.
+
+template<int size, bool big_endian>
+bool
+Powerpc_relobj<size, big_endian>::make_toc_relative(
+ Target_powerpc<size, big_endian>* target,
+ Address* value)
+{
+ if (size != 64)
+ return false;
+
+ // With -mcmodel=medium code it is quite possible to have
+ // toc-relative relocs referring to objects outside the TOC.
+ // Don't try to look at a non-existent TOC.
+ if (this->toc_shndx() == 0)
+ return false;
+
+ // Convert VALUE back to an address by adding got_base (see below),
+ // then to an offset in the TOC by subtracting the TOC output
+ // section address and the TOC output offset. Since this TOC output
+ // section and the got output section are one and the same, we can
+ // omit adding and subtracting the output section address.
+ Address off = (*value + this->toc_base_offset()
+ - this->output_section_offset(this->toc_shndx()));
+ // Is this offset in the TOC? -mcmodel=medium code may be using
+ // TOC relative access to variables outside the TOC. Those of
+ // course can't be optimized. We also don't try to optimize code
+ // that is using a different object's TOC.
+ if (off >= this->section_size(this->toc_shndx()))
+ return false;
+
+ if (this->no_toc_opt(off))
+ return false;
+
+ section_size_type vlen;
+ unsigned char* view = this->get_output_view(this->toc_shndx(), &vlen);
+ Address addr = elfcpp::Swap<size, big_endian>::readval(view + off);
+ // The TOC pointer
+ Address got_base = (target->got_section()->output_section()->address()
+ + this->toc_base_offset());
+ addr -= got_base;
+ if (addr + (uint64_t) 0x80008000 >= (uint64_t) 1 << 32)
+ return false;
+
+ *value = addr;
+ return true;
+}
+
+// Perform the Sized_relobj_file method, then set up opd info from
+// .opd relocs.
+
template<int size, bool big_endian>
void
Powerpc_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
@@ -2075,6 +2221,31 @@ Powerpc_dynobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
}
}
+// Relocate sections.
+
+template<int size, bool big_endian>
+void
+Powerpc_relobj<size, big_endian>::do_relocate_sections(
+ const Symbol_table* symtab, const Layout* layout,
+ const unsigned char* pshdrs, Output_file* of,
+ typename Sized_relobj_file<size, big_endian>::Views* pviews)
+{
+ unsigned int start = 1;
+ if (size == 64
+ && this->relatoc_ != 0
+ && !parameters->options().relocatable())
+ {
+ // Relocate .toc first.
+ this->relocate_section_range(symtab, layout, pshdrs, of, pviews,
+ this->relatoc_, this->relatoc_);
+ this->relocate_section_range(symtab, layout, pshdrs, of, pviews,
+ 1, this->relatoc_ - 1);
+ start = this->relatoc_ + 1;
+ }
+ this->relocate_section_range(symtab, layout, pshdrs, of, pviews,
+ start, this->shnum() - 1);
+}
+
// Set up some symbols.
template<int size, bool big_endian>
@@ -2435,14 +2606,13 @@ class Stub_control
public:
// Determine the stub group size. The group size is the absolute
// value of the parameter --stub-group-size. If --stub-group-size
- // is passed a negative value, we restrict stubs to be always before
+ // is passed a negative value, we restrict stubs to be always after
// the stubbed branches.
- Stub_control(int32_t size, bool no_size_errors)
- : state_(NO_GROUP), stub_group_size_(abs(size)),
- stub14_group_size_(abs(size) >> 10),
- stubs_always_before_branch_(size < 0),
- suppress_size_errors_(no_size_errors),
- group_end_addr_(0), owner_(NULL), output_section_(NULL)
+ Stub_control(int32_t size, bool no_size_errors, bool multi_os)
+ : stub_group_size_(abs(size)), stubs_always_after_branch_(size < 0),
+ suppress_size_errors_(no_size_errors), multi_os_(multi_os),
+ state_(NO_GROUP), group_size_(0), group_start_addr_(0),
+ owner_(NULL), output_section_(NULL)
{
}
@@ -2472,31 +2642,40 @@ class Stub_control
private:
typedef enum
{
+ // Initial state.
NO_GROUP,
+ // Adding group sections before the stubs.
FINDING_STUB_SECTION,
+ // Adding group sections after the stubs.
HAS_STUB_SECTION
} State;
- State state_;
uint32_t stub_group_size_;
- uint32_t stub14_group_size_;
- bool stubs_always_before_branch_;
+ bool stubs_always_after_branch_;
bool suppress_size_errors_;
- uint64_t group_end_addr_;
+ // True if a stub group can serve multiple output sections.
+ bool multi_os_;
+ State state_;
+ // Current max size of group. Starts at stub_group_size_ but is
+ // reduced to stub_group_size_/1024 on seeing a section with
+ // external conditional branches.
+ uint32_t group_size_;
+ uint64_t group_start_addr_;
+ // owner_ and output_section_ specify the section to which stubs are
+ // attached. The stubs are placed at the end of this section.
const Output_section::Input_section* owner_;
Output_section* output_section_;
};
// Return true iff input section can be handled by current stub
-// group.
+// group. Sections are presented to this function in order,
+// so the first section is the head of the group.
bool
Stub_control::can_add_to_stub_group(Output_section* o,
const Output_section::Input_section* i,
bool has14)
{
- uint32_t group_size
- = has14 ? this->stub14_group_size_ : this->stub_group_size_;
bool whole_sec = o->order() == ORDER_INIT || o->order() == ORDER_FINI;
uint64_t this_size;
uint64_t start_addr = o->address();
@@ -2510,46 +2689,88 @@ Stub_control::can_add_to_stub_group(Output_section* o,
start_addr += i->relobj()->output_section_offset(i->shndx());
this_size = i->data_size();
}
+
uint64_t end_addr = start_addr + this_size;
- bool toobig = this_size > group_size;
+ uint32_t group_size = this->stub_group_size_;
+ if (has14)
+ this->group_size_ = group_size = group_size >> 10;
- if (toobig && !this->suppress_size_errors_)
+ if (this_size > group_size && !this->suppress_size_errors_)
gold_warning(_("%s:%s exceeds group size"),
i->relobj()->name().c_str(),
i->relobj()->section_name(i->shndx()).c_str());
- if (this->state_ != HAS_STUB_SECTION
- && (!whole_sec || this->output_section_ != o)
- && (this->state_ == NO_GROUP
- || this->group_end_addr_ - end_addr < group_size))
- {
- this->owner_ = i;
- this->output_section_ = o;
- }
+ gold_debug(DEBUG_TARGET, "maybe add%s %s:%s size=%#llx total=%#llx",
+ has14 ? " 14bit" : "",
+ i->relobj()->name().c_str(),
+ i->relobj()->section_name(i->shndx()).c_str(),
+ (long long) this_size,
+ (this->state_ == NO_GROUP
+ ? this_size
+ : (long long) end_addr - this->group_start_addr_));
if (this->state_ == NO_GROUP)
{
+ // Only here on very first use of Stub_control
+ this->owner_ = i;
+ this->output_section_ = o;
this->state_ = FINDING_STUB_SECTION;
- this->group_end_addr_ = end_addr;
+ this->group_size_ = group_size;
+ this->group_start_addr_ = start_addr;
+ return true;
}
- else if (this->group_end_addr_ - start_addr < group_size)
+ else if (!this->multi_os_ && this->output_section_ != o)
;
- // Adding this section would make the group larger than GROUP_SIZE.
- else if (this->state_ == FINDING_STUB_SECTION
- && !this->stubs_always_before_branch_
- && !toobig)
+ else if (this->state_ == HAS_STUB_SECTION)
{
- // But wait, there's more! Input sections up to GROUP_SIZE
- // bytes before the stub table can be handled by it too.
- this->state_ = HAS_STUB_SECTION;
- this->group_end_addr_ = end_addr;
+ // Can we add this section, which is after the stubs, to the
+ // group?
+ if (end_addr - this->group_start_addr_ <= this->group_size_)
+ return true;
}
- else
+ else if (this->state_ == FINDING_STUB_SECTION)
{
- this->state_ = NO_GROUP;
- return false;
+ if ((whole_sec && this->output_section_ == o)
+ || end_addr - this->group_start_addr_ <= this->group_size_)
+ {
+ // Stubs are added at the end of "owner_".
+ this->owner_ = i;
+ this->output_section_ = o;
+ return true;
+ }
+ // The group before the stubs has reached maximum size.
+ // Now see about adding sections after the stubs to the
+ // group. If the current section has a 14-bit branch and
+ // the group before the stubs exceeds group_size_ (because
+ // they didn't have 14-bit branches), don't add sections
+ // after the stubs: The size of stubs for such a large
+ // group may exceed the reach of a 14-bit branch.
+ if (!this->stubs_always_after_branch_
+ && this_size <= this->group_size_
+ && start_addr - this->group_start_addr_ <= this->group_size_)
+ {
+ gold_debug(DEBUG_TARGET, "adding after stubs");
+ this->state_ = HAS_STUB_SECTION;
+ this->group_start_addr_ = start_addr;
+ return true;
+ }
}
- return true;
+ else
+ gold_unreachable();
+
+ gold_debug(DEBUG_TARGET,
+ !this->multi_os_ && this->output_section_ != o
+ ? "nope, new output section\n"
+ : "nope, didn't fit\n");
+
+ // The section fails to fit in the current group. Set up a few
+ // things for the next group. owner_ and output_section_ will be
+ // set later after we've retrieved those values for the current
+ // group.
+ this->state_ = FINDING_STUB_SECTION;
+ this->group_size_ = group_size;
+ this->group_start_addr_ = start_addr;
+ return false;
}
// Look over all the input sections, deciding where to place stubs.
@@ -2560,7 +2781,8 @@ Target_powerpc<size, big_endian>::group_sections(Layout* layout,
const Task*,
bool no_size_errors)
{
- Stub_control stub_control(this->stub_group_size_, no_size_errors);
+ Stub_control stub_control(this->stub_group_size_, no_size_errors,
+ parameters->options().stub_group_multi());
// Group input sections and insert stub table
Stub_table_owner* table_owner = NULL;
@@ -2568,14 +2790,14 @@ Target_powerpc<size, big_endian>::group_sections(Layout* layout,
Layout::Section_list section_list;
layout->get_executable_sections(&section_list);
std::stable_sort(section_list.begin(), section_list.end(), Sort_sections());
- for (Layout::Section_list::reverse_iterator o = section_list.rbegin();
- o != section_list.rend();
+ for (Layout::Section_list::iterator o = section_list.begin();
+ o != section_list.end();
++o)
{
typedef Output_section::Input_section_list Input_section_list;
- for (Input_section_list::const_reverse_iterator i
- = (*o)->input_sections().rbegin();
- i != (*o)->input_sections().rend();
+ for (Input_section_list::const_iterator i
+ = (*o)->input_sections().begin();
+ i != (*o)->input_sections().end();
++i)
{
if (i->is_input_section()
@@ -2602,26 +2824,8 @@ Target_powerpc<size, big_endian>::group_sections(Layout* layout,
}
if (table_owner != NULL)
{
- const Output_section::Input_section* i = stub_control.owner();
-
- if (tables.size() >= 2 && tables[tables.size() - 2]->owner == i)
- {
- // Corner case. A new stub group was made for the first
- // section (last one looked at here) for some reason, but
- // the first section is already being used as the owner for
- // a stub table for following sections. Force it into that
- // stub group.
- tables.pop_back();
- delete table_owner;
- Powerpc_relobj<size, big_endian>* ppcobj = static_cast
- <Powerpc_relobj<size, big_endian>*>(i->relobj());
- ppcobj->set_stub_table(i->shndx(), tables.size() - 1);
- }
- else
- {
- table_owner->output_section = stub_control.output_section();
- table_owner->owner = i;
- }
+ table_owner->output_section = stub_control.output_section();
+ table_owner->owner = stub_control.owner();;
}
for (typename std::vector<Stub_table_owner*>::iterator t = tables.begin();
t != tables.end();
@@ -2673,6 +2877,8 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
Target_powerpc<size, big_endian>* target =
static_cast<Target_powerpc<size, big_endian>*>(
parameters->sized_target<size, big_endian>());
+ bool ok = true;
+
if (gsym != NULL
? gsym->use_plt_offset(Scan::get_reference_flags(this->r_type_, target))
: this->object_->local_has_plt_offset(this->r_sym_))
@@ -2698,13 +2904,13 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
from += (this->object_->output_section(this->shndx_)->address()
+ this->offset_);
if (gsym != NULL)
- return stub_table->add_plt_call_entry(from,
- this->object_, gsym,
- this->r_type_, this->addend_);
+ ok = stub_table->add_plt_call_entry(from,
+ this->object_, gsym,
+ this->r_type_, this->addend_);
else
- return stub_table->add_plt_call_entry(from,
- this->object_, this->r_sym_,
- this->r_type_, this->addend_);
+ ok = stub_table->add_plt_call_entry(from,
+ this->object_, this->r_sym_,
+ this->r_type_, this->addend_);
}
}
else
@@ -2752,6 +2958,8 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
const Symbol_value<size>* psymval
= this->object_->local_symbol(this->r_sym_);
Symbol_value<size> symval;
+ if (psymval->is_section_symbol())
+ symval.set_is_section_symbol();
typedef Sized_relobj_file<size, big_endian> ObjType;
typename ObjType::Compute_final_local_value_status status
= this->object_->compute_final_local_value(this->r_sym_, psymval,
@@ -2789,12 +2997,22 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
&& gsym != NULL
&& gsym->source() == Symbol::IN_OUTPUT_DATA
&& gsym->output_data() == target->savres_section());
- return stub_table->add_long_branch_entry(this->object_,
- this->r_type_,
- from, to, save_res);
+ ok = stub_table->add_long_branch_entry(this->object_,
+ this->r_type_,
+ from, to, save_res);
}
}
- return true;
+ if (!ok)
+ gold_debug(DEBUG_TARGET,
+ "branch at %s:%s+%#lx\n"
+ "can't reach stub attached to %s:%s",
+ this->object_->name().c_str(),
+ this->object_->section_name(this->shndx_).c_str(),
+ (unsigned long) this->offset_,
+ stub_table->relobj()->name().c_str(),
+ stub_table->relobj()->section_name(stub_table->shndx()).c_str());
+
+ return ok;
}
// Relaxation hook. This is where we do stub generation.
@@ -2887,7 +3105,7 @@ Target_powerpc<size, big_endian>::do_relax(int pass,
}
this->stub_tables_.clear();
this->stub_group_size_ = this->stub_group_size_ / 4 * 3;
- gold_info(_("%s: stub group size is too large; retrying with %d"),
+ gold_info(_("%s: stub group size is too large; retrying with %#x"),
program_name, this->stub_group_size_);
this->group_sections(layout, task, true);
}
@@ -2982,7 +3200,13 @@ Target_powerpc<size, big_endian>::do_relax(int pass,
Stub_table<size, big_endian>* stub_table
= static_cast<Stub_table<size, big_endian>*>(
i->relaxed_input_section());
- off += stub_table->set_address_and_size(os, off);
+ Address stub_table_size = stub_table->set_address_and_size(os, off);
+ off += stub_table_size;
+ // After a few iterations, set current stub table size
+ // as min size threshold, so later stub tables can only
+ // grow in size.
+ if (pass >= 4)
+ stub_table->set_min_size_threshold(stub_table_size);
}
else
off += i->data_size();
@@ -3366,6 +3590,9 @@ Target_powerpc<size, big_endian>::make_plt_section(Symbol_table* symtab,
? ORDER_SMALL_DATA
: ORDER_SMALL_BSS),
false);
+
+ Output_section* rela_plt_os = plt_rel->output_section();
+ rela_plt_os->set_info_section(this->plt_->output_section());
}
}
@@ -3381,11 +3608,13 @@ Target_powerpc<size, big_endian>::make_iplt_section(Symbol_table* symtab,
this->make_plt_section(symtab, layout);
Reloc_section* iplt_rel = new Reloc_section(false);
- this->rela_dyn_->output_section()->add_output_section_data(iplt_rel);
+ if (this->rela_dyn_->output_section())
+ this->rela_dyn_->output_section()->add_output_section_data(iplt_rel);
this->iplt_
= new Output_data_plt_powerpc<size, big_endian>(this, iplt_rel,
"** IPLT");
- this->plt_->output_section()->add_output_section_data(this->iplt_);
+ if (this->plt_->output_section())
+ this->plt_->output_section()->add_output_section_data(this->iplt_);
}
}
@@ -3436,8 +3665,7 @@ class Output_data_brlt_powerpc : public Output_section_data_build
os->set_section_offsets_need_adjustment();
if (this->rel_ != NULL)
{
- unsigned int reloc_size
- = Reloc_types<elfcpp::SHT_RELA, size, big_endian>::reloc_size;
+ const unsigned int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
this->rel_->reset_address_and_file_offset();
this->rel_->set_current_data_size(num_branches * reloc_size);
this->rel_->finalize_data_size();
@@ -3482,14 +3710,16 @@ Target_powerpc<size, big_endian>::make_brlt_section(Layout* layout)
{
// When PIC we can't fill in .branch_lt (like .plt it can be
// a bss style section) but must initialise at runtime via
- // dynamic relocats.
+ // dynamic relocations.
this->rela_dyn_section(layout);
brlt_rel = new Reloc_section(false);
- this->rela_dyn_->output_section()->add_output_section_data(brlt_rel);
+ if (this->rela_dyn_->output_section())
+ this->rela_dyn_->output_section()
+ ->add_output_section_data(brlt_rel);
}
this->brlt_section_
= new Output_data_brlt_powerpc<size, big_endian>(this, brlt_rel);
- if (this->plt_ && is_pic)
+ if (this->plt_ && is_pic && this->plt_->output_section())
this->plt_->output_section()
->add_output_section_data(this->brlt_section_);
else
@@ -3634,8 +3864,8 @@ class Stub_table : public Output_relaxed_input_section
targ_(targ), plt_call_stubs_(), long_branch_stubs_(),
orig_data_size_(owner->current_data_size()),
plt_size_(0), last_plt_size_(0),
- branch_size_(0), last_branch_size_(0), eh_frame_added_(false),
- need_save_res_(false)
+ branch_size_(0), last_branch_size_(0), min_size_threshold_(0),
+ eh_frame_added_(false), need_save_res_(false)
{
this->set_output_section(output_section);
@@ -3726,6 +3956,11 @@ class Stub_table : public Output_relaxed_input_section
off = align_address(off, this->stub_align());
// Include original section size and alignment padding in size
my_size += off - start_off;
+ // Ensure new size is always larger than min size
+ // threshold. Alignment requirement is included in "my_size", so
+ // increase "my_size" does not invalidate alignment.
+ if (my_size < this->min_size_threshold_)
+ my_size = this->min_size_threshold_;
this->reset_address_and_file_offset();
this->set_current_data_size(my_size);
this->set_address_and_file_offset(os->address() + start_off,
@@ -3751,6 +3986,9 @@ class Stub_table : public Output_relaxed_input_section
plt_size() const
{ return this->plt_size_; }
+ void set_min_size_threshold(Address min_size)
+ { this->min_size_threshold_ = min_size; }
+
bool
size_update()
{
@@ -4015,6 +4253,13 @@ class Stub_table : public Output_relaxed_input_section
section_size_type orig_data_size_;
// size of stubs
section_size_type plt_size_, last_plt_size_, branch_size_, last_branch_size_;
+ // Some rare cases cause (PR/20529) fluctuation in stub table
+ // size, which leads to an endless relax loop. This is to be fixed
+ // by, after the first few iterations, allowing only increase of
+ // stub table size. This variable sets the minimal possible size of
+ // a stub table, it is zero for the first few iterations, then
+ // increases monotonically.
+ Address min_size_threshold_;
// Whether .eh_frame info has been created for this stub section.
bool eh_frame_added_;
// Set if this stub group needs a copy of out-of-line register
@@ -5545,6 +5790,45 @@ Target_powerpc<size, big_endian>::Scan::reloc_needs_plt_for_ifunc(
return false;
}
+// Return TRUE iff INSN is one we expect on a _LO variety toc/got
+// reloc.
+
+static bool
+ok_lo_toc_insn(uint32_t insn, unsigned int r_type)
+{
+ return ((insn & (0x3f << 26)) == 12u << 26 /* addic */
+ || (insn & (0x3f << 26)) == 14u << 26 /* addi */
+ || (insn & (0x3f << 26)) == 32u << 26 /* lwz */
+ || (insn & (0x3f << 26)) == 34u << 26 /* lbz */
+ || (insn & (0x3f << 26)) == 36u << 26 /* stw */
+ || (insn & (0x3f << 26)) == 38u << 26 /* stb */
+ || (insn & (0x3f << 26)) == 40u << 26 /* lhz */
+ || (insn & (0x3f << 26)) == 42u << 26 /* lha */
+ || (insn & (0x3f << 26)) == 44u << 26 /* sth */
+ || (insn & (0x3f << 26)) == 46u << 26 /* lmw */
+ || (insn & (0x3f << 26)) == 47u << 26 /* stmw */
+ || (insn & (0x3f << 26)) == 48u << 26 /* lfs */
+ || (insn & (0x3f << 26)) == 50u << 26 /* lfd */
+ || (insn & (0x3f << 26)) == 52u << 26 /* stfs */
+ || (insn & (0x3f << 26)) == 54u << 26 /* stfd */
+ || (insn & (0x3f << 26)) == 56u << 26 /* lq,lfq */
+ || ((insn & (0x3f << 26)) == 57u << 26 /* lxsd,lxssp,lfdp */
+ /* Exclude lfqu by testing reloc. If relocs are ever
+ defined for the reduced D field in psq_lu then those
+ will need testing too. */
+ && r_type != elfcpp::R_PPC64_TOC16_LO
+ && r_type != elfcpp::R_POWERPC_GOT16_LO)
+ || ((insn & (0x3f << 26)) == 58u << 26 /* ld,lwa */
+ && (insn & 1) == 0)
+ || (insn & (0x3f << 26)) == 60u << 26 /* stfq */
+ || ((insn & (0x3f << 26)) == 61u << 26 /* lxv,stx{v,sd,ssp},stfdp */
+ /* Exclude stfqu. psq_stu as above for psq_lu. */
+ && r_type != elfcpp::R_PPC64_TOC16_LO
+ && r_type != elfcpp::R_POWERPC_GOT16_LO)
+ || ((insn & (0x3f << 26)) == 62u << 26 /* std,stq */
+ && (insn & 1) == 0));
+}
+
// Scan a relocation for a local symbol.
template<int size, bool big_endian>
@@ -5708,9 +5992,11 @@ Target_powerpc<size, big_endian>::Scan::local(
case elfcpp::R_POWERPC_REL14_BRTAKEN:
case elfcpp::R_POWERPC_REL14_BRNTAKEN:
if (!is_ifunc)
- target->push_branch(ppc_object, data_shndx, reloc.get_r_offset(),
- r_type, elfcpp::elf_r_sym<size>(reloc.get_r_info()),
- reloc.get_r_addend());
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ target->push_branch(ppc_object, data_shndx, reloc.get_r_offset(),
+ r_type, r_sym, reloc.get_r_addend());
+ }
break;
case elfcpp::R_PPC64_REL64:
@@ -5898,6 +6184,150 @@ Target_powerpc<size, big_endian>::Scan::local(
break;
}
+ if (size == 64
+ && parameters->options().toc_optimize())
+ {
+ if (data_shndx == ppc_object->toc_shndx())
+ {
+ bool ok = true;
+ if (r_type != elfcpp::R_PPC64_ADDR64
+ || (is_ifunc && target->abiversion() < 2))
+ ok = false;
+ else if (parameters->options().output_is_position_independent())
+ {
+ if (is_ifunc)
+ ok = false;
+ else
+ {
+ unsigned int shndx = lsym.get_st_shndx();
+ if (shndx >= elfcpp::SHN_LORESERVE
+ && shndx != elfcpp::SHN_XINDEX)
+ ok = false;
+ }
+ }
+ if (!ok)
+ ppc_object->set_no_toc_opt(reloc.get_r_offset());
+ }
+
+ enum {no_check, check_lo, check_ha} insn_check;
+ switch (r_type)
+ {
+ default:
+ insn_check = no_check;
+ break;
+
+ case elfcpp::R_POWERPC_GOT_TLSLD16_HA:
+ case elfcpp::R_POWERPC_GOT_TLSGD16_HA:
+ case elfcpp::R_POWERPC_GOT_TPREL16_HA:
+ case elfcpp::R_POWERPC_GOT_DTPREL16_HA:
+ case elfcpp::R_POWERPC_GOT16_HA:
+ case elfcpp::R_PPC64_TOC16_HA:
+ insn_check = check_ha;
+ break;
+
+ case elfcpp::R_POWERPC_GOT_TLSLD16_LO:
+ case elfcpp::R_POWERPC_GOT_TLSGD16_LO:
+ case elfcpp::R_POWERPC_GOT_TPREL16_LO:
+ case elfcpp::R_POWERPC_GOT_DTPREL16_LO:
+ case elfcpp::R_POWERPC_GOT16_LO:
+ case elfcpp::R_PPC64_GOT16_LO_DS:
+ case elfcpp::R_PPC64_TOC16_LO:
+ case elfcpp::R_PPC64_TOC16_LO_DS:
+ insn_check = check_lo;
+ break;
+ }
+
+ section_size_type slen;
+ const unsigned char* view = NULL;
+ if (insn_check != no_check)
+ {
+ view = ppc_object->section_contents(data_shndx, &slen, false);
+ section_size_type off =
+ convert_to_section_size_type(reloc.get_r_offset()) & -4;
+ if (off < slen)
+ {
+ uint32_t insn = elfcpp::Swap<32, big_endian>::readval(view + off);
+ if (insn_check == check_lo
+ ? !ok_lo_toc_insn(insn, r_type)
+ : ((insn & ((0x3f << 26) | 0x1f << 16))
+ != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */))
+ {
+ ppc_object->set_no_toc_opt();
+ gold_warning(_("%s: toc optimization is not supported "
+ "for %#08x instruction"),
+ ppc_object->name().c_str(), insn);
+ }
+ }
+ }
+
+ switch (r_type)
+ {
+ default:
+ break;
+ case elfcpp::R_PPC64_TOC16:
+ case elfcpp::R_PPC64_TOC16_LO:
+ case elfcpp::R_PPC64_TOC16_HI:
+ case elfcpp::R_PPC64_TOC16_HA:
+ case elfcpp::R_PPC64_TOC16_DS:
+ case elfcpp::R_PPC64_TOC16_LO_DS:
+ unsigned int shndx = lsym.get_st_shndx();
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ bool is_ordinary;
+ shndx = ppc_object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
+ if (is_ordinary && shndx == ppc_object->toc_shndx())
+ {
+ Address dst_off = lsym.get_st_value() + reloc.get_r_offset();
+ if (dst_off < ppc_object->section_size(shndx))
+ {
+ bool ok = false;
+ if (r_type == elfcpp::R_PPC64_TOC16_HA)
+ ok = true;
+ else if (r_type == elfcpp::R_PPC64_TOC16_LO_DS)
+ {
+ // Need to check that the insn is a ld
+ if (!view)
+ view = ppc_object->section_contents(data_shndx,
+ &slen,
+ false);
+ section_size_type off =
+ (convert_to_section_size_type(reloc.get_r_offset())
+ + (big_endian ? -2 : 3));
+ if (off < slen
+ && (view[off] & (0x3f << 2)) == 58u << 2)
+ ok = true;
+ }
+ if (!ok)
+ ppc_object->set_no_toc_opt(dst_off);
+ }
+ }
+ break;
+ }
+ }
+
+ if (size == 32)
+ {
+ switch (r_type)
+ {
+ case elfcpp::R_POWERPC_REL32:
+ if (ppc_object->got2_shndx() != 0
+ && parameters->options().output_is_position_independent())
+ {
+ unsigned int shndx = lsym.get_st_shndx();
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ bool is_ordinary;
+ shndx = ppc_object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
+ if (is_ordinary && shndx == ppc_object->got2_shndx()
+ && (ppc_object->section_flags(data_shndx)
+ & elfcpp::SHF_EXECINSTR) != 0)
+ gold_error(_("%s: unsupported -mbss-plt code"),
+ ppc_object->name().c_str());
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
switch (r_type)
{
case elfcpp::R_POWERPC_GOT_TLSLD16:
@@ -5971,9 +6401,9 @@ Target_powerpc<size, big_endian>::Scan::global(
bool pushed_ifunc = false;
if (is_ifunc && this->reloc_needs_plt_for_ifunc(target, object, r_type, true))
{
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
target->push_branch(ppc_object, data_shndx, reloc.get_r_offset(),
- r_type, elfcpp::elf_r_sym<size>(reloc.get_r_info()),
- reloc.get_r_addend());
+ r_type, r_sym, reloc.get_r_addend());
target->make_plt_entry(symtab, layout, gsym);
pushed_ifunc = true;
}
@@ -6063,9 +6493,9 @@ Target_powerpc<size, big_endian>::Scan::global(
}
if (!is_ifunc || (!pushed_ifunc && need_ifunc_plt))
{
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
target->push_branch(ppc_object, data_shndx,
- reloc.get_r_offset(), r_type,
- elfcpp::elf_r_sym<size>(reloc.get_r_info()),
+ reloc.get_r_offset(), r_type, r_sym,
reloc.get_r_addend());
target->make_plt_entry(symtab, layout, gsym);
}
@@ -6111,6 +6541,11 @@ Target_powerpc<size, big_endian>::Scan::global(
object, data_shndx,
reloc.get_r_offset(),
reloc.get_r_addend());
+
+ if (size == 64
+ && parameters->options().toc_optimize()
+ && data_shndx == ppc_object->toc_shndx())
+ ppc_object->set_no_toc_opt(reloc.get_r_offset());
}
}
}
@@ -6120,10 +6555,9 @@ Target_powerpc<size, big_endian>::Scan::global(
case elfcpp::R_POWERPC_REL24:
if (!is_ifunc)
{
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
target->push_branch(ppc_object, data_shndx, reloc.get_r_offset(),
- r_type,
- elfcpp::elf_r_sym<size>(reloc.get_r_info()),
- reloc.get_r_addend());
+ r_type, r_sym, reloc.get_r_addend());
if (gsym->needs_plt_entry()
|| (!gsym->final_value_is_known()
&& (gsym->is_undefined()
@@ -6161,9 +6595,11 @@ Target_powerpc<size, big_endian>::Scan::global(
case elfcpp::R_POWERPC_REL14_BRTAKEN:
case elfcpp::R_POWERPC_REL14_BRNTAKEN:
if (!is_ifunc)
- target->push_branch(ppc_object, data_shndx, reloc.get_r_offset(),
- r_type, elfcpp::elf_r_sym<size>(reloc.get_r_info()),
- reloc.get_r_addend());
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ target->push_branch(ppc_object, data_shndx, reloc.get_r_offset(),
+ r_type, r_sym, reloc.get_r_addend());
+ }
break;
case elfcpp::R_POWERPC_REL16:
@@ -6398,6 +6834,136 @@ Target_powerpc<size, big_endian>::Scan::global(
break;
}
+ if (size == 64
+ && parameters->options().toc_optimize())
+ {
+ if (data_shndx == ppc_object->toc_shndx())
+ {
+ bool ok = true;
+ if (r_type != elfcpp::R_PPC64_ADDR64
+ || (is_ifunc && target->abiversion() < 2))
+ ok = false;
+ else if (parameters->options().output_is_position_independent()
+ && (is_ifunc || gsym->is_absolute() || gsym->is_undefined()))
+ ok = false;
+ if (!ok)
+ ppc_object->set_no_toc_opt(reloc.get_r_offset());
+ }
+
+ enum {no_check, check_lo, check_ha} insn_check;
+ switch (r_type)
+ {
+ default:
+ insn_check = no_check;
+ break;
+
+ case elfcpp::R_POWERPC_GOT_TLSLD16_HA:
+ case elfcpp::R_POWERPC_GOT_TLSGD16_HA:
+ case elfcpp::R_POWERPC_GOT_TPREL16_HA:
+ case elfcpp::R_POWERPC_GOT_DTPREL16_HA:
+ case elfcpp::R_POWERPC_GOT16_HA:
+ case elfcpp::R_PPC64_TOC16_HA:
+ insn_check = check_ha;
+ break;
+
+ case elfcpp::R_POWERPC_GOT_TLSLD16_LO:
+ case elfcpp::R_POWERPC_GOT_TLSGD16_LO:
+ case elfcpp::R_POWERPC_GOT_TPREL16_LO:
+ case elfcpp::R_POWERPC_GOT_DTPREL16_LO:
+ case elfcpp::R_POWERPC_GOT16_LO:
+ case elfcpp::R_PPC64_GOT16_LO_DS:
+ case elfcpp::R_PPC64_TOC16_LO:
+ case elfcpp::R_PPC64_TOC16_LO_DS:
+ insn_check = check_lo;
+ break;
+ }
+
+ section_size_type slen;
+ const unsigned char* view = NULL;
+ if (insn_check != no_check)
+ {
+ view = ppc_object->section_contents(data_shndx, &slen, false);
+ section_size_type off =
+ convert_to_section_size_type(reloc.get_r_offset()) & -4;
+ if (off < slen)
+ {
+ uint32_t insn = elfcpp::Swap<32, big_endian>::readval(view + off);
+ if (insn_check == check_lo
+ ? !ok_lo_toc_insn(insn, r_type)
+ : ((insn & ((0x3f << 26) | 0x1f << 16))
+ != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */))
+ {
+ ppc_object->set_no_toc_opt();
+ gold_warning(_("%s: toc optimization is not supported "
+ "for %#08x instruction"),
+ ppc_object->name().c_str(), insn);
+ }
+ }
+ }
+
+ switch (r_type)
+ {
+ default:
+ break;
+ case elfcpp::R_PPC64_TOC16:
+ case elfcpp::R_PPC64_TOC16_LO:
+ case elfcpp::R_PPC64_TOC16_HI:
+ case elfcpp::R_PPC64_TOC16_HA:
+ case elfcpp::R_PPC64_TOC16_DS:
+ case elfcpp::R_PPC64_TOC16_LO_DS:
+ if (gsym->source() == Symbol::FROM_OBJECT
+ && !gsym->object()->is_dynamic())
+ {
+ Powerpc_relobj<size, big_endian>* sym_object
+ = static_cast<Powerpc_relobj<size, big_endian>*>(gsym->object());
+ bool is_ordinary;
+ unsigned int shndx = gsym->shndx(&is_ordinary);
+ if (shndx == sym_object->toc_shndx())
+ {
+ Sized_symbol<size>* sym = symtab->get_sized_symbol<size>(gsym);
+ Address dst_off = sym->value() + reloc.get_r_offset();
+ if (dst_off < sym_object->section_size(shndx))
+ {
+ bool ok = false;
+ if (r_type == elfcpp::R_PPC64_TOC16_HA)
+ ok = true;
+ else if (r_type == elfcpp::R_PPC64_TOC16_LO_DS)
+ {
+ // Need to check that the insn is a ld
+ if (!view)
+ view = ppc_object->section_contents(data_shndx,
+ &slen,
+ false);
+ section_size_type off =
+ (convert_to_section_size_type(reloc.get_r_offset())
+ + (big_endian ? -2 : 3));
+ if (off < slen
+ && (view[off] & (0x3f << 2)) == (58u << 2))
+ ok = true;
+ }
+ if (!ok)
+ sym_object->set_no_toc_opt(dst_off);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if (size == 32)
+ {
+ switch (r_type)
+ {
+ case elfcpp::R_PPC_LOCAL24PC:
+ if (strcmp(gsym->name(), "_GLOBAL_OFFSET_TABLE_") == 0)
+ gold_error(_("%s: unsupported -mbss-plt code"),
+ ppc_object->name().c_str());
+ break;
+ default:
+ break;
+ }
+ }
+
switch (r_type)
{
case elfcpp::R_POWERPC_GOT_TLSLD16:
@@ -6918,31 +7484,40 @@ Target_powerpc<size, big_endian>::do_finalize_sections(
this->copy_relocs_.emit(this->rela_dyn_section(layout));
}
-// Return TRUE iff INSN is one we expect on a _LO variety toc/got
-// reloc.
+// Emit any saved relocs, and mark toc entries using any of these
+// relocs as not optimizable.
-static bool
-ok_lo_toc_insn(uint32_t insn)
+template<int sh_type, int size, bool big_endian>
+void
+Powerpc_copy_relocs<sh_type, size, big_endian>::emit(
+ Output_data_reloc<sh_type, true, size, big_endian>* reloc_section)
{
- return ((insn & (0x3f << 26)) == 14u << 26 /* addi */
- || (insn & (0x3f << 26)) == 32u << 26 /* lwz */
- || (insn & (0x3f << 26)) == 34u << 26 /* lbz */
- || (insn & (0x3f << 26)) == 36u << 26 /* stw */
- || (insn & (0x3f << 26)) == 38u << 26 /* stb */
- || (insn & (0x3f << 26)) == 40u << 26 /* lhz */
- || (insn & (0x3f << 26)) == 42u << 26 /* lha */
- || (insn & (0x3f << 26)) == 44u << 26 /* sth */
- || (insn & (0x3f << 26)) == 46u << 26 /* lmw */
- || (insn & (0x3f << 26)) == 47u << 26 /* stmw */
- || (insn & (0x3f << 26)) == 48u << 26 /* lfs */
- || (insn & (0x3f << 26)) == 50u << 26 /* lfd */
- || (insn & (0x3f << 26)) == 52u << 26 /* stfs */
- || (insn & (0x3f << 26)) == 54u << 26 /* stfd */
- || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */
- && (insn & 3) != 1)
- || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */
- && ((insn & 3) == 0 || (insn & 3) == 3))
- || (insn & (0x3f << 26)) == 12u << 26 /* addic */);
+ if (size == 64
+ && parameters->options().toc_optimize())
+ {
+ for (typename Copy_relocs<sh_type, size, big_endian>::
+ Copy_reloc_entries::iterator p = this->entries_.begin();
+ p != this->entries_.end();
+ ++p)
+ {
+ typename Copy_relocs<sh_type, size, big_endian>::Copy_reloc_entry&
+ entry = *p;
+
+ // If the symbol is no longer defined in a dynamic object,
+ // then we emitted a COPY relocation. If it is still
+ // dynamic then we'll need dynamic relocations and thus
+ // can't optimize toc entries.
+ if (entry.sym_->is_from_dynobj())
+ {
+ Powerpc_relobj<size, big_endian>* ppc_object
+ = static_cast<Powerpc_relobj<size, big_endian>*>(entry.relobj_);
+ if (entry.shndx_ == ppc_object->toc_shndx())
+ ppc_object->set_no_toc_opt(entry.address_);
+ }
+ }
+ }
+
+ Copy_relocs<sh_type, size, big_endian>::emit(reloc_section);
}
// Return the value to use for a branch relocation.
@@ -6964,7 +7539,8 @@ Target_powerpc<size, big_endian>::symval_for_branch(
// descriptor, use the function descriptor code entry address
Powerpc_relobj<size, big_endian>* symobj = object;
if (gsym != NULL
- && gsym->source() != Symbol::FROM_OBJECT)
+ && (gsym->source() != Symbol::FROM_OBJECT
+ || gsym->object()->is_dynamic()))
return true;
if (gsym != NULL)
symobj = static_cast<Powerpc_relobj<size, big_endian>*>(gsym->object());
@@ -7035,8 +7611,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
typedef Powerpc_relocate_functions<size, big_endian> Reloc;
typedef typename elfcpp::Swap<32, big_endian>::Valtype Insn;
- typedef typename Reloc_types<elfcpp::SHT_RELA,
- size, big_endian>::Reloc Reltype;
+ typedef typename elfcpp::Rela<size, big_endian> Reltype;
// Offset from start of insn to d-field reloc.
const int d_offset = big_endian ? 2 : 0;
@@ -7110,7 +7685,6 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
}
else
{
- unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD));
value = object->local_got_offset(r_sym, GOT_TYPE_STANDARD);
}
@@ -7212,7 +7786,6 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
}
else
{
- unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
gold_assert(object->local_has_got_offset(r_sym, got_type));
value = object->local_got_offset(r_sym, got_type);
}
@@ -7312,7 +7885,6 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
}
else
{
- unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_DTPREL));
value = object->local_got_offset(r_sym, GOT_TYPE_DTPREL);
}
@@ -7335,7 +7907,6 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
}
else
{
- unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_TPREL));
value = object->local_got_offset(r_sym, GOT_TYPE_TPREL);
}
@@ -7607,14 +8178,24 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
if (size == 64)
{
- // Multi-instruction sequences that access the TOC can be
- // optimized, eg. addis ra,r2,0; addi rb,ra,x;
- // to nop; addi rb,r2,x;
switch (r_type)
{
default:
break;
+ // Multi-instruction sequences that access the GOT/TOC can
+ // be optimized, eg.
+ // addis ra,r2,x@got@ha; ld rb,x@got@l(ra);
+ // to addis ra,r2,x@toc@ha; addi rb,ra,x@toc@l;
+ // and
+ // addis ra,r2,0; addi rb,ra,x@toc@l;
+ // to nop; addi rb,r2,x@toc;
+ // FIXME: the @got sequence shown above is not yet
+ // optimized. Note that gcc as of 2017-01-07 doesn't use
+ // the ELF @got relocs except for TLS, instead using the
+ // PowerOpen variant of a compiler managed GOT (called TOC).
+ // The PowerOpen TOC sequence equivalent to the first
+ // example is optimized.
case elfcpp::R_POWERPC_GOT_TLSLD16_HA:
case elfcpp::R_POWERPC_GOT_TLSGD16_HA:
case elfcpp::R_POWERPC_GOT_TPREL16_HA:
@@ -7625,12 +8206,15 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
{
Insn* iview = reinterpret_cast<Insn*>(view - d_offset);
Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
- if ((insn & ((0x3f << 26) | 0x1f << 16))
- != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */)
- gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
- _("toc optimization is not supported "
- "for %#08x instruction"), insn);
- else if (value + 0x8000 < 0x10000)
+ if (r_type == elfcpp::R_PPC64_TOC16_HA
+ && object->make_toc_relative(target, &value))
+ {
+ gold_assert((insn & ((0x3f << 26) | 0x1f << 16))
+ == ((15u << 26) | (2 << 16)));
+ }
+ if (((insn & ((0x3f << 26) | 0x1f << 16))
+ == ((15u << 26) | (2 << 16)) /* addis rt,2,imm */)
+ && value + 0x8000 < 0x10000)
{
elfcpp::Swap<32, big_endian>::writeval(iview, nop);
return true;
@@ -7650,11 +8234,17 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
{
Insn* iview = reinterpret_cast<Insn*>(view - d_offset);
Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
- if (!ok_lo_toc_insn(insn))
- gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
- _("toc optimization is not supported "
- "for %#08x instruction"), insn);
- else if (value + 0x8000 < 0x10000)
+ bool changed = false;
+ if (r_type == elfcpp::R_PPC64_TOC16_LO_DS
+ && object->make_toc_relative(target, &value))
+ {
+ gold_assert ((insn & (0x3f << 26)) == 58u << 26 /* ld */);
+ insn ^= (14u << 26) ^ (58u << 26);
+ r_type = elfcpp::R_PPC64_TOC16_LO;
+ changed = true;
+ }
+ if (ok_lo_toc_insn(insn, r_type)
+ && value + 0x8000 < 0x10000)
{
if ((insn & (0x3f << 26)) == 12u << 26 /* addic */)
{
@@ -7667,8 +8257,10 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
insn &= ~(0x1f << 16);
insn |= 2 << 16;
}
- elfcpp::Swap<32, big_endian>::writeval(iview, insn);
+ changed = true;
}
+ if (changed)
+ elfcpp::Swap<32, big_endian>::writeval(iview, insn);
}
break;
@@ -7731,8 +8323,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
&& gsym != NULL
&& strcmp(gsym->name(), ".TOC.") == 0)
{
- const int reloc_size
- = Reloc_types<elfcpp::SHT_RELA, size, big_endian>::reloc_size;
+ const int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
Reltype prev_rela(preloc - reloc_size);
if ((prev_rela.get_r_info()
== elfcpp::elf_r_info<size>(r_sym,
@@ -8205,10 +8796,8 @@ template<int size, bool big_endian>
class Powerpc_scan_relocatable_reloc
{
public:
- typedef typename Reloc_types<elfcpp::SHT_RELA, size, big_endian>::Reloc
- Reltype;
- static const int reloc_size =
- Reloc_types<elfcpp::SHT_RELA, size, big_endian>::reloc_size;
+ typedef typename elfcpp::Rela<size, big_endian> Reltype;
+ static const int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
static const int sh_type = elfcpp::SHT_RELA;
// Return the symbol referred to by the relocation.
@@ -8348,12 +8937,9 @@ Target_powerpc<size, big_endian>::relocate_relocs(
{
gold_assert(sh_type == elfcpp::SHT_RELA);
- typedef typename Reloc_types<elfcpp::SHT_RELA, size, big_endian>::Reloc
- Reltype;
- typedef typename Reloc_types<elfcpp::SHT_RELA, size, big_endian>::Reloc_write
- Reltype_write;
- const int reloc_size
- = Reloc_types<elfcpp::SHT_RELA, size, big_endian>::reloc_size;
+ typedef typename elfcpp::Rela<size, big_endian> Reltype;
+ typedef typename elfcpp::Rela_write<size, big_endian> Reltype_write;
+ const int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
// Offset from start of insn to d-field reloc.
const int d_offset = big_endian ? 2 : 0;
diff --git a/gold/reloc.cc b/gold/reloc.cc
index ca54f153a3f..8bbb07d3960 100644
--- a/gold/reloc.cc
+++ b/gold/reloc.cc
@@ -871,7 +871,30 @@ Sized_relobj_file<size, big_endian>::do_relocate_sections(
Output_file* of,
Views* pviews)
{
- unsigned int shnum = this->shnum();
+ this->relocate_section_range(symtab, layout, pshdrs, of, pviews,
+ 1, this->shnum() - 1);
+}
+
+// Relocate section data for the range of sections START_SHNDX through
+// END_SHNDX.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::relocate_section_range(
+ const Symbol_table* symtab,
+ const Layout* layout,
+ const unsigned char* pshdrs,
+ Output_file* of,
+ Views* pviews,
+ unsigned int start_shndx,
+ unsigned int end_shndx)
+{
+ gold_assert(start_shndx >= 1);
+ gold_assert(end_shndx < this->shnum());
+
+ if (end_shndx < start_shndx)
+ return;
+
Sized_target<size, big_endian>* target =
parameters->sized_target<size, big_endian>();
@@ -883,8 +906,8 @@ Sized_relobj_file<size, big_endian>::do_relocate_sections(
relinfo.layout = layout;
relinfo.object = this;
- const unsigned char* p = pshdrs + This::shdr_size;
- for (unsigned int i = 1; i < shnum; ++i, p += This::shdr_size)
+ const unsigned char* p = pshdrs + start_shndx * This::shdr_size;
+ for (unsigned int i = start_shndx; i <= end_shndx; ++i, p += This::shdr_size)
{
typename This::Shdr shdr(p);
@@ -1718,6 +1741,17 @@ Sized_relobj_file<32, false>::do_relocate_sections(
Views* pviews);
template
+void
+Sized_relobj_file<32, false>::relocate_section_range(
+ const Symbol_table* symtab,
+ const Layout* layout,
+ const unsigned char* pshdrs,
+ Output_file* of,
+ Views* pviews,
+ unsigned int start_shndx,
+ unsigned int end_shndx);
+
+template
unsigned char*
Sized_relobj_file<32, false>::do_get_output_view(
unsigned int shndx,
@@ -1735,6 +1769,17 @@ Sized_relobj_file<32, true>::do_relocate_sections(
Views* pviews);
template
+void
+Sized_relobj_file<32, true>::relocate_section_range(
+ const Symbol_table* symtab,
+ const Layout* layout,
+ const unsigned char* pshdrs,
+ Output_file* of,
+ Views* pviews,
+ unsigned int start_shndx,
+ unsigned int end_shndx);
+
+template
unsigned char*
Sized_relobj_file<32, true>::do_get_output_view(
unsigned int shndx,
@@ -1752,6 +1797,17 @@ Sized_relobj_file<64, false>::do_relocate_sections(
Views* pviews);
template
+void
+Sized_relobj_file<64, false>::relocate_section_range(
+ const Symbol_table* symtab,
+ const Layout* layout,
+ const unsigned char* pshdrs,
+ Output_file* of,
+ Views* pviews,
+ unsigned int start_shndx,
+ unsigned int end_shndx);
+
+template
unsigned char*
Sized_relobj_file<64, false>::do_get_output_view(
unsigned int shndx,
@@ -1769,6 +1825,17 @@ Sized_relobj_file<64, true>::do_relocate_sections(
Views* pviews);
template
+void
+Sized_relobj_file<64, true>::relocate_section_range(
+ const Symbol_table* symtab,
+ const Layout* layout,
+ const unsigned char* pshdrs,
+ Output_file* of,
+ Views* pviews,
+ unsigned int start_shndx,
+ unsigned int end_shndx);
+
+template
unsigned char*
Sized_relobj_file<64, true>::do_get_output_view(
unsigned int shndx,
diff --git a/include/ChangeLog b/include/ChangeLog
index a766ecf9dc3..c3d9db7aea0 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,9 @@
+2017-03-09 Alan Modra <amodra@gmail.com>
+
+ Apply from master
+ 2016-09-26 Alan Modra <amodra@gmail.com>
+ * elf/ppc.h (Tag_GNU_Power_ABI_FP): Comment on new values.
+
2016-06-30 Matthew Wahab <matthew.wahab@arm.com>
* opcode/arm.h (ARM_ARCH_V8_2a): Add FPU_NEON_EXT_RDMA to the set
diff --git a/include/elf/ppc.h b/include/elf/ppc.h
index f4a6bbd6725..5f94a34d4e8 100644
--- a/include/elf/ppc.h
+++ b/include/elf/ppc.h
@@ -219,11 +219,18 @@ END_RELOC_NUMBERS (R_PPC_max)
enum
{
/* 0-3 are generic. */
- Tag_GNU_Power_ABI_FP = 4, /* Value 1 for hard-float, 2 for
- soft-float, 3 for single=precision
- hard-float; 0 for not tagged or not
- using any ABIs affected by the
- differences. */
+
+ /* FP ABI, low 2 bits:
+ 1 for double precision hard-float,
+ 2 for soft-float,
+ 3 for single precision hard-float.
+ 0 for not tagged or not using any ABIs affected by the differences.
+ Next 2 bits:
+ 1 for ibm long double
+ 2 for 64-bit long double
+ 3 for IEEE long double.
+ 0 for not tagged or not using any ABIs affected by the differences. */
+ Tag_GNU_Power_ABI_FP = 4,
/* Value 1 for general purpose registers only, 2 for AltiVec
registers, 3 for SPE registers; 0 for not tagged or not using any
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 6cc35c7e73b..9ecd8c18583 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,43 @@
+2017-03-09 Alan Modra <amodra@gmail.com>
+
+ Apply from master
+ 2016-09-26 Alan Modra <amodra@gmail.com>
+ * testsuite/ld-powerpc/attr-gnu-4-4.s: Delete.
+ * testsuite/ld-powerpc/attr-gnu-4-14.d: Delete.
+ * testsuite/ld-powerpc/attr-gnu-4-24.d: Delete.
+ * testsuite/ld-powerpc/attr-gnu-4-34.d: Delete.
+ * testsuite/ld-powerpc/attr-gnu-4-41.d: Delete.
+ * testsuite/ld-powerpc/attr-gnu-4-32.d: Adjust expected warning.
+ * testsuite/ld-powerpc/attr-gnu-8-23.d: Likewise.
+ * testsuite/ld-powerpc/attr-gnu-4-01.d: Adjust expected output.
+ * testsuite/ld-powerpc/attr-gnu-4-02.d: Likewise.
+ * testsuite/ld-powerpc/attr-gnu-4-03.d: Likewise.
+ * testsuite/ld-powerpc/attr-gnu-4-10.d: Likewise.
+ * testsuite/ld-powerpc/attr-gnu-4-11.d: Likewise.
+ * testsuite/ld-powerpc/attr-gnu-4-20.d: Likewise.
+ * testsuite/ld-powerpc/attr-gnu-4-22.d: Likewise.
+ * testsuite/ld-powerpc/attr-gnu-4-33.d: Likewise.
+ * testsuite/ld-powerpc/attr-gnu-8-11.d: Likewise.
+ * testsuite/ld-powerpc/powerpc.exp: Don't run deleted tests.
+
+2017-02-21 Alan Modra <amodra@gmail.com>
+
+ Apply from master
+ 2016-12-06 Alan Modra <amodra@gmail.com>
+ * testsuite/ld-powerpc/tocopt7.s,
+ * testsuite/ld-powerpc/tocopt7.out,
+ * testsuite/ld-powerpc/tocopt7.d: New test.
+ * testsuite/ld-powerpc/tocopt8.s,
+ * testsuite/ld-powerpc/tocopt8.d: New test.
+ * testsuite/ld-powerpc/powerpc.exp: Run them.
+
+2017-02-15 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR ld/21168
+ * testsuite/ld-i386/i386.exp: Run pr21168.
+ * testsuite/ld-i386/pr21168a.c: New file.
+ * testsuite/ld-i386/pr21168b.S: Likewise.
+
2016-10-14 Alan Modra <amodra@gmail.com>
* scripttempl/DWARF.sc: Add .debug_addr.
diff --git a/ld/testsuite/ld-i386/i386.exp b/ld/testsuite/ld-i386/i386.exp
index 9efe406b9b5..6eb7299fa6b 100644
--- a/ld/testsuite/ld-i386/i386.exp
+++ b/ld/testsuite/ld-i386/i386.exp
@@ -831,6 +831,20 @@ if { [isnative]
"-fPIC -O2 -g" \
{ ifunc-1a.c ifunc-1b.S ifunc-1c.S ifunc-1d.S } \
] \
+ [list \
+ "Build pr21168a.o" \
+ "" \
+ "" \
+ { pr21168a.c } \
+ ] \
+ [list \
+ "Build pr21168.so" \
+ "-shared" \
+ "" \
+ { pr21168b.S } \
+ "" \
+ "pr21168.so" \
+ ] \
]
run_ld_link_exec_tests [] [list \
@@ -852,6 +866,14 @@ if { [isnative]
"ifunc-1b" \
"pass.out" \
] \
+ [list \
+ "Run pr21168" \
+ "tmpdir/pr21168a.o tmpdir/pr21168.so" \
+ "" \
+ { dummy.c } \
+ "pr21168" \
+ "pass.out" \
+ ] \
]
}
diff --git a/ld/testsuite/ld-i386/pr21168a.c b/ld/testsuite/ld-i386/pr21168a.c
new file mode 100644
index 00000000000..a6c0da18ed7
--- /dev/null
+++ b/ld/testsuite/ld-i386/pr21168a.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+
+int foo = 1;
+
+extern int *bar (void);
+extern int bar_ifunc (void);
+
+int
+main (void)
+{
+ if (bar () == &foo && bar_ifunc () == 0xbadbeef)
+ printf ("PASS\n");
+ return 0;
+}
diff --git a/ld/testsuite/ld-i386/pr21168b.S b/ld/testsuite/ld-i386/pr21168b.S
new file mode 100644
index 00000000000..a4ea5c9f7de
--- /dev/null
+++ b/ld/testsuite/ld-i386/pr21168b.S
@@ -0,0 +1,29 @@
+ .text
+ .globl bar
+ .type bar, @function
+bar:
+ call __x86.get_pc_thunk.ax
+ addl $_GLOBAL_OFFSET_TABLE_, %eax
+ lea foo@GOT, %ecx
+ mov (%eax,%ecx,1), %eax
+ ret
+ .globl bar_ifunc
+ .type bar_ifunc, @function
+bar_ifunc:
+ call __x86.get_pc_thunk.ax
+ addl $_GLOBAL_OFFSET_TABLE_, %eax
+ lea ifunc@GOT, %ecx
+ mov (%eax,%ecx,1), %eax
+ ret
+ .type ifunc, @gnu_indirect_function
+ifunc:
+ mov $0xbadbeef, %eax
+ ret
+ .section .text.__x86.get_pc_thunk.ax,"axG",@progbits,__x86.get_pc_thunk.ax,comdat
+ .globl __x86.get_pc_thunk.ax
+ .hidden __x86.get_pc_thunk.ax
+ .type __x86.get_pc_thunk.ax, @function
+__x86.get_pc_thunk.ax:
+ movl (%esp), %eax
+ ret
+ .section .note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-powerpc/attr-gnu-4-01.d b/ld/testsuite/ld-powerpc/attr-gnu-4-01.d
index 212e0c46f0c..62dbec0ec06 100644
--- a/ld/testsuite/ld-powerpc/attr-gnu-4-01.d
+++ b/ld/testsuite/ld-powerpc/attr-gnu-4-01.d
@@ -7,4 +7,4 @@
Attribute Section: gnu
File Attributes
- Tag_GNU_Power_ABI_FP: Hard float
+ Tag_GNU_Power_ABI_FP: hard float, unspecified long double
diff --git a/ld/testsuite/ld-powerpc/attr-gnu-4-02.d b/ld/testsuite/ld-powerpc/attr-gnu-4-02.d
index 9bd42b59ba6..ae270f1a04b 100644
--- a/ld/testsuite/ld-powerpc/attr-gnu-4-02.d
+++ b/ld/testsuite/ld-powerpc/attr-gnu-4-02.d
@@ -7,4 +7,4 @@
Attribute Section: gnu
File Attributes
- Tag_GNU_Power_ABI_FP: Soft float
+ Tag_GNU_Power_ABI_FP: soft float, unspecified long double
diff --git a/ld/testsuite/ld-powerpc/attr-gnu-4-03.d b/ld/testsuite/ld-powerpc/attr-gnu-4-03.d
index 03b0c3c76e2..d79febfd31d 100644
--- a/ld/testsuite/ld-powerpc/attr-gnu-4-03.d
+++ b/ld/testsuite/ld-powerpc/attr-gnu-4-03.d
@@ -7,4 +7,4 @@
Attribute Section: gnu
File Attributes
- Tag_GNU_Power_ABI_FP: Single-precision hard float
+ Tag_GNU_Power_ABI_FP: single-precision hard float, unspecified long double
diff --git a/ld/testsuite/ld-powerpc/attr-gnu-4-10.d b/ld/testsuite/ld-powerpc/attr-gnu-4-10.d
index 93297c20f1f..1e015494d23 100644
--- a/ld/testsuite/ld-powerpc/attr-gnu-4-10.d
+++ b/ld/testsuite/ld-powerpc/attr-gnu-4-10.d
@@ -7,4 +7,4 @@
Attribute Section: gnu
File Attributes
- Tag_GNU_Power_ABI_FP: Hard float
+ Tag_GNU_Power_ABI_FP: hard float, unspecified long double
diff --git a/ld/testsuite/ld-powerpc/attr-gnu-4-11.d b/ld/testsuite/ld-powerpc/attr-gnu-4-11.d
index fb2b76e9571..5027b78c06a 100644
--- a/ld/testsuite/ld-powerpc/attr-gnu-4-11.d
+++ b/ld/testsuite/ld-powerpc/attr-gnu-4-11.d
@@ -7,4 +7,4 @@
Attribute Section: gnu
File Attributes
- Tag_GNU_Power_ABI_FP: Hard float
+ Tag_GNU_Power_ABI_FP: hard float, unspecified long double
diff --git a/ld/testsuite/ld-powerpc/attr-gnu-4-14.d b/ld/testsuite/ld-powerpc/attr-gnu-4-14.d
deleted file mode 100644
index 3bb6661e949..00000000000
--- a/ld/testsuite/ld-powerpc/attr-gnu-4-14.d
+++ /dev/null
@@ -1,6 +0,0 @@
-#source: attr-gnu-4-1.s
-#source: attr-gnu-4-4.s
-#as: -a32
-#ld: -r -melf32ppc
-#warning: Warning: .* uses unknown floating point ABI 4
-#target: powerpc*-*-*
diff --git a/ld/testsuite/ld-powerpc/attr-gnu-4-20.d b/ld/testsuite/ld-powerpc/attr-gnu-4-20.d
index 3d838938020..fca9de66d76 100644
--- a/ld/testsuite/ld-powerpc/attr-gnu-4-20.d
+++ b/ld/testsuite/ld-powerpc/attr-gnu-4-20.d
@@ -7,4 +7,4 @@
Attribute Section: gnu
File Attributes
- Tag_GNU_Power_ABI_FP: Soft float
+ Tag_GNU_Power_ABI_FP: soft float, unspecified long double
diff --git a/ld/testsuite/ld-powerpc/attr-gnu-4-22.d b/ld/testsuite/ld-powerpc/attr-gnu-4-22.d
index f6bd198efdf..80a209cfc35 100644
--- a/ld/testsuite/ld-powerpc/attr-gnu-4-22.d
+++ b/ld/testsuite/ld-powerpc/attr-gnu-4-22.d
@@ -7,4 +7,4 @@
Attribute Section: gnu
File Attributes
- Tag_GNU_Power_ABI_FP: Soft float
+ Tag_GNU_Power_ABI_FP: soft float, unspecified long double
diff --git a/ld/testsuite/ld-powerpc/attr-gnu-4-24.d b/ld/testsuite/ld-powerpc/attr-gnu-4-24.d
deleted file mode 100644
index fc17f918025..00000000000
--- a/ld/testsuite/ld-powerpc/attr-gnu-4-24.d
+++ /dev/null
@@ -1,6 +0,0 @@
-#source: attr-gnu-4-2.s
-#source: attr-gnu-4-4.s
-#as: -a32
-#ld: -r -melf32ppc
-#warning: Warning: .* uses unknown floating point ABI 4
-#target: powerpc*-*-*
diff --git a/ld/testsuite/ld-powerpc/attr-gnu-4-32.d b/ld/testsuite/ld-powerpc/attr-gnu-4-32.d
index 3b7cb2919bd..924a3af0b17 100644
--- a/ld/testsuite/ld-powerpc/attr-gnu-4-32.d
+++ b/ld/testsuite/ld-powerpc/attr-gnu-4-32.d
@@ -2,5 +2,5 @@
#source: attr-gnu-4-2.s
#as: -a32
#ld: -r -melf32ppc
-#warning: Warning: .* uses soft float, .* uses single-precision hard float
+#warning: Warning: .* uses hard float, .* uses soft float
#target: powerpc*-*-*
diff --git a/ld/testsuite/ld-powerpc/attr-gnu-4-33.d b/ld/testsuite/ld-powerpc/attr-gnu-4-33.d
index 88367aef687..6951b427648 100644
--- a/ld/testsuite/ld-powerpc/attr-gnu-4-33.d
+++ b/ld/testsuite/ld-powerpc/attr-gnu-4-33.d
@@ -7,4 +7,4 @@
Attribute Section: gnu
File Attributes
- Tag_GNU_Power_ABI_FP: Single-precision hard float
+ Tag_GNU_Power_ABI_FP: single-precision hard float, unspecified long double
diff --git a/ld/testsuite/ld-powerpc/attr-gnu-4-34.d b/ld/testsuite/ld-powerpc/attr-gnu-4-34.d
deleted file mode 100644
index 6f6e1fe762d..00000000000
--- a/ld/testsuite/ld-powerpc/attr-gnu-4-34.d
+++ /dev/null
@@ -1,6 +0,0 @@
-#source: attr-gnu-4-3.s
-#source: attr-gnu-4-4.s
-#as: -a32
-#ld: -r -melf32ppc
-#warning: Warning: .* uses unknown floating point ABI 4
-#target: powerpc*-*-*
diff --git a/ld/testsuite/ld-powerpc/attr-gnu-4-4.s b/ld/testsuite/ld-powerpc/attr-gnu-4-4.s
deleted file mode 100644
index 3ff129ae7a4..00000000000
--- a/ld/testsuite/ld-powerpc/attr-gnu-4-4.s
+++ /dev/null
@@ -1 +0,0 @@
-.gnu_attribute 4,4
diff --git a/ld/testsuite/ld-powerpc/attr-gnu-4-41.d b/ld/testsuite/ld-powerpc/attr-gnu-4-41.d
deleted file mode 100644
index b9094763ebf..00000000000
--- a/ld/testsuite/ld-powerpc/attr-gnu-4-41.d
+++ /dev/null
@@ -1,6 +0,0 @@
-#source: attr-gnu-4-4.s
-#source: attr-gnu-4-1.s
-#as: -a32
-#ld: -r -melf32ppc
-#warning: Warning: .* uses unknown floating point ABI 4
-#target: powerpc*-*-*
diff --git a/ld/testsuite/ld-powerpc/attr-gnu-8-11.d b/ld/testsuite/ld-powerpc/attr-gnu-8-11.d
index 7e49d4a7ef7..06d7e889117 100644
--- a/ld/testsuite/ld-powerpc/attr-gnu-8-11.d
+++ b/ld/testsuite/ld-powerpc/attr-gnu-8-11.d
@@ -7,4 +7,4 @@
Attribute Section: gnu
File Attributes
- Tag_GNU_Power_ABI_Vector: Generic
+ Tag_GNU_Power_ABI_Vector: generic
diff --git a/ld/testsuite/ld-powerpc/attr-gnu-8-23.d b/ld/testsuite/ld-powerpc/attr-gnu-8-23.d
index b22e4bda3de..b442884e721 100644
--- a/ld/testsuite/ld-powerpc/attr-gnu-8-23.d
+++ b/ld/testsuite/ld-powerpc/attr-gnu-8-23.d
@@ -2,5 +2,5 @@
#source: attr-gnu-8-3.s
#as: -a32
#ld: -r -melf32ppc
-#warning: Warning: .* uses vector ABI "SPE", .* uses "AltiVec"
+#warning: Warning: .* uses AltiVec vector ABI, .* uses SPE vector ABI
#target: powerpc*-*-*
diff --git a/ld/testsuite/ld-powerpc/powerpc.exp b/ld/testsuite/ld-powerpc/powerpc.exp
index 37e53fd1744..8cb4b09ac44 100644
--- a/ld/testsuite/ld-powerpc/powerpc.exp
+++ b/ld/testsuite/ld-powerpc/powerpc.exp
@@ -227,6 +227,10 @@ set ppc64elftests {
{{objdump -s tocopt5.d}} "tocopt5"}
{"TOC opt6" "-melf64ppc" "" "-a64" {tocopt6a.s tocopt6b.s tocopt6c.s}
{{objdump -d tocopt6.d}} "tocopt6"}
+ {"TOC opt7" "-melf64ppc" "" "-a64 -mpower9" {tocopt7.s}
+ {{ld tocopt7.out} {objdump -s tocopt7.d}} "tocopt7"}
+ {"TOC opt8" "-melf64ppc" "" "-a64 -mpower9" {tocopt8.s}
+ {{objdump -s tocopt8.d}} "tocopt8"}
{"ambig shared v1" "-shared -melf64ppc" "" "-a64" {funv1.s} {} "funv1.so"}
{"ambig shared v2" "-shared -melf64ppc" "" "-a64" {funv2.s} {} "funv2.so"}
}
@@ -319,17 +323,13 @@ run_dump_test "attr-gnu-4-10"
run_dump_test "attr-gnu-4-11"
run_dump_test "attr-gnu-4-12"
run_dump_test "attr-gnu-4-13"
-run_dump_test "attr-gnu-4-14"
run_dump_test "attr-gnu-4-20"
run_dump_test "attr-gnu-4-21"
run_dump_test "attr-gnu-4-22"
run_dump_test "attr-gnu-4-23"
-run_dump_test "attr-gnu-4-24"
run_dump_test "attr-gnu-4-31"
run_dump_test "attr-gnu-4-32"
run_dump_test "attr-gnu-4-33"
-run_dump_test "attr-gnu-4-34"
-run_dump_test "attr-gnu-4-41"
run_dump_test "attr-gnu-8-11"
run_dump_test "attr-gnu-8-23"
diff --git a/ld/testsuite/ld-powerpc/tocopt7.d b/ld/testsuite/ld-powerpc/tocopt7.d
new file mode 100644
index 00000000000..7d4638f7b7b
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/tocopt7.d
@@ -0,0 +1,54 @@
+
+.*: file format .*
+
+Contents of section \.text:
+ 100000b0 (0000223d|3d220000) (288029e9|e9298028) (0000823c|3c820000) (3080a438|38a48030) .*
+ 100000c0 (0000c5e8|e8c50000) (0000823f|3f820000) (29803ce9|e93c8029) (0000223d|3d220000) .*
+ 100000d0 (108029e9|e9298010) (0000823c|3c820000) (1880a438|38a48018) (0000c5e8|e8c50000) .*
+ 100000e0 (0000823f|3f820000) (11803ce9|e93c8011) (0000823c|3c820000) (3080a438|38a48030) .*
+ 100000f0 (0000c580|80c50000) (0000223d|3d220000) (10802981|81298010) (0000823c|3c820000) .*
+ 10000100 (1880a438|38a48018) (0000c580|80c50000) (0000823f|3f820000) (10803c85|853c8010) .*
+ 10000110 (0000823c|3c820000) (3080a438|38a48030) (0200c5e8|e8c50002) (0000223d|3d220000) .*
+ 10000120 (128029e9|e9298012) (0000823c|3c820000) (1880a438|38a48018) (0200c5e8|e8c50002) .*
+ 10000130 (0000823c|3c820000) (3080a438|38a48030) (0000c5a0|a0c50000) (0000223d|3d220000) .*
+ 10000140 (108029a1|a1298010) (0000823c|3c820000) (1880a438|38a48018) (0000c5a0|a0c50000) .*
+ 10000150 (0000823f|3f820000) (10803ca5|a53c8010) (0000823c|3c820000) (3080a438|38a48030) .*
+ 10000160 (0000c5a8|a8c50000) (0000223d|3d220000) (108029a9|a9298010) (0000823c|3c820000) .*
+ 10000170 (1880a438|38a48018) (0000c5a8|a8c50000) (0000823c|3c820000) (3080a438|38a48030) .*
+ 10000180 (0000c588|88c50000) (0000223d|3d220000) (10802989|89298010) (0000823c|3c820000) .*
+ 10000190 (1880a438|38a48018) (0000c588|88c50000) (0000823f|3f820000) (10803c8d|8d3c8010) .*
+ 100001a0 (0000823c|3c820000) (3080a438|38a48030) (0000c5c0|c0c50000) (0000223d|3d220000) .*
+ 100001b0 (108029c1|c1298010) (0000823c|3c820000) (1880a438|38a48018) (0000c5c0|c0c50000) .*
+ 100001c0 (0000823f|3f820000) (10803cc5|c53c8010) (0000823c|3c820000) (3080a438|38a48030) .*
+ 100001d0 (0000c5c8|c8c50000) (0000223d|3d220000) (108029c9|c9298010) (0000823c|3c820000) .*
+ 100001e0 (1880a438|38a48018) (0000c5c8|c8c50000) (0000823f|3f820000) (10803ccd|cd3c8010) .*
+ 100001f0 (0000823c|3c820000) (3080a438|38a48030) (0100c5f4|f4c50001) (0000223d|3d220000) .*
+ 10000200 (118029f5|f5298011) (0000823c|3c820000) (2080a438|38a48020) (0100c5f4|f4c50001) .*
+ 10000210 (0000823c|3c820000) (3080a438|38a48030) (0200c5e4|e4c50002) (0000223d|3d220000) .*
+ 10000220 (128029e5|e5298012) (0000823c|3c820000) (1880a438|38a48018) (0200c5e4|e4c50002) .*
+ 10000230 (0000823c|3c820000) (3080a438|38a48030) (0300c5e4|e4c50003) (0000223d|3d220000) .*
+ 10000240 (138029e5|e5298013) (0000823c|3c820000) (1880a438|38a48018) (0300c5e4|e4c50003) .*
+ 10000250 (0000223d|3d220000) (108029f9|f9298010) (0000823c|3c820000) (1880a438|38a48018) .*
+ 10000260 (0000c5f8|f8c50000) (0000823f|3f820000) (11803cf9|f93c8011) (0000223d|3d220000) .*
+ 10000270 (10802991|91298010) (0000823c|3c820000) (1880a438|38a48018) (0000c590|90c50000) .*
+ 10000280 (0000823f|3f820000) (10803c95|953c8010) (0000223d|3d220000) (108029b1|b1298010) .*
+ 10000290 (0000823c|3c820000) (1880a438|38a48018) (0000c5b0|b0c50000) (0000823f|3f820000) .*
+ 100002a0 (10803cb5|b53c8010) (0000223d|3d220000) (10802999|99298010) (0000823c|3c820000) .*
+ 100002b0 (1880a438|38a48018) (0000c598|98c50000) (0000823f|3f820000) (10803c9d|9d3c8010) .*
+ 100002c0 (0000223d|3d220000) (108029d1|d1298010) (0000823c|3c820000) (1880a438|38a48018) .*
+ 100002d0 (0000c5d0|d0c50000) (0000823f|3f820000) (10803cd5|d53c8010) (0000223d|3d220000) .*
+ 100002e0 (108029d9|d9298010) (0000823c|3c820000) (1880a438|38a48018) (0000c5d8|d8c50000) .*
+ 100002f0 (0000823f|3f820000) (10803cdd|dd3c8010) (0000223d|3d220000) (158029f5|f5298015) .*
+ 10000300 (0000823c|3c820000) (2080a438|38a48020) (0500c5f4|f4c50005) (0000223d|3d220000) .*
+ 10000310 (128029f5|f5298012) (0000823c|3c820000) (1880a438|38a48018) (0200c5f4|f4c50002) .*
+ 10000320 (0000223d|3d220000) (138029f5|f5298013) (0000823c|3c820000) (1880a438|38a48018) .*
+ 10000330 (0300c5f4|f4c50003) .*
+Contents of section \.got:
+ 10010400 (00840110|00000000) (00000000|10018400) (00000000|00000000) (00000000|00000000) .*
+ 10010410 (58040110|00000000) (00000000|10010458) (60040110|00000000) (00000000|10010460) .*
+ 10010420 (68040110|00000000) (00000000|10010468) (40040110|00000000) (00000000|10010440) .*
+ 10010430 (48040110|00000000) (00000000|10010448) .*
+Contents of section \.sdata:
+ 10010440 (01000000|00000000) (00000000|00000001) (02000000|00000000) (00000000|00000002) .*
+ 10010450 (03000000|00000000) (00000000|00000003) (04000000|00000000) (00000000|00000004) .*
+ 10010460 (05000000|00000000) (00000000|00000005) (06000000|00000000) (00000000|00000006) .*
diff --git a/ld/testsuite/ld-powerpc/tocopt7.out b/ld/testsuite/ld-powerpc/tocopt7.out
new file mode 100644
index 00000000000..f74d91d308e
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/tocopt7.out
@@ -0,0 +1,26 @@
+.*
+\(\.text\+0x18\): .*
+.*
+\(\.text\+0x34\): .*
+.*
+\(\.text\+0x5c\): .*
+.*
+\(\.text\+0xa4\): .*
+.*
+\(\.text\+0xec\): .*
+.*
+\(\.text\+0x114\): .*
+.*
+\(\.text\+0x13c\): .*
+.*
+\(\.text\+0x1b8\): .*
+.*
+\(\.text\+0x1d4\): .*
+.*
+\(\.text\+0x1f0\): .*
+.*
+\(\.text\+0x20c\): .*
+.*
+\(\.text\+0x228\): .*
+.*
+\(\.text\+0x244\): .*
diff --git a/ld/testsuite/ld-powerpc/tocopt7.s b/ld/testsuite/ld-powerpc/tocopt7.s
new file mode 100644
index 00000000000..dbd8eb16f5b
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/tocopt7.s
@@ -0,0 +1,216 @@
+ .section .toc,"aw"
+ .p2align 4
+x4t:
+ .quad x4
+x5t:
+ .quad x5
+x6t:
+ .quad x6
+
+ .section .sdata,"aw"
+ .p2align 4
+x1:
+ .quad 1
+x2:
+ .quad 2
+x3:
+ .quad 3
+x4:
+ .quad 4
+x5:
+ .quad 5
+x6:
+ .quad 6
+
+ .globl _start
+ .text
+_start:
+# no need for got entry, optimise to nop,addi
+# note: ld doesn't yet do got optimisation, so we get nop,ld
+ addis 9,2,x1@got@ha
+ ld 9,x1@got@l(9)
+# must keep got entry, optimise to nop,addi,ld
+ addis 4,2,x2@got@ha
+ addi 5,4,x2@got@l
+ ld 6,0(5)
+# can't optimise due to possibility that r28 isn't dead
+ addis 28,2,x1@got@ha
+ ldu 9,x1@got@l(28)
+# no need for toc entry, optimise to nop,addi
+ addis 9,2,x4t@toc@ha
+ ld 9,x4t@toc@l(9)
+# must keep toc entry, optimise to nop,addi,ld
+# if we had a reloc tying the ld to x5/x5t then we could throw away
+# the toc entry and optimise to nop,nop,addi
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ ld 6,0(5)
+# can't optimise due to possibility that r28 isn't dead
+ addis 28,2,x4t@toc@ha
+ ldu 9,x4t@toc@l(28)
+
+ addis 4,2,x2@got@ha
+ addi 5,4,x2@got@l
+ lwz 6,0(5)
+ addis 9,2,x4t@toc@ha
+ lwz 9,x4t@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ lwz 6,0(5)
+ addis 28,2,x4t@toc@ha
+ lwzu 9,x4t@toc@l(28)
+
+ addis 4,2,x2@got@ha
+ addi 5,4,x2@got@l
+ lwa 6,0(5)
+ addis 9,2,x4t@toc@ha
+ lwa 9,x4t@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ lwa 6,0(5)
+
+ addis 4,2,x2@got@ha
+ addi 5,4,x2@got@l
+ lhz 6,0(5)
+ addis 9,2,x4t@toc@ha
+ lhz 9,x4t@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ lhz 6,0(5)
+ addis 28,2,x4t@toc@ha
+ lhzu 9,x4t@toc@l(28)
+
+ addis 4,2,x2@got@ha
+ addi 5,4,x2@got@l
+ lha 6,0(5)
+ addis 9,2,x4t@toc@ha
+ lha 9,x4t@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ lha 6,0(5)
+
+ addis 4,2,x2@got@ha
+ addi 5,4,x2@got@l
+ lbz 6,0(5)
+ addis 9,2,x4t@toc@ha
+ lbz 9,x4t@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ lbz 6,0(5)
+ addis 28,2,x4t@toc@ha
+ lbzu 9,x4t@toc@l(28)
+
+ addis 4,2,x2@got@ha
+ addi 5,4,x2@got@l
+ lfs 6,0(5)
+ addis 9,2,x4t@toc@ha
+ lfs 9,x4t@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ lfs 6,0(5)
+ addis 28,2,x4t@toc@ha
+ lfsu 9,x4t@toc@l(28)
+
+ addis 4,2,x2@got@ha
+ addi 5,4,x2@got@l
+ lfd 6,0(5)
+ addis 9,2,x4t@toc@ha
+ lfd 9,x4t@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ lfd 6,0(5)
+ addis 28,2,x4t@toc@ha
+ lfdu 9,x4t@toc@l(28)
+
+ addis 4,2,x2@got@ha
+ addi 5,4,x2@got@l
+ lxv 6,0(5)
+ addis 9,2,x4t@toc@ha
+ lxv 9,x4t@toc@l(9)
+ addis 4,2,x6t@toc@ha
+ addi 5,4,x6t@toc@l
+ lxv 6,0(5)
+
+ addis 4,2,x2@got@ha
+ addi 5,4,x2@got@l
+ lxsd 6,0(5)
+ addis 9,2,x4t@toc@ha
+ lxsd 9,x4t@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ lxsd 6,0(5)
+
+ addis 4,2,x2@got@ha
+ addi 5,4,x2@got@l
+ lxssp 6,0(5)
+ addis 9,2,x4t@toc@ha
+ lxssp 9,x4t@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ lxssp 6,0(5)
+
+ addis 9,2,x4t@toc@ha
+ std 9,x4t@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ std 6,0(5)
+ addis 28,2,x4t@toc@ha
+ stdu 9,x4t@toc@l(28)
+
+ addis 9,2,x4t@toc@ha
+ stw 9,x4t@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ stw 6,0(5)
+ addis 28,2,x4t@toc@ha
+ stwu 9,x4t@toc@l(28)
+
+ addis 9,2,x4t@toc@ha
+ sth 9,x4t@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ sth 6,0(5)
+ addis 28,2,x4t@toc@ha
+ sthu 9,x4t@toc@l(28)
+
+ addis 9,2,x4t@toc@ha
+ stb 9,x4t@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ stb 6,0(5)
+ addis 28,2,x4t@toc@ha
+ stbu 9,x4t@toc@l(28)
+
+ addis 9,2,x4t@toc@ha
+ stfs 9,x4t@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ stfs 6,0(5)
+ addis 28,2,x4t@toc@ha
+ stfsu 9,x4t@toc@l(28)
+
+ addis 9,2,x4t@toc@ha
+ stfd 9,x4t@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ stfd 6,0(5)
+ addis 28,2,x4t@toc@ha
+ stfdu 9,x4t@toc@l(28)
+
+ addis 9,2,x4t@toc@ha
+ stxv 9,x4t@toc@l(9)
+ addis 4,2,x6t@toc@ha
+ addi 5,4,x6t@toc@l
+ stxv 6,0(5)
+
+ addis 9,2,x4t@toc@ha
+ stxsd 9,x4t@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ stxsd 6,0(5)
+
+ addis 9,2,x4t@toc@ha
+ stxssp 9,x4t@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ stxssp 6,0(5)
diff --git a/ld/testsuite/ld-powerpc/tocopt8.d b/ld/testsuite/ld-powerpc/tocopt8.d
new file mode 100644
index 00000000000..c9eff5ac337
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/tocopt8.d
@@ -0,0 +1,46 @@
+
+.*: file format .*
+
+Contents of section \.text:
+ 100000b0 (00000060|60000000) (108022e9|e9228010) (00000060|60000000) (1880a238|38a28018) .*
+ 100000c0 (0000c5e8|e8c50000) (00000060|60000000) (38802239|39228038) (00000060|60000000) .*
+ 100000d0 (0880a238|38a28008) (0000c5e8|e8c50000) (00000060|60000000) (088022e9|e9228008) .*
+ 100000e0 (00000060|60000000) (1880a238|38a28018) (0000c580|80c50000) (00000060|60000000) .*
+ 100000f0 (20802281|81228020) (00000060|60000000) (0880a238|38a28008) (0000c580|80c50000) .*
+ 10000100 (00000060|60000000) (1880a238|38a28018) (0200c5e8|e8c50002) (00000060|60000000) .*
+ 10000110 (228022e9|e9228022) (00000060|60000000) (0880a238|38a28008) (0200c5e8|e8c50002) .*
+ 10000120 (00000060|60000000) (1880a238|38a28018) (0000c5a0|a0c50000) (00000060|60000000) .*
+ 10000130 (208022a1|a1228020) (00000060|60000000) (0880a238|38a28008) (0000c5a0|a0c50000) .*
+ 10000140 (00000060|60000000) (1880a238|38a28018) (0000c5a8|a8c50000) (00000060|60000000) .*
+ 10000150 (208022a9|a9228020) (00000060|60000000) (0880a238|38a28008) (0000c5a8|a8c50000) .*
+ 10000160 (00000060|60000000) (1880a238|38a28018) (0000c588|88c50000) (00000060|60000000) .*
+ 10000170 (20802289|89228020) (00000060|60000000) (0880a238|38a28008) (0000c588|88c50000) .*
+ 10000180 (00000060|60000000) (1880a238|38a28018) (0000c5c0|c0c50000) (00000060|60000000) .*
+ 10000190 (208022c1|c1228020) (00000060|60000000) (0880a238|38a28008) (0000c5c0|c0c50000) .*
+ 100001a0 (00000060|60000000) (1880a238|38a28018) (0000c5c8|c8c50000) (00000060|60000000) .*
+ 100001b0 (208022c9|c9228020) (00000060|60000000) (0880a238|38a28008) (0000c5c8|c8c50000) .*
+ 100001c0 (00000060|60000000) (1880a238|38a28018) (0100c5f4|f4c50001) (00000060|60000000) .*
+ 100001d0 (218022f5|f5228021) (00000060|60000000) (2080a238|38a28020) (0100c5f4|f4c50001) .*
+ 100001e0 (00000060|60000000) (1880a238|38a28018) (0200c5e4|e4c50002) (00000060|60000000) .*
+ 100001f0 (228022e5|e5228022) (00000060|60000000) (0880a238|38a28008) (0200c5e4|e4c50002) .*
+ 10000200 (00000060|60000000) (1880a238|38a28018) (0300c5e4|e4c50003) (00000060|60000000) .*
+ 10000210 (238022e5|e5228023) (00000060|60000000) (0880a238|38a28008) (0300c5e4|e4c50003) .*
+ 10000220 (00000060|60000000) (208022f9|f9228020) (00000060|60000000) (0880a238|38a28008) .*
+ 10000230 (0000c5f8|f8c50000) (00000060|60000000) (20802291|91228020) (00000060|60000000) .*
+ 10000240 (0880a238|38a28008) (0000c590|90c50000) (00000060|60000000) (208022b1|b1228020) .*
+ 10000250 (00000060|60000000) (0880a238|38a28008) (0000c5b0|b0c50000) (00000060|60000000) .*
+ 10000260 (20802299|99228020) (00000060|60000000) (0880a238|38a28008) (0000c598|98c50000) .*
+ 10000270 (00000060|60000000) (208022d1|d1228020) (00000060|60000000) (0880a238|38a28008) .*
+ 10000280 (0000c5d0|d0c50000) (00000060|60000000) (208022d9|d9228020) (00000060|60000000) .*
+ 10000290 (0880a238|38a28008) (0000c5d8|d8c50000) (00000060|60000000) (258022f5|f5228025) .*
+ 100002a0 (00000060|60000000) (2080a238|38a28020) (0500c5f4|f4c50005) (00000060|60000000) .*
+ 100002b0 (228022f5|f5228022) (00000060|60000000) (0880a238|38a28008) (0200c5f4|f4c50002) .*
+ 100002c0 (00000060|60000000) (238022f5|f5228023) (00000060|60000000) (0880a238|38a28008) .*
+ 100002d0 (0300c5f4|f4c50003) .*
+Contents of section \.got:
+ 10010300 (00830110|00000000) (00000000|10018300) (40030110|00000000) (00000000|10010340) .*
+ 10010310 (20030110|00000000) (00000000|10010320) (28030110|00000000) (00000000|10010328) .*
+Contents of section \.sdata:
+ 10010320 (01000000|00000000) (00000000|00000001) (02000000|00000000) (00000000|00000002) .*
+ 10010330 (03000000|00000000) (00000000|00000003) (04000000|00000000) (00000000|00000004) .*
+ 10010340 (05000000|00000000) (00000000|00000005) (06000000|00000000) (00000000|00000006) .*
diff --git a/ld/testsuite/ld-powerpc/tocopt8.s b/ld/testsuite/ld-powerpc/tocopt8.s
new file mode 100644
index 00000000000..219de5ea49b
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/tocopt8.s
@@ -0,0 +1,188 @@
+ .section .toc,"aw"
+x4t:
+ .quad x4
+x5t:
+ .quad x5
+
+ .section .sdata,"aw"
+ .p2align 4
+x1:
+ .quad 1
+x2:
+ .quad 2
+x3:
+ .quad 3
+x4:
+ .quad 4
+x5:
+ .quad 5
+x6:
+ .quad 6
+
+ .globl _start
+ .text
+_start:
+# no need for got entry, optimise to nop,addi
+# note: ld doesn't yet do got optimisation, so we get nop,ld
+ addis 9,2,x1@got@ha
+ ld 9,x1@got@l(9)
+# must keep got entry, optimise to nop,addi,ld
+ addis 4,2,x2@got@ha
+ addi 5,4,x2@got@l
+ ld 6,0(5)
+# no need for toc entry, optimise to nop,addi
+ addis 9,2,x4t@toc@ha
+ ld 9,x4t@toc@l(9)
+# must keep toc entry, optimise to nop,addi,ld
+# if we had a reloc tying the ld to x5/x5t then we could throw away
+# the toc entry and optimise to nop,nop,addi
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ ld 6,0(5)
+# keep toc entry due to other accesses to x5t, optimise to nop,ld
+ addis 9,2,x5t@toc@ha
+ ld 9,x5t@toc@l(9)
+
+ addis 4,2,x2@got@ha
+ addi 5,4,x2@got@l
+ lwz 6,0(5)
+ addis 9,2,x1@toc@ha
+ lwz 9,x1@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ lwz 6,0(5)
+
+ addis 4,2,x2@got@ha
+ addi 5,4,x2@got@l
+ lwa 6,0(5)
+ addis 9,2,x1@toc@ha
+ lwa 9,x1@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ lwa 6,0(5)
+
+ addis 4,2,x2@got@ha
+ addi 5,4,x2@got@l
+ lhz 6,0(5)
+ addis 9,2,x1@toc@ha
+ lhz 9,x1@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ lhz 6,0(5)
+
+ addis 4,2,x2@got@ha
+ addi 5,4,x2@got@l
+ lha 6,0(5)
+ addis 9,2,x1@toc@ha
+ lha 9,x1@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ lha 6,0(5)
+
+ addis 4,2,x2@got@ha
+ addi 5,4,x2@got@l
+ lbz 6,0(5)
+ addis 9,2,x1@toc@ha
+ lbz 9,x1@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ lbz 6,0(5)
+
+ addis 4,2,x2@got@ha
+ addi 5,4,x2@got@l
+ lfs 6,0(5)
+ addis 9,2,x1@toc@ha
+ lfs 9,x1@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ lfs 6,0(5)
+
+ addis 4,2,x2@got@ha
+ addi 5,4,x2@got@l
+ lfd 6,0(5)
+ addis 9,2,x1@toc@ha
+ lfd 9,x1@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ lfd 6,0(5)
+
+ addis 4,2,x2@got@ha
+ addi 5,4,x2@got@l
+ lxv 6,0(5)
+ addis 9,2,x1@toc@ha
+ lxv 9,x1@toc@l(9)
+ addis 4,2,x1@toc@ha
+ addi 5,4,x1@toc@l
+ lxv 6,0(5)
+
+ addis 4,2,x2@got@ha
+ addi 5,4,x2@got@l
+ lxsd 6,0(5)
+ addis 9,2,x1@toc@ha
+ lxsd 9,x1@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ lxsd 6,0(5)
+
+ addis 4,2,x2@got@ha
+ addi 5,4,x2@got@l
+ lxssp 6,0(5)
+ addis 9,2,x1@toc@ha
+ lxssp 9,x1@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ lxssp 6,0(5)
+
+ addis 9,2,x1@toc@ha
+ std 9,x1@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ std 6,0(5)
+
+ addis 9,2,x1@toc@ha
+ stw 9,x1@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ stw 6,0(5)
+
+ addis 9,2,x1@toc@ha
+ sth 9,x1@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ sth 6,0(5)
+
+ addis 9,2,x1@toc@ha
+ stb 9,x1@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ stb 6,0(5)
+
+ addis 9,2,x1@toc@ha
+ stfs 9,x1@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ stfs 6,0(5)
+
+ addis 9,2,x1@toc@ha
+ stfd 9,x1@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ stfd 6,0(5)
+
+ addis 9,2,x1@toc@ha
+ stxv 9,x1@toc@l(9)
+ addis 4,2,x1@toc@ha
+ addi 5,4,x1@toc@l
+ stxv 6,0(5)
+
+ addis 9,2,x1@toc@ha
+ stxsd 9,x1@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ stxsd 6,0(5)
+
+ addis 9,2,x1@toc@ha
+ stxssp 9,x1@toc@l(9)
+ addis 4,2,x5t@toc@ha
+ addi 5,4,x5t@toc@l
+ stxssp 6,0(5)
diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog
index 43841f57972..e5917d4ef3b 100644
--- a/opcodes/ChangeLog
+++ b/opcodes/ChangeLog
@@ -1,3 +1,21 @@
+2017-03-08 Peter Bergner <bergner@vnet.ibm.com>
+
+ * ppc-dis.c (ppc_opts) <altivec>: Do not use PPC_OPCODE_ALTIVEC2;
+ <vsx>: Do not use PPC_OPCODE_VSX3;
+
+2017-03-08 Peter Bergner <bergner@vnet.ibm.com>
+
+ Apply from master.
+ 2017-03-08 Peter Bergner <bergner@vnet.ibm.com>
+ * ppc-opc.c (powerpc_opcodes) <lnia>: New extended mnemonic.
+
+2017-22-28 Peter Bergner <bergner@vnet.ibm.com>
+
+ Apply from master.
+ 2017-02-10 Nicholas Piggin <npiggin@gmail.com>
+
+ * ppc-opc.c (powerpc_opcodes) <scv, rfscv>: New mnemonics.
+
2016-09-16 Peter Bergner <bergner@vnet.ibm.com>
Apply from master.
diff --git a/opcodes/ppc-dis.c b/opcodes/ppc-dis.c
index 77a2a60643b..e7a59b3a243 100644
--- a/opcodes/ppc-dis.c
+++ b/opcodes/ppc-dis.c
@@ -93,7 +93,7 @@ struct ppc_mopt ppc_opts[] = {
| PPC_OPCODE_A2),
0 },
{ "altivec", PPC_OPCODE_PPC,
- PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2 },
+ PPC_OPCODE_ALTIVEC },
{ "any", 0,
PPC_OPCODE_ANY },
{ "booke", PPC_OPCODE_PPC | PPC_OPCODE_BOOKE,
@@ -216,7 +216,7 @@ struct ppc_mopt ppc_opts[] = {
| PPC_OPCODE_E500),
PPC_OPCODE_VLE },
{ "vsx", PPC_OPCODE_PPC,
- PPC_OPCODE_VSX | PPC_OPCODE_VSX3 },
+ PPC_OPCODE_VSX },
{ "htm", PPC_OPCODE_PPC,
PPC_OPCODE_HTM },
};
diff --git a/opcodes/ppc-opc.c b/opcodes/ppc-opc.c
index 7003e0ca8f1..5926db0ee33 100644
--- a/opcodes/ppc-opc.c
+++ b/opcodes/ppc-opc.c
@@ -441,7 +441,7 @@ const struct powerpc_operand powerpc_operands[] =
#define L1 L0 + 1
{ 0x1, 21, insert_l1, extract_l1, 0 },
- /* The LEV field in a POWER SVC form instruction. */
+ /* The LEV field in a POWER SVC / POWER9 SCV form instruction. */
#define SVC_LEV L1 + 1
{ 0x7f, 5, NULL, NULL, 0 },
@@ -2487,6 +2487,8 @@ extract_vleil (unsigned long insn,
/* An DX form instruction. */
#define DX(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x1f) << 1))
#define DX_MASK DX (0x3f, 0x1f)
+/* An DX form instruction with the D bits specified. */
+#define NODX_MASK (DX_MASK | 0x1fffc1)
/* An EVSEL form instruction. */
#define EVSEL(op, xop) (OP (op) | (((unsigned long)(xop)) & 0xff) << 3)
@@ -4185,6 +4187,7 @@ const struct powerpc_opcode powerpc_opcodes[] = {
{"bcla", B(16,1,1), B_MASK, COM, PPCVLE, {BO, BI, BDA}},
{"svc", SC(17,0,0), SC_MASK, POWER, PPCVLE, {SVC_LEV, FL1, FL2}},
+{"scv", SC(17,0,1), SC_MASK, POWER9, PPCVLE, {SVC_LEV}},
{"svcl", SC(17,0,1), SC_MASK, POWER, PPCVLE, {SVC_LEV, FL1, FL2}},
{"sc", SC(17,1,0), SC_MASK, PPC, PPCVLE, {LEV}},
{"svca", SC(17,1,0), SC_MASK, PWRCOM, PPCVLE, {SV}},
@@ -4197,6 +4200,7 @@ const struct powerpc_opcode powerpc_opcodes[] = {
{"mcrf", XL(19,0), XLBB_MASK|(3<<21)|(3<<16), COM, PPCVLE, {BF, BFA}},
+{"lnia", DX(19,2), NODX_MASK, POWER9, PPCVLE, {RT}},
{"addpcis", DX(19,2), DX_MASK, POWER9, PPCVLE, {RT, DXD}},
{"subpcis", DX(19,2), DX_MASK, POWER9, PPCVLE, {RT, NDXD}},
@@ -4434,6 +4438,7 @@ const struct powerpc_opcode powerpc_opcodes[] = {
{"rfi", XL(19,50), 0xffffffff, COM, PPCVLE, {0}},
{"rfci", XL(19,51), 0xffffffff, PPC403|BOOKE|PPCE300|PPCA2|PPC476, PPCVLE, {0}},
+{"rfscv", XL(19,82), 0xffffffff, POWER9, PPCVLE, {0}},
{"rfsvc", XL(19,82), 0xffffffff, POWER, PPCVLE, {0}},
{"rfgi", XL(19,102), 0xffffffff, E500MC|PPCA2, PPCVLE, {0}},