* [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; 17+ 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] 17+ 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; 17+ 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] 17+ 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; 17+ 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] 17+ 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; 17+ 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] 17+ 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; 17+ 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] 17+ 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; 17+ 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] 17+ 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; 17+ 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] 17+ 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; 17+ 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] 17+ 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; 17+ 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] 17+ 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; 17+ 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] 17+ 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; 17+ 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] 17+ 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; 17+ 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] 17+ 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; 17+ 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] 17+ 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; 17+ 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] 17+ 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; 17+ 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] 17+ 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; 17+ 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] 17+ messages in thread