public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/9] PowerPC64 ELFv2 ABI support.
@ 2013-10-30  2:19 Alan Modra
  2013-10-30  2:21 ` [PATCH 1/9] Report overflow on PowerPC64 @h and @ha relocations Alan Modra
                   ` (10 more replies)
  0 siblings, 11 replies; 19+ messages in thread
From: Alan Modra @ 2013-10-30  2:19 UTC (permalink / raw)
  To: binutils

This patch series makes the changes necessary in binutils to support
the updated PowerPC64 ABI, which we're calling ELFv2.  Two major
changes from the previous ABI are

- No function descriptors.
  Functions set up their got/toc pointer as necessary on entry.  The
  plt consists of single dword addresses.  Function pointers point at
  the function code.  To make this work efficiently with static
  linking, functions have *two* entry points, one we call the "global
  entry" and another we call the "local entry".  The global entry
  point is the address stored in function pointers, and it is a
  requirement that calls to the global entry point have that address
  in r12.  This is no hardship since calls via function pointers or
  the plt will always use a sequence that loads the address into a
  general purpose register, moves it to the count register, then
  branches to the count register.  We just needed to make sure r12 was
  the gpr used.  The "local entry" is used when the toc pointer is
  known to already be valid for the function, typically true for
  static linking, allowing the toc pointer setup to be skipped.

- Reduced stack frame size.
  We removed the compiler and linker save words, and removed the
  parameter save area for most functions.  This means the minimum
  stack frame overhead is reduced from 112 bytes to 32 bytes (for
  functions that need a frame), and many functions will used just the
  minimum.  After some debate, we decided to keep the stack back-chain
  word.

The ABI's are incompatible.  It won't be possible to link old objects
with new except in rare cases, or to use old shared libraries with new
executables at run time.

The first two patches in this series make changes that affect the old
ABI too, the first one fixing a hole in the PowerPC64 ABI, and the
second one makes all stubs conform with the ELFv2 ABI requirement on
r12.

-- 
Alan Modra
Australia Development Lab, IBM

  Report overflow on PowerPC64 @h and @ha relocations.
  Change plt stubs to have destination in r12.
  Add .abiversion related support for ELFv2
  Add ELFv2 .localentry support.
  ELFv2 stub, plt and glink changes
  Support ELFv2 stack frame.
  Replace DT_PPC_TLSOPT with DT_PPC_OPT.
  Add PowerPC64 ELFv2 tests.
  PowerPC64 ELFv2 support for gold.

 bfd/ChangeLog                       |   82 ++++
 bfd/bfd-in2.h                       |    6 +
 bfd/elf32-ppc.c                     |    2 +-
 bfd/elf64-ppc.c                     |  884 +++++++++++++++++++++++++----------
 bfd/libbfd.h                        |    6 +
 bfd/reloc.c                         |   12 +
 binutils/ChangeLog                  |   14 +
 binutils/readelf.c                  |   30 +-
 elfcpp/ChangeLog                    |   13 +
 elfcpp/powerpc.h                    |   61 ++-
 gas/ChangeLog                       |   27 ++
 gas/config/tc-ppc.c                 |  284 +++++++++--
 gas/config/tc-ppc.h                 |    3 +
 gold/ChangeLog                      |   47 ++
 gold/powerpc.cc                     |  668 +++++++++++++++++++-------
 include/elf/ChangeLog               |   24 +
 include/elf/ppc.h                   |    3 +-
 include/elf/ppc64.h                 |   73 ++-
 ld/testsuite/ChangeLog              |   29 ++
 ld/testsuite/ld-powerpc/elfv2.s     |   32 ++
 ld/testsuite/ld-powerpc/elfv2exe.d  |   40 ++
 ld/testsuite/ld-powerpc/elfv2so.d   |   82 ++++
 ld/testsuite/ld-powerpc/powerpc.exp |    2 +
 ld/testsuite/ld-powerpc/relbrlt.d   |    8 +-
 ld/testsuite/ld-powerpc/tls.d       |    4 +-
 ld/testsuite/ld-powerpc/tls.g       |    6 +-
 ld/testsuite/ld-powerpc/tls.s       |    7 +-
 ld/testsuite/ld-powerpc/tlsexe.d    |   23 +-
 ld/testsuite/ld-powerpc/tlsexe.g    |    2 +-
 ld/testsuite/ld-powerpc/tlsexe.r    |   56 +--
 ld/testsuite/ld-powerpc/tlsexetoc.d |   23 +-
 ld/testsuite/ld-powerpc/tlsexetoc.g |    2 +-
 ld/testsuite/ld-powerpc/tlsexetoc.r |   58 +--
 ld/testsuite/ld-powerpc/tlsso.d     |   25 +-
 ld/testsuite/ld-powerpc/tlsso.g     |    2 +-
 ld/testsuite/ld-powerpc/tlsso.r     |   60 +--
 ld/testsuite/ld-powerpc/tlstoc.d    |    4 +-
 ld/testsuite/ld-powerpc/tlstoc.g    |   12 +-
 ld/testsuite/ld-powerpc/tlstoc.s    |    7 +-
 ld/testsuite/ld-powerpc/tlstocso.d  |   25 +-
 ld/testsuite/ld-powerpc/tlstocso.g  |    2 +-
 ld/testsuite/ld-powerpc/tlstocso.r  |   62 +--
 42 files changed, 2166 insertions(+), 646 deletions(-)
 create mode 100644 ld/testsuite/ld-powerpc/elfv2.s
 create mode 100644 ld/testsuite/ld-powerpc/elfv2exe.d
 create mode 100644 ld/testsuite/ld-powerpc/elfv2so.d

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 1/9] Report overflow on PowerPC64 @h and @ha relocations.
  2013-10-30  2:19 [PATCH 0/9] PowerPC64 ELFv2 ABI support Alan Modra
@ 2013-10-30  2:21 ` Alan Modra
  2013-10-30  2:22 ` [PATCH 2/9] Change plt stubs to have destination in r12 Alan Modra
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Alan Modra @ 2013-10-30  2:21 UTC (permalink / raw)
  To: binutils

This changes the behaviour of @h and @ha on PowerPC64 to report errors
on 32-bit overflow.  The motivation for this change is that on
PowerPC64, most uses of @h and @ha modifiers and their corresponding
relocations are to build up 32-bit offsets.  We'd like to know when
such offsets overflow.  Only rarely do people use @h or @ha with the
high 32-bit modifiers to build a 64-bit constant.  Those uses will now
need to use two new modifiers, @high and @higha, if the constant isn't
known at assembly time.  For now, we won't report overflow at assembly
time..

This also fixes an error when applying some of the HIGHER and HIGHEST
relocations.

include/elf/
	* ppc64.h (R_PPC64_ADDR16_HIGH, R_PPC64_ADDR16_HIGHA,
	R_PPC64_TPREL16_HIGH, R_PPC64_TPREL16_HIGHA,
	R_PPC64_DTPREL16_HIGH, R_PPC64_DTPREL16_HIGHA): New.
	(IS_PPC64_TLS_RELOC): Match new tls relocs.
bfd/
	* reloc.c (BFD_RELOC_PPC64_ADDR16_HIGH, BFD_RELOC_PPC64_ADDR16_HIGHA,
	BFD_RELOC_PPC64_TPREL16_HIGH, BFD_RELOC_PPC64_TPREL16_HIGHA,
	BFD_RELOC_PPC64_DTPREL16_HIGH, BFD_RELOC_PPC64_DTPREL16_HIGHA): New.
	* elf64-ppc.c (ppc64_elf_howto_raw): Add entries for new relocs.
	Make all _HA and _HI relocs report signed overflow.
	(ppc64_elf_reloc_type_lookup): Handle new relocs.
	(must_be_dyn_reloc, ppc64_elf_check_relocs): Likewise.
	(dec_dynrel_count, ppc64_elf_relocate_section): Likewise.
	(ppc64_elf_relocate_section): Don't apply 0x8000 adjust to
	R_PPC64_TPREL16_HIGHER, R_PPC64_TPREL16_HIGHEST,
	R_PPC64_DTPREL16_HIGHER, and R_PPC64_DTPREL16_HIGHEST.
	* libbfd.h: Regenerate.
	* bfd-in2.h: Regenerate.
gas/
	* config/tc-ppc.c (SEX16): Don't mask.
	(REPORT_OVERFLOW_HI): Define as zero.
	(ppc_elf_suffix): Support @high, @higha, @dtprel@high, @dtprel@higha,
	@tprel@high, and @tprel@higha modifiers.
	(md_assemble): Ignore X_unsigned when applying 16-bit insn fields.
	Add (disabled) code to check @h and @ha reloc overflow for powerpc64.
	Handle new relocs.
	(md_apply_fix): Similarly.
elfcpp/
	* powerpc.h (R_PPC64_ADDR16_HIGH, R_PPC64_ADDR16_HIGHA,
	R_PPC64_TPREL16_HIGH, R_PPC64_TPREL16_HIGHA,
	R_PPC64_DTPREL16_HIGH, R_PPC64_DTPREL16_HIGHA): Define.
gold/
	* powerpc.cc (Target_powerpc::Scan::check_non_pic): Handle new relocs.
	(Target_powerpc::Scan::global, local): Likewise.
	(Target_powerpc::Relocate::relocate): Likewise.  Check for overflow
	on all ppc64 @h and @ha relocs.

-- 
Alan Modra
Australia Development Lab, IBM

diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 3df01f6..63d4eb9 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -309,7 +309,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	/* special_function */
 	 "R_PPC64_ADDR16_HI",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -325,7 +325,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 ppc64_elf_ha_reloc,	/* special_function */
 	 "R_PPC64_ADDR16_HA",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -487,7 +487,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont,/* complain_on_overflow */
+	 complain_overflow_signed,/* complain_on_overflow */
 	 ppc64_elf_unhandled_reloc, /* special_function */
 	 "R_PPC64_GOT16_HI",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -503,7 +503,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont,/* complain_on_overflow */
+	 complain_overflow_signed,/* complain_on_overflow */
 	 ppc64_elf_unhandled_reloc, /* special_function */
 	 "R_PPC64_GOT16_HA",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -680,7 +680,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 ppc64_elf_unhandled_reloc, /* special_function */
 	 "R_PPC64_PLT16_HI",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -696,7 +696,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 ppc64_elf_unhandled_reloc, /* special_function */
 	 "R_PPC64_PLT16_HA",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -741,7 +741,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 ppc64_elf_sectoff_reloc, /* special_function */
 	 "R_PPC64_SECTOFF_HI",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -756,7 +756,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 ppc64_elf_sectoff_ha_reloc, /* special_function */
 	 "R_PPC64_SECTOFF_HA",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -963,7 +963,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 ppc64_elf_toc_reloc,	/* special_function */
 	 "R_PPC64_TOC16_HI",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -982,7 +982,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 ppc64_elf_toc_ha_reloc, /* special_function */
 	 "R_PPC64_TOC16_HA",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -1054,7 +1054,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 ppc64_elf_unhandled_reloc, /* special_function */
 	 "R_PPC64_PLTGOT16_HI",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -1072,7 +1072,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont,/* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 ppc64_elf_unhandled_reloc, /* special_function */
 	 "R_PPC64_PLTGOT16_HA",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -1374,7 +1374,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 ppc64_elf_unhandled_reloc, /* special_function */
 	 "R_PPC64_DTPREL16_HI",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -1389,7 +1389,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 ppc64_elf_unhandled_reloc, /* special_function */
 	 "R_PPC64_DTPREL16_HA",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -1540,7 +1540,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 ppc64_elf_unhandled_reloc, /* special_function */
 	 "R_PPC64_TPREL16_HI",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -1555,7 +1555,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 ppc64_elf_unhandled_reloc, /* special_function */
 	 "R_PPC64_TPREL16_HA",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -1692,7 +1692,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 ppc64_elf_unhandled_reloc, /* special_function */
 	 "R_PPC64_GOT_TLSGD16_HI", /* name */
 	 FALSE,			/* partial_inplace */
@@ -1707,7 +1707,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 ppc64_elf_unhandled_reloc, /* special_function */
 	 "R_PPC64_GOT_TLSGD16_HA", /* name */
 	 FALSE,			/* partial_inplace */
@@ -1754,7 +1754,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 ppc64_elf_unhandled_reloc, /* special_function */
 	 "R_PPC64_GOT_TLSLD16_HI", /* name */
 	 FALSE,			/* partial_inplace */
@@ -1769,7 +1769,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 ppc64_elf_unhandled_reloc, /* special_function */
 	 "R_PPC64_GOT_TLSLD16_HA", /* name */
 	 FALSE,			/* partial_inplace */
@@ -1815,7 +1815,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 ppc64_elf_unhandled_reloc, /* special_function */
 	 "R_PPC64_GOT_DTPREL16_HI", /* name */
 	 FALSE,			/* partial_inplace */
@@ -1830,7 +1830,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 ppc64_elf_unhandled_reloc, /* special_function */
 	 "R_PPC64_GOT_DTPREL16_HA", /* name */
 	 FALSE,			/* partial_inplace */
@@ -1876,7 +1876,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 ppc64_elf_unhandled_reloc, /* special_function */
 	 "R_PPC64_GOT_TPREL16_HI", /* name */
 	 FALSE,			/* partial_inplace */
@@ -1891,7 +1891,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 ppc64_elf_unhandled_reloc, /* special_function */
 	 "R_PPC64_GOT_TPREL16_HA", /* name */
 	 FALSE,			/* partial_inplace */
@@ -1964,7 +1964,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 TRUE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	/* special_function */
 	 "R_PPC64_REL16_HI",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -1980,7 +1980,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 TRUE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_dont, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 ppc64_elf_ha_reloc,	/* special_function */
 	 "R_PPC64_REL16_HA",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -1988,6 +1988,96 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
 	 0xffff,		/* dst_mask */
 	 TRUE),			/* pcrel_offset */
 
