diff options
author | Adhemerval Zanella <adhemerval.zanella@linaro.org> | 2017-08-21 11:34:06 -0300 |
---|---|---|
committer | Adhemerval Zanella <adhemerval.zanella@linaro.org> | 2017-08-21 11:34:06 -0300 |
commit | f3ae7dbacf5aeb9df207f5dacd778a2f6eab24fc (patch) | |
tree | 007fb5f9f137a4cb155cbf457fcd3ae320c2e6f4 | |
parent | 1d72c7445857652f3eb423f2702bc5981580fb63 (diff) | |
parent | b5d3ac25628b1a16409a9816623c34a45377d400 (diff) | |
download | binutils-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
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(§ion_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}}, |