+  /* Like R_PPC64_ADDR16_HI, but no overflow.  */
+  HOWTO (R_PPC64_ADDR16_HIGH,	/* type */
+	 16,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special_function */
+	 "R_PPC64_ADDR16_HIGH",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like R_PPC64_ADDR16_HA, but no overflow.  */
+  HOWTO (R_PPC64_ADDR16_HIGHA,	/* type */
+	 16,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_ha_reloc,	/* special_function */
+	 "R_PPC64_ADDR16_HIGHA",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like R_PPC64_DTPREL16_HI, but no overflow.  */
+  HOWTO (R_PPC64_DTPREL16_HIGH,
+	 16,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_DTPREL16_HIGH", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like R_PPC64_DTPREL16_HA, but no overflow.  */
+  HOWTO (R_PPC64_DTPREL16_HIGHA,
+	 16,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_DTPREL16_HIGHA", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like R_PPC64_TPREL16_HI, but no overflow.  */
+  HOWTO (R_PPC64_TPREL16_HIGH,
+	 16,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_TPREL16_HIGH",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like R_PPC64_TPREL16_HA, but no overflow.  */
+  HOWTO (R_PPC64_TPREL16_HIGHA,
+	 16,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_TPREL16_HIGHA",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
   /* GNU extension to record C++ vtable hierarchy.  */
   HOWTO (R_PPC64_GNU_VTINHERIT,	/* type */
 	 0,			/* rightshift */
@@ -2066,8 +2156,12 @@ ppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
       break;
     case BFD_RELOC_HI16:			r = R_PPC64_ADDR16_HI;
       break;
+    case BFD_RELOC_PPC64_ADDR16_HIGH:		r = R_PPC64_ADDR16_HIGH;
+      break;
     case BFD_RELOC_HI16_S:			r = R_PPC64_ADDR16_HA;
       break;
+    case BFD_RELOC_PPC64_ADDR16_HIGHA:		r = R_PPC64_ADDR16_HIGHA;
+      break;
     case BFD_RELOC_PPC_BA16:			r = R_PPC64_ADDR14;
       break;
     case BFD_RELOC_PPC_BA16_BRTAKEN:		r = R_PPC64_ADDR14_BRTAKEN;
@@ -2186,8 +2280,12 @@ ppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
       break;
     case BFD_RELOC_PPC_TPREL16_HI:		r = R_PPC64_TPREL16_HI;
       break;
+    case BFD_RELOC_PPC64_TPREL16_HIGH:		r = R_PPC64_TPREL16_HIGH;
+      break;
     case BFD_RELOC_PPC_TPREL16_HA:		r = R_PPC64_TPREL16_HA;
       break;
+    case BFD_RELOC_PPC64_TPREL16_HIGHA:		r = R_PPC64_TPREL16_HIGHA;
+      break;
     case BFD_RELOC_PPC_TPREL:			r = R_PPC64_TPREL64;
       break;
     case BFD_RELOC_PPC_DTPREL16:		r = R_PPC64_DTPREL16;
@@ -2196,8 +2294,12 @@ ppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
       break;
     case BFD_RELOC_PPC_DTPREL16_HI:		r = R_PPC64_DTPREL16_HI;
       break;
+    case BFD_RELOC_PPC64_DTPREL16_HIGH:		r = R_PPC64_DTPREL16_HIGH;
+      break;
     case BFD_RELOC_PPC_DTPREL16_HA:		r = R_PPC64_DTPREL16_HA;
       break;
+    case BFD_RELOC_PPC64_DTPREL16_HIGHA:	r = R_PPC64_DTPREL16_HIGHA;
+      break;
     case BFD_RELOC_PPC_DTPREL:			r = R_PPC64_DTPREL64;
       break;
     case BFD_RELOC_PPC_GOT_TLSGD16:		r = R_PPC64_GOT_TLSGD16;
@@ -3514,6 +3616,8 @@ must_be_dyn_reloc (struct bfd_link_info *info,
     case R_PPC64_TPREL16_HA:
     case R_PPC64_TPREL16_DS:
     case R_PPC64_TPREL16_LO_DS:
+    case R_PPC64_TPREL16_HIGH:
+    case R_PPC64_TPREL16_HIGHA:
     case R_PPC64_TPREL16_HIGHER:
     case R_PPC64_TPREL16_HIGHERA:
     case R_PPC64_TPREL16_HIGHEST:
@@ -5208,6 +5312,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	case R_PPC64_DTPREL16_HA:
 	case R_PPC64_DTPREL16_DS:
 	case R_PPC64_DTPREL16_LO_DS:
+	case R_PPC64_DTPREL16_HIGH:
+	case R_PPC64_DTPREL16_HIGHA:
 	case R_PPC64_DTPREL16_HIGHER:
 	case R_PPC64_DTPREL16_HIGHERA:
 	case R_PPC64_DTPREL16_HIGHEST:
@@ -5368,6 +5474,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	case R_PPC64_TPREL16_HA:
 	case R_PPC64_TPREL16_DS:
 	case R_PPC64_TPREL16_LO_DS:
+	case R_PPC64_TPREL16_HIGH:
+	case R_PPC64_TPREL16_HIGHA:
 	case R_PPC64_TPREL16_HIGHER:
 	case R_PPC64_TPREL16_HIGHERA:
 	case R_PPC64_TPREL16_HIGHEST:
@@ -5421,6 +5529,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	case R_PPC64_ADDR16_DS:
 	case R_PPC64_ADDR16_HA:
 	case R_PPC64_ADDR16_HI:
+	case R_PPC64_ADDR16_HIGH:
+	case R_PPC64_ADDR16_HIGHA:
 	case R_PPC64_ADDR16_HIGHER:
 	case R_PPC64_ADDR16_HIGHERA:
 	case R_PPC64_ADDR16_HIGHEST:
@@ -7052,6 +7162,8 @@ dec_dynrel_count (bfd_vma r_info,
     case R_PPC64_TPREL16_HA:
     case R_PPC64_TPREL16_DS:
     case R_PPC64_TPREL16_LO_DS:
+    case R_PPC64_TPREL16_HIGH:
+    case R_PPC64_TPREL16_HIGHA:
     case R_PPC64_TPREL16_HIGHER:
     case R_PPC64_TPREL16_HIGHERA:
     case R_PPC64_TPREL16_HIGHEST:
@@ -7073,6 +7185,8 @@ dec_dynrel_count (bfd_vma r_info,
     case R_PPC64_ADDR16_DS:
     case R_PPC64_ADDR16_HA:
     case R_PPC64_ADDR16_HI:
+    case R_PPC64_ADDR16_HIGH:
+    case R_PPC64_ADDR16_HIGHA:
     case R_PPC64_ADDR16_HIGHER:
     case R_PPC64_ADDR16_HIGHERA:
     case R_PPC64_ADDR16_HIGHEST:
@@ -13531,6 +13645,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	case R_PPC64_TPREL16_HA:
 	case R_PPC64_TPREL16_DS:
 	case R_PPC64_TPREL16_LO_DS:
+	case R_PPC64_TPREL16_HIGH:
+	case R_PPC64_TPREL16_HIGHA:
 	case R_PPC64_TPREL16_HIGHER:
 	case R_PPC64_TPREL16_HIGHERA:
 	case R_PPC64_TPREL16_HIGHEST:
@@ -13565,6 +13681,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	case R_PPC64_DTPREL16_HA:
 	case R_PPC64_DTPREL16_DS:
 	case R_PPC64_DTPREL16_LO_DS:
+	case R_PPC64_DTPREL16_HIGH:
+	case R_PPC64_DTPREL16_HIGHA:
 	case R_PPC64_DTPREL16_HIGHER:
 	case R_PPC64_DTPREL16_HIGHERA:
 	case R_PPC64_DTPREL16_HIGHEST:
@@ -13597,6 +13715,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	case R_PPC64_ADDR16_DS:
 	case R_PPC64_ADDR16_HA:
 	case R_PPC64_ADDR16_HI:
+	case R_PPC64_ADDR16_HIGH:
+	case R_PPC64_ADDR16_HIGHA:
 	case R_PPC64_ADDR16_HIGHER:
 	case R_PPC64_ADDR16_HIGHERA:
 	case R_PPC64_ADDR16_HIGHEST:
@@ -13911,21 +14031,20 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	default:
 	  break;
 
-	case R_PPC64_ADDR16_HA:
 	case R_PPC64_REL16_HA:
+	case R_PPC64_ADDR16_HA:
+	case R_PPC64_ADDR16_HIGHA:
 	case R_PPC64_ADDR16_HIGHERA:
 	case R_PPC64_ADDR16_HIGHESTA:
 	case R_PPC64_TOC16_HA:
 	case R_PPC64_SECTOFF_HA:
 	case R_PPC64_TPREL16_HA:
-	case R_PPC64_DTPREL16_HA:
-	case R_PPC64_TPREL16_HIGHER:
+	case R_PPC64_TPREL16_HIGHA:
 	case R_PPC64_TPREL16_HIGHERA:
-	case R_PPC64_TPREL16_HIGHEST:
 	case R_PPC64_TPREL16_HIGHESTA:
-	case R_PPC64_DTPREL16_HIGHER:
+	case R_PPC64_DTPREL16_HA:
+	case R_PPC64_DTPREL16_HIGHA:
 	case R_PPC64_DTPREL16_HIGHERA:
-	case R_PPC64_DTPREL16_HIGHEST:
 	case R_PPC64_DTPREL16_HIGHESTA:
 	  /* It's just possible that this symbol is a weak symbol
 	     that's not actually defined anywhere. In that case,
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 25c089c..8778e1d 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -2891,6 +2891,10 @@ ENUMX
   BFD_RELOC_PPC64_PLTGOT16_DS
 ENUMX
   BFD_RELOC_PPC64_PLTGOT16_LO_DS
+ENUMX
+  BFD_RELOC_PPC64_ADDR16_HIGH
+ENUMX
+  BFD_RELOC_PPC64_ADDR16_HIGHA
 ENUMDOC
   Power(rs6000) and PowerPC relocations.
 
@@ -2978,6 +2982,14 @@ ENUMX
   BFD_RELOC_PPC64_DTPREL16_HIGHEST
 ENUMX
   BFD_RELOC_PPC64_DTPREL16_HIGHESTA
+ENUMX
+  BFD_RELOC_PPC64_TPREL16_HIGH
+ENUMX
+  BFD_RELOC_PPC64_TPREL16_HIGHA
+ENUMX
+  BFD_RELOC_PPC64_DTPREL16_HIGH
+ENUMX
+  BFD_RELOC_PPC64_DTPREL16_HIGHA
 ENUMDOC
   PowerPC and PowerPC64 thread-local storage relocations.
 
diff --git a/elfcpp/powerpc.h b/elfcpp/powerpc.h
index 2c803af..fb4256b 100644
--- a/elfcpp/powerpc.h
+++ b/elfcpp/powerpc.h
@@ -164,11 +164,17 @@ enum
   R_PPC_EMB_SDA21 = 109,
   R_PPC64_TOCSAVE = 109,
   R_PPC_EMB_MRKREF = 110,
+  R_PPC64_ADDR16_HIGH = 110,
   R_PPC_EMB_RELSEC16 = 111,
+  R_PPC64_ADDR16_HIGHA = 111,
   R_PPC_EMB_RELST_LO = 112,
+  R_PPC64_TPREL16_HIGH = 112,
   R_PPC_EMB_RELST_HI = 113,
+  R_PPC64_TPREL16_HIGHA = 113,
   R_PPC_EMB_RELST_HA = 114,
+  R_PPC64_DTPREL16_HIGH = 114,
   R_PPC_EMB_BIT_FLD = 115,
+  R_PPC64_DTPREL16_HIGHA = 115,
   R_PPC_EMB_RELSDA = 116,
 
   R_PPC_VLE_REL8 = 216,
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index 6b54f5a..34afc91 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -86,7 +86,11 @@ static int set_target_endian = 0;
    compensating for #lo being treated as a signed number.  */
 #define PPC_HIGHESTA(v) PPC_HIGHEST ((v) + 0x8000)
 
-#define SEX16(val) ((((val) & 0xffff) ^ 0x8000) - 0x8000)
+#define SEX16(val) (((val) ^ 0x8000) - 0x8000)
+
+/* For the time being on ppc64, don't report overflow on @h and @ha
+   applied to constants.  */
+#define REPORT_OVERFLOW_HI 0
 
 static bfd_boolean reg_names_p = TARGET_REG_NAMES_P;
 
@@ -1923,6 +1927,8 @@ ppc_elf_suffix (char **str_p, expressionS *exp_p)
     MAP32 ("bitfld",		BFD_RELOC_PPC_EMB_BIT_FLD),
     MAP32 ("relsda",		BFD_RELOC_PPC_EMB_RELSDA),
     MAP32 ("xgot",		BFD_RELOC_PPC_TOC16),
+    MAP64 ("high",		BFD_RELOC_PPC64_ADDR16_HIGH),
+    MAP64 ("higha",		BFD_RELOC_PPC64_ADDR16_HIGHA),
     MAP64 ("higher",		BFD_RELOC_PPC64_HIGHER),
     MAP64 ("highera",		BFD_RELOC_PPC64_HIGHER_S),
     MAP64 ("highest",		BFD_RELOC_PPC64_HIGHEST),
@@ -1932,10 +1938,14 @@ ppc_elf_suffix (char **str_p, expressionS *exp_p)
     MAP64 ("toc@l",		BFD_RELOC_PPC64_TOC16_LO),
     MAP64 ("toc@h",		BFD_RELOC_PPC64_TOC16_HI),
     MAP64 ("toc@ha",		BFD_RELOC_PPC64_TOC16_HA),
+    MAP64 ("dtprel@high",	BFD_RELOC_PPC64_DTPREL16_HIGH),
+    MAP64 ("dtprel@higha",	BFD_RELOC_PPC64_DTPREL16_HIGHA),
     MAP64 ("dtprel@higher",	BFD_RELOC_PPC64_DTPREL16_HIGHER),
     MAP64 ("dtprel@highera",	BFD_RELOC_PPC64_DTPREL16_HIGHERA),
     MAP64 ("dtprel@highest",	BFD_RELOC_PPC64_DTPREL16_HIGHEST),
     MAP64 ("dtprel@highesta",	BFD_RELOC_PPC64_DTPREL16_HIGHESTA),
+    MAP64 ("tprel@high",	BFD_RELOC_PPC64_TPREL16_HIGH),
+    MAP64 ("tprel@higha",	BFD_RELOC_PPC64_TPREL16_HIGHA),
     MAP64 ("tprel@higher",	BFD_RELOC_PPC64_TPREL16_HIGHER),
     MAP64 ("tprel@highera",	BFD_RELOC_PPC64_TPREL16_HIGHERA),
     MAP64 ("tprel@highest",	BFD_RELOC_PPC64_TPREL16_HIGHEST),
@@ -2810,55 +2820,76 @@ md_assemble (char *str)
 		break;
 
 	      case BFD_RELOC_LO16:
-		/* X_unsigned is the default, so if the user has done
-		   something which cleared it, we always produce a
-		   signed value.  */
-		if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
-		  ex.X_add_number &= 0xffff;
-		else
+		ex.X_add_number &= 0xffff;
+		if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
 		  ex.X_add_number = SEX16 (ex.X_add_number);
 		break;
 
 	      case BFD_RELOC_HI16:
-		if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
-		  ex.X_add_number = PPC_HI (ex.X_add_number);
-		else
-		  ex.X_add_number = SEX16 (PPC_HI (ex.X_add_number));
+		if (REPORT_OVERFLOW_HI && ppc_obj64)
+		  {
+		    /* PowerPC64 @h is tested for overflow.  */
+		    ex.X_add_number = (addressT) ex.X_add_number >> 16;
+		    if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
+		      {
+			addressT sign = (((addressT) -1 >> 16) + 1) >> 1;
+			ex.X_add_number
+			  = ((addressT) ex.X_add_number ^ sign) - sign;
+		      }
+		    break;
+		  }
+		/* Fall thru */
+
+	      case BFD_RELOC_PPC64_ADDR16_HIGH:
+		ex.X_add_number = PPC_HI (ex.X_add_number);
+		if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
+		  ex.X_add_number = SEX16 (ex.X_add_number);
 		break;
 
 	      case BFD_RELOC_HI16_S:
-		if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
-		  ex.X_add_number = PPC_HA (ex.X_add_number);
-		else
-		  ex.X_add_number = SEX16 (PPC_HA (ex.X_add_number));
+		if (REPORT_OVERFLOW_HI && ppc_obj64)
+		  {
+		    /* PowerPC64 @ha is tested for overflow.  */
+		    ex.X_add_number
+		      = ((addressT) ex.X_add_number + 0x8000) >> 16;
+		    if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
+		      {
+			addressT sign = (((addressT) -1 >> 16) + 1) >> 1;
+			ex.X_add_number
+			  = ((addressT) ex.X_add_number ^ sign) - sign;
+		      }
+		    break;
+		  }
+		/* Fall thru */
+
+	      case BFD_RELOC_PPC64_ADDR16_HIGHA:
+		ex.X_add_number = PPC_HA (ex.X_add_number);
+		if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
+		  ex.X_add_number = SEX16 (ex.X_add_number);
 		break;
 
 	      case BFD_RELOC_PPC64_HIGHER:
-		if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
-		  ex.X_add_number = PPC_HIGHER (ex.X_add_number);
-		else
-		  ex.X_add_number = SEX16 (PPC_HIGHER (ex.X_add_number));
+		ex.X_add_number = PPC_HIGHER (ex.X_add_number);
+		if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
+		  ex.X_add_number = SEX16 (ex.X_add_number);
 		break;
 
 	      case BFD_RELOC_PPC64_HIGHER_S:
-		if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
-		  ex.X_add_number = PPC_HIGHERA (ex.X_add_number);
-		else
-		  ex.X_add_number = SEX16 (PPC_HIGHERA (ex.X_add_number));
+		ex.X_add_number = PPC_HIGHERA (ex.X_add_number);
+		if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
+		  ex.X_add_number = SEX16 (ex.X_add_number);
 		break;
 
 	      case BFD_RELOC_PPC64_HIGHEST:
-		if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
-		  ex.X_add_number = PPC_HIGHEST (ex.X_add_number);
-		else
-		  ex.X_add_number = SEX16 (PPC_HIGHEST (ex.X_add_number));
+		ex.X_add_number = PPC_HIGHEST (ex.X_add_number);
+		if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
+		  ex.X_add_number = SEX16 (ex.X_add_number);
 		break;
 
 	      case BFD_RELOC_PPC64_HIGHEST_S:
-		if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
-		  ex.X_add_number = PPC_HIGHESTA (ex.X_add_number);
-		else
-		  ex.X_add_number = SEX16 (PPC_HIGHESTA (ex.X_add_number));
+		ex.X_add_number = PPC_HIGHESTA (ex.X_add_number);
+		if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
+		  ex.X_add_number = SEX16 (ex.X_add_number);
 		break;
 	      }
 #endif /* OBJ_ELF */
@@ -6390,25 +6421,51 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       fieldval = value & 0xffff;
     sign_extend_16:
       if (operand != NULL && (operand->flags & PPC_OPERAND_SIGNED) != 0)
-	fieldval = (fieldval ^ 0x8000) - 0x8000;
+	fieldval = SEX16 (fieldval);
       fixP->fx_no_overflow = 1;
       break;
 
+    case BFD_RELOC_HI16:
+    case BFD_RELOC_HI16_PCREL:
 #ifdef OBJ_ELF
+      if (REPORT_OVERFLOW_HI && ppc_obj64)
+	{
+	  fieldval = value >> 16;
+	  if (operand != NULL && (operand->flags & PPC_OPERAND_SIGNED) != 0)
+	    {
+	      valueT sign = (((valueT) -1 >> 16) + 1) >> 1;
+	      fieldval = ((valueT) fieldval ^ sign) - sign;
+	    }
+	  break;
+	}
+      /* Fall thru */
+
     case BFD_RELOC_PPC_VLE_HI16A:
     case BFD_RELOC_PPC_VLE_HI16D:
+    case BFD_RELOC_PPC64_ADDR16_HIGH:
 #endif
-    case BFD_RELOC_HI16:
-    case BFD_RELOC_HI16_PCREL:
       fieldval = PPC_HI (value);
       goto sign_extend_16;
 
+    case BFD_RELOC_HI16_S:
+    case BFD_RELOC_HI16_S_PCREL:
 #ifdef OBJ_ELF
+      if (REPORT_OVERFLOW_HI && ppc_obj64)
+	{
+	  fieldval = (value + 0x8000) >> 16;
+	  if (operand != NULL && (operand->flags & PPC_OPERAND_SIGNED) != 0)
+	    {
+	      valueT sign = (((valueT) -1 >> 16) + 1) >> 1;
+	      fieldval = ((valueT) fieldval ^ sign) - sign;
+	    }
+	  break;
+	}
+      /* Fall thru */
+
     case BFD_RELOC_PPC_VLE_HA16A:
     case BFD_RELOC_PPC_VLE_HA16D:
+    case BFD_RELOC_PPC64_ADDR16_HIGHA:
 #endif
-    case BFD_RELOC_HI16_S:
-    case BFD_RELOC_HI16_S_PCREL:
       fieldval = PPC_HA (value);
       goto sign_extend_16;
 
@@ -6471,10 +6528,14 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 	case BFD_RELOC_PPC_GOT_DTPREL16_HA:
 	case BFD_RELOC_PPC64_TPREL16_DS:
 	case BFD_RELOC_PPC64_TPREL16_LO_DS:
+	case BFD_RELOC_PPC64_TPREL16_HIGH:
+	case BFD_RELOC_PPC64_TPREL16_HIGHA:
 	case BFD_RELOC_PPC64_TPREL16_HIGHER:
 	case BFD_RELOC_PPC64_TPREL16_HIGHERA:
 	case BFD_RELOC_PPC64_TPREL16_HIGHEST:
 	case BFD_RELOC_PPC64_TPREL16_HIGHESTA:
+	case BFD_RELOC_PPC64_DTPREL16_HIGH:
+	case BFD_RELOC_PPC64_DTPREL16_HIGHA:
 	case BFD_RELOC_PPC64_DTPREL16_DS:
 	case BFD_RELOC_PPC64_DTPREL16_LO_DS:
 	case BFD_RELOC_PPC64_DTPREL16_HIGHER:
@@ -6660,6 +6721,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 	case BFD_RELOC_PPC64_HIGHER_S:
 	case BFD_RELOC_PPC64_HIGHEST:
 	case BFD_RELOC_PPC64_HIGHEST_S:
+	case BFD_RELOC_PPC64_ADDR16_HIGH:
+	case BFD_RELOC_PPC64_ADDR16_HIGHA:
 	  break;
 
 	case BFD_RELOC_PPC_DTPMOD:
@@ -6736,10 +6799,14 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 	case BFD_RELOC_PPC64_TOC16_LO:
 	case BFD_RELOC_PPC64_TOC16_HI:
 	case BFD_RELOC_PPC64_TOC16_HA:
+	case BFD_RELOC_PPC64_DTPREL16_HIGH:
+	case BFD_RELOC_PPC64_DTPREL16_HIGHA:
 	case BFD_RELOC_PPC64_DTPREL16_HIGHER:
 	case BFD_RELOC_PPC64_DTPREL16_HIGHERA:
 	case BFD_RELOC_PPC64_DTPREL16_HIGHEST:
 	case BFD_RELOC_PPC64_DTPREL16_HIGHESTA:
+	case BFD_RELOC_PPC64_TPREL16_HIGH:
+	case BFD_RELOC_PPC64_TPREL16_HIGHA:
 	case BFD_RELOC_PPC64_TPREL16_HIGHER:
 	case BFD_RELOC_PPC64_TPREL16_HIGHERA:
 	case BFD_RELOC_PPC64_TPREL16_HIGHEST:
diff --git a/gold/powerpc.cc b/gold/powerpc.cc
index 880b367..75fc604 100644
--- a/gold/powerpc.cc
+++ b/gold/powerpc.cc
@@ -4877,6 +4877,8 @@ Target_powerpc<size, big_endian>::Scan::check_non_pic(Relobj* object,
 	case elfcpp::R_PPC64_JMP_IREL:
 	case elfcpp::R_PPC64_ADDR16_DS:
 	case elfcpp::R_PPC64_ADDR16_LO_DS:
+	case elfcpp::R_PPC64_ADDR16_HIGH:
+	case elfcpp::R_PPC64_ADDR16_HIGHA:
 	case elfcpp::R_PPC64_ADDR16_HIGHER:
 	case elfcpp::R_PPC64_ADDR16_HIGHEST:
 	case elfcpp::R_PPC64_ADDR16_HIGHERA:
@@ -4885,6 +4887,8 @@ Target_powerpc<size, big_endian>::Scan::check_non_pic(Relobj* object,
 	case elfcpp::R_POWERPC_ADDR30:
 	case elfcpp::R_PPC64_TPREL16_DS:
 	case elfcpp::R_PPC64_TPREL16_LO_DS:
+	case elfcpp::R_PPC64_TPREL16_HIGH:
+	case elfcpp::R_PPC64_TPREL16_HIGHA:
 	case elfcpp::R_PPC64_TPREL16_HIGHER:
 	case elfcpp::R_PPC64_TPREL16_HIGHEST:
 	case elfcpp::R_PPC64_TPREL16_HIGHERA:
@@ -5057,7 +5061,6 @@ Target_powerpc<size, big_endian>::Scan::local(
     case elfcpp::R_POWERPC_GNU_VTINHERIT:
     case elfcpp::R_POWERPC_GNU_VTENTRY:
     case elfcpp::R_PPC64_TOCSAVE:
-    case elfcpp::R_PPC_EMB_MRKREF:
     case elfcpp::R_POWERPC_TLS:
       break;
 
@@ -5094,6 +5097,8 @@ Target_powerpc<size, big_endian>::Scan::local(
     case elfcpp::R_POWERPC_ADDR16_HI:
     case elfcpp::R_POWERPC_ADDR16_HA:
     case elfcpp::R_POWERPC_UADDR16:
+    case elfcpp::R_PPC64_ADDR16_HIGH:
+    case elfcpp::R_PPC64_ADDR16_HIGHA:
     case elfcpp::R_PPC64_ADDR16_HIGHER:
     case elfcpp::R_PPC64_ADDR16_HIGHERA:
     case elfcpp::R_PPC64_ADDR16_HIGHEST:
@@ -5152,31 +5157,35 @@ Target_powerpc<size, big_endian>::Scan::local(
     case elfcpp::R_POWERPC_REL16_HI:
     case elfcpp::R_POWERPC_REL16_HA:
     case elfcpp::R_POWERPC_SECTOFF:
-    case elfcpp::R_POWERPC_TPREL16:
-    case elfcpp::R_POWERPC_DTPREL16:
     case elfcpp::R_POWERPC_SECTOFF_LO:
-    case elfcpp::R_POWERPC_TPREL16_LO:
-    case elfcpp::R_POWERPC_DTPREL16_LO:
     case elfcpp::R_POWERPC_SECTOFF_HI:
-    case elfcpp::R_POWERPC_TPREL16_HI:
-    case elfcpp::R_POWERPC_DTPREL16_HI:
     case elfcpp::R_POWERPC_SECTOFF_HA:
+    case elfcpp::R_PPC64_SECTOFF_DS:
+    case elfcpp::R_PPC64_SECTOFF_LO_DS:
+    case elfcpp::R_POWERPC_TPREL16:
+    case elfcpp::R_POWERPC_TPREL16_LO:
+    case elfcpp::R_POWERPC_TPREL16_HI:
     case elfcpp::R_POWERPC_TPREL16_HA:
-    case elfcpp::R_POWERPC_DTPREL16_HA:
-    case elfcpp::R_PPC64_DTPREL16_HIGHER:
+    case elfcpp::R_PPC64_TPREL16_DS:
+    case elfcpp::R_PPC64_TPREL16_LO_DS:
+    case elfcpp::R_PPC64_TPREL16_HIGH:
+    case elfcpp::R_PPC64_TPREL16_HIGHA:
     case elfcpp::R_PPC64_TPREL16_HIGHER:
-    case elfcpp::R_PPC64_DTPREL16_HIGHERA:
     case elfcpp::R_PPC64_TPREL16_HIGHERA:
-    case elfcpp::R_PPC64_DTPREL16_HIGHEST:
     case elfcpp::R_PPC64_TPREL16_HIGHEST:
-    case elfcpp::R_PPC64_DTPREL16_HIGHESTA:
     case elfcpp::R_PPC64_TPREL16_HIGHESTA:
-    case elfcpp::R_PPC64_TPREL16_DS:
-    case elfcpp::R_PPC64_TPREL16_LO_DS:
+    case elfcpp::R_POWERPC_DTPREL16:
+    case elfcpp::R_POWERPC_DTPREL16_LO:
+    case elfcpp::R_POWERPC_DTPREL16_HI:
+    case elfcpp::R_POWERPC_DTPREL16_HA:
     case elfcpp::R_PPC64_DTPREL16_DS:
     case elfcpp::R_PPC64_DTPREL16_LO_DS:
-    case elfcpp::R_PPC64_SECTOFF_DS:
-    case elfcpp::R_PPC64_SECTOFF_LO_DS:
+    case elfcpp::R_PPC64_DTPREL16_HIGH:
+    case elfcpp::R_PPC64_DTPREL16_HIGHA:
+    case elfcpp::R_PPC64_DTPREL16_HIGHER:
+    case elfcpp::R_PPC64_DTPREL16_HIGHERA:
+    case elfcpp::R_PPC64_DTPREL16_HIGHEST:
+    case elfcpp::R_PPC64_DTPREL16_HIGHESTA:
     case elfcpp::R_PPC64_TLSGD:
     case elfcpp::R_PPC64_TLSLD:
       break;
@@ -5407,7 +5416,6 @@ Target_powerpc<size, big_endian>::Scan::global(
     case elfcpp::R_POWERPC_GNU_VTINHERIT:
     case elfcpp::R_POWERPC_GNU_VTENTRY:
     case elfcpp::R_PPC_LOCAL24PC:
-    case elfcpp::R_PPC_EMB_MRKREF:
     case elfcpp::R_POWERPC_TLS:
       break;
 
@@ -5456,6 +5464,8 @@ Target_powerpc<size, big_endian>::Scan::global(
     case elfcpp::R_POWERPC_ADDR16_HI:
     case elfcpp::R_POWERPC_ADDR16_HA:
     case elfcpp::R_POWERPC_UADDR16:
+    case elfcpp::R_PPC64_ADDR16_HIGH:
+    case elfcpp::R_PPC64_ADDR16_HIGHA:
     case elfcpp::R_PPC64_ADDR16_HIGHER:
     case elfcpp::R_PPC64_ADDR16_HIGHERA:
     case elfcpp::R_PPC64_ADDR16_HIGHEST:
@@ -5581,31 +5591,35 @@ Target_powerpc<size, big_endian>::Scan::global(
     case elfcpp::R_POWERPC_REL16_HI:
     case elfcpp::R_POWERPC_REL16_HA:
     case elfcpp::R_POWERPC_SECTOFF:
-    case elfcpp::R_POWERPC_TPREL16:
-    case elfcpp::R_POWERPC_DTPREL16:
     case elfcpp::R_POWERPC_SECTOFF_LO:
-    case elfcpp::R_POWERPC_TPREL16_LO:
-    case elfcpp::R_POWERPC_DTPREL16_LO:
     case elfcpp::R_POWERPC_SECTOFF_HI:
-    case elfcpp::R_POWERPC_TPREL16_HI:
-    case elfcpp::R_POWERPC_DTPREL16_HI:
     case elfcpp::R_POWERPC_SECTOFF_HA:
+    case elfcpp::R_PPC64_SECTOFF_DS:
+    case elfcpp::R_PPC64_SECTOFF_LO_DS:
+    case elfcpp::R_POWERPC_TPREL16:
+    case elfcpp::R_POWERPC_TPREL16_LO:
+    case elfcpp::R_POWERPC_TPREL16_HI:
     case elfcpp::R_POWERPC_TPREL16_HA:
-    case elfcpp::R_POWERPC_DTPREL16_HA:
-    case elfcpp::R_PPC64_DTPREL16_HIGHER:
+    case elfcpp::R_PPC64_TPREL16_DS:
+    case elfcpp::R_PPC64_TPREL16_LO_DS:
+    case elfcpp::R_PPC64_TPREL16_HIGH:
+    case elfcpp::R_PPC64_TPREL16_HIGHA:
     case elfcpp::R_PPC64_TPREL16_HIGHER:
-    case elfcpp::R_PPC64_DTPREL16_HIGHERA:
     case elfcpp::R_PPC64_TPREL16_HIGHERA:
-    case elfcpp::R_PPC64_DTPREL16_HIGHEST:
     case elfcpp::R_PPC64_TPREL16_HIGHEST:
-    case elfcpp::R_PPC64_DTPREL16_HIGHESTA:
     case elfcpp::R_PPC64_TPREL16_HIGHESTA:
-    case elfcpp::R_PPC64_TPREL16_DS:
-    case elfcpp::R_PPC64_TPREL16_LO_DS:
+    case elfcpp::R_POWERPC_DTPREL16:
+    case elfcpp::R_POWERPC_DTPREL16_LO:
+    case elfcpp::R_POWERPC_DTPREL16_HI:
+    case elfcpp::R_POWERPC_DTPREL16_HA:
     case elfcpp::R_PPC64_DTPREL16_DS:
     case elfcpp::R_PPC64_DTPREL16_LO_DS:
-    case elfcpp::R_PPC64_SECTOFF_DS:
-    case elfcpp::R_PPC64_SECTOFF_LO_DS:
+    case elfcpp::R_PPC64_DTPREL16_HIGH:
+    case elfcpp::R_PPC64_DTPREL16_HIGHA:
+    case elfcpp::R_PPC64_DTPREL16_HIGHER:
+    case elfcpp::R_PPC64_DTPREL16_HIGHERA:
+    case elfcpp::R_PPC64_DTPREL16_HIGHEST:
+    case elfcpp::R_PPC64_DTPREL16_HIGHESTA:
     case elfcpp::R_PPC64_TLSGD:
     case elfcpp::R_PPC64_TLSLD:
       break;
@@ -6748,8 +6762,10 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
 
     case elfcpp::R_PPC64_TPREL16_DS:
     case elfcpp::R_PPC64_TPREL16_LO_DS:
+    case elfcpp::R_PPC64_TPREL16_HIGH:
+    case elfcpp::R_PPC64_TPREL16_HIGHA:
       if (size != 64)
-	// R_PPC_TLSGD and R_PPC_TLSLD
+	// R_PPC_TLSGD, R_PPC_TLSLD, R_PPC_EMB_RELST_LO, R_PPC_EMB_RELST_HI
 	break;
     case elfcpp::R_POWERPC_TPREL16:
     case elfcpp::R_POWERPC_TPREL16_LO:
@@ -6779,6 +6795,8 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
     case elfcpp::R_POWERPC_DTPREL16_HI:
     case elfcpp::R_POWERPC_DTPREL16_HA:
     case elfcpp::R_POWERPC_DTPREL:
+    case elfcpp::R_PPC64_DTPREL16_HIGH:
+    case elfcpp::R_PPC64_DTPREL16_HIGHA:
       // tls symbol values are relative to tls_segment()->vaddr()
       value -= dtp_offset;
       break;
@@ -6919,6 +6937,34 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
       overflow = Reloc::CHECK_BITFIELD;
       break;
 
+    case elfcpp::R_POWERPC_ADDR16_HI:
+    case elfcpp::R_POWERPC_ADDR16_HA:
+    case elfcpp::R_POWERPC_GOT16_HI:
+    case elfcpp::R_POWERPC_GOT16_HA:
+    case elfcpp::R_POWERPC_PLT16_HI:
+    case elfcpp::R_POWERPC_PLT16_HA:
+    case elfcpp::R_POWERPC_SECTOFF_HI:
+    case elfcpp::R_POWERPC_SECTOFF_HA:
+    case elfcpp::R_PPC64_TOC16_HI:
+    case elfcpp::R_PPC64_TOC16_HA:
+    case elfcpp::R_PPC64_PLTGOT16_HI:
+    case elfcpp::R_PPC64_PLTGOT16_HA:
+    case elfcpp::R_POWERPC_TPREL16_HI:
+    case elfcpp::R_POWERPC_TPREL16_HA:
+    case elfcpp::R_POWERPC_DTPREL16_HI:
+    case elfcpp::R_POWERPC_DTPREL16_HA:
+    case elfcpp::R_POWERPC_GOT_TLSGD16_HI:
+    case elfcpp::R_POWERPC_GOT_TLSGD16_HA:
+    case elfcpp::R_POWERPC_GOT_TLSLD16_HI:
+    case elfcpp::R_POWERPC_GOT_TLSLD16_HA:
+    case elfcpp::R_POWERPC_GOT_TPREL16_HI:
+    case elfcpp::R_POWERPC_GOT_TPREL16_HA:
+    case elfcpp::R_POWERPC_GOT_DTPREL16_HI:
+    case elfcpp::R_POWERPC_GOT_DTPREL16_HA:
+    case elfcpp::R_POWERPC_REL16_HI:
+    case elfcpp::R_POWERPC_REL16_HA:
+      if (size == 32)
+	break;
     case elfcpp::R_POWERPC_REL24:
     case elfcpp::R_PPC_PLTREL24:
     case elfcpp::R_PPC_LOCAL24PC:
@@ -6952,7 +6998,6 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
     case elfcpp::R_POWERPC_TLS:
     case elfcpp::R_POWERPC_GNU_VTINHERIT:
     case elfcpp::R_POWERPC_GNU_VTENTRY:
-    case elfcpp::R_PPC_EMB_MRKREF:
       break;
 
     case elfcpp::R_PPC64_ADDR64:
@@ -7023,6 +7068,12 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
       status = Reloc::addr16_u(view, value, overflow);
       break;
 
+    case elfcpp::R_PPC64_ADDR16_HIGH:
+    case elfcpp::R_PPC64_TPREL16_HIGH:
+    case elfcpp::R_PPC64_DTPREL16_HIGH:
+      if (size == 32)
+	// R_PPC_EMB_MRKREF, R_PPC_EMB_RELST_LO, R_PPC_EMB_RELST_HA
+	goto unsupp;
     case elfcpp::R_POWERPC_ADDR16_HI:
     case elfcpp::R_POWERPC_REL16_HI:
     case elfcpp::R_PPC64_TOC16_HI:
@@ -7037,6 +7088,12 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
       Reloc::addr16_hi(view, value);
       break;
 
+    case elfcpp::R_PPC64_ADDR16_HIGHA:
+    case elfcpp::R_PPC64_TPREL16_HIGHA:
+    case elfcpp::R_PPC64_DTPREL16_HIGHA:
+      if (size == 32)
+	// R_PPC_EMB_RELSEC16, R_PPC_EMB_RELST_HI, R_PPC_EMB_BIT_FLD
+	goto unsupp;
     case elfcpp::R_POWERPC_ADDR16_HA:
     case elfcpp::R_POWERPC_REL16_HA:
     case elfcpp::R_PPC64_TOC16_HA:
@@ -7161,11 +7218,6 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
     case elfcpp::R_PPC64_PLT16_LO_DS:
     case elfcpp::R_PPC64_PLTGOT16_DS:
     case elfcpp::R_PPC64_PLTGOT16_LO_DS:
-    case elfcpp::R_PPC_EMB_RELSEC16:
-    case elfcpp::R_PPC_EMB_RELST_LO:
-    case elfcpp::R_PPC_EMB_RELST_HI:
-    case elfcpp::R_PPC_EMB_RELST_HA:
-    case elfcpp::R_PPC_EMB_BIT_FLD:
     case elfcpp::R_PPC_EMB_RELSDA:
     case elfcpp::R_PPC_TOC16:
     default:
diff --git a/include/elf/ppc64.h b/include/elf/ppc64.h
index f1c80f1..221786f 100644
--- a/include/elf/ppc64.h
+++ b/include/elf/ppc64.h
@@ -141,6 +141,14 @@ START_RELOC_NUMBERS (elf_ppc64_reloc_type)
   RELOC_NUMBER (R_PPC64_TLSLD,		   108)
   RELOC_NUMBER (R_PPC64_TOCSAVE,	   109)
 
+/* Added when HA and HI relocs were changed to report overflows.  */
+  RELOC_NUMBER (R_PPC64_ADDR16_HIGH,	   110)
+  RELOC_NUMBER (R_PPC64_ADDR16_HIGHA,	   111)
+  RELOC_NUMBER (R_PPC64_TPREL16_HIGH,	   112)
+  RELOC_NUMBER (R_PPC64_TPREL16_HIGHA,	   113)
+  RELOC_NUMBER (R_PPC64_DTPREL16_HIGH,	   114)
+  RELOC_NUMBER (R_PPC64_DTPREL16_HIGHA,	   115)
+
 #ifndef RELOC_MACROS_GEN_FUNC
 /* Fake relocation only used internally by ld.  */
   RELOC_NUMBER (R_PPC64_LO_DS_OPT,	   128)
@@ -161,8 +169,9 @@ START_RELOC_NUMBERS (elf_ppc64_reloc_type)
 
 END_RELOC_NUMBERS (R_PPC64_max)
 
-#define IS_PPC64_TLS_RELOC(R) \
-  ((R) >= R_PPC64_TLS && (R) <= R_PPC64_DTPREL16_HIGHESTA)
+#define IS_PPC64_TLS_RELOC(R)						\
+  (((R) >= R_PPC64_TLS && (R) <= R_PPC64_DTPREL16_HIGHESTA)		\
+   || ((R) >= R_PPC64_TPREL16_HIGH && (R) <= R_PPC64_DTPREL16_HIGHA))
 
 /* Specify the start of the .glink section.  */
 #define DT_PPC64_GLINK		DT_LOPROC

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 2/9] Change plt stubs to have destination in r12.
  2013-10-30  2:19 [PATCH 0/9] PowerPC64 ELFv2 ABI support Alan Modra
  2013-10-30  2:21 ` [PATCH 1/9] Report overflow on PowerPC64 @h and @ha relocations Alan Modra
@ 2013-10-30  2:22 ` Alan Modra
  2013-10-30  2:23 ` [PATCH 3/9] Add .abiversion related support for ELFv2 Alan Modra
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Alan Modra @ 2013-10-30  2:22 UTC (permalink / raw)
  To: binutils

This change is to support the new ELFv2 ABI, which uses the value in
r12 on function entry to calculate the got/toc pointer.

bfd/
	* elf64-ppc.c (build_plt_stub): Switch stubs to use r11 as base
	reg and r12 as destination.
	(ppc_build_one_stub): Likewise.
	(ppc64_elf_build_stubs): Likewise for glink.
ld/testsuite/
	* ld-powerpc/tls.s: Add proper .opd entry for _start.
	* ld-powerpc/tlstoc.s: Likewise.
	* ld-powerpc/relbrlt.d: Update for changed stubs.
	* ld-powerpc/tls.d: Update for changed stubs and _start .opd entry.
	* ld-powerpc/tls.g: Likewise.
	* ld-powerpc/tlsexe.d: Likewise.
	* ld-powerpc/tlsexe.g: Likewise.
	* ld-powerpc/tlsexe.r: Likewise.
	* ld-powerpc/tlsexetoc.d: Likewise.
	* ld-powerpc/tlsexetoc.g: Likewise.
	* ld-powerpc/tlsexetoc.r: Likewise.
	* ld-powerpc/tlsso.d: Likewise.
	* ld-powerpc/tlsso.g: Likewise.
	* ld-powerpc/tlsso.r: Likewise.
	* ld-powerpc/tlstoc.d: Likewise.
	* ld-powerpc/tlstoc.g: Likewise.
	* ld-powerpc/tlstocso.d: Likewise.
	* ld-powerpc/tlstocso.g: Likewise.
	* ld-powerpc/tlstocso.r: Likewise.

-- 
Alan Modra
Australia Development Lab, IBM

diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 63d4eb9..94a9402 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -137,29 +137,29 @@ static bfd_vma opd_entry_value
 
 /* .plt call stub instructions.  The normal stub is like this, but
    sometimes the .plt entry crosses a 64k boundary and we need to
-   insert an addi to adjust r12.  */
+   insert an addi to adjust r11.  */
 #define PLT_CALL_STUB_SIZE (7*4)
-#define ADDIS_R12_R2	0x3d820000	/* addis %r12,%r2,xxx@ha     */
 #define STD_R2_40R1	0xf8410028	/* std	 %r2,40(%r1)	     */
-#define LD_R11_0R12	0xe96c0000	/* ld	 %r11,xxx+0@l(%r12)  */
-#define MTCTR_R11	0x7d6903a6	/* mtctr %r11		     */
-#define LD_R2_0R12	0xe84c0000	/* ld	 %r2,xxx+8@l(%r12)   */
-					/* ld	 %r11,xxx+16@l(%r12) */
+#define ADDIS_R11_R2	0x3d620000	/* addis %r11,%r2,xxx@ha     */
+#define LD_R12_0R11	0xe98b0000	/* ld	 %r12,xxx+0@l(%r11)  */
+#define MTCTR_R12	0x7d8903a6	/* mtctr %r12		     */
+#define LD_R2_0R11	0xe84b0000	/* ld	 %r2,xxx+8@l(%r11)   */
+#define LD_R11_0R11	0xe96b0000	/* ld	 %r11,xxx+16@l(%r11) */
 #define BCTR		0x4e800420	/* bctr			     */
 
-
-#define ADDIS_R12_R12	0x3d8c0000	/* addis %r12,%r12,off@ha  */
-#define ADDI_R12_R12	0x398c0000	/* addi %r12,%r12,off@l  */
+#define ADDI_R11_R11	0x396b0000	/* addi %r11,%r11,off@l  */
 #define ADDIS_R2_R2	0x3c420000	/* addis %r2,%r2,off@ha  */
 #define ADDI_R2_R2	0x38420000	/* addi  %r2,%r2,off@l   */
 
-#define XOR_R11_R11_R11	0x7d6b5a78	/* xor   %r11,%r11,%r11  */
-#define ADD_R12_R12_R11	0x7d8c5a14	/* add   %r12,%r12,%r11  */
+#define XOR_R2_R12_R12	0x7d826278	/* xor   %r2,%r12,%r12   */
+#define ADD_R11_R11_R2	0x7d6b1214	/* add   %r11,%r11,%r2   */
+#define XOR_R11_R12_R12	0x7d8b6278	/* xor   %r11,%r12,%r12  */
 #define ADD_R2_R2_R11	0x7c425a14	/* add   %r2,%r2,%r11    */
 #define CMPLDI_R2_0	0x28220000	/* cmpldi %r2,0          */
 #define BNECTR		0x4ca20420	/* bnectr+               */
 #define BNECTR_P4	0x4ce20420	/* bnectr+               */
 
+#define LD_R12_0R2	0xe9820000	/* ld	 %r12,xxx+0(%r2) */
 #define LD_R11_0R2	0xe9620000	/* ld	 %r11,xxx+0(%r2) */
 #define LD_R2_0R2	0xe8420000	/* ld	 %r2,xxx+0(%r2)  */
 
@@ -174,13 +174,13 @@ static bfd_vma opd_entry_value
 #define BCL_20_31	0x429f0005	/*  bcl 20,31,1f		*/
 					/* 1:				*/
 #define MFLR_R11	0x7d6802a6	/*  mflr %11			*/
-#define LD_R2_M16R11	0xe84bfff0	/*  ld %2,(0b-1b)(%11)		*/
+					/*  ld %2,(0b-1b)(%11)		*/
 #define MTLR_R12	0x7d8803a6	/*  mtlr %12			*/
-#define ADD_R12_R2_R11	0x7d825a14	/*  add %12,%2,%11		*/
-					/*  ld %11,0(%12)		*/
-					/*  ld %2,8(%12)		*/
-					/*  mtctr %11			*/
-					/*  ld %11,16(%12)		*/
+#define ADD_R11_R2_R11	0x7d625a14	/*  add %11,%2,%11		*/
+					/*  ld %12,0(%11)		*/
+					/*  ld %2,8(%11)		*/
+					/*  mtctr %12			*/
+					/*  ld %11,16(%11)		*/
 					/*  bctr			*/
 
 /* Pad with this.  */
@@ -3559,13 +3559,13 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
    .
    .
    .	.foo_stub:
-   .		addis	12,2,Lfoo@toc@ha	# in practice, the call stub
-   .		addi	12,12,Lfoo@toc@l	# is slightly optimized, but
-   .		std	2,40(1)			# this is the general idea
-   .		ld	11,0(12)
-   .		ld	2,8(12)
-   .		mtctr	11
-   .		ld	11,16(12)
+   .		std	2,40(1)			# in practice, the call stub
+   .		addis	11,2,Lfoo@toc@ha	# is slightly optimized, but
+   .		addi	11,11,Lfoo@toc@l	# this is the general idea
+   .		ld	12,0(11)
+   .		ld	2,8(11)
+   .		mtctr	12
+   .		ld	11,16(11)
    .		bctr
    .
    .		.section .plt
@@ -3657,21 +3657,21 @@ must_be_dyn_reloc (struct bfd_link_info *info,
    ppc_stub_plt_branch:
    Similar to the above, but a 24 bit branch in the stub section won't
    reach its destination.
-   .	addis	%r12,%r2,xxx@toc@ha
-   .	ld	%r11,xxx@toc@l(%r12)
-   .	mtctr	%r11
+   .	addis	%r11,%r2,xxx@toc@ha
+   .	ld	%r12,xxx@toc@l(%r11)
+   .	mtctr	%r12
    .	bctr
 
    ppc_stub_plt_call:
    Used to call a function in a shared library.  If it so happens that
    the plt entry referenced crosses a 64k boundary, then an extra
-   "addi %r12,%r12,xxx@toc@l" will be inserted before the "mtctr".
-   .	addis	%r12,%r2,xxx@toc@ha
+   "addi %r11,%r11,xxx@toc@l" will be inserted before the "mtctr".
    .	std	%r2,40(%r1)
-   .	ld	%r11,xxx+0@toc@l(%r12)
-   .	mtctr	%r11
-   .	ld	%r2,xxx+8@toc@l(%r12)
-   .	ld	%r11,xxx+16@toc@l(%r12)
+   .	addis	%r11,%r2,xxx@toc@ha
+   .	ld	%r12,xxx+0@toc@l(%r11)
+   .	mtctr	%r12
+   .	ld	%r2,xxx+8@toc@l(%r11)
+   .	ld	%r11,xxx+16@toc@l(%r11)
    .	bctr
 
    ppc_stub_long_branch and ppc_stub_plt_branch may also have additional
@@ -3684,11 +3684,11 @@ must_be_dyn_reloc (struct bfd_link_info *info,
 
    A ppc_stub_plt_branch with an r2 offset looks like:
    .	std	%r2,40(%r1)
-   .	addis	%r12,%r2,xxx@toc@ha
-   .	ld	%r11,xxx@toc@l(%r12)
+   .	addis	%r11,%r2,xxx@toc@ha
+   .	ld	%r12,xxx@toc@l(%r11)
    .	addis	%r2,%r2,off@ha
    .	addi	%r2,%r2,off@l
-   .	mtctr	%r11
+   .	mtctr	%r12
    .	bctr
 
    In cases where the "addis" instruction would add zero, the "addis" is
@@ -9779,9 +9779,9 @@ ppc_type_of_stub (asection *input_sec,
    the appropriate glink entry if so.
 
    .	fake dep barrier	compare
-   .	ld 11,xxx(2)		ld 11,xxx(2)
-   .	mtctr 11		mtctr 11
-   .	xor 11,11,11		ld 2,xxx+8(2)
+   .	ld 12,xxx(2)		ld 12,xxx(2)
+   .	mtctr 12		mtctr 12
+   .	xor 11,12,12		ld 2,xxx+8(2)
    .	add 2,2,11		cmpldi 2,0
    .	ld 2,xxx+8(2)		bnectr+
    .	bctr			b <glink_entry>
@@ -9916,22 +9916,22 @@ build_plt_stub (struct ppc_link_hash_table *htab,
       if (ALWAYS_EMIT_R2SAVE
 	  || stub_entry->stub_type == ppc_stub_plt_call_r2save)
 	bfd_put_32 (obfd, STD_R2_40R1, p),			p += 4;
-      bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p),	p += 4;
-      bfd_put_32 (obfd, LD_R11_0R12 | PPC_LO (offset), p),	p += 4;
+      bfd_put_32 (obfd, ADDIS_R11_R2 | PPC_HA (offset), p),	p += 4;
+      bfd_put_32 (obfd, LD_R12_0R11 | PPC_LO (offset), p),	p += 4;
       if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
 	{
-	  bfd_put_32 (obfd, ADDI_R12_R12 | PPC_LO (offset), p),	p += 4;
+	  bfd_put_32 (obfd, ADDI_R11_R11 | PPC_LO (offset), p),	p += 4;
 	  offset = 0;
 	}
-      bfd_put_32 (obfd, MTCTR_R11, p),				p += 4;
+      bfd_put_32 (obfd, MTCTR_R12, p),				p += 4;
       if (use_fake_dep)
 	{
-	  bfd_put_32 (obfd, XOR_R11_R11_R11, p),		p += 4;
-	  bfd_put_32 (obfd, ADD_R12_R12_R11, p),		p += 4;
+	  bfd_put_32 (obfd, XOR_R2_R12_R12, p),			p += 4;
+	  bfd_put_32 (obfd, ADD_R11_R11_R2, p),			p += 4;
 	}
-      bfd_put_32 (obfd, LD_R2_0R12 | PPC_LO (offset + 8), p),	p += 4;
+      bfd_put_32 (obfd, LD_R2_0R11 | PPC_LO (offset + 8), p),	p += 4;
       if (plt_static_chain)
-	bfd_put_32 (obfd, LD_R11_0R12 | PPC_LO (offset + 16), p), p += 4;
+	bfd_put_32 (obfd, LD_R11_0R11 | PPC_LO (offset + 16), p), p += 4;
     }
   else
     {
@@ -9963,16 +9963,16 @@ build_plt_stub (struct ppc_link_hash_table *htab,
       if (ALWAYS_EMIT_R2SAVE
 	  || stub_entry->stub_type == ppc_stub_plt_call_r2save)
 	bfd_put_32 (obfd, STD_R2_40R1, p),			p += 4;
-      bfd_put_32 (obfd, LD_R11_0R2 | PPC_LO (offset), p),	p += 4;
+      bfd_put_32 (obfd, LD_R12_0R2 | PPC_LO (offset), p),	p += 4;
       if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
 	{
 	  bfd_put_32 (obfd, ADDI_R2_R2 | PPC_LO (offset), p),	p += 4;
 	  offset = 0;
 	}
-      bfd_put_32 (obfd, MTCTR_R11, p),				p += 4;
+      bfd_put_32 (obfd, MTCTR_R12, p),				p += 4;
       if (use_fake_dep)
 	{
-	  bfd_put_32 (obfd, XOR_R11_R11_R11, p),		p += 4;
+	  bfd_put_32 (obfd, XOR_R11_R12_R12, p),		p += 4;
 	  bfd_put_32 (obfd, ADD_R2_R2_R11, p),			p += 4;
 	}
       if (plt_static_chain)
@@ -10321,14 +10321,14 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 	  if (PPC_HA (off) != 0)
 	    {
 	      size = 16;
-	      bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (off), loc);
+	      bfd_put_32 (htab->stub_bfd, ADDIS_R11_R2 | PPC_HA (off), loc);
 	      loc += 4;
-	      bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (off), loc);
+	      bfd_put_32 (htab->stub_bfd, LD_R12_0R11 | PPC_LO (off), loc);
 	    }
 	  else
 	    {
 	      size = 12;
-	      bfd_put_32 (htab->stub_bfd, LD_R11_0R2 | PPC_LO (off), loc);
+	      bfd_put_32 (htab->stub_bfd, LD_R12_0R2 | PPC_LO (off), loc);
 	    }
 	}
       else
@@ -10347,14 +10347,14 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 	  if (PPC_HA (off) != 0)
 	    {
 	      size += 4;
-	      bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (off), loc);
+	      bfd_put_32 (htab->stub_bfd, ADDIS_R11_R2 | PPC_HA (off), loc);
 	      loc += 4;
-	      bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (off), loc);
+	      bfd_put_32 (htab->stub_bfd, LD_R12_0R11 | PPC_LO (off), loc);
 	      loc += 4;
 	    }
 	  else
 	    {
-	      bfd_put_32 (htab->stub_bfd, LD_R11_0R2 | PPC_LO (off), loc);
+	      bfd_put_32 (htab->stub_bfd, LD_R12_0R2 | PPC_LO (off), loc);
 	      loc += 4;
 	    }
 
@@ -10367,7 +10367,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 	  bfd_put_32 (htab->stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc);
 	}
       loc += 4;
-      bfd_put_32 (htab->stub_bfd, MTCTR_R11, loc);
+      bfd_put_32 (htab->stub_bfd, MTCTR_R12, loc);
       loc += 4;
       bfd_put_32 (htab->stub_bfd, BCTR, loc);
       break;
@@ -12131,19 +12131,19 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
       p += 4;
       bfd_put_32 (htab->glink->owner, MFLR_R11, p);
       p += 4;
-      bfd_put_32 (htab->glink->owner, LD_R2_M16R11, p);
+      bfd_put_32 (htab->glink->owner, LD_R2_0R11 | (-16 & 0xfffc), p);
       p += 4;
       bfd_put_32 (htab->glink->owner, MTLR_R12, p);
       p += 4;
-      bfd_put_32 (htab->glink->owner, ADD_R12_R2_R11, p);
+      bfd_put_32 (htab->glink->owner, ADD_R11_R2_R11, p);
       p += 4;
-      bfd_put_32 (htab->glink->owner, LD_R11_0R12, p);
+      bfd_put_32 (htab->glink->owner, LD_R12_0R11, p);
       p += 4;
-      bfd_put_32 (htab->glink->owner, LD_R2_0R12 | 8, p);
+      bfd_put_32 (htab->glink->owner, LD_R2_0R11 | 8, p);
       p += 4;
-      bfd_put_32 (htab->glink->owner, MTCTR_R11, p);
+      bfd_put_32 (htab->glink->owner, MTCTR_R12, p);
       p += 4;
-      bfd_put_32 (htab->glink->owner, LD_R11_0R12 | 16, p);
+      bfd_put_32 (htab->glink->owner, LD_R11_0R11 | 16, p);
       p += 4;
       bfd_put_32 (htab->glink->owner, BCTR, p);
       p += 4;
diff --git a/ld/testsuite/ld-powerpc/relbrlt.d b/ld/testsuite/ld-powerpc/relbrlt.d
index 128e2e3..b04ae7d 100644
--- a/ld/testsuite/ld-powerpc/relbrlt.d
+++ b/ld/testsuite/ld-powerpc/relbrlt.d
@@ -22,9 +22,9 @@ Disassembly of section \.text:
 	\.\.\.
 
 [0-9a-f	 ]*<.*plt_branch.*>:
-[0-9a-f	 ]*:	(e9 62 80 00|00 80 62 e9) 	ld      r11,-32768\(r2\)
+[0-9a-f	 ]*:	(e9 82 80 00|00 80 82 e9) 	ld      r12,-32768\(r2\)
 [0-9a-f	 ]*: R_PPC64_TOC16_DS	\*ABS\*\+0x157f00e8
-[0-9a-f	 ]*:	(7d 69 03 a6|a6 03 69 7d) 	mtctr   r11
+[0-9a-f	 ]*:	(7d 89 03 a6|a6 03 89 7d) 	mtctr   r12
 [0-9a-f	 ]*:	(4e 80 04 20|20 04 80 4e) 	bctr
 
 [0-9a-f	 ]*<.*long_branch.*>:
@@ -32,9 +32,9 @@ Disassembly of section \.text:
 [0-9a-f	 ]*: R_PPC64_REL24	\*ABS\*\+0x137e00fc
 
 [0-9a-f	 ]*<.*plt_branch.*>:
-[0-9a-f	 ]*:	(e9 62 80 08|08 80 62 e9) 	ld      r11,-32760\(r2\)
+[0-9a-f	 ]*:	(e9 82 80 08|08 80 82 e9) 	ld      r12,-32760\(r2\)
 [0-9a-f	 ]*: R_PPC64_TOC16_DS	\*ABS\*\+0x157f00f0
-[0-9a-f	 ]*:	(7d 69 03 a6|a6 03 69 7d) 	mtctr   r11
+[0-9a-f	 ]*:	(7d 89 03 a6|a6 03 89 7d) 	mtctr   r12
 [0-9a-f	 ]*:	(4e 80 04 20|20 04 80 4e) 	bctr
 	\.\.\.
 
diff --git a/ld/testsuite/ld-powerpc/tls.d b/ld/testsuite/ld-powerpc/tls.d
index 3c32980..7082028 100644
--- a/ld/testsuite/ld-powerpc/tls.d
+++ b/ld/testsuite/ld-powerpc/tls.d
@@ -1,7 +1,7 @@
 #source: tls.s
 #source: tlslib.s
 #as: -a64
-#ld: 
+#ld:
 #objdump: -dr
 #target: powerpc64*-*-*
 
@@ -9,7 +9,7 @@
 
 Disassembly of section \.text:
 
-0+100000e8 <_start>:
+0+100000e8 <\._start>:
 .*:	(3c 6d 00 00|00 00 6d 3c) 	addis   r3,r13,0
 .*:	(60 00 00 00|00 00 00 60) 	nop
 .*:	(38 63 90 78|78 90 63 38) 	addi    r3,r3,-28552
diff --git a/ld/testsuite/ld-powerpc/tls.g b/ld/testsuite/ld-powerpc/tls.g
index 83f8e06..d4910ca 100644
--- a/ld/testsuite/ld-powerpc/tls.g
+++ b/ld/testsuite/ld-powerpc/tls.g
@@ -1,12 +1,12 @@
 #source: tls.s
 #source: tlslib.s
 #as: -a64
-#ld: 
+#ld:
 #objdump: -sj.got
 #target: powerpc64*-*-*
 
 .*
 
 Contents of section \.got:
- 100101e0 (00000000|e0810110) (100181e0|00000000) (ffffffff|1880ffff) (ffff8018|ffffffff)  .*
- 100101f0 (ffffffff|5880ffff) (ffff8058|ffffffff)                    .*
+ 100101f8 (00000000|f8810110) (100181f8|00000000) (ffffffff|1880ffff) (ffff8018|ffffffff)  .*
+ 10010208 (ffffffff|5880ffff) (ffff8058|ffffffff)                    .*
diff --git a/ld/testsuite/ld-powerpc/tls.s b/ld/testsuite/ld-powerpc/tls.s
index 5ad9f3d..49828d0 100644
--- a/ld/testsuite/ld-powerpc/tls.s
+++ b/ld/testsuite/ld-powerpc/tls.s
@@ -19,8 +19,13 @@ ie4:	.quad 0x56789abcdef01234
 le4:	.quad 0x6789abcdef012345
 le5:	.quad 0x789abcdef0123456
 
-	.text
+	.section ".opd","aw",@progbits
+	.p2align 3
 _start:
+	.quad	.L_start,.TOC.@tocbase,0
+
+	.text
+.L_start:
 #extern syms
 #GD
  addi 3,2,gd@got@tlsgd		#R_PPC64_GOT_TLSGD16	gd
diff --git a/ld/testsuite/ld-powerpc/tlsexe.d b/ld/testsuite/ld-powerpc/tlsexe.d
index ebbf2f0..747b5e1 100644
--- a/ld/testsuite/ld-powerpc/tlsexe.d
+++ b/ld/testsuite/ld-powerpc/tlsexe.d
@@ -14,13 +14,13 @@ Disassembly of section \.text:
 .*	(7c 60 1b 78|78 1b 60 7c) 	mr      r0,r3
 .*	(2c 2b 00 00|00 00 2b 2c) 	cmpdi   r11,0
 .*	(7c 6c 6a 14|14 6a 6c 7c) 	add     r3,r12,r13
-.*	(4d 82 00 20|20 00 82 4d) 	beqlr   
+.*	(4d 82 00 20|20 00 82 4d) 	beqlr *
 .*	(7c 03 03 78|78 03 03 7c) 	mr      r3,r0
 .*	(7d 68 02 a6|a6 02 68 7d) 	mflr    r11
 .*	(f9 61 00 20|20 00 61 f9) 	std     r11,32\(r1\)
 .*	(f8 41 00 28|28 00 41 f8) 	std     r2,40\(r1\)
-.*	(e9 62 80 48|48 80 62 e9) 	ld      r11,-32696\(r2\)
-.*	(7d 69 03 a6|a6 03 69 7d) 	mtctr   r11
+.*	(e9 82 80 48|48 80 82 e9) 	ld      r12,-32696\(r2\)
+.*	(7d 89 03 a6|a6 03 89 7d) 	mtctr   r12
 .*	(e8 42 80 50|50 80 42 e8) 	ld      r2,-32688\(r2\)
 .*	(4e 80 04 21|21 04 80 4e) 	bctrl
 .*	(e9 61 00 20|20 00 61 e9) 	ld      r11,32\(r1\)
@@ -28,7 +28,7 @@ Disassembly of section \.text:
 .*	(7d 68 03 a6|a6 03 68 7d) 	mtlr    r11
 .*	(4e 80 00 20|20 00 80 4e) 	blr
 
-.* <_start>:
+.* <._start>:
 .*	(e8 62 80 10|10 80 62 e8) 	ld      r3,-32752\(r2\)
 .*	(60 00 00 00|00 00 00 60) 	nop
 .*	(7c 63 6a 14|14 6a 63 7c) 	add     r3,r3,r13
@@ -67,22 +67,23 @@ Disassembly of section \.text:
 .*	(e9 4d 90 2a|2a 90 4d e9) 	lwa     r10,-28632\(r13\)
 .*	(3d 2d 00 00|00 00 2d 3d) 	addis   r9,r13,0
 .*	(a9 49 90 30|30 90 49 a9) 	lha     r10,-28624\(r9\)
-.*	(00 00 00 00|00 02 01 00) .*
-.*	(00 01 02 00|00 00 00 00) .*
+.*	(00 00 00 00|18 02 01 00) .*
+.*	(00 01 02 18|00 00 00 00) .*
 .* <__glink_PLTresolve>:
 .*	(7d 88 02 a6|a6 02 88 7d) 	mflr    r12
 .*	(42 9f 00 05|05 00 9f 42) 	bcl     20,4\*cr7\+so,.*
 .*	(7d 68 02 a6|a6 02 68 7d) 	mflr    r11
 .*	(e8 4b ff f0|f0 ff 4b e8) 	ld      r2,-16\(r11\)
 .*	(7d 88 03 a6|a6 03 88 7d) 	mtlr    r12
-.*	(7d 82 5a 14|14 5a 82 7d) 	add     r12,r2,r11
-.*	(e9 6c 00 00|00 00 6c e9) 	ld      r11,0\(r12\)
-.*	(e8 4c 00 08|08 00 4c e8) 	ld      r2,8\(r12\)
-.*	(7d 69 03 a6|a6 03 69 7d) 	mtctr   r11
-.*	(e9 6c 00 10|10 00 6c e9) 	ld      r11,16\(r12\)
+.*	(7d 62 5a 14|14 5a 62 7d) 	add     r11,r2,r11
+.*	(e9 8b 00 00|00 00 8b e9) 	ld      r12,0\(r11\)
+.*	(e8 4b 00 08|08 00 4b e8) 	ld      r2,8\(r11\)
+.*	(7d 89 03 a6|a6 03 89 7d) 	mtctr   r12
+.*	(e9 6b 00 10|10 00 6b e9) 	ld      r11,16\(r11\)
 .*	(4e 80 04 20|20 04 80 4e) 	bctr
 .*	(60 00 00 00|00 00 00 60) 	nop
 .*	(60 00 00 00|00 00 00 60) 	nop
 .*	(60 00 00 00|00 00 00 60) 	nop
+.* <__tls_get_addr_opt@plt>:
 .*	(38 00 00 00|00 00 00 38) 	li      r0,0
 .*	(4b ff ff c4|c4 ff ff 4b) 	b       .*
diff --git a/ld/testsuite/ld-powerpc/tlsexe.g b/ld/testsuite/ld-powerpc/tlsexe.g
index 3420d20..fb8dbb3 100644
--- a/ld/testsuite/ld-powerpc/tlsexe.g
+++ b/ld/testsuite/ld-powerpc/tlsexe.g
@@ -7,6 +7,6 @@
 .*
 
 Contents of section \.got:
-.* (00000000|20860110) (10018620|00000000) (ffffffff|1880ffff) (ffff8018|ffffffff)  .*
+.* (00000000|38860110) (10018638|00000000) (ffffffff|1880ffff) (ffff8018|ffffffff)  .*
 .* 00000000 00000000 00000000 00000000  .*
 .* 00000000 00000000 00000000 00000000  .*
diff --git a/ld/testsuite/ld-powerpc/tlsexe.r b/ld/testsuite/ld-powerpc/tlsexe.r
index 788e6ac..f78f300 100644
--- a/ld/testsuite/ld-powerpc/tlsexe.r
+++ b/ld/testsuite/ld-powerpc/tlsexe.r
@@ -1,7 +1,7 @@
 #source: tls.s
 #source: tlslib.s
 #as: -a64
-#ld: 
+#ld:
 #readelf: -WSsrl
 #target: powerpc64*-*-*
 
@@ -20,6 +20,7 @@ Section Headers:
  +\[[ 0-9]+\] \.tdata +PROGBITS .* 0+38 0+ WAT +0 +0 +8
  +\[[ 0-9]+\] \.tbss +NOBITS .* 0+38 0+ WAT +0 +0 +8
  +\[[ 0-9]+\] \.dynamic +DYNAMIC .* 0+160 10 +WA +4 +0 +8
+ +\[[ 0-9]+\] \.opd .*
  +\[[ 0-9]+\] \.got +PROGBITS .* 0+30 08 +WA +0 +0 +8
  +\[[ 0-9]+\] \.plt +.*
  +\[[ 0-9]+\] \.shstrtab +.*
@@ -44,11 +45,11 @@ Program Headers:
  Section to Segment mapping:
  +Segment Sections\.\.\.
  +0+ +
- +01 +\.interp 
- +02 +\.interp \.hash \.dynsym \.dynstr \.rela\.dyn \.rela\.plt \.text 
- +03 +\.tdata \.dynamic \.got \.plt 
- +04 +\.dynamic 
- +05 +\.tdata \.tbss 
+ +01 +\.interp *
+ +02 +\.interp \.hash \.dynsym \.dynstr \.rela\.dyn \.rela\.plt \.text *
+ +03 +\.tdata \.dynamic \.opd \.got \.plt *
+ +04 +\.dynamic *
+ +05 +\.tdata \.tbss *
 
 Relocation section '\.rela\.dyn' at offset .* contains 3 entries:
  +Offset +Info +Type +Symbol's Value +Symbol's Name \+ Addend
@@ -62,30 +63,31 @@ Relocation section '\.rela\.plt' at offset .* contains 1 entries:
 
 Symbol table '\.dynsym' contains [0-9]+ entries:
  +Num: +Value +Size +Type +Bind +Vis +Ndx +Name
-.* NOTYPE +LOCAL +DEFAULT +UND 
+.* NOTYPE +LOCAL +DEFAULT +UND *
 .* TLS +GLOBAL +DEFAULT +UND gd
 .* TLS +GLOBAL +DEFAULT +UND ld
 .* TLS +GLOBAL +DEFAULT +9 ld2
-.* NOTYPE +GLOBAL +DEFAULT +12 __bss_start
+.* NOTYPE +GLOBAL +DEFAULT +13 __bss_start
 .* FUNC +GLOBAL +DEFAULT +UND __tls_get_addr_opt
-.* NOTYPE +GLOBAL +DEFAULT +11 _edata
-.* NOTYPE +GLOBAL +DEFAULT +12 _end
+.* NOTYPE +GLOBAL +DEFAULT +12 _edata
+.* NOTYPE +GLOBAL +DEFAULT +13 _end
 
 Symbol table '\.symtab' contains [0-9]+ entries:
  +Num: +Value +Size +Type +Bind +Vis +Ndx +Name
-.* 0+ +0 +NOTYPE +LOCAL +DEFAULT +UND 
-.* SECTION +LOCAL +DEFAULT +1 
-.* SECTION +LOCAL +DEFAULT +2 
-.* SECTION +LOCAL +DEFAULT +3 
-.* SECTION +LOCAL +DEFAULT +4 
-.* SECTION +LOCAL +DEFAULT +5 
-.* SECTION +LOCAL +DEFAULT +6 
-.* SECTION +LOCAL +DEFAULT +7 
-.* SECTION +LOCAL +DEFAULT +8 
-.* SECTION +LOCAL +DEFAULT +9 
-.* SECTION +LOCAL +DEFAULT +10 
-.* SECTION +LOCAL +DEFAULT +11 
-.* SECTION +LOCAL +DEFAULT +12 
+.* 0+ +0 +NOTYPE +LOCAL +DEFAULT +UND *
+.* SECTION +LOCAL +DEFAULT +1 *
+.* SECTION +LOCAL +DEFAULT +2 *
+.* SECTION +LOCAL +DEFAULT +3 *
+.* SECTION +LOCAL +DEFAULT +4 *
+.* SECTION +LOCAL +DEFAULT +5 *
+.* SECTION +LOCAL +DEFAULT +6 *
+.* SECTION +LOCAL +DEFAULT +7 *
+.* SECTION +LOCAL +DEFAULT +8 *
+.* SECTION +LOCAL +DEFAULT +9 *
+.* SECTION +LOCAL +DEFAULT +10 *
+.* SECTION +LOCAL +DEFAULT +11 *
+.* SECTION +LOCAL +DEFAULT +12 *
+.* SECTION +LOCAL +DEFAULT +13 *
 .* FILE +LOCAL +DEFAULT +ABS .*
 .* TLS +LOCAL +DEFAULT +8 gd4
 .* TLS +LOCAL +DEFAULT +8 ld4
@@ -104,12 +106,12 @@ Symbol table '\.symtab' contains [0-9]+ entries:
 .* GLOBAL +DEFAULT +9 ld0
 .* GLOBAL +DEFAULT +9 le1
 .* GLOBAL +DEFAULT +UND ld
-.* NOTYPE +GLOBAL +DEFAULT +7 _start
+.* FUNC +GLOBAL +DEFAULT +11 _start
 .* TLS +GLOBAL +DEFAULT +9 ld2
 .* TLS +GLOBAL +DEFAULT +9 ld1
-.* NOTYPE +GLOBAL +DEFAULT +12 __bss_start
+.* NOTYPE +GLOBAL +DEFAULT +13 __bss_start
 .* FUNC +GLOBAL +DEFAULT +UND __tls_get_addr_opt
-.* NOTYPE +GLOBAL +DEFAULT +11 _edata
-.* NOTYPE +GLOBAL +DEFAULT +12 _end
+.* NOTYPE +GLOBAL +DEFAULT +12 _edata
+.* NOTYPE +GLOBAL +DEFAULT +13 _end
 .* TLS +GLOBAL +DEFAULT +9 gd0
 .* TLS +GLOBAL +DEFAULT +9 ie0
diff --git a/ld/testsuite/ld-powerpc/tlsexetoc.d b/ld/testsuite/ld-powerpc/tlsexetoc.d
index 635b0eb..f38ca9c 100644
--- a/ld/testsuite/ld-powerpc/tlsexetoc.d
+++ b/ld/testsuite/ld-powerpc/tlsexetoc.d
@@ -14,13 +14,13 @@ Disassembly of section \.text:
 .*	(7c 60 1b 78|78 1b 60 7c) 	mr      r0,r3
 .*	(2c 2b 00 00|00 00 2b 2c) 	cmpdi   r11,0
 .*	(7c 6c 6a 14|14 6a 6c 7c) 	add     r3,r12,r13
-.*	(4d 82 00 20|20 00 82 4d) 	beqlr   
+.*	(4d 82 00 20|20 00 82 4d) 	beqlr *
 .*	(7c 03 03 78|78 03 03 7c) 	mr      r3,r0
 .*	(7d 68 02 a6|a6 02 68 7d) 	mflr    r11
 .*	(f9 61 00 20|20 00 61 f9) 	std     r11,32\(r1\)
 .*	(f8 41 00 28|28 00 41 f8) 	std     r2,40\(r1\)
-.*	(e9 62 80 70|70 80 62 e9) 	ld      r11,-32656\(r2\)
-.*	(7d 69 03 a6|a6 03 69 7d) 	mtctr   r11
+.*	(e9 82 80 70|70 80 82 e9) 	ld      r12,-32656\(r2\)
+.*	(7d 89 03 a6|a6 03 89 7d) 	mtctr   r12
 .*	(e8 42 80 78|78 80 42 e8) 	ld      r2,-32648\(r2\)
 .*	(4e 80 04 21|21 04 80 4e) 	bctrl
 .*	(e9 61 00 20|20 00 61 e9) 	ld      r11,32\(r1\)
@@ -28,7 +28,7 @@ Disassembly of section \.text:
 .*	(7d 68 03 a6|a6 03 68 7d) 	mtlr    r11
 .*	(4e 80 00 20|20 00 80 4e) 	blr
 
-.* <_start>:
+.* <\._start>:
 .*	(38 62 80 08|08 80 62 38) 	addi    r3,r2,-32760
 .*	(4b ff ff b5|b5 ff ff 4b) 	bl      .*
 .*	(60 00 00 00|00 00 00 60) 	nop
@@ -51,22 +51,23 @@ Disassembly of section \.text:
 .*	(89 4d 90 60|60 90 4d 89) 	lbz     r10,-28576\(r13\)
 .*	(3d 2d 00 00|00 00 2d 3d) 	addis   r9,r13,0
 .*	(99 49 90 68|68 90 49 99) 	stb     r10,-28568\(r9\)
-.*	(00 00 00 00|28 02 01 00) .*
-.*	(00 01 02 28|00 00 00 00) .*
+.*	(00 00 00 00|40 02 01 00) .*
+.*	(00 01 02 40|00 00 00 00) .*
 .* <__glink_PLTresolve>:
 .*	(7d 88 02 a6|a6 02 88 7d) 	mflr    r12
 .*	(42 9f 00 05|05 00 9f 42) 	bcl     20,4\*cr7\+so,.*
 .*	(7d 68 02 a6|a6 02 68 7d) 	mflr    r11
 .*	(e8 4b ff f0|f0 ff 4b e8) 	ld      r2,-16\(r11\)
 .*	(7d 88 03 a6|a6 03 88 7d) 	mtlr    r12
-.*	(7d 82 5a 14|14 5a 82 7d) 	add     r12,r2,r11
-.*	(e9 6c 00 00|00 00 6c e9) 	ld      r11,0\(r12\)
-.*	(e8 4c 00 08|08 00 4c e8) 	ld      r2,8\(r12\)
-.*	(7d 69 03 a6|a6 03 69 7d) 	mtctr   r11
-.*	(e9 6c 00 10|10 00 6c e9) 	ld      r11,16\(r12\)
+.*	(7d 62 5a 14|14 5a 62 7d) 	add     r11,r2,r11
+.*	(e9 8b 00 00|00 00 8b e9) 	ld      r12,0\(r11\)
+.*	(e8 4b 00 08|08 00 4b e8) 	ld      r2,8\(r11\)
+.*	(7d 89 03 a6|a6 03 89 7d) 	mtctr   r12
+.*	(e9 6b 00 10|10 00 6b e9) 	ld      r11,16\(r11\)
 .*	(4e 80 04 20|20 04 80 4e) 	bctr
 .*	(60 00 00 00|00 00 00 60) 	nop
 .*	(60 00 00 00|00 00 00 60) 	nop
 .*	(60 00 00 00|00 00 00 60) 	nop
+.* <__tls_get_addr_opt@plt>:
 .*	(38 00 00 00|00 00 00 38) 	li      r0,0
 .*	(4b ff ff c4|c4 ff ff 4b) 	b       .*
diff --git a/ld/testsuite/ld-powerpc/tlsexetoc.g b/ld/testsuite/ld-powerpc/tlsexetoc.g
index 095e111..b75c8e6 100644
--- a/ld/testsuite/ld-powerpc/tlsexetoc.g
+++ b/ld/testsuite/ld-powerpc/tlsexetoc.g
@@ -7,7 +7,7 @@
 .*
 
 Contents of section \.got:
-.* (00000000|c0850110) (100185c0|00000000) 00000000 00000000  .*
+.* (00000000|d8850110) (100185d8|00000000) 00000000 00000000  .*
 .* 00000000 00000000 00000000 00000000  .*
 .* 00000000 00000000 (00000000|01000000) (00000001|00000000)  .*
 .* 00000000 00000000 (00000000|01000000) (00000001|00000000)  .*
diff --git a/ld/testsuite/ld-powerpc/tlsexetoc.r b/ld/testsuite/ld-powerpc/tlsexetoc.r
index 8905d3f..d238f26 100644
--- a/ld/testsuite/ld-powerpc/tlsexetoc.r
+++ b/ld/testsuite/ld-powerpc/tlsexetoc.r
@@ -1,7 +1,7 @@
 #source: tlslib.s
 #source: tlstoc.s
 #as: -a64
-#ld: 
+#ld:
 #readelf: -WSsrl
 #target: powerpc64*-*-*
 
@@ -20,6 +20,7 @@ Section Headers:
  +\[[ 0-9]+\] \.tdata +PROGBITS .* 0+38 0+ WAT +0 +0 +8
  +\[[ 0-9]+\] \.tbss +NOBITS .* 0+38 0+ WAT +0 +0 +8
  +\[[ 0-9]+\] \.dynamic +DYNAMIC .* 0+160 10 +WA +4 +0 +8
+ +\[[ 0-9]+\] \.opd .*
  +\[[ 0-9]+\] \.got +PROGBITS .* 0+58 08 +WA +0 +0 +8
  +\[[ 0-9]+\] \.plt +.*
  +\[[ 0-9]+\] \.shstrtab +.*
@@ -44,11 +45,11 @@ Program Headers:
  Section to Segment mapping:
  +Segment Sections\.\.\.
  +0+ +
- +01 +\.interp 
- +02 +\.interp \.hash \.dynsym \.dynstr \.rela\.dyn \.rela\.plt \.text 
- +03 +\.tdata \.dynamic \.got \.plt 
- +04 +\.dynamic 
- +05 +\.tdata \.tbss 
+ +01 +\.interp *
+ +02 +\.interp \.hash \.dynsym \.dynstr \.rela\.dyn \.rela\.plt \.text *
+ +03 +\.tdata \.dynamic \.opd \.got \.plt *
+ +04 +\.dynamic *
+ +05 +\.tdata \.tbss *
 
 Relocation section '\.rela\.dyn' at offset .* contains 3 entries:
  +Offset +Info +Type +Symbol's Value +Symbol's Name \+ Addend
@@ -62,29 +63,30 @@ Relocation section '\.rela\.plt' at offset .* contains 1 entries:
 
 Symbol table '\.dynsym' contains [0-9]+ entries:
  +Num: +Value +Size +Type +Bind +Vis +Ndx +Name
-.* NOTYPE +LOCAL +DEFAULT +UND 
+.* NOTYPE +LOCAL +DEFAULT +UND *
 .* TLS +GLOBAL +DEFAULT +UND gd
 .* TLS +GLOBAL +DEFAULT +UND ld
-.* NOTYPE +GLOBAL +DEFAULT +12 __bss_start
+.* NOTYPE +GLOBAL +DEFAULT +13 __bss_start
 .* FUNC +GLOBAL +DEFAULT +UND __tls_get_addr_opt
-.* NOTYPE +GLOBAL +DEFAULT +11 _edata
-.* NOTYPE +GLOBAL +DEFAULT +12 _end
+.* NOTYPE +GLOBAL +DEFAULT +12 _edata
+.* NOTYPE +GLOBAL +DEFAULT +13 _end
 
 Symbol table '\.symtab' contains [0-9]+ entries:
  +Num: +Value +Size +Type +Bind +Vis +Ndx +Name
-.* NOTYPE +LOCAL +DEFAULT +UND 
-.* SECTION +LOCAL +DEFAULT +1 
-.* SECTION +LOCAL +DEFAULT +2 
-.* SECTION +LOCAL +DEFAULT +3 
-.* SECTION +LOCAL +DEFAULT +4 
-.* SECTION +LOCAL +DEFAULT +5 
-.* SECTION +LOCAL +DEFAULT +6 
-.* SECTION +LOCAL +DEFAULT +7 
-.* SECTION +LOCAL +DEFAULT +8 
-.* SECTION +LOCAL +DEFAULT +9 
-.* SECTION +LOCAL +DEFAULT +10 
-.* SECTION +LOCAL +DEFAULT +11 
-.* SECTION +LOCAL +DEFAULT +12 
+.* NOTYPE +LOCAL +DEFAULT +UND *
+.* SECTION +LOCAL +DEFAULT +1 *
+.* SECTION +LOCAL +DEFAULT +2 *
+.* SECTION +LOCAL +DEFAULT +3 *
+.* SECTION +LOCAL +DEFAULT +4 *
+.* SECTION +LOCAL +DEFAULT +5 *
+.* SECTION +LOCAL +DEFAULT +6 *
+.* SECTION +LOCAL +DEFAULT +7 *
+.* SECTION +LOCAL +DEFAULT +8 *
+.* SECTION +LOCAL +DEFAULT +9 *
+.* SECTION +LOCAL +DEFAULT +10 *
+.* SECTION +LOCAL +DEFAULT +11 *
+.* SECTION +LOCAL +DEFAULT +12 *
+.* SECTION +LOCAL +DEFAULT +13 *
 .* FILE +LOCAL +DEFAULT +ABS .*
 .* TLS +LOCAL +DEFAULT +8 gd4
 .* TLS +LOCAL +DEFAULT +8 ld4
@@ -93,7 +95,7 @@ Symbol table '\.symtab' contains [0-9]+ entries:
 .* TLS +LOCAL +DEFAULT +8 ie4
 .* TLS +LOCAL +DEFAULT +8 le4
 .* TLS +LOCAL +DEFAULT +8 le5
-.* NOTYPE +LOCAL +DEFAULT +11 \.Lie0
+.* NOTYPE +LOCAL +DEFAULT +12 \.Lie0
 .* (FUNC|NOTYPE) +LOCAL +DEFAULT +UND \.__tls_get_addr(|_opt)
 .* FILE +LOCAL +DEFAULT +ABS .*
 .* OBJECT +LOCAL +DEFAULT +10 _DYNAMIC
@@ -104,12 +106,12 @@ Symbol table '\.symtab' contains [0-9]+ entries:
 .* TLS +GLOBAL +DEFAULT +9 ld0
 .* TLS +GLOBAL +DEFAULT +9 le1
 .* TLS +GLOBAL +DEFAULT +UND ld
-.* NOTYPE +GLOBAL +DEFAULT +7 _start
+.* FUNC +GLOBAL +DEFAULT +11 _start
 .* TLS +GLOBAL +DEFAULT +9 ld2
 .* TLS +GLOBAL +DEFAULT +9 ld1
-.* NOTYPE +GLOBAL +DEFAULT +12 __bss_start
+.* NOTYPE +GLOBAL +DEFAULT +13 __bss_start
 .* FUNC +GLOBAL +DEFAULT +UND __tls_get_addr_opt
-.* NOTYPE +GLOBAL +DEFAULT +11 _edata
-.* NOTYPE +GLOBAL +DEFAULT +12 _end
+.* NOTYPE +GLOBAL +DEFAULT +12 _edata
+.* NOTYPE +GLOBAL +DEFAULT +13 _end
 .* TLS +GLOBAL +DEFAULT +9 gd0
 .* TLS +GLOBAL +DEFAULT +9 ie0
diff --git a/ld/testsuite/ld-powerpc/tlsso.d b/ld/testsuite/ld-powerpc/tlsso.d
index 67c07fb..7fe7e87 100644
--- a/ld/testsuite/ld-powerpc/tlsso.d
+++ b/ld/testsuite/ld-powerpc/tlsso.d
@@ -10,14 +10,14 @@ Disassembly of section \.text:
 
 .* <.*plt_call\.__tls_get_addr(|_opt)>:
 .*	(f8 41 00 28|28 00 41 f8) 	std     r2,40\(r1\)
-.*	(e9 62 80 78|78 80 62 e9) 	ld      r11,-32648\(r2\)
-.*	(7d 69 03 a6|a6 03 69 7d) 	mtctr   r11
+.*	(e9 82 80 78|78 80 82 e9) 	ld      r12,-32648\(r2\)
+.*	(7d 89 03 a6|a6 03 89 7d) 	mtctr   r12
 .*	(e8 42 80 80|80 80 42 e8) 	ld      r2,-32640\(r2\)
 .*	(28 22 00 00|00 00 22 28) 	cmpldi  r2,0
-.*	(4c e2 04 20|20 04 e2 4c) 	bnectr\+ 
-.*	(48 00 00 ..|.. 00 00 48) 	b       .* <__glink_PLTresolve\+0x38>
+.*	(4c e2 04 20|20 04 e2 4c) 	bnectr\+ *
+.*	(48 00 00 ..|.. 00 00 48) 	b       .* <__tls_get_addr@plt>
 
-.* <_start>:
+.* <\._start>:
 .*	(38 62 80 20|20 80 62 38) 	addi    r3,r2,-32736
 .*	(4b ff ff ..|.. ff ff 4b) 	bl      .*plt_call.__tls_get_addr.*
 .*	(e8 41 00 28|28 00 41 e8) 	ld      r2,40\(r1\)
@@ -57,22 +57,23 @@ Disassembly of section \.text:
 .*	(3d 2d 00 00|00 00 2d 3d) 	addis   r9,r13,0
 .*	(a9 49 00 00|00 00 49 a9) 	lha     r10,0\(r9\)
 .*	(60 00 00 00|00 00 00 60) 	nop
-.*	(00 00 00 00|20 02 01 00) .*
-.*	(00 01 02 20|00 00 00 00) .*
+.*	(00 00 00 00|38 02 01 00) .*
+.*	(00 01 02 38|00 00 00 00) .*
 .* <__glink_PLTresolve>:
 .*	(7d 88 02 a6|a6 02 88 7d) 	mflr    r12
 .*	(42 9f 00 05|05 00 9f 42) 	bcl     20,4\*cr7\+so,.*
 .*	(7d 68 02 a6|a6 02 68 7d) 	mflr    r11
 .*	(e8 4b ff f0|f0 ff 4b e8) 	ld      r2,-16\(r11\)
 .*	(7d 88 03 a6|a6 03 88 7d) 	mtlr    r12
-.*	(7d 82 5a 14|14 5a 82 7d) 	add     r12,r2,r11
-.*	(e9 6c 00 00|00 00 6c e9) 	ld      r11,0\(r12\)
-.*	(e8 4c 00 08|08 00 4c e8) 	ld      r2,8\(r12\)
-.*	(7d 69 03 a6|a6 03 69 7d) 	mtctr   r11
-.*	(e9 6c 00 10|10 00 6c e9) 	ld      r11,16\(r12\)
+.*	(7d 62 5a 14|14 5a 62 7d) 	add     r11,r2,r11
+.*	(e9 8b 00 00|00 00 8b e9) 	ld      r12,0\(r11\)
+.*	(e8 4b 00 08|08 00 4b e8) 	ld      r2,8\(r11\)
+.*	(7d 89 03 a6|a6 03 89 7d) 	mtctr   r12
+.*	(e9 6b 00 10|10 00 6b e9) 	ld      r11,16\(r11\)
 .*	(4e 80 04 20|20 04 80 4e) 	bctr
 .*	(60 00 00 00|00 00 00 60) 	nop
 .*	(60 00 00 00|00 00 00 60) 	nop
 .*	(60 00 00 00|00 00 00 60) 	nop
+.* <__tls_get_addr@plt>:
 .*	(38 00 00 00|00 00 00 38) 	li      r0,0
 .*	(4b ff ff c4|c4 ff ff 4b) 	b       .*
diff --git a/ld/testsuite/ld-powerpc/tlsso.g b/ld/testsuite/ld-powerpc/tlsso.g
index 85577a6..0ba9fda 100644
--- a/ld/testsuite/ld-powerpc/tlsso.g
+++ b/ld/testsuite/ld-powerpc/tlsso.g
@@ -7,7 +7,7 @@
 .*
 
 Contents of section \.got:
- 10788 (00000000|88870100) (00018788|00000000) 00000000 00000000  .*
+ 107e0 (00000000|e0870100) (000187e0|00000000) 00000000 00000000  .*
 .* 00000000 00000000 00000000 00000000  .*
 .* 00000000 00000000 00000000 00000000  .*
 .* 00000000 00000000 00000000 00000000  .*
diff --git a/ld/testsuite/ld-powerpc/tlsso.r b/ld/testsuite/ld-powerpc/tlsso.r
index bc0c2ca..ddaaebc 100644
--- a/ld/testsuite/ld-powerpc/tlsso.r
+++ b/ld/testsuite/ld-powerpc/tlsso.r
@@ -18,6 +18,7 @@ Section Headers:
  +\[[ 0-9]+\] \.tdata +PROGBITS .* 0+38 0+ WAT +0 +0 +8
  +\[[ 0-9]+\] \.tbss +NOBITS .* 0+38 0+ WAT +0 +0 +8
  +\[[ 0-9]+\] \.dynamic .*
+ +\[[ 0-9]+\] \.opd .*
  +\[[ 0-9]+\] \.got .*
  +\[[ 0-9]+\] \.plt .*
  +\[[ 0-9]+\] \.shstrtab .*
@@ -38,13 +39,15 @@ Program Headers:
 
  Section to Segment mapping:
  +Segment Sections\.\.\.
- +0+ +\.hash \.dynsym \.dynstr \.rela\.dyn \.rela\.plt \.text 
- +01 +\.tdata \.dynamic .got \.plt 
- +02 +\.dynamic 
- +03 +\.tdata \.tbss 
+ +0+ +\.hash \.dynsym \.dynstr \.rela\.dyn \.rela\.plt \.text *
+ +01 +\.tdata \.dynamic \.opd \.got \.plt *
+ +02 +\.dynamic *
+ +03 +\.tdata \.tbss *
 
-Relocation section '\.rela\.dyn' at offset .* contains 16 entries:
+Relocation section '\.rela\.dyn' at offset .* contains 18 entries:
  +Offset +Info +Type +Symbol's Value +Symbol's Name \+ Addend
+[0-9a-f ]+R_PPC64_RELATIVE +55c
+[0-9a-f ]+R_PPC64_RELATIVE +187e0
 [0-9a-f ]+R_PPC64_TPREL16 +0+60 le0 \+ 0
 [0-9a-f ]+R_PPC64_TPREL16_HA +0+68 le1 \+ 0
 [0-9a-f ]+R_PPC64_TPREL16_LO +0+68 le1 \+ 0
@@ -68,38 +71,39 @@ Relocation section '\.rela\.plt' at offset .* contains 1 entries:
 
 Symbol table '\.dynsym' contains [0-9]+ entries:
  +Num: +Value +Size +Type +Bind +Vis +Ndx +Name
-.* NOTYPE +LOCAL +DEFAULT +UND 
-.* SECTION +LOCAL +DEFAULT +6 
-.* SECTION +LOCAL +DEFAULT +7 
+.* NOTYPE +LOCAL +DEFAULT +UND *
+.* SECTION +LOCAL +DEFAULT +6 *
+.* SECTION +LOCAL +DEFAULT +7 *
 .* TLS +GLOBAL +DEFAULT +UND gd
 .* TLS +GLOBAL +DEFAULT +8 le0
 .* NOTYPE +GLOBAL +DEFAULT +UND __tls_get_addr
 .* TLS +GLOBAL +DEFAULT +8 ld0
 .* TLS +GLOBAL +DEFAULT +8 le1
 .* TLS +GLOBAL +DEFAULT +UND ld
-.* NOTYPE +GLOBAL +DEFAULT +6 _start
+.* FUNC +GLOBAL +DEFAULT +10 _start
 .* TLS +GLOBAL +DEFAULT +8 ld2
 .* TLS +GLOBAL +DEFAULT +8 ld1
-.* NOTYPE +GLOBAL +DEFAULT +11 __bss_start
-.* NOTYPE +GLOBAL +DEFAULT +10 _edata
-.* NOTYPE +GLOBAL +DEFAULT +11 _end
+.* NOTYPE +GLOBAL +DEFAULT +12 __bss_start
+.* NOTYPE +GLOBAL +DEFAULT +11 _edata
+.* NOTYPE +GLOBAL +DEFAULT +12 _end
 .* TLS +GLOBAL +DEFAULT +8 gd0
 .* TLS +GLOBAL +DEFAULT +8 ie0
 
 Symbol table '\.symtab' contains [0-9]+ entries:
  +Num: +Value +Size +Type +Bind +Vis +Ndx +Name
-.* NOTYPE +LOCAL +DEFAULT +UND 
-.* SECTION +LOCAL +DEFAULT +1 
-.* SECTION +LOCAL +DEFAULT +2 
-.* SECTION +LOCAL +DEFAULT +3 
-.* SECTION +LOCAL +DEFAULT +4 
-.* SECTION +LOCAL +DEFAULT +5 
-.* SECTION +LOCAL +DEFAULT +6 
-.* SECTION +LOCAL +DEFAULT +7 
-.* SECTION +LOCAL +DEFAULT +8 
-.* SECTION +LOCAL +DEFAULT +9 
-.* SECTION +LOCAL +DEFAULT +10 
-.* SECTION +LOCAL +DEFAULT +11 
+.* NOTYPE +LOCAL +DEFAULT +UND *
+.* SECTION +LOCAL +DEFAULT +1 *
+.* SECTION +LOCAL +DEFAULT +2 *
+.* SECTION +LOCAL +DEFAULT +3 *
+.* SECTION +LOCAL +DEFAULT +4 *
+.* SECTION +LOCAL +DEFAULT +5 *
+.* SECTION +LOCAL +DEFAULT +6 *
+.* SECTION +LOCAL +DEFAULT +7 *
+.* SECTION +LOCAL +DEFAULT +8 *
+.* SECTION +LOCAL +DEFAULT +9 *
+.* SECTION +LOCAL +DEFAULT +10 *
+.* SECTION +LOCAL +DEFAULT +11 *
+.* SECTION +LOCAL +DEFAULT +12 *
 .* FILE +LOCAL +DEFAULT +ABS .*
 .* TLS +LOCAL +DEFAULT +7 gd4
 .* TLS +LOCAL +DEFAULT +7 ld4
@@ -119,11 +123,11 @@ Symbol table '\.symtab' contains [0-9]+ entries:
 .* TLS +GLOBAL +DEFAULT +8 ld0
 .* TLS +GLOBAL +DEFAULT +8 le1
 .* TLS +GLOBAL +DEFAULT +UND ld
-.* NOTYPE +GLOBAL +DEFAULT +6 _start
+.* FUNC +GLOBAL +DEFAULT +10 _start
 .* TLS +GLOBAL +DEFAULT +8 ld2
 .* TLS +GLOBAL +DEFAULT +8 ld1
-.* NOTYPE +GLOBAL +DEFAULT +11 __bss_start
-.* NOTYPE +GLOBAL +DEFAULT +10 _edata
-.* NOTYPE +GLOBAL +DEFAULT +11 _end
+.* NOTYPE +GLOBAL +DEFAULT +12 __bss_start
+.* NOTYPE +GLOBAL +DEFAULT +11 _edata
+.* NOTYPE +GLOBAL +DEFAULT +12 _end
 .* TLS +GLOBAL +DEFAULT +8 gd0
 .* TLS +GLOBAL +DEFAULT +8 ie0
diff --git a/ld/testsuite/ld-powerpc/tlstoc.d b/ld/testsuite/ld-powerpc/tlstoc.d
index faea1c4..dccf82e 100644
--- a/ld/testsuite/ld-powerpc/tlstoc.d
+++ b/ld/testsuite/ld-powerpc/tlstoc.d
@@ -1,7 +1,7 @@
 #source: tlslib.s
 #source: tlstoc.s
 #as: -a64
-#ld: 
+#ld:
 #objdump: -dr
 #target: powerpc64*-*-*
 
@@ -12,7 +12,7 @@ Disassembly of section \.text:
 .* <\.__tls_get_addr>:
 .*	(4e 80 00 20|20 00 80 4e) 	blr
 
-.* <_start>:
+.* <\._start>:
 .*	(3c 6d 00 00|00 00 6d 3c) 	addis   r3,r13,0
 .*	(60 00 00 00|00 00 00 60) 	nop
 .*	(38 63 90 40|40 90 63 38) 	addi    r3,r3,-28608
diff --git a/ld/testsuite/ld-powerpc/tlstoc.g b/ld/testsuite/ld-powerpc/tlstoc.g
index 9ca4302..e5c1e31 100644
--- a/ld/testsuite/ld-powerpc/tlstoc.g
+++ b/ld/testsuite/ld-powerpc/tlstoc.g
@@ -1,15 +1,15 @@
 #source: tlslib.s
 #source: tlstoc.s
 #as: -a64
-#ld: 
+#ld:
 #objdump: -sj.got
 #target: powerpc64*-*-*
 
 .*
 
 Contents of section \.got:
- 100101a0 (00000000|01000000) (00000001|00000000) 00000000 00000000  .*
- 100101b0 (00000000|01000000) (00000001|00000000) 00000000 00000000  .*
- 100101c0 (00000000|01000000) (00000001|00000000) 00000000 00000000  .*
- 100101d0 (00000000|01000000) (00000001|00000000) 00000000 00000000  .*
- 100101e0 (ffffffff|6080ffff) (ffff8060|ffffffff) 00000000 00000000  .*
+ 100101b8 (00000000|01000000) (00000001|00000000) 00000000 00000000  .*
+ 100101c8 (00000000|01000000) (00000001|00000000) 00000000 00000000  .*
+ 100101d8 (00000000|01000000) (00000001|00000000) 00000000 00000000  .*
+ 100101e8 (00000000|01000000) (00000001|00000000) 00000000 00000000  .*
+ 100101f8 (ffffffff|6080ffff) (ffff8060|ffffffff) 00000000 00000000  .*
diff --git a/ld/testsuite/ld-powerpc/tlstoc.s b/ld/testsuite/ld-powerpc/tlstoc.s
index 5008d89..f5dbfdd 100644
--- a/ld/testsuite/ld-powerpc/tlstoc.s
+++ b/ld/testsuite/ld-powerpc/tlstoc.s
@@ -19,8 +19,13 @@ ie4:	.quad 0x56789abcdef01234
 le4:	.quad 0x6789abcdef012345
 le5:	.quad 0x789abcdef0123456
 
-	.text
+	.section ".opd","aw",@progbits
+	.p2align 3
 _start:
+	.quad	.L_start,.TOC.@tocbase,0
+
+	.text
+.L_start:
 #extern syms
 #GD
  addi 3,2,.Lgd@toc
diff --git a/ld/testsuite/ld-powerpc/tlstocso.d b/ld/testsuite/ld-powerpc/tlstocso.d
index 890c31c..6aa1056 100644
--- a/ld/testsuite/ld-powerpc/tlstocso.d
+++ b/ld/testsuite/ld-powerpc/tlstocso.d
@@ -10,14 +10,14 @@ Disassembly of section \.text:
 
 .* <.*plt_call\.__tls_get_addr(|_opt)>:
 .*	(f8 41 00 28|28 00 41 f8) 	std     r2,40\(r1\)
-.*	(e9 62 80 70|70 80 62 e9) 	ld      r11,-32656\(r2\)
-.*	(7d 69 03 a6|a6 03 69 7d) 	mtctr   r11
+.*	(e9 82 80 70|70 80 82 e9) 	ld      r12,-32656\(r2\)
+.*	(7d 89 03 a6|a6 03 89 7d) 	mtctr   r12
 .*	(e8 42 80 78|78 80 42 e8) 	ld      r2,-32648\(r2\)
 .*	(28 22 00 00|00 00 22 28) 	cmpldi  r2,0
-.*	(4c e2 04 20|20 04 e2 4c) 	bnectr\+ 
-.*	(48 00 00 ..|.. 00 00 48) 	b       .* <__glink_PLTresolve\+0x38>
+.*	(4c e2 04 20|20 04 e2 4c) 	bnectr\+ *
+.*	(48 00 00 ..|.. 00 00 48) 	b       .* <__tls_get_addr@plt>
 
-.* <_start>:
+.* <\._start>:
 .*	(38 62 80 08|08 80 62 38) 	addi    r3,r2,-32760
 .*	(4b ff ff ..|.. ff ff 4b) 	bl      .*plt_call.__tls_get_addr.*
 .*	(e8 41 00 28|28 00 41 e8) 	ld      r2,40\(r1\)
@@ -41,22 +41,23 @@ Disassembly of section \.text:
 .*	(3d 2d 00 00|00 00 2d 3d) 	addis   r9,r13,0
 .*	(99 49 00 00|00 00 49 99) 	stb     r10,0\(r9\)
 .*	(60 00 00 00|00 00 00 60) 	nop
-.*	(00 00 00 00|18 02 01 00) .*
-.*	(00 01 02 18|00 00 00 00) .*
+.*	(00 00 00 00|30 02 01 00) .*
+.*	(00 01 02 30|00 00 00 00) .*
 .* <__glink_PLTresolve>:
 .*	(7d 88 02 a6|a6 02 88 7d) 	mflr    r12
 .*	(42 9f 00 05|05 00 9f 42) 	bcl     20,4\*cr7\+so,.*
 .*	(7d 68 02 a6|a6 02 68 7d) 	mflr    r11
 .*	(e8 4b ff f0|f0 ff 4b e8) 	ld      r2,-16\(r11\)
 .*	(7d 88 03 a6|a6 03 88 7d) 	mtlr    r12
-.*	(7d 82 5a 14|14 5a 82 7d) 	add     r12,r2,r11
-.*	(e9 6c 00 00|00 00 6c e9) 	ld      r11,0\(r12\)
-.*	(e8 4c 00 08|08 00 4c e8) 	ld      r2,8\(r12\)
-.*	(7d 69 03 a6|a6 03 69 7d) 	mtctr   r11
-.*	(e9 6c 00 10|10 00 6c e9) 	ld      r11,16\(r12\)
+.*	(7d 62 5a 14|14 5a 62 7d) 	add     r11,r2,r11
+.*	(e9 8b 00 00|00 00 8b e9) 	ld      r12,0\(r11\)
+.*	(e8 4b 00 08|08 00 4b e8) 	ld      r2,8\(r11\)
+.*	(7d 89 03 a6|a6 03 89 7d) 	mtctr   r12
+.*	(e9 6b 00 10|10 00 6b e9) 	ld      r11,16\(r11\)
 .*	(4e 80 04 20|20 04 80 4e) 	bctr
 .*	(60 00 00 00|00 00 00 60) 	nop
 .*	(60 00 00 00|00 00 00 60) 	nop
 .*	(60 00 00 00|00 00 00 60) 	nop
+.* <__tls_get_addr@plt>:
 .*	(38 00 00 00|00 00 00 38) 	li      r0,0
 .*	(4b ff ff c4|c4 ff ff 4b) 	b       .*
diff --git a/ld/testsuite/ld-powerpc/tlstocso.g b/ld/testsuite/ld-powerpc/tlstocso.g
index bb06ba5..9da93ec 100644
--- a/ld/testsuite/ld-powerpc/tlstocso.g
+++ b/ld/testsuite/ld-powerpc/tlstocso.g
@@ -7,7 +7,7 @@
 .*
 
 Contents of section \.got:
- 106c8 (00000000|c8860100) (000186c8|00000000) 00000000 00000000  .*
+ 10720 (00000000|20870100) (00018720|00000000) 00000000 00000000  .*
 .* 00000000 00000000 00000000 00000000  .*
 .* 00000000 00000000 00000000 00000000  .*
 .* 00000000 00000000 00000000 00000000  .*
diff --git a/ld/testsuite/ld-powerpc/tlstocso.r b/ld/testsuite/ld-powerpc/tlstocso.r
index 76943e7..f5bdfe3 100644
--- a/ld/testsuite/ld-powerpc/tlstocso.r
+++ b/ld/testsuite/ld-powerpc/tlstocso.r
@@ -18,6 +18,7 @@ Section Headers:
  +\[[ 0-9]+\] \.tdata +PROGBITS .* 0+38 0+ WAT +0 +0 +8
  +\[[ 0-9]+\] \.tbss +NOBITS .* 0+38 0+ WAT +0 +0 +8
  +\[[ 0-9]+\] \.dynamic .*
+ +\[[ 0-9]+\] \.opd .*
  +\[[ 0-9]+\] \.got .*
  +\[[ 0-9]+\] \.plt .*
  +\[[ 0-9]+\] \.shstrtab .*
@@ -38,13 +39,15 @@ Program Headers:
 
  Section to Segment mapping:
  +Segment Sections\.\.\.
- +0+ +\.hash \.dynsym \.dynstr \.rela\.dyn \.rela\.plt \.text 
- +01 +\.tdata \.dynamic \.got \.plt 
- +02 +\.dynamic 
- +03 +\.tdata \.tbss 
+ +0+ +\.hash \.dynsym \.dynstr \.rela\.dyn \.rela\.plt \.text *
+ +01 +\.tdata \.dynamic \.opd \.got \.plt *
+ +02 +\.dynamic *
+ +03 +\.tdata \.tbss *
 
-Relocation section '\.rela\.dyn' at offset .* contains 11 entries:
+Relocation section '\.rela\.dyn' at offset .* contains 13 entries:
  +Offset +Info +Type +Symbol's Value +Symbol's Name \+ Addend
+[0-9a-f ]+R_PPC64_RELATIVE +4dc
+[0-9a-f ]+R_PPC64_RELATIVE +18720
 [0-9a-f ]+R_PPC64_TPREL16 +0+60 le0 \+ 0
 [0-9a-f ]+R_PPC64_TPREL16_HA +0+68 le1 \+ 0
 [0-9a-f ]+R_PPC64_TPREL16_LO +0+68 le1 \+ 0
@@ -63,38 +66,39 @@ Relocation section '\.rela\.plt' at offset .* contains 1 entries:
 
 Symbol table '\.dynsym' contains [0-9]+ entries:
  +Num: +Value +Size +Type +Bind +Vis +Ndx +Name
-.* NOTYPE +LOCAL +DEFAULT +UND 
-.* SECTION +LOCAL +DEFAULT +6 
-.* SECTION +LOCAL +DEFAULT +7 
+.* NOTYPE +LOCAL +DEFAULT +UND *
+.* SECTION +LOCAL +DEFAULT +6 *
+.* SECTION +LOCAL +DEFAULT +7 *
 .* TLS +GLOBAL +DEFAULT +UND gd
 .* TLS +GLOBAL +DEFAULT +8 le0
 .* NOTYPE +GLOBAL +DEFAULT +UND __tls_get_addr
 .* TLS +GLOBAL +DEFAULT +8 ld0
 .* TLS +GLOBAL +DEFAULT +8 le1
 .* TLS +GLOBAL +DEFAULT +UND ld
-.* NOTYPE +GLOBAL +DEFAULT +6 _start
+.* FUNC +GLOBAL +DEFAULT +10 _start
 .* TLS +GLOBAL +DEFAULT +8 ld2
 .* TLS +GLOBAL +DEFAULT +8 ld1
-.* NOTYPE +GLOBAL +DEFAULT +11 __bss_start
-.* NOTYPE +GLOBAL +DEFAULT +10 _edata
-.* NOTYPE +GLOBAL +DEFAULT +11 _end
+.* NOTYPE +GLOBAL +DEFAULT +12 __bss_start
+.* NOTYPE +GLOBAL +DEFAULT +11 _edata
+.* NOTYPE +GLOBAL +DEFAULT +12 _end
 .* TLS +GLOBAL +DEFAULT +8 gd0
 .* TLS +GLOBAL +DEFAULT +8 ie0
 
 Symbol table '\.symtab' contains [0-9]+ entries:
  +Num: +Value +Size +Type +Bind +Vis +Ndx +Name
-.* NOTYPE +LOCAL +DEFAULT +UND 
-.* SECTION +LOCAL +DEFAULT +1 
-.* SECTION +LOCAL +DEFAULT +2 
-.* SECTION +LOCAL +DEFAULT +3 
-.* SECTION +LOCAL +DEFAULT +4 
-.* SECTION +LOCAL +DEFAULT +5 
-.* SECTION +LOCAL +DEFAULT +6 
-.* SECTION +LOCAL +DEFAULT +7 
-.* SECTION +LOCAL +DEFAULT +8 
-.* SECTION +LOCAL +DEFAULT +9 
-.* SECTION +LOCAL +DEFAULT +10 
-.* SECTION +LOCAL +DEFAULT +11 
+.* NOTYPE +LOCAL +DEFAULT +UND *
+.* SECTION +LOCAL +DEFAULT +1 *
+.* SECTION +LOCAL +DEFAULT +2 *
+.* SECTION +LOCAL +DEFAULT +3 *
+.* SECTION +LOCAL +DEFAULT +4 *
+.* SECTION +LOCAL +DEFAULT +5 *
+.* SECTION +LOCAL +DEFAULT +6 *
+.* SECTION +LOCAL +DEFAULT +7 *
+.* SECTION +LOCAL +DEFAULT +8 *
+.* SECTION +LOCAL +DEFAULT +9 *
+.* SECTION +LOCAL +DEFAULT +10 *
+.* SECTION +LOCAL +DEFAULT +11 *
+.* SECTION +LOCAL +DEFAULT +12 *
 .* FILE +LOCAL +DEFAULT +ABS .*
 .* TLS +LOCAL +DEFAULT +7 gd4
 .* TLS +LOCAL +DEFAULT +7 ld4
@@ -103,7 +107,7 @@ Symbol table '\.symtab' contains [0-9]+ entries:
 .* TLS +LOCAL +DEFAULT +7 ie4
 .* TLS +LOCAL +DEFAULT +7 le4
 .* TLS +LOCAL +DEFAULT +7 le5
-.* NOTYPE +LOCAL +DEFAULT +10 \.Lie0
+.* NOTYPE +LOCAL +DEFAULT +11 \.Lie0
 .* NOTYPE +LOCAL +DEFAULT +UND \.__tls_get_addr
 .* FILE +LOCAL +DEFAULT +ABS .*
 .* OBJECT +LOCAL +DEFAULT +9 _DYNAMIC
@@ -115,11 +119,11 @@ Symbol table '\.symtab' contains [0-9]+ entries:
 .* TLS +GLOBAL +DEFAULT +8 ld0
 .* TLS +GLOBAL +DEFAULT +8 le1
 .* TLS +GLOBAL +DEFAULT +UND ld
-.* NOTYPE +GLOBAL +DEFAULT +6 _start
+.* FUNC +GLOBAL +DEFAULT +10 _start
 .* TLS +GLOBAL +DEFAULT +8 ld2
 .* TLS +GLOBAL +DEFAULT +8 ld1
-.* NOTYPE +GLOBAL +DEFAULT +11 __bss_start
-.* NOTYPE +GLOBAL +DEFAULT +10 _edata
-.* NOTYPE +GLOBAL +DEFAULT +11 _end
+.* NOTYPE +GLOBAL +DEFAULT +12 __bss_start
+.* NOTYPE +GLOBAL +DEFAULT +11 _edata
+.* NOTYPE +GLOBAL +DEFAULT +12 _end
 .* TLS +GLOBAL +DEFAULT +8 gd0
 .* TLS +GLOBAL +DEFAULT +8 ie0

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 3/9] Add .abiversion related support for ELFv2
  2013-10-30  2:19 [PATCH 0/9] PowerPC64 ELFv2 ABI support Alan Modra
  2013-10-30  2:21 ` [PATCH 1/9] Report overflow on PowerPC64 @h and @ha relocations Alan Modra
  2013-10-30  2:22 ` [PATCH 2/9] Change plt stubs to have destination in r12 Alan Modra
@ 2013-10-30  2:23 ` Alan Modra
  2013-10-30  2:25 ` [PATCH 4/9] Add ELFv2 .localentry support Alan Modra
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Alan Modra @ 2013-10-30  2:23 UTC (permalink / raw)
  To: binutils

Defines bits in ELF e_flags to differentiate ELFv2 objects from ELFv2,
adds .abiversion directive to explicitly choose the ABI, and code to
check and automatically select ABI.

include/elf/
	* ppc64.h (EF_PPC64_ABI): Define.
bfd/
	* elf64-ppc.c (abiversion, set_abiversion): New functions.
	(ppc64_elf_get_synthetic_symtab): Handle ELFv2 objects without .opd.
	(struct ppc_link_hash_table): Add opd_abi.
	(ppc64_elf_check_relocs): Check no .opd with ELFv2.
	(ppc64_elf_merge_private_bfd_data): New function.
	(ppc64_elf_print_private_bfd_data): New function.
	(ppc64_elf_tls_setup): Set htab->opd_abi.
	(ppc64_elf_size_dynamic_sections): Don't emit OPD related dynamic
	tags for ELFv2.
	(ppc_build_one_stub): Use R_PPC64_IRELATIVE for ELFv2 ifunc.
	(ppc64_elf_finish_dynamic_symbol): Likewise
binutils/
	* readelf.c (get_machine_flags): Display ABI version for EM_PPC64.
gas/
	* config/tc-ppc.c: Include elf/ppc64.h.
	(ppc_abiversion): New variable.
	(md_pseudo_table): Add .abiversion.
	(ppc_elf_abiversion, ppc_elf_end): New functions.
	* config/tc-ppc.h (md_end): Define.

-- 
Alan Modra
Australia Development Lab, IBM

diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 94a9402..0067295 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -81,7 +81,8 @@ static bfd_vma opd_entry_value
 #define bfd_elf64_mkobject		      ppc64_elf_mkobject
 #define bfd_elf64_bfd_reloc_type_lookup	      ppc64_elf_reloc_type_lookup
 #define bfd_elf64_bfd_reloc_name_lookup	      ppc64_elf_reloc_name_lookup
-#define bfd_elf64_bfd_merge_private_bfd_data  _bfd_generic_verify_endian_match
+#define bfd_elf64_bfd_merge_private_bfd_data  ppc64_elf_merge_private_bfd_data
+#define bfd_elf64_bfd_print_private_bfd_data  ppc64_elf_print_private_bfd_data
 #define bfd_elf64_new_section_hook	      ppc64_elf_new_section_hook
 #define bfd_elf64_bfd_link_hash_table_create  ppc64_elf_link_hash_table_create
 #define bfd_elf64_bfd_link_hash_table_free    ppc64_elf_link_hash_table_free
@@ -2943,6 +2944,19 @@ get_opd_info (asection * sec)
     return &ppc64_elf_section_data (sec)->u.opd;
   return NULL;
 }
+
+static inline int
+abiversion (bfd *abfd)
+{
+  return elf_elfheader (abfd)->e_flags & EF_PPC64_ABI;
+}
+
+static inline void
+set_abiversion (bfd *abfd, int ver)
+{
+  elf_elfheader (abfd)->e_flags &= ~EF_PPC64_ABI;
+  elf_elfheader (abfd)->e_flags |= ver & EF_PPC64_ABI;
+}
 \f
 /* Parameters for the qsort hook.  */
 static bfd_boolean synthetic_relocatable;
@@ -3089,15 +3103,19 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
   long count;
   char *names;
   long symcount, codesecsym, codesecsymend, secsymend, opdsymend;
-  asection *opd;
+  asection *opd = NULL;
   bfd_boolean relocatable = (abfd->flags & (EXEC_P | DYNAMIC)) == 0;
   asymbol **syms;
+  int abi = abiversion (abfd);
 
   *ret = NULL;
 
-  opd = bfd_get_section_by_name (abfd, ".opd");
-  if (opd == NULL)
-    return 0;
+  if (abi < 2)
+    {
+      opd = bfd_get_section_by_name (abfd, ".opd");
+      if (opd == NULL && abi == 1)
+	return 0;
+    }
 
   symcount = static_count;
   if (!relocatable)
@@ -3266,20 +3284,18 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
   else
     {
       bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
-      bfd_byte *contents;
+      bfd_byte *contents = NULL;
       size_t size;
       long plt_count = 0;
       bfd_vma glink_vma = 0, resolv_vma = 0;
       asection *dynamic, *glink = NULL, *relplt = NULL;
       arelent *p;
 
-      if (!bfd_malloc_and_get_section (abfd, opd, &contents))
+      if (opd != NULL && !bfd_malloc_and_get_section (abfd, opd, &contents))
 	{
+	free_contents_and_exit:
 	  if (contents)
-	    {
-	    free_contents_and_exit:
-	      free (contents);
-	    }
+	    free (contents);
 	  count = -1;
 	  goto done;
 	}
@@ -3890,6 +3906,9 @@ struct ppc_link_hash_table
   /* Alignment of PLT call stubs.  */
   unsigned int plt_stub_align:4;
 
+  /* Set if we're linking code with function descriptors.  */
+  unsigned int opd_abi:1;
+
   /* Set if PLT call stubs should load r11.  */
   unsigned int plt_static_chain:1;
 
@@ -5089,6 +5108,15 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	 information about the associated function section.  */
       bfd_size_type amt;
 
+      if (abiversion (abfd) == 0)
+	set_abiversion (abfd, 1);
+      else if (abiversion (abfd) == 2)
+	{
+	  info->callbacks->einfo (_("%P: .opd not allowed in ABI version %d\n"),
+				  abiversion (abfd));
+	  bfd_set_error (bfd_error_bad_value);
+	  return FALSE;
+	}
       amt = sec->size * sizeof (*opd_sym_map) / 8;
       opd_sym_map = bfd_zalloc (abfd, amt);
       if (opd_sym_map == NULL)
@@ -5674,6 +5702,78 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
   return TRUE;
 }
 
+/* Merge backend specific data from an object file to the output
+   object file when linking.  */
+
+static bfd_boolean
+ppc64_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
+{
+  unsigned long iflags, oflags;
+
+  if ((ibfd->flags & BFD_LINKER_CREATED) != 0)
+    return TRUE;
+
+  if (!is_ppc64_elf (ibfd) || !is_ppc64_elf (obfd))
+    return TRUE;
+
+  if (!_bfd_generic_verify_endian_match (ibfd, obfd))
+    return FALSE;
+
+  iflags = elf_elfheader (ibfd)->e_flags;
+  oflags = elf_elfheader (obfd)->e_flags;
+
+  if (!elf_flags_init (obfd) || oflags == 0)
+    {
+      elf_flags_init (obfd) = TRUE;
+      elf_elfheader (obfd)->e_flags = iflags;
+    }
+  else if (iflags == oflags || iflags == 0)
+    ;
+  else if (iflags & ~EF_PPC64_ABI)
+    {
+      (*_bfd_error_handler)
+	(_("%B uses unknown e_flags 0x%lx"), ibfd, iflags);
+      bfd_set_error (bfd_error_bad_value);
+      return FALSE;
+    }
+  else
+    {
+      (*_bfd_error_handler)
+	(_("%B: ABI version %ld is not compatible with ABI version %ld output"),
+	 ibfd, iflags, oflags);
+      bfd_set_error (bfd_error_bad_value);
+      return FALSE;
+    }
+
+  /* Merge Tag_compatibility attributes and any common GNU ones.  */
+  _bfd_elf_merge_object_attributes (ibfd, obfd);
+
+  return TRUE;
+}
+
+static bfd_boolean
+ppc64_elf_print_private_bfd_data (bfd *abfd, void *ptr)
+{
+  /* Print normal ELF private data.  */
+  _bfd_elf_print_private_bfd_data (abfd, ptr);
+
+  if (elf_elfheader (abfd)->e_flags != 0)
+    {
+      FILE *file = ptr;
+
+      /* xgettext:c-format */
+      fprintf (file, _("private flags = 0x%lx:"),
+	       elf_elfheader (abfd)->e_flags);
+
+      if ((elf_elfheader (abfd)->e_flags & EF_PPC64_ABI) != 0)
+	fprintf (file, _(" [abiv%ld]"),
+		 elf_elfheader (abfd)->e_flags & EF_PPC64_ABI);
+      fputc ('\n', file);
+    }
+
+  return TRUE;
+}
+
 /* OFFSET in OPD_SEC specifies a function descriptor.  Return the address
    of the code entry point, and its section.  */
 
@@ -7711,6 +7811,9 @@ ppc64_elf_tls_setup (struct bfd_link_info *info,
   if (htab == NULL)
     return NULL;
 
+  if (abiversion (info->output_bfd) == 1)
+    htab->opd_abi = 1;
+
   if (*no_multi_toc)
     htab->do_multi_toc = 0;
   else if (!htab->do_multi_toc)
@@ -9333,7 +9436,7 @@ readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 /* Set the sizes of the dynamic sections.  */
 
 static bfd_boolean
-ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
+ppc64_elf_size_dynamic_sections (bfd *output_bfd,
 				 struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab;
@@ -9649,7 +9752,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 	    return FALSE;
 	}
 
-      if (NO_OPD_RELOCS)
+      if (NO_OPD_RELOCS && abiversion (output_bfd) <= 1)
 	{
 	  if (!add_dynamic_entry (DT_PPC64_OPD, 0)
 	      || !add_dynamic_entry (DT_PPC64_OPDSZ, 0))
@@ -10412,7 +10515,10 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 	  bfd_byte *rl;
 
 	  rela.r_offset = dest;
-	  rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
+	  if (htab->opd_abi)
+	    rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
+	  else
+	    rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
 	  rela.r_addend = (stub_entry->target_value
 			   + stub_entry->target_section->output_offset
 			   + stub_entry->target_section->output_section->vma);
@@ -14271,7 +14377,10 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
 	    rela.r_offset = (htab->iplt->output_section->vma
 			     + htab->iplt->output_offset
 			     + ent->plt.offset);
-	    rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
+	    if (htab->opd_abi)
+	      rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
+	    else
+	      rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
 	    rela.r_addend = (h->root.u.def.value
 			     + h->root.u.def.section->output_offset
 			     + h->root.u.def.section->output_section->vma
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 7920100..ab2943d 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -2461,6 +2461,16 @@ get_machine_flags (unsigned e_flags, unsigned e_machine)
 	    strcat (buf, _(", relocatable-lib"));
 	  break;
 
+	case EM_PPC64:
+	  if (e_flags & EF_PPC64_ABI)
+	    {
+	      char abi[] = ", abiv0";
+
+	      abi[6] += e_flags & EF_PPC64_ABI;
+	      strcat (buf, abi);
+	    }
+	  break;
+
 	case EM_V800:
 	  if ((e_flags & EF_RH850_ABI) == EF_RH850_ABI)
 	    strcat (buf, ", RH850 ABI");
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index 34afc91..c249cec 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -29,6 +29,7 @@
 
 #ifdef OBJ_ELF
 #include "elf/ppc.h"
+#include "elf/ppc64.h"
 #include "dwarf2dbg.h"
 #endif
 
@@ -133,6 +134,7 @@ static void ppc_vbyte (int);
 static void ppc_elf_cons (int);
 static void ppc_elf_rdata (int);
 static void ppc_elf_lcomm (int);
+static void ppc_elf_abiversion (int);
 #endif
 
 #ifdef TE_PE
@@ -203,6 +205,9 @@ unsigned long nop_limit = 4;
 ppc_cpu_t ppc_cpu = 0;
 ppc_cpu_t sticky = 0;
 
+/* Value for ELF e_flags EF_PPC64_ABI.  */
+unsigned int ppc_abiversion = 0;
+
 /* Flags set on encountering toc relocs.  */
 enum {
   has_large_toc_reloc = 1,
@@ -261,6 +266,7 @@ const pseudo_typeS md_pseudo_table[] =
   { "rdata",	ppc_elf_rdata,	0 },
   { "rodata",	ppc_elf_rdata,	0 },
   { "lcomm",	ppc_elf_lcomm,	0 },
+  { "abiversion", ppc_elf_abiversion,	0 },
 #endif
 
 #ifdef TE_PE
@@ -2220,6 +2226,39 @@ ppc_elf_lcomm (int xxx ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 }
 
+/* Pseudo op to set ABI version.  */
+static void
+ppc_elf_abiversion (int ignore ATTRIBUTE_UNUSED)
+{
+  expressionS exp;
+
+  expression (&exp);
+  if (exp.X_op == O_absent)
+    {
+      as_bad (_("missing expression in .abiversion directive"));
+      exp.X_op = O_constant;
+      exp.X_add_number = 0;
+    }
+
+  if (resolve_expression (&exp)
+      && exp.X_op == O_constant)
+    ppc_abiversion = exp.X_add_number;
+  else
+    as_bad (_(".abiversion expression does not evaluate to a constant"));
+  demand_empty_rest_of_line ();
+}
+
+/* Set ABI version in output file.  */
+void
+ppc_elf_end (void)
+{
+  if (ppc_obj64 && ppc_abiversion != 0)
+    {
+      elf_elfheader (stdoutput)->e_flags &= ~EF_PPC64_ABI;
+      elf_elfheader (stdoutput)->e_flags |= ppc_abiversion & EF_PPC64_ABI;
+    }
+}
+
 /* Validate any relocations emitted for -mrelocatable, possibly adding
    fixups for word relocations in writable segments, so we can adjust
    them at runtime.  */
diff --git a/gas/config/tc-ppc.h b/gas/config/tc-ppc.h
index 3dd3f81..6095416 100644
--- a/gas/config/tc-ppc.h
+++ b/gas/config/tc-ppc.h
@@ -238,6 +238,9 @@ extern void ppc_frob_file_before_adjust (void);
 #define tc_adjust_symtab() ppc_elf_adjust_symtab ()
 extern void ppc_elf_adjust_symtab (void);
 
+extern void ppc_elf_end (void);
+#define md_end ppc_elf_end
+
 #endif /* OBJ_ELF */
 
 #if defined (OBJ_ELF) || defined (OBJ_XCOFF)
diff --git a/include/elf/ppc64.h b/include/elf/ppc64.h
index 221786f..1121649 100644
--- a/include/elf/ppc64.h
+++ b/include/elf/ppc64.h
@@ -173,6 +173,13 @@ END_RELOC_NUMBERS (R_PPC64_max)
   (((R) >= R_PPC64_TLS && (R) <= R_PPC64_DTPREL16_HIGHESTA)		\
    || ((R) >= R_PPC64_TPREL16_HIGH && (R) <= R_PPC64_DTPREL16_HIGHA))
 
+
+/* e_flags bits specifying ABI.
+   1 for original function descriptor using ABI,
+   2 for revised ABI without function descriptors,
+   0 for unspecified or not using any features affected by the differences.  */
+#define EF_PPC64_ABI	3
+
 /* Specify the start of the .glink section.  */
 #define DT_PPC64_GLINK		DT_LOPROC

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 4/9] Add ELFv2 .localentry support.
  2013-10-30  2:19 [PATCH 0/9] PowerPC64 ELFv2 ABI support Alan Modra
                   ` (2 preceding siblings ...)
  2013-10-30  2:23 ` [PATCH 3/9] Add .abiversion related support for ELFv2 Alan Modra
@ 2013-10-30  2:25 ` Alan Modra
  2013-10-30 19:08   ` Richard Henderson
  2013-10-30  2:26 ` [PATCH 5/9] ELFv2 stub, plt and glink changes Alan Modra
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 19+ messages in thread
From: Alan Modra @ 2013-10-30  2:25 UTC (permalink / raw)
  To: binutils

This defines the ELF symbol st_other field used to encode the number
of instructions between a function "global entry" and its "local entry",
and adds support related to the local entry offset.

include/elf/
	* ppc64.h (STO_PPC64_LOCAL_BIT, STO_PPC64_LOCAL_MASK): Define.
	(ppc64_decode_local_entry, ppc64_encode_local_entry): New functions.
	(PPC64_LOCAL_ENTRY_OFFSET, PPC64_SET_LOCAL_ENTRY_OFFSET): Define.
bfd/
	* elf64-ppc.c (struct ppc_stub_hash_entry): Add "other".
	(stub_hash_newfunc): Init new ppc_stub_hash_entry field, and one
	we forgot, "plt_ent".
	(ppc64_elf_add_symbol_hook): Check ELFv1 objects don't have
	st_other bits only valid in ELFv2.
	(ppc64_elf_merge_symbol_attribute): New function.
	(ppc_type_of_stub): Add local_off param to test branch range.
	(ppc_build_one_stub): Adjust destinations for ELFv2 locals.
	(ppc_size_one_stub, toc_adjusting_stub_needed): Similarly.
	(ppc64_elf_size_stubs): Pass local_off to ppc_type_of_stub.
	Set "other" field.
	(ppc64_elf_relocate_section): Adjust destination for ELFv2 local
	calls.
gas/
	* config/tc-ppc.c (md_pseudo_table): Add .localentry.
	(ppc_elf_localentry): New function.
	(ppc_force_relocation): Force relocs on all branches to localenty
	symbols.
	(ppc_fix_adjustable): Don't reduce such symbols to section+offset.
binutils/
	* readelf.c (get_ppc64_symbol_other): New function.
	(get_symbol_other): Use it for EM_PPC64.

-- 
Alan Modra
Australia Development Lab, IBM

diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 0067295..1d03f84 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -118,6 +118,7 @@ static bfd_vma opd_entry_value
 #define elf_backend_link_output_symbol_hook   ppc64_elf_output_symbol_hook
 #define elf_backend_special_sections	      ppc64_elf_special_sections
 #define elf_backend_post_process_headers      _bfd_elf_set_osabi
+#define elf_backend_merge_symbol_attribute    ppc64_elf_merge_symbol_attribute
 
 /* The name of the dynamic interpreter.  This is put in the .interp
    section.  */
@@ -3746,6 +3747,9 @@ struct ppc_stub_hash_entry {
   /* Where this stub is being called from, or, in the case of combined
      stub sections, the first input section in the group.  */
   asection *id_sec;
+
+  /* Symbol st_other.  */
+  unsigned char other;
 };
 
 struct ppc_branch_hash_entry {
@@ -4004,7 +4008,9 @@ stub_hash_newfunc (struct bfd_hash_entry *entry,
       eh->target_value = 0;
       eh->target_section = NULL;
       eh->h = NULL;
+      eh->plt_ent = NULL;
       eh->id_sec = NULL;
+      eh->other = 0;
     }
 
   return entry;
@@ -4750,7 +4756,7 @@ static bfd_boolean
 ppc64_elf_add_symbol_hook (bfd *ibfd,
 			   struct bfd_link_info *info,
 			   Elf_Internal_Sym *isym,
-			   const char **name ATTRIBUTE_UNUSED,
+			   const char **name,
 			   flagword *flags ATTRIBUTE_UNUSED,
 			   asection **sec,
 			   bfd_vma *value ATTRIBUTE_UNUSED)
@@ -4770,9 +4776,35 @@ ppc64_elf_add_symbol_hook (bfd *ibfd,
 	   && strcmp ((*sec)->name, ".opd") == 0)
     isym->st_info = ELF_ST_INFO (ELF_ST_BIND (isym->st_info), STT_FUNC);
 
+  if ((STO_PPC64_LOCAL_MASK & isym->st_other) != 0)
+    {
+      if (abiversion (ibfd) == 0)
+	set_abiversion (ibfd, 2);
+      else if (abiversion (ibfd) == 1)
+	{
+	  info->callbacks->einfo (_("%P: symbol '%s' has invalid st_other"
+				    " for ABI version 1\n"), name);
+	  bfd_set_error (bfd_error_bad_value);
+	  return FALSE;
+	}
+    }
+
   return TRUE;
 }
 
+/* Merge non-visibility st_other attributes: local entry point.  */
+
+static void
+ppc64_elf_merge_symbol_attribute (struct elf_link_hash_entry *h,
+				  const Elf_Internal_Sym *isym,
+				  bfd_boolean definition,
+				  bfd_boolean dynamic)
+{
+  if (definition && !dynamic)
+    h->other = ((isym->st_other & ~ELF_ST_VISIBILITY (-1))
+		| ELF_ST_VISIBILITY (h->other));
+}
+
 /* This function makes an old ABI object reference to ".bar" cause the
    inclusion of a new ABI object archive that defines "bar".
    NAME is a symbol defined in an archive.  Return a symbol in the hash
@@ -9796,7 +9828,8 @@ ppc_type_of_stub (asection *input_sec,
 		  const Elf_Internal_Rela *rel,
 		  struct ppc_link_hash_entry **hash,
 		  struct plt_entry **plt_ent,
-		  bfd_vma destination)
+		  bfd_vma destination,
+		  unsigned long local_off)
 {
   struct ppc_link_hash_entry *h = *hash;
   bfd_vma location;
@@ -9865,7 +9898,7 @@ ppc_type_of_stub (asection *input_sec,
   if (r_type != R_PPC64_REL24)
     max_branch_offset = 1 << 15;
 
-  if (branch_offset + max_branch_offset >= 2 * max_branch_offset)
+  if (branch_offset + max_branch_offset >= 2 * max_branch_offset - local_off)
     /* We need a stub.  Figure out whether a long_branch or plt_branch
        is needed later.  */
     return ppc_stub_long_branch;
@@ -10233,9 +10266,11 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
     case ppc_stub_long_branch:
     case ppc_stub_long_branch_r2off:
       /* Branches are relative.  This is where we are going to.  */
-      off = dest = (stub_entry->target_value
-		    + stub_entry->target_section->output_offset
-		    + stub_entry->target_section->output_section->vma);
+      dest = (stub_entry->target_value
+	      + stub_entry->target_section->output_offset
+	      + stub_entry->target_section->output_section->vma);
+      dest += PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other);
+      off = dest;
 
       /* And this is where we are coming from.  */
       off -= (stub_entry->stub_offset
@@ -10338,6 +10373,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       dest = (stub_entry->target_value
 	      + stub_entry->target_section->output_offset
 	      + stub_entry->target_section->output_section->vma);
+      if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
+	dest += PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other);
 
       bfd_put_64 (htab->brlt->owner, dest,
 		  htab->brlt->contents + br_entry->offset);
@@ -10682,6 +10719,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       /* ppc_stub_long_branch or ppc_stub_plt_branch, or their r2off
 	 variants.  */
       bfd_vma r2off = 0;
+      bfd_vma local_off = 0;
 
       off = (stub_entry->target_value
 	     + stub_entry->target_section->output_offset
@@ -10710,8 +10748,10 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 	  off -= size - 4;
 	}
 
+      local_off = PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other);
+
       /* If the branch offset if too big, use a ppc_stub_plt_branch.  */
-      if (off + (1 << 25) >= (bfd_vma) (1 << 26))
+      if (off + (1 << 25) >= (bfd_vma) (1 << 26) - local_off)
 	{
 	  struct ppc_branch_hash_entry *br_entry;
 
@@ -11308,7 +11348,10 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
 	     need a plt_branch stub.  A plt_branch stub uses r2.  */
 	  else if (dest - (isec->output_offset
 			   + isec->output_section->vma
-			   + rel->r_offset) + (1 << 25) >= (2 << 25))
+			   + rel->r_offset) + (1 << 25)
+		   >= (2u << 25) - PPC64_LOCAL_ENTRY_OFFSET (h
+							     ? h->other
+							     : sym->st_other))
 	    {
 	      ret = 1;
 	      break;
@@ -11761,6 +11804,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
 		  asection *sym_sec, *code_sec;
 		  bfd_vma sym_value, code_value;
 		  bfd_vma destination;
+		  unsigned long local_off;
 		  bfd_boolean ok_dest;
 		  struct ppc_link_hash_entry *hash;
 		  struct ppc_link_hash_entry *fdh;
@@ -11837,12 +11881,16 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
 		    }
 
 		  destination = 0;
+		  local_off = 0;
 		  if (ok_dest)
 		    {
 		      sym_value += irela->r_addend;
 		      destination = (sym_value
 				     + sym_sec->output_offset
 				     + sym_sec->output_section->vma);
+		      local_off = PPC64_LOCAL_ENTRY_OFFSET (hash
+							    ? hash->elf.other
+							    : sym->st_other);
 		    }
 
 		  code_sec = sym_sec;
@@ -11879,7 +11927,8 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
 		  /* Determine what (if any) linker stub is needed.  */
 		  plt_ent = NULL;
 		  stub_type = ppc_type_of_stub (section, irela, &hash,
-						&plt_ent, destination);
+						&plt_ent, destination,
+						local_off);
 
 		  if (stub_type != ppc_stub_plt_call)
 		    {
@@ -11979,6 +12028,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
 		    }
 		  stub_entry->h = hash;
 		  stub_entry->plt_ent = plt_ent;
+		  stub_entry->other = hash ? hash->elf.other : sym->st_other;
 
 		  if (stub_entry->h != NULL)
 		    htab->stub_globals += 1;
@@ -13357,6 +13407,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 		  + input_section->output_offset
 		  + input_section->output_section->vma);
 
+	  relocation += PPC64_LOCAL_ENTRY_OFFSET (fdh
+						  ? fdh->elf.other
+						  : sym->st_other);
+
 	  if (stub_entry != NULL
 	      && (stub_entry->stub_type == ppc_stub_long_branch
 		  || stub_entry->stub_type == ppc_stub_plt_branch)
diff --git a/binutils/readelf.c b/binutils/readelf.c
index ab2943d..c99b46e 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -9211,6 +9211,19 @@ get_ia64_symbol_other (unsigned int other)
 }
 
 static const char *
+get_ppc64_symbol_other (unsigned int other)
+{
+  if (PPC64_LOCAL_ENTRY_OFFSET (other) != 0)
+    {
+      static char buf[32];
+      snprintf (buf, sizeof buf, _("<localentry>: %d"),
+		PPC64_LOCAL_ENTRY_OFFSET (other));
+      return buf;
+    }
+  return NULL;
+}
+
+static const char *
 get_symbol_other (unsigned int other)
 {
   const char * result = NULL;
@@ -9227,6 +9240,9 @@ get_symbol_other (unsigned int other)
     case EM_IA_64:
       result = get_ia64_symbol_other (other);
       break;
+    case EM_PPC64:
+      result = get_ppc64_symbol_other (other);
+      break;
     default:
       break;
     }
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index c249cec..822f5a2 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -134,6 +134,7 @@ static void ppc_vbyte (int);
 static void ppc_elf_cons (int);
 static void ppc_elf_rdata (int);
 static void ppc_elf_lcomm (int);
+static void ppc_elf_localentry (int);
 static void ppc_elf_abiversion (int);
 #endif
 
@@ -266,6 +267,7 @@ const pseudo_typeS md_pseudo_table[] =
   { "rdata",	ppc_elf_rdata,	0 },
   { "rodata",	ppc_elf_rdata,	0 },
   { "lcomm",	ppc_elf_lcomm,	0 },
+  { "localentry", ppc_elf_localentry,	0 },
   { "abiversion", ppc_elf_abiversion,	0 },
 #endif
 
@@ -2226,6 +2228,68 @@ ppc_elf_lcomm (int xxx ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 }
 
+/* Pseudo op to set symbol local entry point.  */
+static void
+ppc_elf_localentry (int ignore ATTRIBUTE_UNUSED)
+{
+  char *name = input_line_pointer;
+  char c = get_symbol_end ();
+  char *p;
+  expressionS exp;
+  symbolS *sym;
+  asymbol *bfdsym;
+  elf_symbol_type *elfsym;
+
+  p = input_line_pointer;
+  *p = c;
+  SKIP_WHITESPACE ();
+  if (*input_line_pointer != ',')
+    {
+      *p = 0;
+      as_bad (_("expected comma after name `%s' in .localentry directive"),
+	      name);
+      *p = c;
+      ignore_rest_of_line ();
+      return;
+    }
+  input_line_pointer++;
+  expression (&exp);
+  if (exp.X_op == O_absent)
+    {
+      as_bad (_("missing expression in .localentry directive"));
+      exp.X_op = O_constant;
+      exp.X_add_number = 0;
+    }
+  *p = 0;
+  sym = symbol_find_or_make (name);
+  *p = c;
+
+  if (resolve_expression (&exp)
+      && exp.X_op == O_constant)
+    {
+      unsigned char encoded = PPC64_SET_LOCAL_ENTRY_OFFSET (exp.X_add_number);
+
+      if (exp.X_add_number != PPC64_LOCAL_ENTRY_OFFSET (encoded))
+        as_bad (_(".localentry expression for `%s' "
+		  "is not a valid power of 2"), S_GET_NAME (sym));
+      else
+	{
+	  bfdsym = symbol_get_bfdsym (sym);
+	  elfsym = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym);
+	  gas_assert (elfsym);
+	  elfsym->internal_elf_sym.st_other &= ~STO_PPC64_LOCAL_MASK;
+	  elfsym->internal_elf_sym.st_other |= encoded;
+	  if (ppc_abiversion == 0)
+	    ppc_abiversion = 2;
+	}
+    }
+  else
+    as_bad (_(".localentry expression for `%s' "
+	      "does not evaluate to a constant"), S_GET_NAME (sym));
+
+  demand_empty_rest_of_line ();
+}
+
 /* Pseudo op to set ABI version.  */
 static void
 ppc_elf_abiversion (int ignore ATTRIBUTE_UNUSED)
@@ -6229,6 +6293,22 @@ ppc_force_relocation (fixS *fix)
     case BFD_RELOC_24_PLT_PCREL:
     case BFD_RELOC_PPC64_TOC:
       return 1;
+    case BFD_RELOC_PPC_B26:
+    case BFD_RELOC_PPC_BA26:
+    case BFD_RELOC_PPC_B16:
+    case BFD_RELOC_PPC_BA16:
+      /* All branch fixups targeting a localentry symbol must
+         force a relocation.  */
+      if (fix->fx_addsy)
+	{
+	  asymbol *bfdsym = symbol_get_bfdsym (fix->fx_addsy);
+	  elf_symbol_type *elfsym
+	    = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym);
+	  gas_assert (elfsym);
+	  if ((STO_PPC64_LOCAL_MASK & elfsym->internal_elf_sym.st_other) != 0)
+	    return 1;
+	}
+      break;
     default:
       break;
     }
@@ -6243,6 +6323,32 @@ ppc_force_relocation (fixS *fix)
 int
 ppc_fix_adjustable (fixS *fix)
 {
+  switch (fix->fx_r_type)
+    {
+      /* All branch fixups targeting a localentry symbol must
+         continue using the symbol.  */
+    case BFD_RELOC_PPC_B26:
+    case BFD_RELOC_PPC_BA26:
+    case BFD_RELOC_PPC_B16:
+    case BFD_RELOC_PPC_BA16:
+    case BFD_RELOC_PPC_B16_BRTAKEN:
+    case BFD_RELOC_PPC_B16_BRNTAKEN:
+    case BFD_RELOC_PPC_BA16_BRTAKEN:
+    case BFD_RELOC_PPC_BA16_BRNTAKEN:
+      if (fix->fx_addsy)
+	{
+	  asymbol *bfdsym = symbol_get_bfdsym (fix->fx_addsy);
+	  elf_symbol_type *elfsym
+	    = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym);
+	  gas_assert (elfsym);
+	  if ((STO_PPC64_LOCAL_MASK & elfsym->internal_elf_sym.st_other) != 0)
+	    return 0;
+	}
+      break;
+    default:
+      break;
+    }
+
   return (fix->fx_r_type != BFD_RELOC_16_GOTOFF
 	  && fix->fx_r_type != BFD_RELOC_LO16_GOTOFF
 	  && fix->fx_r_type != BFD_RELOC_HI16_GOTOFF
diff --git a/include/elf/ppc64.h b/include/elf/ppc64.h
index 1121649..d3cfdfb 100644
--- a/include/elf/ppc64.h
+++ b/include/elf/ppc64.h
@@ -180,6 +180,53 @@ END_RELOC_NUMBERS (R_PPC64_max)
    0 for unspecified or not using any features affected by the differences.  */
 #define EF_PPC64_ABI	3
 
+/* The ELFv2 ABI uses three bits in the symbol st_other field of a
+   function definition to specify the number of instructions between a
+   function's global entry point and local entry point.
+   The global entry point is used when it is necessary to set up the
+   toc pointer (r2) for the function.  Callers must enter the global
+   entry point with r12 set to the global entry point address.  On
+   return from the function, r2 may have a different value to that
+   which it had on entry.
+   The local entry point is used when r2 is known to already be valid
+   for the function.  There is no requirement on r12 when using the
+   local entry point, and on return r2 will contain the same value as
+   at entry.
+   A value of zero in these bits means that the function has a single
+   entry point with no requirement on r12 or r2, and that on return r2
+   will contain the same value as at entry.
+   Values of one and seven are reserved.  */
+#define STO_PPC64_LOCAL_BIT		5
+#define STO_PPC64_LOCAL_MASK		(7 << STO_PPC64_LOCAL_BIT)
+
+// 3 bit other field to bytes.
+static inline unsigned int
+ppc64_decode_local_entry(unsigned int other)
+{
+  return ((1 << other) >> 2) << 2;
+}
+
+// bytes to field value.
+static inline unsigned int
+ppc64_encode_local_entry(unsigned int val)
+{
+  return (val >= 4 * 4
+	  ? (val >= 8 * 4
+	     ? (val >= 16 * 4 ? 6 : 5)
+	     : 4)
+	  : (val >= 2 * 4
+	     ? 3
+	     : (val >= 1 * 4 ? 2 : 0)));
+}
+
+/* st_other to number of bytes.  */
+#define PPC64_LOCAL_ENTRY_OFFSET(other)				\
+  ppc64_decode_local_entry (((other) & STO_PPC64_LOCAL_MASK)	\
+			    >> STO_PPC64_LOCAL_BIT)
+/* number of bytes to st_other.  */
+#define PPC64_SET_LOCAL_ENTRY_OFFSET(val)		\
+  ppc64_encode_local_entry (val) << STO_PPC64_LOCAL_BIT
+
 /* Specify the start of the .glink section.  */
 #define DT_PPC64_GLINK		DT_LOPROC

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 5/9] ELFv2 stub, plt and glink changes
  2013-10-30  2:19 [PATCH 0/9] PowerPC64 ELFv2 ABI support Alan Modra
                   ` (3 preceding siblings ...)
  2013-10-30  2:25 ` [PATCH 4/9] Add ELFv2 .localentry support Alan Modra
@ 2013-10-30  2:26 ` Alan Modra
  2013-10-30  2:29 ` [PATCH 6/9] Support ELFv2 stack frame Alan Modra
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Alan Modra @ 2013-10-30  2:26 UTC (permalink / raw)
  To: binutils

An ELFv2 PLT entry is simply the address of the target function rather
than three (or two) words to specify entry, toc and static chain.  PLT
call stubs are correspondingly simpler and need no thread safety
barrier.  The glink resolver stub and branch table also is simplified,
a change that could be applied to ELFv1 too, but isn't as yet.

	* elf64-ppc.c (PLT_ENTRY_SIZE, PLT_INITIAL_ENTRY_SIZE): Add htab
	parameter and adjust for ELFv2.  Update all uses.
	(PLT_CALL_STUB_SIZE): Delete.
	(ppc64_elf_get_synthetic_symtab): Support new glink layout.
	(allocate_dynrelocs): Likewise.
	(plt_stub_size, build_plt_stub): Adjust for ELFv2.
	(get_r2off): Return 0 for ELFv2 -R.
	(ppc_build_one_stub, ppc_size_one_stub): Adjust for ELFv2.
	(ppc64_elf_size_stubs): Likewise.
	(ppc64_elf_build_stubs): Add new ELFv2 glink.

-- 
Alan Modra
Australia Development Lab, IBM

diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 1d03f84..6fbcdf0 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -125,10 +125,10 @@ static bfd_vma opd_entry_value
 #define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1"
 
 /* The size in bytes of an entry in the procedure linkage table.  */
-#define PLT_ENTRY_SIZE 24
+#define PLT_ENTRY_SIZE(htab) (htab->opd_abi ? 24 : 8)
 
 /* The initial size of the plt reserved for the dynamic linker.  */
-#define PLT_INITIAL_ENTRY_SIZE PLT_ENTRY_SIZE
+#define PLT_INITIAL_ENTRY_SIZE(htab) (htab->opd_abi ? 24 : 16)
 
 /* TOC base pointers offset from start of TOC.  */
 #define TOC_BASE_OFF	0x8000
@@ -140,7 +140,6 @@ static bfd_vma opd_entry_value
 /* .plt call stub instructions.  The normal stub is like this, but
    sometimes the .plt entry crosses a 64k boundary and we need to
    insert an addi to adjust r11.  */
-#define PLT_CALL_STUB_SIZE (7*4)
 #define STD_R2_40R1	0xf8410028	/* std	 %r2,40(%r1)	     */
 #define ADDIS_R11_R2	0x3d620000	/* addis %r11,%r2,xxx@ha     */
 #define LD_R12_0R11	0xe98b0000	/* ld	 %r12,xxx+0@l(%r11)  */
@@ -184,6 +183,11 @@ static bfd_vma opd_entry_value
 					/*  mtctr %12			*/
 					/*  ld %11,16(%11)		*/
 					/*  bctr			*/
+#define MFLR_R0		0x7c0802a6	/*  mflr %r0			*/
+#define MTLR_R0		0x7c0803a6	/*  mtlr %r0			*/
+#define SUB_R12_R12_R11	0x7d8b6050	/*  subf %r12,%r11,%r12		*/
+#define ADDI_R0_R12	0x380c0000	/*  addi %r0,%r12,0		*/
+#define SRDI_R0_R0_2	0x7800f082	/*  rldicl %r0,%r0,62,2		*/
 
 /* Pad with this.  */
 #define NOP		0x60000000
@@ -3345,9 +3349,9 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
 
 	      if (dyn.d_tag == DT_PPC64_GLINK)
 		{
-		  /* The first glink stub starts at offset 32; see comment in
-		     ppc64_elf_finish_dynamic_sections. */
-		  glink_vma = dyn.d_un.d_val + 32;
+		  /* The first glink stub starts at offset 32; see
+		     comment in ppc64_elf_finish_dynamic_sections. */
+		  glink_vma = dyn.d_un.d_val + GLINK_CALL_STUB_SIZE - 8 * 4;
 		  /* The .glink section usually does not survive the final
 		     link; search for the section (usually .text) where the
 		     glink stubs now reside.  */
@@ -3365,13 +3369,21 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
 	  /* Determine __glink trampoline by reading the relative branch
 	     from the first glink stub.  */
 	  bfd_byte buf[4];
-	  if (bfd_get_section_contents (abfd, glink, buf,
-					glink_vma + 4 - glink->vma, 4))
+	  unsigned int off = 0;
+
+	  while (bfd_get_section_contents (abfd, glink, buf,
+					   glink_vma + off - glink->vma, 4))
 	    {
 	      unsigned int insn = bfd_get_32 (abfd, buf);
 	      insn ^= B_DOT;
 	      if ((insn & ~0x3fffffc) == 0)
-		resolv_vma = glink_vma + 4 + (insn ^ 0x2000000) - 0x2000000;
+		{
+		  resolv_vma = glink_vma + off + (insn ^ 0x2000000) - 0x2000000;
+		  break;
+		}
+	      off += 4;
+	      if (off > 4)
+		break;
 	    }
 
 	  if (resolv_vma)
@@ -3524,8 +3536,13 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
 	      memcpy (names, "@plt", sizeof ("@plt"));
 	      names += sizeof ("@plt");
 	      s++;
-	      glink_vma += 8;
-	      if (i >= 0x8000)
+	      if (abi < 2)
+		{
+		  glink_vma += 8;
+		  if (i >= 0x8000)
+		    glink_vma += 4;
+		}
+	      else
 		glink_vma += 4;
 	    }
 	  count += plt_count;
@@ -9227,7 +9244,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 	      {
 		s = htab->iplt;
 		pent->plt.offset = s->size;
-		s->size += PLT_ENTRY_SIZE;
+		s->size += PLT_ENTRY_SIZE (htab);
 		s = htab->reliplt;
 	      }
 	    else
@@ -9236,21 +9253,26 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 		   first entry.  */
 		s = htab->plt;
 		if (s->size == 0)
-		  s->size += PLT_INITIAL_ENTRY_SIZE;
+		  s->size += PLT_INITIAL_ENTRY_SIZE (htab);
 
 		pent->plt.offset = s->size;
 
 		/* Make room for this entry.  */
-		s->size += PLT_ENTRY_SIZE;
+		s->size += PLT_ENTRY_SIZE (htab);
 
 		/* Make room for the .glink code.  */
 		s = htab->glink;
 		if (s->size == 0)
 		  s->size += GLINK_CALL_STUB_SIZE;
-		/* We need bigger stubs past index 32767.  */
-		if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4)
+		if (htab->opd_abi)
+		  {
+		    /* We need bigger stubs past index 32767.  */
+		    if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4)
+		      s->size += 4;
+		    s->size += 2*4;
+		  }
+		else
 		  s->size += 4;
-		s->size += 2*4;
 
 		/* We also need to make an entry in the .rela.plt section.  */
 		s = htab->relplt;
@@ -9603,7 +9625,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
 	      {
 		s = htab->iplt;
 		ent->plt.offset = s->size;
-		s->size += PLT_ENTRY_SIZE;
+		s->size += PLT_ENTRY_SIZE (htab);
 
 		htab->reliplt->size += sizeof (Elf64_External_Rela);
 	      }
@@ -9937,19 +9959,23 @@ plt_stub_size (struct ppc_link_hash_table *htab,
 	       struct ppc_stub_hash_entry *stub_entry,
 	       bfd_vma off)
 {
-  unsigned size = PLT_CALL_STUB_SIZE;
-
-  if (!(ALWAYS_EMIT_R2SAVE
-	|| stub_entry->stub_type == ppc_stub_plt_call_r2save))
-    size -= 4;
-  if (!htab->plt_static_chain)
-    size -= 4;
-  if (htab->plt_thread_safe)
-    size += 8;
-  if (PPC_HA (off) == 0)
-    size -= 4;
-  if (PPC_HA (off + 8 + 8 * htab->plt_static_chain) != PPC_HA (off))
+  unsigned size = 12;
+
+  if (ALWAYS_EMIT_R2SAVE
+      || stub_entry->stub_type == ppc_stub_plt_call_r2save)
+    size += 4;
+  if (PPC_HA (off) != 0)
     size += 4;
+  if (htab->opd_abi)
+    {
+      size += 4;
+      if (htab->plt_static_chain)
+	size += 4;
+      if (htab->plt_thread_safe)
+	size += 8;
+      if (PPC_HA (off + 8 + 8 * htab->plt_static_chain) != PPC_HA (off))
+	size += 4;
+    }
   if (stub_entry->h != NULL
       && (stub_entry->h == htab->tls_get_addr_fd
 	  || stub_entry->h == htab->tls_get_addr)
@@ -9983,12 +10009,14 @@ build_plt_stub (struct ppc_link_hash_table *htab,
 		bfd_byte *p, bfd_vma offset, Elf_Internal_Rela *r)
 {
   bfd *obfd = htab->stub_bfd;
+  bfd_boolean plt_load_toc = htab->opd_abi;
   bfd_boolean plt_static_chain = htab->plt_static_chain;
   bfd_boolean plt_thread_safe = htab->plt_thread_safe;
   bfd_boolean use_fake_dep = plt_thread_safe;
   bfd_vma cmp_branch_off = 0;
 
   if (!ALWAYS_USE_FAKE_DEP
+      && plt_load_toc
       && plt_thread_safe
       && !(stub_entry->h != NULL
 	   && (stub_entry->h == htab->tls_get_addr_fd
@@ -9996,7 +10024,8 @@ build_plt_stub (struct ppc_link_hash_table *htab,
 	   && !htab->no_tls_get_addr_opt))
     {
       bfd_vma pltoff = stub_entry->plt_ent->plt.offset & ~1;
-      bfd_vma pltindex = (pltoff - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE;
+      bfd_vma pltindex = ((pltoff - PLT_INITIAL_ENTRY_SIZE (htab))
+			  / PLT_ENTRY_SIZE (htab));
       bfd_vma glinkoff = GLINK_CALL_STUB_SIZE + pltindex * 8;
       bfd_vma to, from;
 
@@ -10030,22 +10059,25 @@ build_plt_stub (struct ppc_link_hash_table *htab,
 	  r[1].r_offset = r[0].r_offset + 4;
 	  r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
 	  r[1].r_addend = r[0].r_addend;
-	  if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
+	  if (plt_load_toc)
 	    {
-	      r[2].r_offset = r[1].r_offset + 4;
-	      r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO);
-	      r[2].r_addend = r[0].r_addend;
-	    }
-	  else
-	    {
-	      r[2].r_offset = r[1].r_offset + 8 + 8 * use_fake_dep;
-	      r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
-	      r[2].r_addend = r[0].r_addend + 8;
-	      if (plt_static_chain)
+	      if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
 		{
-		  r[3].r_offset = r[2].r_offset + 4;
-		  r[3].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
-		  r[3].r_addend = r[0].r_addend + 16;
+		  r[2].r_offset = r[1].r_offset + 4;
+		  r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO);
+		  r[2].r_addend = r[0].r_addend;
+		}
+	      else
+		{
+		  r[2].r_offset = r[1].r_offset + 8 + 8 * use_fake_dep;
+		  r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
+		  r[2].r_addend = r[0].r_addend + 8;
+		  if (plt_static_chain)
+		    {
+		      r[3].r_offset = r[2].r_offset + 4;
+		      r[3].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
+		      r[3].r_addend = r[0].r_addend + 16;
+		    }
 		}
 	    }
 	}
@@ -10054,20 +10086,24 @@ build_plt_stub (struct ppc_link_hash_table *htab,
 	bfd_put_32 (obfd, STD_R2_40R1, p),			p += 4;
       bfd_put_32 (obfd, ADDIS_R11_R2 | PPC_HA (offset), p),	p += 4;
       bfd_put_32 (obfd, LD_R12_0R11 | PPC_LO (offset), p),	p += 4;
-      if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
+      if (plt_load_toc
+	  && PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
 	{
 	  bfd_put_32 (obfd, ADDI_R11_R11 | PPC_LO (offset), p),	p += 4;
 	  offset = 0;
 	}
       bfd_put_32 (obfd, MTCTR_R12, p),				p += 4;
-      if (use_fake_dep)
+      if (plt_load_toc)
 	{
-	  bfd_put_32 (obfd, XOR_R2_R12_R12, p),			p += 4;
-	  bfd_put_32 (obfd, ADD_R11_R11_R2, p),			p += 4;
+	  if (use_fake_dep)
+	    {
+	      bfd_put_32 (obfd, XOR_R2_R12_R12, p),		p += 4;
+	      bfd_put_32 (obfd, ADD_R11_R11_R2, p),		p += 4;
+	    }
+	  bfd_put_32 (obfd, LD_R2_0R11 | PPC_LO (offset + 8), p), p += 4;
+	  if (plt_static_chain)
+	    bfd_put_32 (obfd, LD_R11_0R11 | PPC_LO (offset + 16), p), p += 4;
 	}
-      bfd_put_32 (obfd, LD_R2_0R11 | PPC_LO (offset + 8), p),	p += 4;
-      if (plt_static_chain)
-	bfd_put_32 (obfd, LD_R11_0R11 | PPC_LO (offset + 16), p), p += 4;
     }
   else
     {
@@ -10077,22 +10113,25 @@ build_plt_stub (struct ppc_link_hash_table *htab,
 	      || stub_entry->stub_type == ppc_stub_plt_call_r2save)
 	    r[0].r_offset += 4;
 	  r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
-	  if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
+	  if (plt_load_toc)
 	    {
-	      r[1].r_offset = r[0].r_offset + 4;
-	      r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16);
-	      r[1].r_addend = r[0].r_addend;
-	    }
-	  else
-	    {
-	      r[1].r_offset = r[0].r_offset + 8 + 8 * use_fake_dep;
-	      r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
-	      r[1].r_addend = r[0].r_addend + 8 + 8 * plt_static_chain;
-	      if (plt_static_chain)
+	      if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
 		{
-		  r[2].r_offset = r[1].r_offset + 4;
-		  r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
-		  r[2].r_addend = r[0].r_addend + 8;
+		  r[1].r_offset = r[0].r_offset + 4;
+		  r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16);
+		  r[1].r_addend = r[0].r_addend;
+		}
+	      else
+		{
+		  r[1].r_offset = r[0].r_offset + 8 + 8 * use_fake_dep;
+		  r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
+		  r[1].r_addend = r[0].r_addend + 8 + 8 * plt_static_chain;
+		  if (plt_static_chain)
+		    {
+		      r[2].r_offset = r[1].r_offset + 4;
+		      r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
+		      r[2].r_addend = r[0].r_addend + 8;
+		    }
 		}
 	    }
 	}
@@ -10100,22 +10139,26 @@ build_plt_stub (struct ppc_link_hash_table *htab,
 	  || stub_entry->stub_type == ppc_stub_plt_call_r2save)
 	bfd_put_32 (obfd, STD_R2_40R1, p),			p += 4;
       bfd_put_32 (obfd, LD_R12_0R2 | PPC_LO (offset), p),	p += 4;
-      if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
+      if (plt_load_toc
+	  && PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
 	{
 	  bfd_put_32 (obfd, ADDI_R2_R2 | PPC_LO (offset), p),	p += 4;
 	  offset = 0;
 	}
       bfd_put_32 (obfd, MTCTR_R12, p),				p += 4;
-      if (use_fake_dep)
+      if (plt_load_toc)
 	{
-	  bfd_put_32 (obfd, XOR_R11_R12_R12, p),		p += 4;
-	  bfd_put_32 (obfd, ADD_R2_R2_R11, p),			p += 4;
+	  if (use_fake_dep)
+	    {
+	      bfd_put_32 (obfd, XOR_R11_R12_R12, p),		p += 4;
+	      bfd_put_32 (obfd, ADD_R2_R2_R11, p),		p += 4;
+	    }
+	  if (plt_static_chain)
+	    bfd_put_32 (obfd, LD_R11_0R2 | PPC_LO (offset + 16), p), p += 4;
+	  bfd_put_32 (obfd, LD_R2_0R2 | PPC_LO (offset + 8), p), p += 4;
 	}
-      if (plt_static_chain)
-	bfd_put_32 (obfd, LD_R11_0R2 | PPC_LO (offset + 16), p), p += 4;
-      bfd_put_32 (obfd, LD_R2_0R2 | PPC_LO (offset + 8), p),	p += 4;
     }
-  if (plt_thread_safe && !use_fake_dep)
+  if (plt_load_toc && plt_thread_safe && !use_fake_dep)
     {
       bfd_put_32 (obfd, CMPLDI_R2_0, p),			p += 4;
       bfd_put_32 (obfd, BNECTR_P4, p),				p += 4;
@@ -10214,6 +10257,8 @@ get_r2off (struct bfd_link_info *info,
       /* Support linking -R objects.  Get the toc pointer from the
 	 opd entry.  */
       char buf[8];
+      if (!htab->opd_abi)
+	return r2off;
       asection *opd = stub_entry->h->elf.root.u.def.section;
       bfd_vma opd_off = stub_entry->h->elf.root.u.def.value;
 
@@ -10443,7 +10488,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 	  r[0].r_offset = loc - stub_entry->stub_sec->contents;
 	  if (bfd_big_endian (info->output_bfd))
 	    r[0].r_offset += 2;
-	  if (stub_entry->stub_type == ppc_stub_plt_branch_r2off)
+	  if (stub_entry->stub_type == ppc_stub_plt_branch_r2off
+	      && htab->opd_abi)
 	    r[0].r_offset += 4;
 	  r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
 	  r[0].r_addend = dest;
@@ -10456,7 +10502,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 	    }
 	}
 
-      if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
+      if (stub_entry->stub_type != ppc_stub_plt_branch_r2off
+	  || !htab->opd_abi)
 	{
 	  if (PPC_HA (off) != 0)
 	    {
@@ -10707,10 +10754,11 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       if (info->emitrelocations)
 	{
 	  stub_entry->stub_sec->reloc_count
-	    += (2
-		+ (PPC_HA (off) != 0)
-		+ (htab->plt_static_chain
-		   && PPC_HA (off + 16) == PPC_HA (off)));
+	    += ((PPC_HA (off) != 0)
+		+ (htab->opd_abi
+		   ? 2 + (htab->plt_static_chain
+			  && PPC_HA (off + 16) == PPC_HA (off))
+		   : 1));
 	  stub_entry->stub_sec->flags |= SEC_RELOC;
 	}
     }
@@ -10737,7 +10785,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       if (stub_entry->stub_type == ppc_stub_long_branch_r2off)
 	{
 	  r2off = get_r2off (info, stub_entry);
-	  if (r2off == 0)
+	  if (r2off == 0 && htab->opd_abi)
 	    {
 	      htab->stub_error = TRUE;
 	      return FALSE;
@@ -10750,8 +10798,11 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       local_off = PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other);
 
-      /* If the branch offset if too big, use a ppc_stub_plt_branch.  */
-      if (off + (1 << 25) >= (bfd_vma) (1 << 26) - local_off)
+      /* If the branch offset if too big, use a ppc_stub_plt_branch.
+	 Do the same for -R objects without function descriptors.  */
+      if (off + (1 << 25) >= (bfd_vma) (1 << 26) - local_off
+	  || (stub_entry->stub_type == ppc_stub_long_branch_r2off
+	      && r2off == 0))
 	{
 	  struct ppc_branch_hash_entry *br_entry;
 
@@ -10794,7 +10845,8 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 	      stub_entry->stub_sec->flags |= SEC_RELOC;
 	    }
 
-	  if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
+	  if (stub_entry->stub_type != ppc_stub_plt_branch_r2off
+	      || !htab->opd_abi)
 	    {
 	      size = 12;
 	      if (PPC_HA (off) != 0)
@@ -11698,7 +11750,9 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
   htab->plt_stub_align = plt_stub_align;
   if (plt_thread_safe == -1 && !info->executable)
     plt_thread_safe = 1;
-  if (plt_thread_safe == -1)
+  if (!htab->opd_abi)
+    plt_thread_safe = 0;
+  else if (plt_thread_safe == -1)
     {
       static const char *const thread_starter[] =
 	{
@@ -12281,26 +12335,56 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
       plt0 -= htab->glink->output_section->vma + htab->glink->output_offset;
       bfd_put_64 (htab->glink->owner, plt0, p);
       p += 8;
-      bfd_put_32 (htab->glink->owner, MFLR_R12, p);
-      p += 4;
-      bfd_put_32 (htab->glink->owner, BCL_20_31, p);
-      p += 4;
-      bfd_put_32 (htab->glink->owner, MFLR_R11, p);
-      p += 4;
-      bfd_put_32 (htab->glink->owner, LD_R2_0R11 | (-16 & 0xfffc), p);
-      p += 4;
-      bfd_put_32 (htab->glink->owner, MTLR_R12, p);
-      p += 4;
-      bfd_put_32 (htab->glink->owner, ADD_R11_R2_R11, p);
-      p += 4;
-      bfd_put_32 (htab->glink->owner, LD_R12_0R11, p);
-      p += 4;
-      bfd_put_32 (htab->glink->owner, LD_R2_0R11 | 8, p);
-      p += 4;
-      bfd_put_32 (htab->glink->owner, MTCTR_R12, p);
-      p += 4;
-      bfd_put_32 (htab->glink->owner, LD_R11_0R11 | 16, p);
-      p += 4;
+      if (htab->opd_abi)
+	{
+	  bfd_put_32 (htab->glink->owner, MFLR_R12, p);
+	  p += 4;
+	  bfd_put_32 (htab->glink->owner, BCL_20_31, p);
+	  p += 4;
+	  bfd_put_32 (htab->glink->owner, MFLR_R11, p);
+	  p += 4;
+	  bfd_put_32 (htab->glink->owner, LD_R2_0R11 | (-16 & 0xfffc), p);
+	  p += 4;
+	  bfd_put_32 (htab->glink->owner, MTLR_R12, p);
+	  p += 4;
+	  bfd_put_32 (htab->glink->owner, ADD_R11_R2_R11, p);
+	  p += 4;
+	  bfd_put_32 (htab->glink->owner, LD_R12_0R11, p);
+	  p += 4;
+	  bfd_put_32 (htab->glink->owner, LD_R2_0R11 | 8, p);
+	  p += 4;
+	  bfd_put_32 (htab->glink->owner, MTCTR_R12, p);
+	  p += 4;
+	  bfd_put_32 (htab->glink->owner, LD_R11_0R11 | 16, p);
+	  p += 4;
+	}
+      else
+	{
+	  bfd_put_32 (htab->glink->owner, MFLR_R0, p);
+	  p += 4;
+	  bfd_put_32 (htab->glink->owner, BCL_20_31, p);
+	  p += 4;
+	  bfd_put_32 (htab->glink->owner, MFLR_R11, p);
+	  p += 4;
+	  bfd_put_32 (htab->glink->owner, LD_R2_0R11 | (-16 & 0xfffc), p);
+	  p += 4;
+	  bfd_put_32 (htab->glink->owner, MTLR_R0, p);
+	  p += 4;
+	  bfd_put_32 (htab->glink->owner, SUB_R12_R12_R11, p);
+	  p += 4;
+	  bfd_put_32 (htab->glink->owner, ADD_R11_R2_R11, p);
+	  p += 4;
+	  bfd_put_32 (htab->glink->owner, ADDI_R0_R12 | (-48 & 0xffff), p);
+	  p += 4;
+	  bfd_put_32 (htab->glink->owner, LD_R12_0R11, p);
+	  p += 4;
+	  bfd_put_32 (htab->glink->owner, SRDI_R0_R0_2, p);
+	  p += 4;
+	  bfd_put_32 (htab->glink->owner, MTCTR_R12, p);
+	  p += 4;
+	  bfd_put_32 (htab->glink->owner, LD_R11_0R11 | 8, p);
+	  p += 4;
+	}
       bfd_put_32 (htab->glink->owner, BCTR, p);
       p += 4;
       while (p - htab->glink->contents < GLINK_CALL_STUB_SIZE)
@@ -12313,17 +12397,21 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
       indx = 0;
       while (p < htab->glink->contents + htab->glink->size)
 	{
-	  if (indx < 0x8000)
-	    {
-	      bfd_put_32 (htab->glink->owner, LI_R0_0 | indx, p);
-	      p += 4;
-	    }
-	  else
+	  if (htab->opd_abi)
 	    {
-	      bfd_put_32 (htab->glink->owner, LIS_R0_0 | PPC_HI (indx), p);
-	      p += 4;
-	      bfd_put_32 (htab->glink->owner, ORI_R0_R0_0 | PPC_LO (indx), p);
-	      p += 4;
+	      if (indx < 0x8000)
+		{
+		  bfd_put_32 (htab->glink->owner, LI_R0_0 | indx, p);
+		  p += 4;
+		}
+	      else
+		{
+		  bfd_put_32 (htab->glink->owner, LIS_R0_0 | PPC_HI (indx), p);
+		  p += 4;
+		  bfd_put_32 (htab->glink->owner, ORI_R0_R0_0 | PPC_LO (indx),
+			      p);
+		  p += 4;
+		}
 	    }
 	  bfd_put_32 (htab->glink->owner,
 		      B_DOT | ((htab->glink->contents - p + 8) & 0x3fffffc), p);
@@ -14451,8 +14539,8 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
 	    rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
 	    rela.r_addend = ent->addend;
 	    loc = (htab->relplt->contents
-		   + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE)
-		      / (PLT_ENTRY_SIZE / sizeof (Elf64_External_Rela))));
+		   + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE (htab))
+		      / PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela)));
 	  }
 	bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
       }
@@ -14553,7 +14641,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
 		 of glink rather than the first entry point, which is
 		 what ld.so needs, and now have a bigger stub to
 		 support automatic multiple TOCs.  */
-	      dyn.d_un.d_ptr += GLINK_CALL_STUB_SIZE - 32;
+	      dyn.d_un.d_ptr += GLINK_CALL_STUB_SIZE - 8 * 4;
 	      break;
 
 	    case DT_PPC64_OPD:
@@ -14626,7 +14714,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
     {
       /* Set .plt entry size.  */
       elf_section_data (htab->plt->output_section)->this_hdr.sh_entsize
-	= PLT_ENTRY_SIZE;
+	= PLT_ENTRY_SIZE (htab);
     }
 
   /* brlt is SEC_LINKER_CREATED, so we need to write out relocs for

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 6/9] Support ELFv2 stack frame.
  2013-10-30  2:19 [PATCH 0/9] PowerPC64 ELFv2 ABI support Alan Modra
                   ` (4 preceding siblings ...)
  2013-10-30  2:26 ` [PATCH 5/9] ELFv2 stub, plt and glink changes Alan Modra
@ 2013-10-30  2:29 ` Alan Modra
  2013-10-30  2:30 ` [PATCH 7/9] Replace DT_PPC_TLSOPT with DT_PPC_OPT Alan Modra
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Alan Modra @ 2013-10-30  2:29 UTC (permalink / raw)
  To: binutils

The toc pointer save slot changes on ELFv2 from 40(1) to 24(1).

	* elf64-ppc.c (STK_LR, STK_TOC, STK_LINKER): Define.
	(savegpr0_tail, restgpr0_tail, savefpr0_tail, restfpr0_tail)
	build_plt_stub, build_tls_get_addr_stub, ppc_build_one_stub,
	ppc64_elf_relocate_section): Use new defines.

-- 
Alan Modra
Australia Development Lab, IBM

diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 6fbcdf0..8f74333 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -130,6 +130,14 @@ static bfd_vma opd_entry_value
 /* The initial size of the plt reserved for the dynamic linker.  */
 #define PLT_INITIAL_ENTRY_SIZE(htab) (htab->opd_abi ? 24 : 16)
 
+/* Offsets to some stack save slots.  */
+#define STK_LR 16
+#define STK_TOC(htab) (htab->opd_abi ? 40 : 24)
+/* This one is dodgy.  ABIv2 does not have a linker word, so use the
+   CR save slot.  Used only by optimised __tls_get_addr call stub,
+   relying on __tls_get_addr_opt not saving CR..  */
+#define STK_LINKER(htab) (htab->opd_abi ? 32 : 8)
+
 /* TOC base pointers offset from start of TOC.  */
 #define TOC_BASE_OFF	0x8000
 
@@ -140,7 +148,7 @@ static bfd_vma opd_entry_value
 /* .plt call stub instructions.  The normal stub is like this, but
    sometimes the .plt entry crosses a 64k boundary and we need to
    insert an addi to adjust r11.  */
-#define STD_R2_40R1	0xf8410028	/* std	 %r2,40(%r1)	     */
+#define STD_R2_0R1	0xf8410000	/* std	 %r2,0+40(%r1)	     */
 #define ADDIS_R11_R2	0x3d620000	/* addis %r11,%r2,xxx@ha     */
 #define LD_R12_0R11	0xe98b0000	/* ld	 %r12,xxx+0@l(%r11)  */
 #define MTCTR_R12	0x7d8903a6	/* mtctr %r12		     */
@@ -164,7 +172,7 @@ static bfd_vma opd_entry_value
 #define LD_R11_0R2	0xe9620000	/* ld	 %r11,xxx+0(%r2) */
 #define LD_R2_0R2	0xe8420000	/* ld	 %r2,xxx+0(%r2)  */
 
-#define LD_R2_40R1	0xe8410028	/* ld    %r2,40(%r1)     */
+#define LD_R2_0R1	0xe8410000	/* ld    %r2,0(%r1)      */
 
 /* glink call stub instructions.  We enter with the index in R0.  */
 #define GLINK_CALL_STUB_SIZE (16*4)
@@ -6505,7 +6513,7 @@ static bfd_byte *
 savegpr0_tail (bfd *abfd, bfd_byte *p, int r)
 {
   p = savegpr0 (abfd, p, r);
-  bfd_put_32 (abfd, STD_R0_0R1 + 16, p);
+  bfd_put_32 (abfd, STD_R0_0R1 + STK_LR, p);
   p = p + 4;
   bfd_put_32 (abfd, BLR, p);
   return p + 4;
@@ -6521,7 +6529,7 @@ restgpr0 (bfd *abfd, bfd_byte *p, int r)
 static bfd_byte *
 restgpr0_tail (bfd *abfd, bfd_byte *p, int r)
 {
-  bfd_put_32 (abfd, LD_R0_0R1 + 16, p);
+  bfd_put_32 (abfd, LD_R0_0R1 + STK_LR, p);
   p = p + 4;
   p = restgpr0 (abfd, p, r);
   bfd_put_32 (abfd, MTLR_R0, p);
@@ -6576,7 +6584,7 @@ static bfd_byte *
 savefpr0_tail (bfd *abfd, bfd_byte *p, int r)
 {
   p = savefpr (abfd, p, r);
-  bfd_put_32 (abfd, STD_R0_0R1 + 16, p);
+  bfd_put_32 (abfd, STD_R0_0R1 + STK_LR, p);
   p = p + 4;
   bfd_put_32 (abfd, BLR, p);
   return p + 4;
@@ -6592,7 +6600,7 @@ restfpr (bfd *abfd, bfd_byte *p, int r)
 static bfd_byte *
 restfpr0_tail (bfd *abfd, bfd_byte *p, int r)
 {
-  bfd_put_32 (abfd, LD_R0_0R1 + 16, p);
+  bfd_put_32 (abfd, LD_R0_0R1 + STK_LR, p);
   p = p + 4;
   p = restfpr (abfd, p, r);
   bfd_put_32 (abfd, MTLR_R0, p);
@@ -10083,7 +10091,7 @@ build_plt_stub (struct ppc_link_hash_table *htab,
 	}
       if (ALWAYS_EMIT_R2SAVE
 	  || stub_entry->stub_type == ppc_stub_plt_call_r2save)
-	bfd_put_32 (obfd, STD_R2_40R1, p),			p += 4;
+	bfd_put_32 (obfd, STD_R2_0R1 + STK_TOC (htab), p),	p += 4;
       bfd_put_32 (obfd, ADDIS_R11_R2 | PPC_HA (offset), p),	p += 4;
       bfd_put_32 (obfd, LD_R12_0R11 | PPC_LO (offset), p),	p += 4;
       if (plt_load_toc
@@ -10137,7 +10145,7 @@ build_plt_stub (struct ppc_link_hash_table *htab,
 	}
       if (ALWAYS_EMIT_R2SAVE
 	  || stub_entry->stub_type == ppc_stub_plt_call_r2save)
-	bfd_put_32 (obfd, STD_R2_40R1, p),			p += 4;
+	bfd_put_32 (obfd, STD_R2_0R1 + STK_TOC (htab), p),	p += 4;
       bfd_put_32 (obfd, LD_R12_0R2 | PPC_LO (offset), p),	p += 4;
       if (plt_load_toc
 	  && PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
@@ -10178,11 +10186,9 @@ build_plt_stub (struct ppc_link_hash_table *htab,
 #define ADD_R3_R12_R13	0x7c6c6a14
 #define BEQLR		0x4d820020
 #define MR_R3_R0	0x7c030378
-#define MFLR_R11	0x7d6802a6
 #define STD_R11_0R1	0xf9610000
 #define BCTRL		0x4e800421
 #define LD_R11_0R1	0xe9610000
-#define LD_R2_0R1	0xe8410000
 #define MTLR_R11	0x7d6803a6
 
 static inline bfd_byte *
@@ -10200,15 +10206,15 @@ build_tls_get_addr_stub (struct ppc_link_hash_table *htab,
   bfd_put_32 (obfd, BEQLR, p),			p += 4;
   bfd_put_32 (obfd, MR_R3_R0, p),		p += 4;
   bfd_put_32 (obfd, MFLR_R11, p),		p += 4;
-  bfd_put_32 (obfd, STD_R11_0R1 + 32, p),	p += 4;
+  bfd_put_32 (obfd, STD_R11_0R1 + STK_LINKER (htab), p), p += 4;
 
   if (r != NULL)
     r[0].r_offset += 9 * 4;
   p = build_plt_stub (htab, stub_entry, p, offset, r);
   bfd_put_32 (obfd, BCTRL, p - 4);
 
-  bfd_put_32 (obfd, LD_R11_0R1 + 32, p),	p += 4;
-  bfd_put_32 (obfd, LD_R2_0R1 + 40, p),		p += 4;
+  bfd_put_32 (obfd, LD_R11_0R1 + STK_LINKER (htab), p),	p += 4;
+  bfd_put_32 (obfd, LD_R2_0R1 + STK_TOC (htab), p),	p += 4;
   bfd_put_32 (obfd, MTLR_R11, p),		p += 4;
   bfd_put_32 (obfd, BLR, p),			p += 4;
 
@@ -10332,7 +10338,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 	      htab->stub_error = TRUE;
 	      return FALSE;
 	    }
-	  bfd_put_32 (htab->stub_bfd, STD_R2_40R1, loc);
+	  bfd_put_32 (htab->stub_bfd, STD_R2_0R1 + STK_TOC (htab), loc);
 	  loc += 4;
 	  size = 12;
 	  if (PPC_HA (r2off) != 0)
@@ -10528,7 +10534,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 	      return FALSE;
 	    }
 
-	  bfd_put_32 (htab->stub_bfd, STD_R2_40R1, loc);
+	  bfd_put_32 (htab->stub_bfd, STD_R2_0R1 + STK_TOC (htab), loc);
 	  loc += 4;
 	  size = 20;
 	  if (PPC_HA (off) != 0)
@@ -13336,7 +13342,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	      insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
 	      if (insn == NOP
 		  || insn == CROR_151515 || insn == CROR_313131)
-		bfd_put_32 (input_bfd, STD_R2_40R1,
+		bfd_put_32 (input_bfd,
+			    STD_R2_0R1 + STK_TOC (htab),
 			    contents + rel->r_offset);
 	    }
 	  break;
@@ -13406,7 +13413,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 			      /* Special stub used, leave nop alone.  */
 			    }
 			  else
-			    bfd_put_32 (input_bfd, LD_R2_40R1,
+			    bfd_put_32 (input_bfd,
+					LD_R2_0R1 + STK_TOC (htab),
 					contents + rel->r_offset + 4);
 			  can_plt_call = TRUE;
 			}

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 7/9] Replace DT_PPC_TLSOPT with DT_PPC_OPT.
  2013-10-30  2:19 [PATCH 0/9] PowerPC64 ELFv2 ABI support Alan Modra
                   ` (5 preceding siblings ...)
  2013-10-30  2:29 ` [PATCH 6/9] Support ELFv2 stack frame Alan Modra
@ 2013-10-30  2:30 ` Alan Modra
  2013-10-30  2:31 ` [PATCH 8/9] Add PowerPC64 ELFv2 tests Alan Modra
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Alan Modra @ 2013-10-30  2:30 UTC (permalink / raw)
  To: binutils

This removes the DT_PPC_TLSOPT/DT_PPC64_TLSOPT dynamic tag and replaces
it with DT_PPC_OPT/DT_PPC64_OPT tag to provide the same functionality
and more.  This isn't backwards compatible, but the TLSOPT tag hasn't
been used as the tls optimisation support was never submitted to
glibc.

/include/elf/
	* ppc.h (DT_PPC_TLSOPT): Delete.
	(DT_PPC_OPT, PPC_OPT_TLS): Define.
	* ppc64.h (DT_PPC64_TLSOPT): Delete.
	(DT_PPC64_OPT, PPC64_OPT_TLS, PPC64_OPT_MULTI_TOC): Define.
bfd/
	* elf32-ppc.c (ppc_elf_size_dynamic_sections): Use new DT_PPC_OPT
	tag to specify tls optimisation.
	* elf64-ppc.c (ppc64_elf_size_dynamic_sections): Likewise.
	(ppc64_elf_finish_dynamic_sections): Specify whether multiple
	toc pointers are used via DT_PPC64_OPT.
binutils/
	* readelf.c (get_ppc_dynamic_type): Replace PPC_TLSOPT with PPC_OPT.
	(get_ppc64_dynamic_type): Replace PPC64_TLSOPT with PPC64_OPT.

-- 
Alan Modra
Australia Development Lab, IBM

diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index d6aae81..63928dc 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -6488,7 +6488,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 	  if (!htab->no_tls_get_addr_opt
 	      && htab->tls_get_addr != NULL
 	      && htab->tls_get_addr->plt.plist != NULL
-	      && !add_dynamic_entry (DT_PPC_TLSOPT, 0))
+	      && !add_dynamic_entry (DT_PPC_OPT, PPC_OPT_TLS))
 	    return FALSE;
 	}
 
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 8f74333..6a8ec51 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -9790,6 +9790,8 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
 
   if (htab->elf.dynamic_sections_created)
     {
+      bfd_boolean tls_opt;
+
       /* Add some entries to the .dynamic section.  We fill in the
 	 values later, in ppc64_elf_finish_dynamic_sections, but we
 	 must add the entries now so that we get the correct size for
@@ -9821,11 +9823,14 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
 	    return FALSE;
 	}
 
-      if (!htab->no_tls_get_addr_opt
-	  && htab->tls_get_addr_fd != NULL
-	  && htab->tls_get_addr_fd->elf.plt.plist != NULL
-	  && !add_dynamic_entry (DT_PPC64_TLSOPT, 0))
-	return FALSE;
+      tls_opt = (!htab->no_tls_get_addr_opt
+		 && htab->tls_get_addr_fd != NULL
+		 && htab->tls_get_addr_fd->elf.plt.plist != NULL);
+      if (tls_opt || !htab->opd_abi)
+	{
+	  if (!add_dynamic_entry (DT_PPC64_OPT, tls_opt ? PPC64_OPT_TLS : 0))
+	    return FALSE;
+	}
 
       if (relocs)
 	{
@@ -14659,6 +14664,11 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
 	      dyn.d_un.d_ptr = s->vma;
 	      break;
 
+	    case DT_PPC64_OPT:
+	      if (htab->do_multi_toc && htab->multi_toc_needed)
+		dyn.d_un.d_val |= PPC64_OPT_MULTI_TOC;
+	      break;
+
 	    case DT_PPC64_OPDSZ:
 	      s = bfd_get_section_by_name (output_bfd, ".opd");
 	      if (s == NULL)
diff --git a/binutils/readelf.c b/binutils/readelf.c
index c99b46e..0389f14 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -1575,7 +1575,7 @@ get_ppc_dynamic_type (unsigned long type)
   switch (type)
     {
     case DT_PPC_GOT:    return "PPC_GOT";
-    case DT_PPC_TLSOPT: return "PPC_TLSOPT";
+    case DT_PPC_OPT:    return "PPC_OPT";
     default:
       return NULL;
     }
@@ -1589,7 +1589,7 @@ get_ppc64_dynamic_type (unsigned long type)
     case DT_PPC64_GLINK:  return "PPC64_GLINK";
     case DT_PPC64_OPD:    return "PPC64_OPD";
     case DT_PPC64_OPDSZ:  return "PPC64_OPDSZ";
-    case DT_PPC64_TLSOPT: return "PPC64_TLSOPT";
+    case DT_PPC64_OPT:    return "PPC64_OPT";
     default:
       return NULL;
     }
diff --git a/include/elf/ppc.h b/include/elf/ppc.h
index f80a1e8..da00df8 100644
--- a/include/elf/ppc.h
+++ b/include/elf/ppc.h
@@ -176,7 +176,8 @@ END_RELOC_NUMBERS (R_PPC_max)
 #define DT_PPC_GOT		(DT_LOPROC)
 
 /* Specify that tls descriptors should be optimized.  */
-#define DT_PPC_TLSOPT		(DT_LOPROC + 1)
+#define DT_PPC_OPT		(DT_LOPROC + 1)
+#define PPC_OPT_TLS		1
 
 /* Processor specific flags for the ELF header e_flags field.  */
 
diff --git a/include/elf/ppc64.h b/include/elf/ppc64.h
index d3cfdfb..78d947b 100644
--- a/include/elf/ppc64.h
+++ b/include/elf/ppc64.h
@@ -234,7 +234,9 @@ ppc64_encode_local_entry(unsigned int val)
 #define DT_PPC64_OPD		(DT_LOPROC + 1)
 #define DT_PPC64_OPDSZ		(DT_LOPROC + 2)
 
-/* Specify that tls descriptors should be optimized.  */
-#define DT_PPC64_TLSOPT		(DT_LOPROC + 3)
+/* Specify whether various optimisations are possible.  */
+#define DT_PPC64_OPT		(DT_LOPROC + 3)
+#define PPC64_OPT_TLS		1
+#define PPC64_OPT_MULTI_TOC	2
 
 #endif /* _ELF_PPC64_H */

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 8/9] Add PowerPC64 ELFv2 tests.
  2013-10-30  2:19 [PATCH 0/9] PowerPC64 ELFv2 ABI support Alan Modra
                   ` (6 preceding siblings ...)
  2013-10-30  2:30 ` [PATCH 7/9] Replace DT_PPC_TLSOPT with DT_PPC_OPT Alan Modra
@ 2013-10-30  2:31 ` Alan Modra
  2013-10-30  2:44 ` [PATCH 9/9] PowerPC64 ELFv2 support for gold Alan Modra
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Alan Modra @ 2013-10-30  2:31 UTC (permalink / raw)
  To: binutils

	* ld-powerpc/elfv2.s,
	* ld-powerpc/elfv2so.d,
	* ld-powerpc/elfv2exe.d: New tests.
	* ld-powerpc/powerpc.exp: Run them.

-- 
Alan Modra
Australia Development Lab, IBM

diff --git a/ld/testsuite/ld-powerpc/elfv2.s b/ld/testsuite/ld-powerpc/elfv2.s
new file mode 100644
index 0000000..c2a4c3b
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/elfv2.s
@@ -0,0 +1,32 @@
+ .section .toc,"aw",@progbits
+.L0:
+ .quad x
+
+ .data
+x:
+ .quad f1
+
+ .globl f1
+ .type f1,@function
+ .text
+f1:
+ addis 2,12,.TOC.-f1@ha
+ addi 2,2,.TOC.-f1@l
+ .localentry f1,.-f1
+ mflr 0
+ stdu 1,-32(1)
+ std 0,48(1)
+ bl f1
+ ld 3,.L0@toc(2)
+ bl f2
+ nop
+ ld 3,x@got(2)
+ bl f3
+ nop
+ bl f4
+ nop
+ ld 0,48(1)
+ addi 1,1,32
+ mtlr 0
+ blr
+ .size f1,.-f1
diff --git a/ld/testsuite/ld-powerpc/elfv2exe.d b/ld/testsuite/ld-powerpc/elfv2exe.d
new file mode 100644
index 0000000..50d4685
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/elfv2exe.d
@@ -0,0 +1,40 @@
+#source: elfv2.s
+#as: -a64
+#ld: -melf64ppc --defsym f2=0x1234 --defsym f3=0x10008888 --defsym f4=0x1200000 --defsym _start=f1
+#objdump: -dr
+
+.*
+
+Disassembly of section \.text:
+
+0+100000c0 <.*\.plt_branch\.f2>:
+.*:	(ff ff 62 3d|3d 62 ff ff) 	addis   r11,r2,-1
+.*:	(f0 7f 8b e9|e9 8b 7f f0) 	ld      r12,32752\(r11\)
+.*:	(a6 03 89 7d|7d 89 03 a6) 	mtctr   r12
+.*:	(20 04 80 4e|4e 80 04 20) 	bctr
+
+0+100000d0 <.*\.plt_branch\.f4>:
+.*:	(ff ff 62 3d|3d 62 ff ff) 	addis   r11,r2,-1
+.*:	(f8 7f 8b e9|e9 8b 7f f8) 	ld      r12,32760\(r11\)
+.*:	(a6 03 89 7d|7d 89 03 a6) 	mtctr   r12
+.*:	(20 04 80 4e|4e 80 04 20) 	bctr
+
+0+100000e0 <_start>:
+.*:	(02 00 4c 3c|3c 4c 00 02) 	addis   r2,r12,2
+.*:	(60 80 42 38|38 42 80 60) 	addi    r2,r2,-32672
+.*:	(a6 02 08 7c|7c 08 02 a6) 	mflr    r0
+.*:	(e1 ff 21 f8|f8 21 ff e1) 	stdu    r1,-32\(r1\)
+.*:	(30 00 01 f8|f8 01 00 30) 	std     r0,48\(r1\)
+.*:	(f5 ff ff 4b|4b ff ff f5) 	bl      .* <_start\+0x8>
+.*:	(08 80 62 e8|e8 62 80 08) 	ld      r3,-32760\(r2\)
+.*:	(c5 ff ff 4b|4b ff ff c5) 	bl      .*\.plt_branch\.f2>
+.*:	(00 00 00 60|60 00 00 00) 	nop
+.*:	(10 80 62 e8|e8 62 80 10) 	ld      r3,-32752\(r2\)
+.*:	(81 87 00 48|48 00 87 81) 	bl      10008888 <f3>
+.*:	(00 00 00 60|60 00 00 00) 	nop
+.*:	(c1 ff ff 4b|4b ff ff c1) 	bl      .*\.plt_branch\.f4>
+.*:	(00 00 00 60|60 00 00 00) 	nop
+.*:	(30 00 01 e8|e8 01 00 30) 	ld      r0,48\(r1\)
+.*:	(20 00 21 38|38 21 00 20) 	addi    r1,r1,32
+.*:	(a6 03 08 7c|7c 08 03 a6) 	mtlr    r0
+.*:	(20 00 80 4e|4e 80 00 20) 	blr
diff --git a/ld/testsuite/ld-powerpc/elfv2so.d b/ld/testsuite/ld-powerpc/elfv2so.d
new file mode 100644
index 0000000..963dbb6
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/elfv2so.d
@@ -0,0 +1,82 @@
+#source: elfv2.s
+#as: -a64
+#ld: -melf64ppc -shared
+#objdump: -dr
+
+.*
+
+Disassembly of section \.text:
+
+0+300 <.*\.plt_call\.f4>:
+.*:	(18 00 41 f8|f8 41 00 18) 	std     r2,24\(r1\)
+.*:	(38 80 82 e9|e9 82 80 38) 	ld      r12,-32712\(r2\)
+.*:	(a6 03 89 7d|7d 89 03 a6) 	mtctr   r12
+.*:	(20 04 80 4e|4e 80 04 20) 	bctr
+
+0+310 <.*\.plt_call\.f3>:
+.*:	(18 00 41 f8|f8 41 00 18) 	std     r2,24\(r1\)
+.*:	(28 80 82 e9|e9 82 80 28) 	ld      r12,-32728\(r2\)
+.*:	(a6 03 89 7d|7d 89 03 a6) 	mtctr   r12
+.*:	(20 04 80 4e|4e 80 04 20) 	bctr
+
+0+320 <.*\.plt_call\.f2>:
+.*:	(18 00 41 f8|f8 41 00 18) 	std     r2,24\(r1\)
+.*:	(30 80 82 e9|e9 82 80 30) 	ld      r12,-32720\(r2\)
+.*:	(a6 03 89 7d|7d 89 03 a6) 	mtctr   r12
+.*:	(20 04 80 4e|4e 80 04 20) 	bctr
+
+0+330 <.*\.plt_call\.f1>:
+.*:	(18 00 41 f8|f8 41 00 18) 	std     r2,24\(r1\)
+.*:	(40 80 82 e9|e9 82 80 40) 	ld      r12,-32704\(r2\)
+.*:	(a6 03 89 7d|7d 89 03 a6) 	mtctr   r12
+.*:	(20 04 80 4e|4e 80 04 20) 	bctr
+
+0+340 <f1>:
+.*:	(02 00 4c 3c|3c 4c 00 02) 	addis   r2,r12,2
+.*:	(e0 81 42 38|38 42 81 e0) 	addi    r2,r2,-32288
+.*:	(a6 02 08 7c|7c 08 02 a6) 	mflr    r0
+.*:	(e1 ff 21 f8|f8 21 ff e1) 	stdu    r1,-32\(r1\)
+.*:	(30 00 01 f8|f8 01 00 30) 	std     r0,48\(r1\)
+.*:	(dd ff ff 4b|4b ff ff dd) 	bl      .*\.plt_call\.f1>
+.*:	(08 80 62 e8|e8 62 80 08) 	ld      r3,-32760\(r2\)
+.*:	(c5 ff ff 4b|4b ff ff c5) 	bl      .*\.plt_call\.f2>
+.*:	(18 00 41 e8|e8 41 00 18) 	ld      r2,24\(r1\)
+.*:	(10 80 62 e8|e8 62 80 10) 	ld      r3,-32752\(r2\)
+.*:	(a9 ff ff 4b|4b ff ff a9) 	bl      .*\.plt_call\.f3>
+.*:	(18 00 41 e8|e8 41 00 18) 	ld      r2,24\(r1\)
+.*:	(91 ff ff 4b|4b ff ff 91) 	bl      .*\.plt_call\.f4>
+.*:	(18 00 41 e8|e8 41 00 18) 	ld      r2,24\(r1\)
+.*:	(30 00 01 e8|e8 01 00 30) 	ld      r0,48\(r1\)
+.*:	(20 00 21 38|38 21 00 20) 	addi    r1,r1,32
+.*:	(a6 03 08 7c|7c 08 03 a6) 	mtlr    r0
+.*:	(20 00 80 4e|4e 80 00 20) 	blr
+.*:	(a0 01 01 00|00 00 00 00) 	.*
+.*:	(00 00 00 00|00 01 01 a0) 	.*
+
+0+390 <__glink_PLTresolve>:
+.*:	(a6 02 08 7c|7c 08 02 a6) 	mflr    r0
+.*:	(05 00 9f 42|42 9f 00 05) 	bcl     .*
+.*:	(a6 02 68 7d|7d 68 02 a6) 	mflr    r11
+.*:	(f0 ff 4b e8|e8 4b ff f0) 	ld      r2,-16\(r11\)
+.*:	(a6 03 08 7c|7c 08 03 a6) 	mtlr    r0
+.*:	(50 60 8b 7d|7d 8b 60 50) 	subf    r12,r11,r12
+.*:	(14 5a 62 7d|7d 62 5a 14) 	add     r11,r2,r11
+.*:	(d0 ff 0c 38|38 0c ff d0) 	addi    r0,r12,-48
+.*:	(00 00 8b e9|e9 8b 00 00) 	ld      r12,0\(r11\)
+.*:	(82 f0 00 78|78 00 f0 82) 	rldicl  r0,r0,62,2
+.*:	(a6 03 89 7d|7d 89 03 a6) 	mtctr   r12
+.*:	(08 00 6b e9|e9 6b 00 08) 	ld      r11,8\(r11\)
+.*:	(20 04 80 4e|4e 80 04 20) 	bctr
+.*:	(00 00 00 60|60 00 00 00) 	nop
+
+.* <f3@plt>:
+.*:	(c8 ff ff 4b|4b ff ff c8) 	b       .* <__glink_PLTresolve>
+
+.* <f2@plt>:
+.*:	(c4 ff ff 4b|4b ff ff c4) 	b       .* <__glink_PLTresolve>
+
+.* <f4@plt>:
+.*:	(c0 ff ff 4b|4b ff ff c0) 	b       .* <__glink_PLTresolve>
+
+.* <f1@plt>:
+.*:	(bc ff ff 4b|4b ff ff bc) 	b       .* <__glink_PLTresolve>
diff --git a/ld/testsuite/ld-powerpc/powerpc.exp b/ld/testsuite/ld-powerpc/powerpc.exp
index 8b33fcc..87e4ea8 100644
--- a/ld/testsuite/ld-powerpc/powerpc.exp
+++ b/ld/testsuite/ld-powerpc/powerpc.exp
@@ -269,6 +269,8 @@ run_ld_link_tests $ppcelftests
 if [ supports_ppc64 ] then {
     run_ld_link_tests $ppc64elftests
     run_dump_test "relbrlt"
+    run_dump_test "elfv2so"
+    run_dump_test "elfv2exe"
 }
 
 if { [istarget "powerpc*-eabi*"] } {

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 9/9] PowerPC64 ELFv2 support for gold.
  2013-10-30  2:19 [PATCH 0/9] PowerPC64 ELFv2 ABI support Alan Modra
                   ` (7 preceding siblings ...)
  2013-10-30  2:31 ` [PATCH 8/9] Add PowerPC64 ELFv2 tests Alan Modra
@ 2013-10-30  2:44 ` Alan Modra
  2013-10-30 17:25 ` [PATCH 0/9] PowerPC64 ELFv2 ABI support Joseph S. Myers
  2013-10-31  7:50 ` Matt Thomas
  10 siblings, 0 replies; 19+ messages in thread
From: Alan Modra @ 2013-10-30  2:44 UTC (permalink / raw)
  To: binutils

From bdecb06a3505cc6a972a4709f06b3b2f27bf3b4b Mon Sep 17 00:00:00 2001
From: Alan Modra <amodra@gmail.com>
Date: Tue, 29 Oct 2013 17:45:48 +1030
Subject: [PATCH 9/9] PowerPC64 ELFv2 support for gold.

The same changes as in patch 1-7, but for gold.  One extra, define .TOC.
as we do already in the bfd linker so typical ELFV2 function prologue
code works.

f1:
 addis 2,12,.TOC.-f1@ha
 addi 2,2,.TOC.-f1@l
 .localentry f1,.-f1

elfcpp/
	* powerpc.h (EF_PPC64_ABI): New enum constant.
	(STO_PPC64_LOCAL_BIT, STO_PPC64_LOCAL_MASK): Likewise.
	(ppc64_decode_local_entry): New function.
	(ppc64_encode_local_entry): Likewise.
gold/
	* powerpc.cc (Powerpc_relobj::abiversion, set_abiversion,
	ppc64_local_entry_offset, ppc64_local_entry_offset,
	do_read_symbols): New functions.
	(Powerpc_relobj::e_flags_, st_other_): New vars.
	(Powerpc_relobj::Powerpc_relobj): Call set_abiversion.
	(Powerpc_dynobj::abiversion, set_abiversion): New functions.
	(Powerpc_relobj::e_flags_): New var.
	(Target_powerpc::first_plt_entry_offset, plt_entry_size): Inline
	and adjust for ELFv2.
	(Target_powerpc::abiversion, set_abiversion, stk_toc): New functions.
	(Powerpc_relobj::do_find_special_sections): Check no .opd in ELFv2.
	(Powerpc_dynobj::do_find_special_sections): Likewise.
	(Target_powerpc::do_define_standard_symbols): Define ".TOC.".
	(Target_powerpc::Branch_info::make_stub): Adjust stub destination
	to ELFv2 local entry.
	(Target_powerpc::do_relax): No thread safe barriers needed for
	ELFv2.
	(Output_data_plt_powerpc::initial_plt_entry_size_,
	plt_entry_size): Delete.  Replace all uses with
	first_plt_entry_offset() and plt_entry_size().
	(Output_data_plt_powerpc::Output_data_plt_powerpc): Remove
	reserved_size parm.  Update callers.
	(Output_data_plt_powerpc::entry_count): Update.
	(Output_data_plt_powerpc::first_plt_entry_offset): Make private
	and use Target_powerpc::first_plt_entry_offset().
	(Output_data_plt_powerpc::get_plt_entry_size): Similarly and
	rename to plt_entry_size.
	(Output_data_plt_powerpc::add_ifunc_entry,
	add_local_ifunc_entry): Adjust reloc for ELFv2.
	(glink_eh_frame_fde_64): Rename to glink_eh_frame_fde_64v1.
	(glink_eh_frame_fde_64v2): New.
	(Stub_table::plt_call_size): Support ELFv2 sizing.
	(Output_data_glink::add_eh_frame): Use the new FDE.
	(Output_data_glink::set_final_data_size): Adjust for ELFv2 glink.
	(Stub_table::do_write): Write ELFv2 stubs and glink.
	(Target_powerpc::Relocate::relocate): Replaces nop after call
	with ld 2,24(1) and adjust local offset destination for ELFv2.

-- 
Alan Modra
Australia Development Lab, IBM

diff --git a/elfcpp/powerpc.h b/elfcpp/powerpc.h
index fb4256b..98354a2 100644
--- a/elfcpp/powerpc.h
+++ b/elfcpp/powerpc.h
@@ -1,6 +1,6 @@
 // powerpc.h -- ELF definitions specific to EM_PPC and EM_PPC64  -*- C++ -*-
 
-// Copyright 2008, 2010, 2012 Free Software Foundation, Inc.
+// Copyright 2008, 2010, 2012, 2013 Free Software Foundation, Inc.
 // Written by David S. Miller <davem@davemloft.net>.
 
 // This file is part of elfcpp.
@@ -214,6 +214,59 @@ enum
   EF_PPC_RELOCATABLE_LIB = 0x00008000, // PowerPC -mrelocatable-lib flag.  */
 };
 
+// e_flags values defined for powerpc64
+enum
+{
+  // ABI version
+  // 1 for original function descriptor using ABI,
+  // 2 for revised ABI without function descriptors,
+  // 0 for unspecified or not using any features affected by the differences.
+  EF_PPC64_ABI = 3
+};
+
+enum
+{
+  // The ELFv2 ABI uses three bits in the symbol st_other field of a
+  // function definition to specify the number of instructions between a
+  // function's global entry point and local entry point.
+  // The global entry point is used when it is necessary to set up the
+  // toc pointer (r2) for the function.  Callers must enter the global
+  // entry point with r12 set to the global entry point address.  On
+  // return from the function, r2 may have a different value to that
+  // which it had on entry.
+  // The local entry point is used when r2 is known to already be valid
+  // for the function.  There is no requirement on r12 when using the
+  // local entry point, and on return r2 will contain the same value as
+  // at entry.
+  // A value of zero in these bits means that the function has a single
+  // entry point with no requirement on r12 or r2, and that on return r2
+  // will contain the same value as at entry.
+  // Values of one and seven are reserved.
+
+  STO_PPC64_LOCAL_BIT = 5,
+  STO_PPC64_LOCAL_MASK = 0xE0
+};
+
+// 3 bit other field to bytes.
+static inline unsigned int
+ppc64_decode_local_entry(unsigned int other)
+{
+  return ((1 << other) >> 2) << 2;
+}
+
+// bytes to field value.
+static inline unsigned int
+ppc64_encode_local_entry(unsigned int val)
+{
+  return (val >= 4 * 4
+	  ? (val >= 8 * 4
+	     ? (val >= 16 * 4 ? 6 : 5)
+	     : 4)
+	  : (val >= 2 * 4
+	     ? 3
+	     : (val >= 1 * 4 ? 2 : 0)));
+}
+
 } // End namespace elfcpp.
 
 #endif // !defined(ELFCPP_POWERPC_H)
diff --git a/gold/powerpc.cc b/gold/powerpc.cc
index 75fc604..0d6822d 100644
--- a/gold/powerpc.cc
+++ b/gold/powerpc.cc
@@ -77,12 +77,19 @@ public:
 		 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_()
-  { }
+      opd_ent_(), access_from_map_(), has14_(), stub_table_(),
+      e_flags_(ehdr.get_e_flags()), st_other_()
+  {
+    this->set_abiversion(0);
+  }
 
   ~Powerpc_relobj()
   { }
 
+  // Read the symbols then set up st_other vector.
+  void
+  do_read_symbols(Read_symbols_data*);
+
   // The .got2 section shndx.
   unsigned int
   got2_shndx() const
@@ -268,6 +275,22 @@ public:
     return NULL;
   }
 
+  int
+  abiversion() const
+  { return this->e_flags_ & elfcpp::EF_PPC64_ABI; }
+
+  // Set ABI version for input and output
+  void
+  set_abiversion(int ver);
+
+  unsigned int
+  ppc64_local_entry_offset(const Symbol* sym) const
+  { return elfcpp::ppc64_decode_local_entry(sym->nonvis() >> 3); }
+
+  unsigned int
+  ppc64_local_entry_offset(unsigned int symndx) const
+  { return elfcpp::ppc64_decode_local_entry(this->st_other_[symndx] >> 5); }
+
 private:
   struct Opd_ent
   {
@@ -321,6 +344,12 @@ private:
 
   // The stub table to use for a given input section.
   std::vector<Stub_table<size, big_endian>*> stub_table_;
+
+  // Header e_flags
+  elfcpp::Elf_Word e_flags_;
+
+  // ELF st_other field for local symbols.
+  std::vector<unsigned char> st_other_;
 };
 
 template<int size, bool big_endian>
@@ -332,8 +361,10 @@ public:
   Powerpc_dynobj(const std::string& name, Input_file* input_file, off_t offset,
 		 const typename elfcpp::Ehdr<size, big_endian>& ehdr)
     : Sized_dynobj<size, big_endian>(name, input_file, offset, ehdr),
-      opd_shndx_(0), opd_ent_()
-  { }
+      opd_shndx_(0), opd_ent_(), e_flags_(ehdr.get_e_flags())
+  {
+    this->set_abiversion(0);
+  }
 
   ~Powerpc_dynobj()
   { }
@@ -387,6 +418,14 @@ public:
     this->opd_ent_[ndx].off = value;
   }
 
+  int
+  abiversion() const
+  { return this->e_flags_ & elfcpp::EF_PPC64_ABI; }
+
+  // Set ABI version for input and output.
+  void
+  set_abiversion(int ver);
+
 private:
   // Used to specify extent of executable sections.
   struct Sec_info
@@ -424,6 +463,9 @@ private:
   // corresponding to the address.  Note that in dynamic objects,
   // offset is *not* relative to the section.
   std::vector<Opd_ent> opd_ent_;
+
+  // Header e_flags
+  elfcpp::Elf_Word e_flags_;
 };
 
 template<int size, bool big_endian>
@@ -679,11 +721,25 @@ class Target_powerpc : public Sized_target<size, big_endian>
 
   // Return the offset of the first non-reserved PLT entry.
   unsigned int
-  first_plt_entry_offset() const;
+  first_plt_entry_offset() const
+  {
+    if (size == 32)
+      return 0;
+    if (this->abiversion() >= 2)
+      return 16;
+    return 24;
+  }
 
   // Return the size of each PLT entry.
   unsigned int
-  plt_entry_size() const;
+  plt_entry_size() const
+  {
+    if (size == 32)
+      return 4;
+    if (this->abiversion() >= 2)
+      return 8;
+    return 24;
+  }
 
   // Add any special sections for this symbol to the gc work list.
   // For powerpc64, this adds the code section of a function
@@ -743,6 +799,24 @@ class Target_powerpc : public Sized_target<size, big_endian>
   plt_thread_safe() const
   { return this->plt_thread_safe_; }
 
+  int
+  abiversion () const
+  { return this->processor_specific_flags() & elfcpp::EF_PPC64_ABI; }
+
+  void
+  set_abiversion (int ver)
+  {
+    elfcpp::Elf_Word flags = this->processor_specific_flags();
+    flags &= ~elfcpp::EF_PPC64_ABI;
+    flags |= ver & elfcpp::EF_PPC64_ABI;
+    this->set_processor_specific_flags(flags);
+  }
+
+  // Offset to to save stack slot
+  int
+  stk_toc () const
+  { return this->abiversion() < 2 ? 40 : 24; }
+
  private:
 
   class Track_tls
@@ -1659,6 +1733,29 @@ public:
   }
 };
 
+// Set ABI version for input and output.
+
+template<int size, bool big_endian>
+void
+Powerpc_relobj<size, big_endian>::set_abiversion(int ver)
+{
+  this->e_flags_ |= ver;
+  if (this->abiversion() != 0)
+    {
+      Target_powerpc<size, big_endian>* target =
+	static_cast<Target_powerpc<size, big_endian>*>(
+	   parameters->sized_target<size, big_endian>());
+      if (target->abiversion() == 0)
+	target->set_abiversion(this->abiversion());
+      else if (target->abiversion() != this->abiversion())
+	gold_error(_("%s: ABI version %d is not compatible "
+		     "with ABI version %d output"),
+		   this->name().c_str(),
+		   this->abiversion(), target->abiversion());
+
+    }
+}
+
 // Stash away the index of .got2 or .opd in a relocatable object, if
 // such a section exists.
 
@@ -1680,6 +1777,14 @@ Powerpc_relobj<size, big_endian>::do_find_special_sections(
     {
       unsigned int ndx = (s - pshdrs) / elfcpp::Elf_sizes<size>::shdr_size;
       this->special_ = ndx;
+      if (size == 64)
+	{
+	  if (this->abiversion() == 0)
+	    this->set_abiversion(1);
+	  else if (this->abiversion() > 1)
+	    gold_error(_("%s: .opd invalid in abiv%d"),
+		       this->name().c_str(), this->abiversion());
+	}
     }
   return Sized_relobj_file<size, big_endian>::do_find_special_sections(sd);
 }
@@ -1790,6 +1895,69 @@ Powerpc_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
     }
 }
 
+// Read the symbols then set up st_other vector.
+
+template<int size, bool big_endian>
+void
+Powerpc_relobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
+{
+  Sized_relobj_file<size, big_endian>::do_read_symbols(sd);
+  if (size == 64)
+    {
+      const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
+      const unsigned char* const pshdrs = sd->section_headers->data();
+      const unsigned int loccount = this->do_local_symbol_count();
+      if (loccount != 0)
+	{
+	  this->st_other_.resize(loccount);
+	  const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+	  off_t locsize = loccount * sym_size;
+	  const unsigned int symtab_shndx = this->symtab_shndx();
+	  const unsigned char *psymtab = pshdrs + symtab_shndx * shdr_size;
+	  typename elfcpp::Shdr<size, big_endian> shdr(psymtab);
+	  const unsigned char* psyms = this->get_view(shdr.get_sh_offset(),
+						      locsize, true, false);
+	  psyms += sym_size;
+	  for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size)
+	    {
+	      elfcpp::Sym<size, big_endian> sym(psyms);
+	      unsigned char st_other = sym.get_st_other();
+	      this->st_other_[i] = st_other;
+	      if ((st_other & elfcpp::STO_PPC64_LOCAL_MASK) != 0)
+		{
+		  if (this->abiversion() == 0)
+		    this->set_abiversion(2);
+		  else if (this->abiversion() < 2)
+		    gold_error(_("%s: local symbol %d has invalid st_other"
+				 " for ABI version 1"),
+			       this->name().c_str(), i);
+		}
+	    }
+	}
+    }
+}
+
+template<int size, bool big_endian>
+void
+Powerpc_dynobj<size, big_endian>::set_abiversion(int ver)
+{
+  this->e_flags_ |= ver;
+  if (this->abiversion() != 0)
+    {
+      Target_powerpc<size, big_endian>* target =
+	static_cast<Target_powerpc<size, big_endian>*>(
+	  parameters->sized_target<size, big_endian>());
+      if (target->abiversion() == 0)
+	target->set_abiversion(this->abiversion());
+      else if (target->abiversion() != this->abiversion())
+	gold_error(_("%s: ABI version %d is not compatible "
+		     "with ABI version %d output"),
+		   this->name().c_str(),
+		   this->abiversion(), target->abiversion());
+
+    }
+}
+
 // Call Sized_dynobj::do_read_symbols to read the symbols then
 // read .opd from a dynamic object, filling in opd_ent_ vector,
 
@@ -1821,6 +1989,12 @@ Powerpc_dynobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
 	  if (shdr.get_sh_type() == elfcpp::SHT_PROGBITS
 	      && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) != 0)
 	    {
+	      if (this->abiversion() == 0)
+		this->set_abiversion(1);
+	      else if (this->abiversion() > 1)
+		gold_error(_("%s: .opd invalid in abiv%d"),
+			   this->name().c_str(), this->abiversion());
+
 	      this->opd_shndx_ = (s - pshdrs) / shdr_size;
 	      this->opd_address_ = shdr.get_sh_addr();
 	      opd_size = convert_to_section_size_type(shdr.get_sh_size());
@@ -1937,6 +2111,26 @@ Target_powerpc<size, big_endian>::do_define_standard_symbols(
 					0, false, false);
 	}
     }
+  else
+    {
+      // Define .TOC. as for 32-bit _GLOBAL_OFFSET_TABLE_
+      Symbol *gotsym = symtab->lookup(".TOC.", NULL);
+      if (gotsym != NULL && gotsym->is_undefined())
+	{
+	  Target_powerpc<size, big_endian>* target =
+	    static_cast<Target_powerpc<size, big_endian>*>(
+		parameters->sized_target<size, big_endian>());
+	  Output_data_got_powerpc<size, big_endian>* got
+	    = target->got_section(symtab, layout);
+	  symtab->define_in_output_data(".TOC.", NULL,
+					Symbol_table::PREDEFINED,
+					got, 0x8000, 0,
+					elfcpp::STT_OBJECT,
+					elfcpp::STB_LOCAL,
+					elfcpp::STV_HIDDEN, 0,
+					false, false);
+	}
+    }
 }
 
 // Set up PowerPC target specific relobj.
@@ -2446,7 +2640,7 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
     }
   else
     {
-      unsigned int max_branch_offset;
+      unsigned long max_branch_offset;
       if (this->r_type_ == elfcpp::R_POWERPC_REL14
 	  || this->r_type_ == elfcpp::R_POWERPC_REL14_BRTAKEN
 	  || this->r_type_ == elfcpp::R_POWERPC_REL14_BRNTAKEN)
@@ -2489,6 +2683,7 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
 	  to = symtab->compute_final_value<size>(gsym, &status);
 	  if (status != Symbol_table::CFVS_OK)
 	    return;
+	  to += this->object_->ppc64_local_entry_offset(gsym);
 	}
       else
 	{
@@ -2503,6 +2698,7 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
 	      || !symval.has_output_value())
 	    return;
 	  to = symval.value(this->object_, 0);
+	  to += this->object_->ppc64_local_entry_offset(this->r_sym_);
 	}
       to += this->addend_;
       if (stub_table == NULL)
@@ -2545,8 +2741,12 @@ Target_powerpc<size, big_endian>::do_relax(int pass,
   unsigned int prev_brlt_size = 0;
   if (pass == 1)
     {
-      bool thread_safe = parameters->options().plt_thread_safe();
-      if (size == 64 && !parameters->options().user_set_plt_thread_safe())
+      bool thread_safe
+	= this->abiversion() < 2 && parameters->options().plt_thread_safe();
+      if (size == 64
+	  && this->abiversion() < 2
+	  && !thread_safe
+	  && !parameters->options().user_set_plt_thread_safe())
 	{
 	  static const char* const thread_starter[] =
 	    {
@@ -2758,12 +2958,10 @@ class Output_data_plt_powerpc : public Output_section_data_build
 
   Output_data_plt_powerpc(Target_powerpc<size, big_endian>* targ,
 			  Reloc_section* plt_rel,
-			  unsigned int reserved_size,
 			  const char* name)
     : Output_section_data_build(size == 32 ? 4 : 8),
       rel_(plt_rel),
       targ_(targ),
-      initial_plt_entry_size_(reserved_size),
       name_(name)
   { }
 
@@ -2790,20 +2988,10 @@ class Output_data_plt_powerpc : public Output_section_data_build
   {
     if (this->current_data_size() == 0)
       return 0;
-    return ((this->current_data_size() - this->initial_plt_entry_size_)
-	    / plt_entry_size);
+    return ((this->current_data_size() - this->first_plt_entry_offset())
+	    / this->plt_entry_size());
   }
 
-  // Return the offset of the first non-reserved PLT entry.
-  unsigned int
-  first_plt_entry_offset()
-  { return this->initial_plt_entry_size_; }
-
-  // Return the size of a PLT entry.
-  static unsigned int
-  get_plt_entry_size()
-  { return plt_entry_size; }
-
  protected:
   void
   do_adjust_output_section(Output_section* os)
@@ -2817,8 +3005,22 @@ class Output_data_plt_powerpc : public Output_section_data_build
   { mapfile->print_output_data(this, this->name_); }
 
  private:
-  // The size of an entry in the PLT.
-  static const int plt_entry_size = size == 32 ? 4 : 24;
+  // Return the offset of the first non-reserved PLT entry.
+  unsigned int
+  first_plt_entry_offset() const
+  {
+    // IPLT has no reserved entry.
+    if (this->name_[3] == 'I')
+      return 0;
+    return this->targ_->first_plt_entry_offset();
+  }
+
+  // Return the size of each PLT entry.
+  unsigned int
+  plt_entry_size() const
+  {
+    return this->targ_->plt_entry_size();
+  }
 
   // Write out the PLT data.
   void
@@ -2828,8 +3030,6 @@ class Output_data_plt_powerpc : public Output_section_data_build
   Reloc_section* rel_;
   // Allows access to .glink for do_write.
   Target_powerpc<size, big_endian>* targ_;
-  // The size of the first reserved entry.
-  int initial_plt_entry_size_;
   // What to report in map file.
   const char *name_;
 };
@@ -2849,7 +3049,7 @@ Output_data_plt_powerpc<size, big_endian>::add_entry(Symbol* gsym)
       gsym->set_needs_dynsym_entry();
       unsigned int dynrel = elfcpp::R_POWERPC_JMP_SLOT;
       this->rel_->add_global(gsym, dynrel, this, off, 0);
-      off += plt_entry_size;
+      off += this->plt_entry_size();
       this->set_current_data_size(off);
     }
 }
@@ -2865,10 +3065,10 @@ Output_data_plt_powerpc<size, big_endian>::add_ifunc_entry(Symbol* gsym)
       section_size_type off = this->current_data_size();
       gsym->set_plt_offset(off);
       unsigned int dynrel = elfcpp::R_POWERPC_IRELATIVE;
-      if (size == 64)
+      if (size == 64 && this->targ_->abiversion() < 2)
 	dynrel = elfcpp::R_PPC64_JMP_IREL;
       this->rel_->add_symbolless_global_addend(gsym, dynrel, this, off, 0);
-      off += plt_entry_size;
+      off += this->plt_entry_size();
       this->set_current_data_size(off);
     }
 }
@@ -2886,11 +3086,11 @@ Output_data_plt_powerpc<size, big_endian>::add_local_ifunc_entry(
       section_size_type off = this->current_data_size();
       relobj->set_local_plt_offset(local_sym_index, off);
       unsigned int dynrel = elfcpp::R_POWERPC_IRELATIVE;
-      if (size == 64)
+      if (size == 64 && this->targ_->abiversion() < 2)
 	dynrel = elfcpp::R_PPC64_JMP_IREL;
       this->rel_->add_symbolless_local_addend(relobj, local_sym_index, dynrel,
 					      this, off, 0);
-      off += plt_entry_size;
+      off += this->plt_entry_size();
       this->set_current_data_size(off);
     }
 }
@@ -2900,50 +3100,50 @@ static const uint32_t add_2_2_11	= 0x7c425a14;
 static const uint32_t add_3_3_2		= 0x7c631214;
 static const uint32_t add_3_3_13	= 0x7c636a14;
 static const uint32_t add_11_0_11	= 0x7d605a14;
-static const uint32_t add_12_2_11	= 0x7d825a14;
-static const uint32_t add_12_12_11	= 0x7d8c5a14;
-static const uint32_t addi_11_11	= 0x396b0000;
-static const uint32_t addi_12_12	= 0x398c0000;
+static const uint32_t add_11_2_11	= 0x7d625a14;
+static const uint32_t add_11_11_2	= 0x7d6b1214;
+static const uint32_t addi_0_12		= 0x380c0000;
 static const uint32_t addi_2_2		= 0x38420000;
-static const uint32_t addi_3_2		= 0x38620000;
 static const uint32_t addi_3_3		= 0x38630000;
+static const uint32_t addi_11_11	= 0x396b0000;
+static const uint32_t addi_12_12	= 0x398c0000;
 static const uint32_t addis_0_2		= 0x3c020000;
 static const uint32_t addis_0_13	= 0x3c0d0000;
+static const uint32_t addis_3_2		= 0x3c620000;
+static const uint32_t addis_3_13	= 0x3c6d0000;
+static const uint32_t addis_11_2	= 0x3d620000;
 static const uint32_t addis_11_11	= 0x3d6b0000;
 static const uint32_t addis_11_30	= 0x3d7e0000;
 static const uint32_t addis_12_12	= 0x3d8c0000;
-static const uint32_t addis_12_2	= 0x3d820000;
-static const uint32_t addis_3_2		= 0x3c620000;
-static const uint32_t addis_3_13	= 0x3c6d0000;
 static const uint32_t b			= 0x48000000;
 static const uint32_t bcl_20_31		= 0x429f0005;
 static const uint32_t bctr		= 0x4e800420;
 static const uint32_t blr		= 0x4e800020;
-static const uint32_t blrl		= 0x4e800021;
 static const uint32_t bnectr_p4		= 0x4ce20420;
 static const uint32_t cmpldi_2_0	= 0x28220000;
 static const uint32_t cror_15_15_15	= 0x4def7b82;
 static const uint32_t cror_31_31_31	= 0x4ffffb82;
 static const uint32_t ld_0_1		= 0xe8010000;
 static const uint32_t ld_0_12		= 0xe80c0000;
-static const uint32_t ld_11_12		= 0xe96c0000;
-static const uint32_t ld_11_2		= 0xe9620000;
 static const uint32_t ld_2_1		= 0xe8410000;
-static const uint32_t ld_2_11		= 0xe84b0000;
-static const uint32_t ld_2_12		= 0xe84c0000;
 static const uint32_t ld_2_2		= 0xe8420000;
+static const uint32_t ld_2_11		= 0xe84b0000;
+static const uint32_t ld_11_2		= 0xe9620000;
+static const uint32_t ld_11_11		= 0xe96b0000;
+static const uint32_t ld_12_2		= 0xe9820000;
+static const uint32_t ld_12_11		= 0xe98b0000;
 static const uint32_t lfd_0_1		= 0xc8010000;
 static const uint32_t li_0_0		= 0x38000000;
 static const uint32_t li_12_0		= 0x39800000;
 static const uint32_t lis_0_0		= 0x3c000000;
 static const uint32_t lis_11		= 0x3d600000;
 static const uint32_t lis_12		= 0x3d800000;
+static const uint32_t lvx_0_12_0	= 0x7c0c00ce;
 static const uint32_t lwz_0_12		= 0x800c0000;
 static const uint32_t lwz_11_11		= 0x816b0000;
 static const uint32_t lwz_11_30		= 0x817e0000;
 static const uint32_t lwz_12_12		= 0x818c0000;
 static const uint32_t lwzu_0_12		= 0x840c0000;
-static const uint32_t lvx_0_12_0	= 0x7c0c00ce;
 static const uint32_t mflr_0		= 0x7c0802a6;
 static const uint32_t mflr_11		= 0x7d6802a6;
 static const uint32_t mflr_12		= 0x7d8802a6;
@@ -2954,13 +3154,16 @@ static const uint32_t mtlr_0		= 0x7c0803a6;
 static const uint32_t mtlr_12		= 0x7d8803a6;
 static const uint32_t nop		= 0x60000000;
 static const uint32_t ori_0_0_0		= 0x60000000;
+static const uint32_t srdi_0_0_2	= 0x7800f082;
 static const uint32_t std_0_1		= 0xf8010000;
 static const uint32_t std_0_12		= 0xf80c0000;
 static const uint32_t std_2_1		= 0xf8410000;
 static const uint32_t stfd_0_1		= 0xd8010000;
 static const uint32_t stvx_0_12_0	= 0x7c0c01ce;
 static const uint32_t sub_11_11_12	= 0x7d6c5850;
-static const uint32_t xor_11_11_11	= 0x7d6b5a78;
+static const uint32_t sub_12_12_11	= 0x7d8b6050;
+static const uint32_t xor_2_12_12	= 0x7d826278;
+static const uint32_t xor_11_12_12	= 0x7d8b6278;
 
 // Write out the PLT.
 
@@ -3019,7 +3222,6 @@ Target_powerpc<size, big_endian>::make_plt_section(Symbol_table* symtab,
 				      ORDER_DYNAMIC_PLT_RELOCS, false);
       this->plt_
 	= new Output_data_plt_powerpc<size, big_endian>(this, plt_rel,
-							size == 32 ? 0 : 24,
 							"** PLT");
       layout->add_output_section_data(".plt",
 				      (size == 32
@@ -3049,7 +3251,7 @@ Target_powerpc<size, big_endian>::make_iplt_section(Symbol_table* symtab,
       this->rela_dyn_->output_section()->add_output_section_data(iplt_rel);
       this->iplt_
 	= new Output_data_plt_powerpc<size, big_endian>(this, iplt_rel,
-							0, "** IPLT");
+							"** IPLT");
       this->plt_->output_section()->add_output_section_data(this->iplt_);
     }
 }
@@ -3225,8 +3427,8 @@ const unsigned char Eh_cie<size>::eh_frame_cie[] =
   elfcpp::DW_CFA_def_cfa, 1, 0		// def_cfa: r1 offset 0.
 };
 
-// Describe __glink_PLTresolve use of LR, 64-bit version.
-static const unsigned char glink_eh_frame_fde_64[] =
+// Describe __glink_PLTresolve use of LR, 64-bit version ABIv1.
+static const unsigned char glink_eh_frame_fde_64v1[] =
 {
   0, 0, 0, 0,				// Replaced with offset to .glink.
   0, 0, 0, 0,				// Replaced with size of .glink.
@@ -3237,6 +3439,18 @@ static const unsigned char glink_eh_frame_fde_64[] =
   elfcpp::DW_CFA_restore_extended, 65
 };
 
+// Describe __glink_PLTresolve use of LR, 64-bit version ABIv2.
+static const unsigned char glink_eh_frame_fde_64v2[] =
+{
+  0, 0, 0, 0,				// Replaced with offset to .glink.
+  0, 0, 0, 0,				// Replaced with size of .glink.
+  0,					// Augmentation size.
+  elfcpp::DW_CFA_advance_loc + 1,
+  elfcpp::DW_CFA_register, 65, 0,
+  elfcpp::DW_CFA_advance_loc + 4,
+  elfcpp::DW_CFA_restore_extended, 65
+};
+
 // Describe __glink_PLTresolve use of LR, 32-bit version.
 static const unsigned char glink_eh_frame_fde_32[] =
 {
@@ -3493,13 +3707,16 @@ class Stub_table : public Output_relaxed_input_section
       <const Powerpc_relobj<size, big_endian>*>(p->first.object_);
     got_addr += ppcobj->toc_base_offset();
     Address off = plt_addr - got_addr;
-    bool static_chain = parameters->options().plt_static_chain();
-    bool thread_safe = this->targ_->plt_thread_safe();
-    unsigned int bytes = (4 * 5
-			  + 4 * static_chain
-			  + 8 * thread_safe
-			  + 4 * (ha(off) != 0)
-			  + 4 * (ha(off + 8 + 8 * static_chain) != ha(off)));
+    unsigned int bytes = 4 * 4 + 4 * (ha(off) != 0);
+    if (this->targ_->abiversion() < 2)
+      {
+	bool static_chain = parameters->options().plt_static_chain();
+	bool thread_safe = this->targ_->plt_thread_safe();
+	bytes += (4
+		  + 4 * static_chain
+		  + 8 * thread_safe
+		  + 4 * (ha(off + 8 + 8 * static_chain) != ha(off)));
+      }
     unsigned int align = 1 << parameters->options().plt_align();
     if (align > 1)
       bytes = (bytes + align - 1) & -align;
@@ -3805,11 +4022,20 @@ class Output_data_glink : public Output_section_data
       return;
 
     if (size == 64)
-      layout->add_eh_frame_for_plt(this,
-				   Eh_cie<64>::eh_frame_cie,
-				   sizeof (Eh_cie<64>::eh_frame_cie),
-				   glink_eh_frame_fde_64,
-				   sizeof (glink_eh_frame_fde_64));
+      {
+	if (this->targ_->abiversion() < 2)
+	  layout->add_eh_frame_for_plt(this,
+				       Eh_cie<64>::eh_frame_cie,
+				       sizeof (Eh_cie<64>::eh_frame_cie),
+				       glink_eh_frame_fde_64v1,
+				       sizeof (glink_eh_frame_fde_64v1));
+	else
+	  layout->add_eh_frame_for_plt(this,
+				       Eh_cie<64>::eh_frame_cie,
+				       sizeof (Eh_cie<64>::eh_frame_cie),
+				       glink_eh_frame_fde_64v2,
+				       sizeof (glink_eh_frame_fde_64v2));
+      }
     else
       {
 	// 32-bit .glink can use the default since the CIE return
@@ -3869,9 +4095,13 @@ Output_data_glink<size, big_endian>::set_final_data_size()
 	  total += this->pltresolve_size;
 
 	  // space for branch table
-	  total += 8 * count;
-	  if (count > 0x8000)
-	    total += 4 * (count - 0x8000);
+	  total += 4 * count;
+	  if (this->targ_->abiversion() < 2)
+	    {
+	      total += 4 * count;
+	      if (count > 0x8000)
+		total += 4 * (count - 0x8000);
+	    }
 	}
     }
 
@@ -3934,8 +4164,11 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
 			   cs->first.object_->name().c_str(),
 			   cs->first.sym_->demangled_name().c_str());
 
-	      bool static_chain = parameters->options().plt_static_chain();
-	      bool thread_safe = this->targ_->plt_thread_safe();
+	      bool plt_load_toc = this->targ_->abiversion() < 2;
+	      bool static_chain
+		= plt_load_toc && parameters->options().plt_static_chain();
+	      bool thread_safe
+		= plt_load_toc && this->targ_->plt_thread_safe();
 	      bool use_fake_dep = false;
 	      Address cmp_branch_off = 0;
 	      if (thread_safe)
@@ -3962,47 +4195,78 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
 	      p = oview + cs->second;
 	      if (ha(off) != 0)
 		{
-		  write_insn<big_endian>(p, std_2_1 + 40),		p += 4;
-		  write_insn<big_endian>(p, addis_12_2 + ha(off)),	p += 4;
-		  write_insn<big_endian>(p, ld_11_12 + l(off)),		p += 4;
-		  if (ha(off + 8 + 8 * static_chain) != ha(off))
+		  write_insn<big_endian>(p, std_2_1 + this->targ_->stk_toc());
+		  p += 4;
+		  write_insn<big_endian>(p, addis_11_2 + ha(off));
+		  p += 4;
+		  write_insn<big_endian>(p, ld_12_11 + l(off));
+		  p += 4;
+		  if (plt_load_toc
+		      && ha(off + 8 + 8 * static_chain) != ha(off))
 		    {
-		      write_insn<big_endian>(p, addi_12_12 + l(off)),	p += 4;
+		      write_insn<big_endian>(p, addi_11_11 + l(off));
+		      p += 4;
 		      off = 0;
 		    }
-		  write_insn<big_endian>(p, mtctr_11),			p += 4;
-		  if (use_fake_dep)
+		  write_insn<big_endian>(p, mtctr_12);
+		  p += 4;
+		  if (plt_load_toc)
 		    {
-		      write_insn<big_endian>(p, xor_11_11_11),		p += 4;
-		      write_insn<big_endian>(p, add_12_12_11),		p += 4;
+		      if (use_fake_dep)
+			{
+			  write_insn<big_endian>(p, xor_2_12_12);
+			  p += 4;
+			  write_insn<big_endian>(p, add_11_11_2);
+			  p += 4;
+			}
+		      write_insn<big_endian>(p, ld_2_11 + l(off + 8));
+		      p += 4;
+		      if (static_chain)
+			{
+			  write_insn<big_endian>(p, ld_11_11 + l(off + 16));
+			  p += 4;
+			}
 		    }
-		  write_insn<big_endian>(p, ld_2_12 + l(off + 8)),	p += 4;
-		  if (static_chain)
-		    write_insn<big_endian>(p, ld_11_12 + l(off + 16)),	p += 4;
 		}
 	      else
 		{
-		  write_insn<big_endian>(p, std_2_1 + 40),		p += 4;
-		  write_insn<big_endian>(p, ld_11_2 + l(off)),		p += 4;
-		  if (ha(off + 8 + 8 * static_chain) != ha(off))
+		  write_insn<big_endian>(p, std_2_1 + this->targ_->stk_toc());
+		  p += 4;
+		  write_insn<big_endian>(p, ld_12_2 + l(off));
+		  p += 4;
+		  if (plt_load_toc
+		      && ha(off + 8 + 8 * static_chain) != ha(off))
 		    {
-		      write_insn<big_endian>(p, addi_2_2 + l(off)),	p += 4;
+		      write_insn<big_endian>(p, addi_2_2 + l(off));
+		      p += 4;
 		      off = 0;
 		    }
-		  write_insn<big_endian>(p, mtctr_11),			p += 4;
-		  if (use_fake_dep)
+		  write_insn<big_endian>(p, mtctr_12);
+		  p += 4;
+		  if (plt_load_toc)
 		    {
-		      write_insn<big_endian>(p, xor_11_11_11),		p += 4;
-		      write_insn<big_endian>(p, add_2_2_11),		p += 4;
+		      if (use_fake_dep)
+			{
+			  write_insn<big_endian>(p, xor_11_12_12);
+			  p += 4;
+			  write_insn<big_endian>(p, add_2_2_11);
+			  p += 4;
+			}
+		      if (static_chain)
+			{
+			  write_insn<big_endian>(p, ld_11_2 + l(off + 16));
+			  p += 4;
+			}
+		      write_insn<big_endian>(p, ld_2_2 + l(off + 8));
+		      p += 4;
 		    }
-		  if (static_chain)
-		    write_insn<big_endian>(p, ld_11_2 + l(off + 16)),	p += 4;
-		  write_insn<big_endian>(p, ld_2_2 + l(off + 8)),	p += 4;
 		}
 	      if (thread_safe && !use_fake_dep)
 		{
-		  write_insn<big_endian>(p, cmpldi_2_0),		p += 4;
-		  write_insn<big_endian>(p, bnectr_p4),			p += 4;
+		  write_insn<big_endian>(p, cmpldi_2_0);
+		  p += 4;
+		  write_insn<big_endian>(p, bnectr_p4);
+		  p += 4;
 		  write_insn<big_endian>(p, b | (cmp_branch_off & 0x3fffffc));
 		}
 	      else
@@ -4031,14 +4295,14 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
 	      Address brltoff = brlt_addr - got_addr;
 	      if (ha(brltoff) == 0)
 		{
-		  write_insn<big_endian>(p, ld_11_2 + l(brltoff)),	p += 4;
+		  write_insn<big_endian>(p, ld_12_2 + l(brltoff)),	p += 4;
 		}
 	      else
 		{
-		  write_insn<big_endian>(p, addis_12_2 + ha(brltoff)),	p += 4;
-		  write_insn<big_endian>(p, ld_11_12 + l(brltoff)),	p += 4;
+		  write_insn<big_endian>(p, addis_11_2 + ha(brltoff)),	p += 4;
+		  write_insn<big_endian>(p, ld_12_11 + l(brltoff)),	p += 4;
 		}
-	      write_insn<big_endian>(p, mtctr_11),			p += 4;
+	      write_insn<big_endian>(p, mtctr_12),			p += 4;
 	      write_insn<big_endian>(p, bctr);
 	    }
 	}
@@ -4180,16 +4444,34 @@ Output_data_glink<size, big_endian>::do_write(Output_file* of)
 
       elfcpp::Swap<64, big_endian>::writeval(p, pltoff),	p += 8;
 
-      write_insn<big_endian>(p, mflr_12),			p += 4;
-      write_insn<big_endian>(p, bcl_20_31),			p += 4;
-      write_insn<big_endian>(p, mflr_11),			p += 4;
-      write_insn<big_endian>(p, ld_2_11 + l(-16)),		p += 4;
-      write_insn<big_endian>(p, mtlr_12),			p += 4;
-      write_insn<big_endian>(p, add_12_2_11),			p += 4;
-      write_insn<big_endian>(p, ld_11_12 + 0),			p += 4;
-      write_insn<big_endian>(p, ld_2_12 + 8),			p += 4;
-      write_insn<big_endian>(p, mtctr_11),			p += 4;
-      write_insn<big_endian>(p, ld_11_12 + 16),			p += 4;
+      if (this->targ_->abiversion() < 2)
+	{
+	  write_insn<big_endian>(p, mflr_12),			p += 4;
+	  write_insn<big_endian>(p, bcl_20_31),			p += 4;
+	  write_insn<big_endian>(p, mflr_11),			p += 4;
+	  write_insn<big_endian>(p, ld_2_11 + l(-16)),		p += 4;
+	  write_insn<big_endian>(p, mtlr_12),			p += 4;
+	  write_insn<big_endian>(p, add_11_2_11),		p += 4;
+	  write_insn<big_endian>(p, ld_12_11 + 0),		p += 4;
+	  write_insn<big_endian>(p, ld_2_11 + 8),		p += 4;
+	  write_insn<big_endian>(p, mtctr_12),			p += 4;
+	  write_insn<big_endian>(p, ld_11_11 + 16),		p += 4;
+	}
+      else
+	{
+	  write_insn<big_endian>(p, mflr_0),			p += 4;
+	  write_insn<big_endian>(p, bcl_20_31),			p += 4;
+	  write_insn<big_endian>(p, mflr_11),			p += 4;
+	  write_insn<big_endian>(p, ld_2_11 + l(-16)),		p += 4;
+	  write_insn<big_endian>(p, mtlr_0),			p += 4;
+	  write_insn<big_endian>(p, sub_12_12_11),		p += 4;
+	  write_insn<big_endian>(p, add_11_2_11),		p += 4;
+	  write_insn<big_endian>(p, addi_0_12 + l(-48)),	p += 4;
+	  write_insn<big_endian>(p, ld_12_11 + 0),		p += 4;
+	  write_insn<big_endian>(p, srdi_0_0_2),		p += 4;
+	  write_insn<big_endian>(p, mtctr_12),			p += 4;
+	  write_insn<big_endian>(p, ld_11_11 + 8),		p += 4;
+	}
       write_insn<big_endian>(p, bctr),				p += 4;
       while (p < oview + this->pltresolve_size)
 	write_insn<big_endian>(p, nop), p += 4;
@@ -4198,14 +4480,17 @@ Output_data_glink<size, big_endian>::do_write(Output_file* of)
       uint32_t indx = 0;
       while (p < oview + oview_size)
 	{
-	  if (indx < 0x8000)
+	  if (this->targ_->abiversion() < 2)
 	    {
-	      write_insn<big_endian>(p, li_0_0 + indx),			p += 4;
-	    }
-	  else
-	    {
-	      write_insn<big_endian>(p, lis_0_0 + hi(indx)),		p += 4;
-	      write_insn<big_endian>(p, ori_0_0_0 + l(indx)),		p += 4;
+	      if (indx < 0x8000)
+		{
+		  write_insn<big_endian>(p, li_0_0 + indx),		p += 4;
+		}
+	      else
+		{
+		  write_insn<big_endian>(p, lis_0_0 + hi(indx)),	p += 4;
+		  write_insn<big_endian>(p, ori_0_0_0 + l(indx)),	p += 4;
+		}
 	    }
 	  uint32_t branch_off = 8 - (p - oview);
 	  write_insn<big_endian>(p, b + (branch_off & 0x3fffffc)),	p += 4;
@@ -4690,24 +4975,6 @@ Target_powerpc<size, big_endian>::plt_entry_count() const
   return this->plt_->entry_count();
 }
 
-// Return the offset of the first non-reserved PLT entry.
-
-template<int size, bool big_endian>
-unsigned int
-Target_powerpc<size, big_endian>::first_plt_entry_offset() const
-{
-  return this->plt_->first_plt_entry_offset();
-}
-
-// Return the size of each PLT entry.
-
-template<int size, bool big_endian>
-unsigned int
-Target_powerpc<size, big_endian>::plt_entry_size() const
-{
-  return Output_data_plt_powerpc<size, big_endian>::get_plt_entry_size();
-}
-
 // Create a GOT entry for local dynamic __tls_get_addr calls.
 
 template<int size, bool big_endian>
@@ -6403,7 +6670,8 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
 		  && (insn2 == nop
 		      || insn2 == cror_15_15_15 || insn2 == cror_31_31_31))
 		{
-		  elfcpp::Swap<32, big_endian>::writeval(wv + 1, ld_2_1 + 40);
+		  elfcpp::Swap<32, big_endian>::
+		    writeval(wv + 1, ld_2_1 + target->stk_toc());
 		  can_plt_call = true;
 		}
 	    }
@@ -6695,6 +6963,10 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
       if (r_type != elfcpp::R_PPC_PLTREL24)
 	addend = rela.get_r_addend();
       value = psymval->value(object, addend);
+      if (gsym != NULL)
+	value += object->ppc64_local_entry_offset(gsym);
+      else
+	value += object->ppc64_local_entry_offset(r_sym);
       if (size == 64 && is_branch_reloc(r_type))
 	value = target->symval_for_branch(relinfo->symtab, value,
 					  gsym, object, &dest_shndx);

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 0/9] PowerPC64 ELFv2 ABI support.
  2013-10-30  2:19 [PATCH 0/9] PowerPC64 ELFv2 ABI support Alan Modra
                   ` (8 preceding siblings ...)
  2013-10-30  2:44 ` [PATCH 9/9] PowerPC64 ELFv2 support for gold Alan Modra
@ 2013-10-30 17:25 ` Joseph S. Myers
  2013-10-31  7:47   ` Alan Modra
  2013-10-31  7:50 ` Matt Thomas
  10 siblings, 1 reply; 19+ messages in thread
From: Joseph S. Myers @ 2013-10-30 17:25 UTC (permalink / raw)
  To: Alan Modra; +Cc: binutils, powerabi

On Wed, 30 Oct 2013, Alan Modra wrote:

> This patch series makes the changes necessary in binutils to support
> the updated PowerPC64 ABI, which we're calling ELFv2.  Two major
> changes from the previous ABI are

Is there an actual ABI document for this (or one with the old/new 
variations tagged appropriately like in the 32-bit unified ABI)?

Are things changing that don't affect binutils (such as long double format 
as suggested for little-endian in 
<https://sourceware.org/ml/libc-alpha/2013-10/msg00597.html> - or the 
places where the function calling ABI is based on accidents of how GCC 
assigned machine modes to structures, rather than being anything that was 
particularly logically designed)?

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 4/9] Add ELFv2 .localentry support.
  2013-10-30  2:25 ` [PATCH 4/9] Add ELFv2 .localentry support Alan Modra
@ 2013-10-30 19:08   ` Richard Henderson
  2013-10-31  8:40     ` Alan Modra
  0 siblings, 1 reply; 19+ messages in thread
From: Richard Henderson @ 2013-10-30 19:08 UTC (permalink / raw)
  To: binutils

On 10/29/2013 07:25 PM, Alan Modra wrote:
> +/* The ELFv2 ABI uses three bits in the symbol st_other field of a
> +   function definition to specify the number of instructions between a
> +   function's global entry point and local entry point.
> +   The global entry point is used when it is necessary to set up the
> +   toc pointer (r2) for the function.  Callers must enter the global
> +   entry point with r12 set to the global entry point address.  On
> +   return from the function, r2 may have a different value to that
> +   which it had on entry.
> +   The local entry point is used when r2 is known to already be valid
> +   for the function.  There is no requirement on r12 when using the
> +   local entry point, and on return r2 will contain the same value as
> +   at entry.
> +   A value of zero in these bits means that the function has a single
> +   entry point with no requirement on r12 or r2, and that on return r2
> +   will contain the same value as at entry.
> +   Values of one and seven are reserved.  */
> +#define STO_PPC64_LOCAL_BIT		5
> +#define STO_PPC64_LOCAL_MASK		(7 << STO_PPC64_LOCAL_BIT)
> +
> +// 3 bit other field to bytes.
> +static inline unsigned int
> +ppc64_decode_local_entry(unsigned int other)
> +{
> +  return ((1 << other) >> 2) << 2;
> +}

Is this really the best definition?  How might one record that one that there
is no local entry point, i.e. one must always enter with r12 set to the global
entry address?

Why have you chosen an encoding that records powers of 2?  Are you really ever
going to have 32 insns in the global entry point before the local entry point?

I would have thought that one would pretty much always have exactly two insns
in the global entry point before the local entry point (addis+addi).  Reserving
3 bits would allow 0-7 insns to be skipped, which still seems way more than enough.

Compare your scheme with the one used on Alpha, where we have two bits in
s_other to optimize this.  If STO_ALPHA_NOPV is set, then local_entry ==
global_entry, equivalent to your st_other == 0 above.  If STO_ALPHA_STD_GPLOAD
is set, then local_entry == global_entry + 8.  If neither bit is set, then
there is no local_entry and the global_entry must be used.

For dealing with hand-written assembly, this requirement that the user actually
set the .localentry before local entry optimization occurs seems the safest route.


r~

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 0/9] PowerPC64 ELFv2 ABI support.
  2013-10-30 17:25 ` [PATCH 0/9] PowerPC64 ELFv2 ABI support Joseph S. Myers
@ 2013-10-31  7:47   ` Alan Modra
  2013-11-01 17:33     ` Joseph S. Myers
  0 siblings, 1 reply; 19+ messages in thread
From: Alan Modra @ 2013-10-31  7:47 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: binutils, powerabi

On Wed, Oct 30, 2013 at 05:25:25PM +0000, Joseph S. Myers wrote:
> On Wed, 30 Oct 2013, Alan Modra wrote:
> 
> > This patch series makes the changes necessary in binutils to support
> > the updated PowerPC64 ABI, which we're calling ELFv2.  Two major
> > changes from the previous ABI are
> 
> Is there an actual ABI document for this (or one with the old/new 
> variations tagged appropriately like in the 32-bit unified ABI)?

There is, but it's not ready for general release yet, I think.

> Are things changing that don't affect binutils (such as long double format 
> as suggested for little-endian in 
> <https://sourceware.org/ml/libc-alpha/2013-10/msg00597.html> - or the 

Long double is remaining as is for the time being, but I believe the
intent is to change to ieee128 at some point in the future.  More than
anything, it was time and resource constraints that prevented us
changing immediately.

> places where the function calling ABI is based on accidents of how GCC 
> assigned machine modes to structures, rather than being anything that was 
> particularly logically designed)?

The new ABI generally keeps the same conventions as the old one,
except that homgenous floating point or vector aggregates passed by
value will be passed in registers, and returned in registers if they
fit into 8 or fewer register.  We'll also return other structs up to a
certains size in general purpose registers.  So, yes, we'll be keeping
some accidents.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 0/9] PowerPC64 ELFv2 ABI support.
  2013-10-30  2:19 [PATCH 0/9] PowerPC64 ELFv2 ABI support Alan Modra
                   ` (9 preceding siblings ...)
  2013-10-30 17:25 ` [PATCH 0/9] PowerPC64 ELFv2 ABI support Joseph S. Myers
@ 2013-10-31  7:50 ` Matt Thomas
  2013-10-31 12:55   ` Alan Modra
  10 siblings, 1 reply; 19+ messages in thread
From: Matt Thomas @ 2013-10-31  7:50 UTC (permalink / raw)
  To: Alan Modra; +Cc: binutils


On Oct 29, 2013, at 7:19 PM, Alan Modra <amodra@gmail.com> wrote:

> This patch series makes the changes necessary in binutils to support
> the updated PowerPC64 ABI, which we're calling ELFv2.  Two major
> changes from the previous ABI are
> 
> - No function descriptors.

It would be nice if there was a similar ppc32 ABI which would make
sharing code between ppc32 and ppc64 easier.

> The global entry
>  point is the address stored in function pointers, and it is a
>  requirement that calls to the global entry point have that address
>  in r12.  

This sounds similar to ABICALLS on mips (where the function pointer
is stored in $25 (t9) upon call entry).  That value is used to derive
the $gp value by adding a constant (done by the linker) to the value
in $25.  One nice thing about the existing PPC64 ABI is that the toc 
pointer is independent of the PC and thus you can the text and 
non-text parts of a shareable library in independent parts of the 
address space.  One shared segment can have  all the read-only text 
segments and each process can have a private segment with the 
read-write segments.  If you switch to add value to r12 to get the 
toc, you can't share segments anymore.  

Unlike ABICALLS, I assume a plt is still used instead of fetching
the address of each function from the GOT and doing an indirect call.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 4/9] Add ELFv2 .localentry support.
  2013-10-30 19:08   ` Richard Henderson
@ 2013-10-31  8:40     ` Alan Modra
  0 siblings, 0 replies; 19+ messages in thread
From: Alan Modra @ 2013-10-31  8:40 UTC (permalink / raw)
  To: Richard Henderson; +Cc: binutils

On Wed, Oct 30, 2013 at 12:08:28PM -0700, Richard Henderson wrote:
> Is this really the best definition?  How might one record that one that there
> is no local entry point, i.e. one must always enter with r12 set to the global
> entry address?

You're correct, we don't allow that possibility, but it doesn't seem a
particularly useful option.  Why would you not want a local entry?

> Why have you chosen an encoding that records powers of 2?  Are you really ever
> going to have 32 insns in the global entry point before the local entry point?
> 
> I would have thought that one would pretty much always have exactly two insns
> in the global entry point before the local entry point (addis+addi).  Reserving
> 3 bits would allow 0-7 insns to be skipped, which still seems way more than enough.

The thought behind the encoding was to allow both global and local
entries to be cache line aligned.

It's true that current gcc support just generates addis,addi before
the local entry, but this really doesn't support -mcmodel=large
properly.  We'll need to change that to ld,add and store a 64-bit
offset before the function, or ld,b,dword offset,add.  There are other
interesting possibilities too..  For instance, if you align the toc
correctly then non-pic executables can just use a single lis.

> Compare your scheme with the one used on Alpha, where we have two bits in
> s_other to optimize this.  If STO_ALPHA_NOPV is set, then local_entry ==
> global_entry, equivalent to your st_other == 0 above.  If STO_ALPHA_STD_GPLOAD
> is set, then local_entry == global_entry + 8.  If neither bit is set, then
> there is no local_entry and the global_entry must be used.
> 
> For dealing with hand-written assembly, this requirement that the user actually
> set the .localentry before local entry optimization occurs seems the safest route.

We really have more stringent requirements on the global entry point,
and it's accidental use of the global entry, eg. fall through from one
function into another, that has caused some trouble with hand-written
assembly.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 0/9] PowerPC64 ELFv2 ABI support.
  2013-10-31  7:50 ` Matt Thomas
@ 2013-10-31 12:55   ` Alan Modra
  0 siblings, 0 replies; 19+ messages in thread
From: Alan Modra @ 2013-10-31 12:55 UTC (permalink / raw)
  To: Matt Thomas; +Cc: binutils

On Thu, Oct 31, 2013 at 12:49:58AM -0700, Matt Thomas wrote:
> 
> On Oct 29, 2013, at 7:19 PM, Alan Modra <amodra@gmail.com> wrote:
> 
> > This patch series makes the changes necessary in binutils to support
> > the updated PowerPC64 ABI, which we're calling ELFv2.  Two major
> > changes from the previous ABI are
> > 
> > - No function descriptors.
> 
> It would be nice if there was a similar ppc32 ABI which would make
> sharing code between ppc32 and ppc64 easier.

Well, yes..

> > The global entry
> >  point is the address stored in function pointers, and it is a
> >  requirement that calls to the global entry point have that address
> >  in r12.  
> 
> This sounds similar to ABICALLS on mips (where the function pointer
> is stored in $25 (t9) upon call entry).  That value is used to derive
> the $gp value by adding a constant (done by the linker) to the value
> in $25.

Yes.

>  One nice thing about the existing PPC64 ABI is that the toc 
> pointer is independent of the PC and thus you can the text and 
> non-text parts of a shareable library in independent parts of the 
> address space.  One shared segment can have  all the read-only text 
> segments and each process can have a private segment with the 
> read-write segments.  If you switch to add value to r12 to get the 
> toc, you can't share segments anymore.  

Another thing that was nice was no need for trampolines on the stack,
but we lose that when throwing out function descriptors.

> Unlike ABICALLS, I assume a plt is still used instead of fetching
> the address of each function from the GOT and doing an indirect call.

Right, but I'd like to try something like that on ELFv2 some day.
Since the code to do an indirect call shrinks a little with ELFv2,
inlining is more attractive.  I envisage a scheme where the compiler
emits the indirect call insns suitably marked so the linker can either
create a .plt entry (what we call .plt others call .got.plt), or edit
the indirect call back to a direct call as appropriate.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 0/9] PowerPC64 ELFv2 ABI support.
  2013-10-31  7:47   ` Alan Modra
@ 2013-11-01 17:33     ` Joseph S. Myers
  0 siblings, 0 replies; 19+ messages in thread
From: Joseph S. Myers @ 2013-11-01 17:33 UTC (permalink / raw)
  To: Alan Modra; +Cc: binutils, powerabi

On Thu, 31 Oct 2013, Alan Modra wrote:

> On Wed, Oct 30, 2013 at 05:25:25PM +0000, Joseph S. Myers wrote:
> > On Wed, 30 Oct 2013, Alan Modra wrote:
> > 
> > > This patch series makes the changes necessary in binutils to support
> > > the updated PowerPC64 ABI, which we're calling ELFv2.  Two major
> > > changes from the previous ABI are
> > 
> > Is there an actual ABI document for this (or one with the old/new 
> > variations tagged appropriately like in the 32-bit unified ABI)?
> 
> There is, but it's not ready for general release yet, I think.

Thanks.  FWIW, in the Power.org ABI TSC there was a suggestion we should 
work on updating the 64-bit ABI (for things such as VSX) having got the 
32-bit one done, but nothing ever came of it.  (There was some work on 
adding VSX to the 32-bit ABI - on the vsx branch of 
git://github.com/ryanarn/powerabi - though this tailed off without us 
getting a 1.1 release out.)

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 0/9] PowerPC64 ELFv2 ABI support.
  2013-11-04 20:32 Jack Carter
@ 2013-11-06  1:05 ` Alan Modra
  0 siblings, 0 replies; 19+ messages in thread
From: Alan Modra @ 2013-11-06  1:05 UTC (permalink / raw)
  To: Jack Carter; +Cc: binutils

On Mon, Nov 04, 2013 at 08:32:27PM +0000, Jack Carter wrote:
> Could you point me to the ELFv2 ABI documentation and has it been 
> registered anywhere official? My googling doesn't seem to be finding
> it.

As I said in a previous email, the updated ABI document isn't ready
for general release yet.  I expect it will appear on power.org
eventually.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 0/9] PowerPC64 ELFv2 ABI support.
@ 2013-11-04 20:32 Jack Carter
  2013-11-06  1:05 ` Alan Modra
  0 siblings, 1 reply; 19+ messages in thread
From: Jack Carter @ 2013-11-04 20:32 UTC (permalink / raw)
  To: amodra; +Cc: binutils


Alan,

Could you point me to the ELFv2 ABI documentation and has it been 
registered anywhere official? My googling doesn't seem to be finding
it.

Thanks,

Jack

On 10/29/2013 07:19 PM, Alan Modra wrote:> This patch series makes the changes necessary in binutils to support
> the updated PowerPC64 ABI, which we're calling ELFv2.  Two major
> changes from the previous ABI are
> 
> - No function descriptors.
>    Functions set up their got/toc pointer as necessary on entry.  The
>    plt consists of single dword addresses.  Function pointers point at
>    the function code.  To make this work efficiently with static
>    linking, functions have *two* entry points, one we call the "global
>    entry" and another we call the "local entry".  The global entry
>    point is the address stored in function pointers, and it is a
>    requirement that calls to the global entry point have that address
>    in r12.  This is no hardship since calls via function pointers or
>    the plt will always use a sequence that loads the address into a
>    general purpose register, moves it to the count register, then
>    branches to the count register.  We just needed to make sure r12 was
>    the gpr used.  The "local entry" is used when the toc pointer is
>    known to already be valid for the function, typically true for
>    static linking, allowing the toc pointer setup to be skipped.
> 
> - Reduced stack frame size.
>    We removed the compiler and linker save words, and removed the
>    parameter save area for most functions.  This means the minimum
>    stack frame overhead is reduced from 112 bytes to 32 bytes (for
>    functions that need a frame), and many functions will used just the
>    minimum.  After some debate, we decided to keep the stack back-chain
>    word.
> 
> The ABI's are incompatible.  It won't be possible to link old objects
> with new except in rare cases, or to use old shared libraries with new
> executables at run time.
> 
> The first two patches in this series make changes that affect the old
> ABI too, the first one fixing a hole in the PowerPC64 ABI, and the
> second one makes all stubs conform with the ELFv2 ABI requirement on
> r12.
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2013-11-06  1:05 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-10-30  2:19 [PATCH 0/9] PowerPC64 ELFv2 ABI support Alan Modra
2013-10-30  2:21 ` [PATCH 1/9] Report overflow on PowerPC64 @h and @ha relocations Alan Modra
2013-10-30  2:22 ` [PATCH 2/9] Change plt stubs to have destination in r12 Alan Modra
2013-10-30  2:23 ` [PATCH 3/9] Add .abiversion related support for ELFv2 Alan Modra
2013-10-30  2:25 ` [PATCH 4/9] Add ELFv2 .localentry support Alan Modra
2013-10-30 19:08   ` Richard Henderson
2013-10-31  8:40     ` Alan Modra
2013-10-30  2:26 ` [PATCH 5/9] ELFv2 stub, plt and glink changes Alan Modra
2013-10-30  2:29 ` [PATCH 6/9] Support ELFv2 stack frame Alan Modra
2013-10-30  2:30 ` [PATCH 7/9] Replace DT_PPC_TLSOPT with DT_PPC_OPT Alan Modra
2013-10-30  2:31 ` [PATCH 8/9] Add PowerPC64 ELFv2 tests Alan Modra
2013-10-30  2:44 ` [PATCH 9/9] PowerPC64 ELFv2 support for gold Alan Modra
2013-10-30 17:25 ` [PATCH 0/9] PowerPC64 ELFv2 ABI support Joseph S. Myers
2013-10-31  7:47   ` Alan Modra
2013-11-01 17:33     ` Joseph S. Myers
2013-10-31  7:50 ` Matt Thomas
2013-10-31 12:55   ` Alan Modra
2013-11-04 20:32 Jack Carter
2013-11-06  1:05 ` Alan Modra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).