aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog29
-rw-r--r--bfd/bfd-in2.h10
-rw-r--r--bfd/coff-rs6000.c217
-rw-r--r--bfd/coff64-rs6000.c109
-rw-r--r--bfd/coffcode.h67
-rw-r--r--bfd/coffswap.h11
-rw-r--r--bfd/libbfd.h10
-rw-r--r--bfd/libxcoff.h1
-rw-r--r--bfd/reloc.c20
-rw-r--r--bfd/xcofflink.c18
-rw-r--r--gas/ChangeLog23
-rw-r--r--gas/config/tc-ppc.c231
-rw-r--r--gas/config/tc-ppc.h17
-rw-r--r--include/ChangeLog12
-rw-r--r--include/coff/internal.h9
-rw-r--r--include/coff/rs6000.h50
-rw-r--r--include/coff/rs6k64.h54
-rw-r--r--include/coff/xcoff.h19
-rw-r--r--ld/ChangeLog15
-rw-r--r--ld/emultempl/aix.em38
-rw-r--r--ld/scripttempl/aix.sc30
-rw-r--r--ld/testsuite/ld-powerpc/aix-tls-reloc-32.d35
-rw-r--r--ld/testsuite/ld-powerpc/aix-tls-reloc-64.d31
-rw-r--r--ld/testsuite/ld-powerpc/aix-tls-reloc.ex1
-rw-r--r--ld/testsuite/ld-powerpc/aix-tls-reloc.s65
-rw-r--r--ld/testsuite/ld-powerpc/aix-tls-section-32.d15
-rw-r--r--ld/testsuite/ld-powerpc/aix-tls-section-64.d15
-rw-r--r--ld/testsuite/ld-powerpc/aix-tls-section.ex2
-rw-r--r--ld/testsuite/ld-powerpc/aix-tls-section.s8
-rw-r--r--ld/testsuite/ld-powerpc/aix52.exp10
30 files changed, 1039 insertions, 133 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index d955f78..6d61abe 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,5 +1,34 @@
2021-03-12 Clément Chigot <clement.chigot@atos.net>
+ * reloc.c (BFD_RELOC_PPC_TLS_LE, BFD_RELOC_PPC_TLS_IE,
+ BFD_RELOC_PPC_TLS_M, BFD_RELOC_PPC_TLS_ML, BFD_RELOC_PPC64_TLS_GD,
+ BFD_RELOC_PPC64_TLS_LD, BFD_RELOC_PPC64_TLS_LE,
+ BFD_RELOC_PPC64_TLS_IE, BFD_RELOC_PPC64_TLS_M,
+ BFD_RELOC_PPC64_TLS_ML): New relocations.
+ * bfd-in2.h: Regenerate.
+ * libbfd.h: Regenerate.
+ * coff-rs6000.c (xcoff_calculate_relocation): Call
+ xcoff_reloc_type_tls for TLS relocations.
+ (xcoff_howto_table): Implement TLS relocations.
+ (_bfd_xcoff_reloc_type_lookup): Add cases TLS relocations.
+ (xcoff_reloc_type_tls): New function.
+ * coff64-rs6000.c (xcoff_calculate_relocation): Likewise.
+ (xcoff_howto_table): Likewise.
+ (_bfd_xcoff_reloc_type_lookup): Likewise.
+ * coffcode.h (sec_to_styp_flags): Handle TLS sections.
+ (styp_to_sec_flags): Likewise.
+ (coff_compute_section_file_positions): Avoid file offset
+ optimisation for .data when the previous section is .tdata.
+ (coff_write_object_contents): Handle TLS sections.
+ * coffswap.h (coff_swap_aouthdr_out): Add support for
+ new fields in aouthdr.
+ * libxcoff.h (xcoff_reloc_type_tls): Add prototype.
+ * xcofflink.c (xcoff_link_add_symbols): Handle XMC_UL.
+ (xcoff_need_ldrel_p): Add cases for TLS relocations.
+ (xcoff_create_ldrel): Add l_symndx for TLS sections.
+
+2021-03-12 Clément Chigot <clement.chigot@atos.net>
+
* reloc.c (BFD_RELOC_PPC_TOC16_HI, BFD_RELOC_PPC_TOC16_LO):
New relocations.
* bfd-in2.h: Regenerate.
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 9bd61b1..54c1c9a 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -3003,6 +3003,10 @@ instruction. */
BFD_RELOC_PPC_TLS,
BFD_RELOC_PPC_TLSGD,
BFD_RELOC_PPC_TLSLD,
+ BFD_RELOC_PPC_TLSLE,
+ BFD_RELOC_PPC_TLSIE,
+ BFD_RELOC_PPC_TLSM,
+ BFD_RELOC_PPC_TLSML,
BFD_RELOC_PPC_DTPMOD,
BFD_RELOC_PPC_TPREL16,
BFD_RELOC_PPC_TPREL16_LO,
@@ -3030,6 +3034,12 @@ instruction. */
BFD_RELOC_PPC_GOT_DTPREL16_LO,
BFD_RELOC_PPC_GOT_DTPREL16_HI,
BFD_RELOC_PPC_GOT_DTPREL16_HA,
+ BFD_RELOC_PPC64_TLSGD,
+ BFD_RELOC_PPC64_TLSLD,
+ BFD_RELOC_PPC64_TLSLE,
+ BFD_RELOC_PPC64_TLSIE,
+ BFD_RELOC_PPC64_TLSM,
+ BFD_RELOC_PPC64_TLSML,
BFD_RELOC_PPC64_TPREL16_DS,
BFD_RELOC_PPC64_TPREL16_LO_DS,
BFD_RELOC_PPC64_TPREL16_HIGH,
diff --git a/bfd/coff-rs6000.c b/bfd/coff-rs6000.c
index b77ff0c..a29cf5b 100644
--- a/bfd/coff-rs6000.c
+++ b/bfd/coff-rs6000.c
@@ -190,12 +190,12 @@ xcoff_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION] =
xcoff_reloc_type_fail, /* (0x1d) */
xcoff_reloc_type_fail, /* (0x1e) */
xcoff_reloc_type_fail, /* (0x1f) */
- xcoff_reloc_type_fail, /* R_TLS (0x20) */
- xcoff_reloc_type_fail, /* R_TLS_IE (0x21) */
- xcoff_reloc_type_fail, /* R_TLS_LD (0x22) */
- xcoff_reloc_type_fail, /* R_TLS_LE (0x23) */
- xcoff_reloc_type_fail, /* R_TLSM (0x24) */
- xcoff_reloc_type_fail, /* R_TLSML (0x25) */
+ xcoff_reloc_type_tls, /* R_TLS (0x20) */
+ xcoff_reloc_type_tls, /* R_TLS_IE (0x21) */
+ xcoff_reloc_type_tls, /* R_TLS_LD (0x22) */
+ xcoff_reloc_type_tls, /* R_TLS_LE (0x23) */
+ xcoff_reloc_type_tls, /* R_TLSM (0x24) */
+ xcoff_reloc_type_tls, /* R_TLSML (0x25) */
xcoff_reloc_type_fail, /* (0x26) */
xcoff_reloc_type_fail, /* (0x27) */
xcoff_reloc_type_fail, /* (0x28) */
@@ -1064,22 +1064,95 @@ reloc_howto_type xcoff_howto_table[] =
EMPTY_HOWTO (0x1f),
/* 0x20: General-dynamic TLS relocation. */
- EMPTY_HOWTO (R_TLS),
+ HOWTO (R_TLS, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ 0, /* special_function */
+ "R_TLS", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
/* 0x21: Initial-exec TLS relocation. */
- EMPTY_HOWTO (R_TLS_IE),
+ HOWTO (R_TLS_IE, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ 0, /* special_function */
+ "R_TLS_IE", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
/* 0x22: Local-dynamic TLS relocation. */
- EMPTY_HOWTO (R_TLS_LD),
+ HOWTO (R_TLS_LD, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ 0, /* special_function */
+ "R_TLS_LD", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
/* 0x23: Local-exec TLS relocation. */
- EMPTY_HOWTO (R_TLS_LE),
+ HOWTO (R_TLS_LE, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ 0, /* special_function */
+ "R_TLS_LE", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
/* 0x24: TLS relocation. */
- EMPTY_HOWTO(R_TLSM),
+ HOWTO (R_TLSM, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ 0, /* special_function */
+ "R_TLSM", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
/* 0x25: TLS module relocation. */
- EMPTY_HOWTO(R_TLSML),
+ HOWTO (R_TLSML, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ 0, /* special_function */
+ "R_TLSM", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
EMPTY_HOWTO(0x26),
EMPTY_HOWTO(0x27),
@@ -1180,6 +1253,18 @@ _bfd_xcoff_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
return &xcoff_howto_table[0];
case BFD_RELOC_NONE:
return &xcoff_howto_table[0xf];
+ case BFD_RELOC_PPC_TLSGD:
+ return &xcoff_howto_table[0x20];
+ case BFD_RELOC_PPC_TLSIE:
+ return &xcoff_howto_table[0x21];
+ case BFD_RELOC_PPC_TLSLD:
+ return &xcoff_howto_table[0x22];
+ case BFD_RELOC_PPC_TLSLE:
+ return &xcoff_howto_table[0x23];
+ case BFD_RELOC_PPC_TLSM:
+ return &xcoff_howto_table[0x24];
+ case BFD_RELOC_PPC_TLSML:
+ return &xcoff_howto_table[0x25];
default:
return NULL;
}
@@ -3127,6 +3212,88 @@ xcoff_reloc_type_crel (bfd *input_bfd ATTRIBUTE_UNUSED,
return TRUE;
}
+bfd_boolean
+xcoff_reloc_type_tls (bfd *input_bfd ATTRIBUTE_UNUSED,
+ asection *input_section ATTRIBUTE_UNUSED,
+ bfd *output_bfd ATTRIBUTE_UNUSED,
+ struct internal_reloc *rel ATTRIBUTE_UNUSED,
+ struct internal_syment *sym ATTRIBUTE_UNUSED,
+ struct reloc_howto_struct *howto,
+ bfd_vma val,
+ bfd_vma addend,
+ bfd_vma *relocation,
+ bfd_byte *contents ATTRIBUTE_UNUSED)
+{
+ struct xcoff_link_hash_entry *h;
+
+ if (0 > rel->r_symndx)
+ return FALSE;
+
+ h = obj_xcoff_sym_hashes (input_bfd)[rel->r_symndx];
+
+ /* FIXME: R_TLSML is targeting a internal TOC symbol, which will
+ make the following checks failing. It should be moved with
+ R_TLSM bellow once it works. */
+ if (howto->type == R_TLSML)
+ {
+ *relocation = 0;
+ return TRUE;
+ }
+
+ /* FIXME: h is sometimes null, if the TLS symbol is not exported. */
+ if (!h)
+ {
+ _bfd_error_handler
+ (_("%pB: TLS relocation at (0x%" BFD_VMA_FMT "x) over "
+ "internal symbols (C_HIDEXT) not yet possible\n"),
+ input_bfd, rel->r_vaddr);
+ return FALSE;
+ }
+
+
+ /* TLS relocations must target a TLS symbol. */
+ if (h->smclas != XMC_TL && h->smclas != XMC_UL)
+ {
+ _bfd_error_handler
+ (_("%pB: TLS relocation at (0x%" BFD_VMA_FMT "x) over "
+ "non-TLS symbol %s (0x%x)\n"),
+ input_bfd, rel->r_vaddr, h->root.root.string, h->smclas);
+ return FALSE;
+ }
+
+ /* Local TLS relocations must target a local symbol, ie
+ non-imported. */
+ if ((rel->r_type == R_TLS_LD || rel->r_type == R_TLS_LE)
+ && (((h->flags & XCOFF_DEF_REGULAR) == 0
+ && (h->flags & XCOFF_DEF_DYNAMIC) != 0)
+ || (h->flags & XCOFF_IMPORT) != 0))
+ {
+ _bfd_error_handler
+ (_("%pB: TLS local relocation at (0x%" BFD_VMA_FMT "x) over "
+ "imported symbol %s\n"),
+ input_bfd, rel->r_vaddr, h->root.root.string);
+ return FALSE;
+ }
+
+ /* R_TLSM and R_TLSML are relocations used by the loader.
+ The value must be 0.
+ FIXME: move R_TLSML here. */
+ if (howto->type == R_TLSM)
+ {
+ *relocation = 0;
+ return TRUE;
+ }
+
+ /* Other TLS relocations aims to put offsets from TLS pointers
+ starting at -0x7c00 (or -0x7800 in XCOFF64). It becomes a
+ simple R_POS relocation as long as .tdata and .tbss addresses
+ start at the same value. This is done in aix ld scripts.
+ TODO: implement optimization when tls size is < 62K. */
+ *relocation = val + addend;
+
+ return TRUE;
+}
+
static bfd_boolean
xcoff_complain_overflow_dont_func (bfd *input_bfd ATTRIBUTE_UNUSED,
bfd_vma val ATTRIBUTE_UNUSED,
@@ -3335,13 +3502,6 @@ xcoff_complain_overflow_unsigned_func (bfd *input_bfd,
quite figure out when this is useful. These relocs are
not defined by the PowerOpen ABI.
- R_TLS
- R_TLS_IE
- R_TLS_LD
- R_TLSLE
-
- Not yet implemented.
-
Supported r_type's
R_POS:
@@ -3437,6 +3597,25 @@ xcoff_complain_overflow_unsigned_func (bfd *input_bfd,
fixed address which may be modified to a relative branch.
The PowerOpen ABI does not define this relocation type.
+ R_TLS:
+ Thread-local storage relocation using general-dynamic
+ model.
+
+ R_TLS_IE:
+ Thread-local storage relocation using initial-exec model.
+
+ R_TLS_LD:
+ Thread-local storage relocation using local-dynamic model.
+
+ R_TLS_LE:
+ Thread-local storage relocation using local-exec model.
+
+ R_TLS:
+ Tread-local storage relocation used by the loader.
+
+ R_TLSM:
+ Tread-local storage relocation used by the loader.
+
R_TOCU:
Upper TOC relative relocation. The value is the
high-order 16 bit of a TOC relative relocation.
diff --git a/bfd/coff64-rs6000.c b/bfd/coff64-rs6000.c
index 55a6821..f8e6849 100644
--- a/bfd/coff64-rs6000.c
+++ b/bfd/coff64-rs6000.c
@@ -212,12 +212,12 @@ xcoff64_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION] =
xcoff_reloc_type_fail, /* (0x1d) */
xcoff_reloc_type_fail, /* (0x1e) */
xcoff_reloc_type_fail, /* (0x1f) */
- xcoff_reloc_type_fail, /* R_TLS (0x20) */
- xcoff_reloc_type_fail, /* R_TLS_IE (0x21) */
- xcoff_reloc_type_fail, /* R_TLS_LD (0x22) */
- xcoff_reloc_type_fail, /* R_TLS_LE (0x23) */
- xcoff_reloc_type_fail, /* R_TLSM (0x24) */
- xcoff_reloc_type_fail, /* R_TLSML (0x25) */
+ xcoff_reloc_type_tls, /* R_TLS (0x20) */
+ xcoff_reloc_type_tls, /* R_TLS_IE (0x21) */
+ xcoff_reloc_type_tls, /* R_TLS_LD (0x22) */
+ xcoff_reloc_type_tls, /* R_TLS_LE (0x23) */
+ xcoff_reloc_type_tls, /* R_TLSM (0x24) */
+ xcoff_reloc_type_tls, /* R_TLSML (0x25) */
xcoff_reloc_type_fail, /* (0x26) */
xcoff_reloc_type_fail, /* (0x27) */
xcoff_reloc_type_fail, /* (0x28) */
@@ -1230,24 +1230,95 @@ reloc_howto_type xcoff64_howto_table[] =
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
-
/* 0x20: General-dynamic TLS relocation. */
- EMPTY_HOWTO (R_TLS),
+ HOWTO (R_TLS, /* type */
+ 0, /* rightshift */
+ 4, /* size (0 = byte, 1 = short, 2 = long) */
+ 64, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ 0, /* special_function */
+ "R_TLS", /* name */
+ TRUE, /* partial_inplace */
+ MINUS_ONE, /* src_mask */
+ MINUS_ONE, /* dst_mask */
+ FALSE), /* pcrel_offset */
/* 0x21: Initial-exec TLS relocation. */
- EMPTY_HOWTO (R_TLS_IE),
+ HOWTO (R_TLS_IE, /* type */
+ 0, /* rightshift */
+ 4, /* size (0 = byte, 1 = short, 2 = long) */
+ 64, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ 0, /* special_function */
+ "R_TLS_IE", /* name */
+ TRUE, /* partial_inplace */
+ MINUS_ONE, /* src_mask */
+ MINUS_ONE, /* dst_mask */
+ FALSE), /* pcrel_offset */
/* 0x22: Local-dynamic TLS relocation. */
- EMPTY_HOWTO (R_TLS_LD),
+ HOWTO (R_TLS_LD, /* type */
+ 0, /* rightshift */
+ 4, /* size (0 = byte, 1 = short, 2 = long) */
+ 64, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ 0, /* special_function */
+ "R_TLS_LD", /* name */
+ TRUE, /* partial_inplace */
+ MINUS_ONE, /* src_mask */
+ MINUS_ONE, /* dst_mask */
+ FALSE), /* pcrel_offset */
/* 0x23: Local-exec TLS relocation. */
- EMPTY_HOWTO (R_TLS_LE),
+ HOWTO (R_TLS_LE, /* type */
+ 0, /* rightshift */
+ 4, /* size (0 = byte, 1 = short, 2 = long) */
+ 64, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ 0, /* special_function */
+ "R_TLS_LE", /* name */
+ TRUE, /* partial_inplace */
+ MINUS_ONE, /* src_mask */
+ MINUS_ONE, /* dst_mask */
+ FALSE), /* pcrel_offset */
/* 0x24: TLS relocation. */
- EMPTY_HOWTO(R_TLSM),
+ HOWTO (R_TLSM, /* type */
+ 0, /* rightshift */
+ 4, /* size (0 = byte, 1 = short, 2 = long) */
+ 64, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ 0, /* special_function */
+ "R_TLSM", /* name */
+ TRUE, /* partial_inplace */
+ MINUS_ONE, /* src_mask */
+ MINUS_ONE, /* dst_mask */
+ FALSE), /* pcrel_offset */
/* 0x25: TLS module relocation. */
- EMPTY_HOWTO(R_TLSML),
+ HOWTO (R_TLSML, /* type */
+ 0, /* rightshift */
+ 4, /* size (0 = byte, 1 = short, 2 = long) */
+ 64, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ 0, /* special_function */
+ "R_TLSM", /* name */
+ TRUE, /* partial_inplace */
+ MINUS_ONE, /* src_mask */
+ MINUS_ONE, /* dst_mask */
+ FALSE), /* pcrel_offset */
EMPTY_HOWTO(0x26),
EMPTY_HOWTO(0x27),
@@ -1355,6 +1426,18 @@ xcoff64_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
return &xcoff64_howto_table[0];
case BFD_RELOC_NONE:
return &xcoff64_howto_table[0xf];
+ case BFD_RELOC_PPC64_TLSGD:
+ return &xcoff64_howto_table[0x20];
+ case BFD_RELOC_PPC64_TLSIE:
+ return &xcoff64_howto_table[0x21];
+ case BFD_RELOC_PPC64_TLSLD:
+ return &xcoff64_howto_table[0x22];
+ case BFD_RELOC_PPC64_TLSLE:
+ return &xcoff64_howto_table[0x23];
+ case BFD_RELOC_PPC64_TLSM:
+ return &xcoff64_howto_table[0x24];
+ case BFD_RELOC_PPC64_TLSML:
+ return &xcoff64_howto_table[0x25];
default:
return NULL;
}
diff --git a/bfd/coffcode.h b/bfd/coffcode.h
index b0ca266..bcd34d4 100644
--- a/bfd/coffcode.h
+++ b/bfd/coffcode.h
@@ -548,6 +548,14 @@ sec_to_styp_flags (const char *sec_name, flagword sec_flags)
}
#endif
#ifdef RS6000COFF_C
+ else if (!strcmp (sec_name, _TDATA))
+ {
+ styp_flags = STYP_TDATA;
+ }
+ else if (!strcmp (sec_name, _TBSS))
+ {
+ styp_flags = STYP_TBSS;
+ }
else if (!strcmp (sec_name, _PAD))
{
styp_flags = STYP_PAD;
@@ -787,6 +795,22 @@ styp_to_sec_flags (bfd *abfd,
else if (styp_flags & STYP_PAD)
sec_flags = 0;
#ifdef RS6000COFF_C
+ else if (styp_flags & STYP_TDATA)
+ {
+ if (sec_flags & SEC_NEVER_LOAD)
+ sec_flags |= SEC_DATA | SEC_THREAD_LOCAL | SEC_COFF_SHARED_LIBRARY;
+ else
+ sec_flags |= SEC_DATA | SEC_THREAD_LOCAL | SEC_LOAD | SEC_ALLOC;
+ }
+ else if (styp_flags & STYP_TBSS)
+ {
+#ifdef BSS_NOLOAD_IS_SHARED_LIBRARY
+ if (sec_flags & SEC_NEVER_LOAD)
+ sec_flags |= SEC_ALLOC | SEC_THREAD_LOCAL | SEC_COFF_SHARED_LIBRARY;
+ else
+#endif
+ sec_flags |= SEC_ALLOC | SEC_THREAD_LOCAL;
+ }
else if (styp_flags & STYP_EXCEPT)
sec_flags |= SEC_LOAD;
else if (styp_flags & STYP_LOADER)
@@ -3168,10 +3192,15 @@ coff_compute_section_file_positions (bfd * abfd)
0 .text 000054cc 10000128 10000128 00000128 2**5
CONTENTS, ALLOC, LOAD, CODE
+
+ Don't perform the above tweak if the previous one is .tdata,
+ as it will increase the memory allocated for every threads
+ created and not just improve performances with gdb.
*/
- if (!strcmp (current->name, _TEXT)
- || !strcmp (current->name, _DATA))
+ if ((!strcmp (current->name, _TEXT)
+ || !strcmp (current->name, _DATA))
+ && (previous == NULL || strcmp(previous->name, _TDATA)))
{
bfd_vma align = 4096;
bfd_vma sofar_off = sofar % align;
@@ -3381,6 +3410,10 @@ coff_write_object_contents (bfd * abfd)
asection *text_sec = NULL;
asection *data_sec = NULL;
asection *bss_sec = NULL;
+#ifdef RS6000COFF_C
+ asection *tdata_sec = NULL;
+ asection *tbss_sec = NULL;
+#endif
struct internal_filehdr internal_f;
struct internal_aouthdr internal_a;
#ifdef COFF_LONG_SECTION_NAMES
@@ -3603,6 +3636,13 @@ coff_write_object_contents (bfd * abfd)
data_sec = current;
else if (!strcmp (current->name, _BSS))
bss_sec = current;
+#ifdef RS6000COFF_C
+ else if (!strcmp (current->name, _TDATA))
+ tdata_sec = current;
+ else if (!strcmp (current->name, _TBSS))
+ tbss_sec = current;
+#endif
+
#ifdef COFF_ENCODE_ALIGNMENT
COFF_ENCODE_ALIGNMENT(section, current->alignment_power);
@@ -4041,6 +4081,29 @@ coff_write_object_contents (bfd * abfd)
else
internal_a.o_snbss = 0;
+ if (tdata_sec != NULL)
+ {
+ internal_a.o_sntdata = tdata_sec->target_index;
+ /* TODO: o_flags should be set to RS6K_AOUTHDR_TLS_LE
+ if there is at least one R_TLS_LE relocations. */
+ internal_a.o_flags = 0;
+#ifdef XCOFF64
+ internal_a.o_x64flags = 0;
+#endif
+ }
+ else
+ {
+ internal_a.o_sntdata = 0;
+ internal_a.o_flags = 0;
+#ifdef XCOFF64
+ internal_a.o_x64flags = 0;
+#endif
+ }
+ if (tbss_sec != NULL)
+ internal_a.o_sntbss = tbss_sec->target_index;
+ else
+ internal_a.o_sntbss = 0;
+
toc = xcoff_data (abfd)->toc;
internal_a.o_toc = toc;
internal_a.o_sntoc = xcoff_data (abfd)->sntoc;
diff --git a/bfd/coffswap.h b/bfd/coffswap.h
index b97b66c..63a0026 100644
--- a/bfd/coffswap.h
+++ b/bfd/coffswap.h
@@ -695,9 +695,16 @@ coff_swap_aouthdr_out (bfd * abfd, void * in, void * out)
H_PUT_32 (abfd, aouthdr_in->o_maxstack, aouthdr_out->o_maxstack);
H_PUT_32 (abfd, aouthdr_in->o_maxdata, aouthdr_out->o_maxdata);
#endif
- memset (aouthdr_out->o_resv2, 0, sizeof aouthdr_out->o_resv2);
+ /* TODO: set o_*psize dynamically */
+ H_PUT_8 (abfd, 0, aouthdr_out->o_textpsize);
+ H_PUT_8 (abfd, 0, aouthdr_out->o_datapsize);
+ H_PUT_8 (abfd, 0, aouthdr_out->o_stackpsize);
+ H_PUT_8 (abfd, aouthdr_in->o_flags, aouthdr_out->o_flags);
+ H_PUT_16 (abfd, aouthdr_in->o_sntdata, aouthdr_out->o_sntdata);
+ H_PUT_16 (abfd, aouthdr_in->o_sntbss, aouthdr_out->o_sntbss);
+ H_PUT_32 (abfd, 0, aouthdr_out->o_debugger);
#ifdef XCOFF64
- memset (aouthdr_out->o_debugger, 0, sizeof aouthdr_out->o_debugger);
+ H_PUT_16 (abfd, aouthdr_in->o_x64flags, aouthdr_out->o_x64flags);
memset (aouthdr_out->o_resv3, 0, sizeof aouthdr_out->o_resv3);
#endif
#endif
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 62b6bf8..9cb079e 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -1564,6 +1564,10 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_RELOC_PPC_TLS",
"BFD_RELOC_PPC_TLSGD",
"BFD_RELOC_PPC_TLSLD",
+ "BFD_RELOC_PPC_TLSLE",
+ "BFD_RELOC_PPC_TLSIE",
+ "BFD_RELOC_PPC_TLSM",
+ "BFD_RELOC_PPC_TLSML",
"BFD_RELOC_PPC_DTPMOD",
"BFD_RELOC_PPC_TPREL16",
"BFD_RELOC_PPC_TPREL16_LO",
@@ -1591,6 +1595,12 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_RELOC_PPC_GOT_DTPREL16_LO",
"BFD_RELOC_PPC_GOT_DTPREL16_HI",
"BFD_RELOC_PPC_GOT_DTPREL16_HA",
+ "BFD_RELOC_PPC64_TLSGD",
+ "BFD_RELOC_PPC64_TLSLD",
+ "BFD_RELOC_PPC64_TLSLE",
+ "BFD_RELOC_PPC64_TLSIE",
+ "BFD_RELOC_PPC64_TLSM",
+ "BFD_RELOC_PPC64_TLSML",
"BFD_RELOC_PPC64_TPREL16_DS",
"BFD_RELOC_PPC64_TPREL16_LO_DS",
"BFD_RELOC_PPC64_TPREL16_HIGH",
diff --git a/bfd/libxcoff.h b/bfd/libxcoff.h
index 229e47c..bffdee2 100644
--- a/bfd/libxcoff.h
+++ b/bfd/libxcoff.h
@@ -234,6 +234,7 @@ extern xcoff_reloc_function xcoff_reloc_type_rel;
extern xcoff_reloc_function xcoff_reloc_type_toc;
extern xcoff_reloc_function xcoff_reloc_type_ba;
extern xcoff_reloc_function xcoff_reloc_type_crel;
+extern xcoff_reloc_function xcoff_reloc_type_tls;
/* Structure to describe dwarf sections.
Useful to convert from XCOFF section name to flag and vice-versa.
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 6864521..6fae177 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -2944,6 +2944,14 @@ ENUMX
ENUMX
BFD_RELOC_PPC_TLSLD
ENUMX
+ BFD_RELOC_PPC_TLSLE
+ENUMX
+ BFD_RELOC_PPC_TLSIE
+ENUMX
+ BFD_RELOC_PPC_TLSM
+ENUMX
+ BFD_RELOC_PPC_TLSML
+ENUMX
BFD_RELOC_PPC_DTPMOD
ENUMX
BFD_RELOC_PPC_TPREL16
@@ -2998,6 +3006,18 @@ ENUMX
ENUMX
BFD_RELOC_PPC_GOT_DTPREL16_HA
ENUMX
+ BFD_RELOC_PPC64_TLSGD
+ENUMX
+ BFD_RELOC_PPC64_TLSLD
+ENUMX
+ BFD_RELOC_PPC64_TLSLE
+ENUMX
+ BFD_RELOC_PPC64_TLSIE
+ENUMX
+ BFD_RELOC_PPC64_TLSM
+ENUMX
+ BFD_RELOC_PPC64_TLSML
+ENUMX
BFD_RELOC_PPC64_TPREL16_DS
ENUMX
BFD_RELOC_PPC64_TPREL16_LO_DS
diff --git a/bfd/xcofflink.c b/bfd/xcofflink.c
index f0d6c8d..f0dd0e9 100644
--- a/bfd/xcofflink.c
+++ b/bfd/xcofflink.c
@@ -1814,6 +1814,12 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
csect = bfd_make_section_anyway_with_flags (abfd, ".td",
SEC_ALLOC);
}
+ else if (aux.x_csect.x_smclas == XMC_UL)
+ {
+ /* This is a thread-local unitialized csect. */
+ csect = bfd_make_section_anyway_with_flags (abfd, ".tbss",
+ SEC_ALLOC | SEC_THREAD_LOCAL);
+ }
else
csect = bfd_make_section_anyway_with_flags (abfd, ".bss",
SEC_ALLOC);
@@ -2697,6 +2703,14 @@ xcoff_need_ldrel_p (struct bfd_link_info *info, struct internal_reloc *rel,
return FALSE;
}
return TRUE;
+
+ case R_TLS:
+ case R_TLS_LE:
+ case R_TLS_IE:
+ case R_TLS_LD:
+ case R_TLSM:
+ case R_TLSML:
+ return TRUE;
}
}
@@ -4060,6 +4074,10 @@ xcoff_create_ldrel (bfd *output_bfd, struct xcoff_final_link_info *flinfo,
ldrel.l_symndx = 1;
else if (strcmp (secname, ".bss") == 0)
ldrel.l_symndx = 2;
+ else if (strcmp (secname, ".tdata") == 0)
+ ldrel.l_symndx = -1;
+ else if (strcmp (secname, ".tbss") == 0)
+ ldrel.l_symndx = -2;
else
{
_bfd_error_handler
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 3713209..01161d5 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,5 +1,28 @@
2021-03-12 Clément Chigot <clement.chigot@atos.net>
+ * config/tc-ppc.c (ppc_xcoff_text_section, ppc_xcoff_data_section,
+ (ppc_xcoff_bss_section, ppc_xcoff_tdata_section,
+ (ppc_xcoff_tbss_section): New variables.
+ (ppc_text_subsegment, ppc_text_csects, ppc_data_subgments,
+ (ppc_data_csects): Removed.
+ (ppc_xcoff_section_is_initialized, ppc_init_xcoff_section,
+ ppc_xcoff_parse_cons): New functions.
+ (md_being): Initialize XCOFF sections.
+ (ppc_xcoff_suffix): Add support for TLS relocations
+ (fixup_size, md_apply_fix): Add support for new BFD_RELOC.
+ (ppc_change_csect): Handle XMC_TL, XMC_UL. Correctly, add XMC_BS
+ to .bss section. Handle new XCOFF section variables.
+ (ppc_comm): Likewise.
+ (ppc_toc): Likewise.
+ (ppc_symbol_new_hook): Likewise.
+ (ppc_frob_symbol): Likewise.
+ (ppc_fix_adjustable): Add tbss support.
+ * config/tc-ppc.h (TC_PARSE_CONS_EXPRESSION): New define.
+ (ppc_xcoff_parse_cons): Add prototype.
+ (struct ppc_xcoff_section): New structure.
+
+2021-03-12 Clément Chigot <clement.chigot@atos.net>
+
* config/tc-ppc.c (ppc_xcoff_suffix): New function.
(MAP, MAP32, MAP64): New macros for XCOFF.
(ppc_xcoff_fixup_addis): New function.
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index 5ae9020..0c78b93 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -992,21 +992,41 @@ static bfd_boolean msolaris = SOLARIS_P;
/* The RS/6000 assembler uses the .csect pseudo-op to generate code
using a bunch of different sections. These assembler sections,
- however, are all encompassed within the .text or .data sections of
- the final output file. We handle this by using different
- subsegments within these main segments. */
-
-/* Next subsegment to allocate within the .text segment. */
-static subsegT ppc_text_subsegment = 2;
-
-/* Linked list of csects in the text section. */
-static symbolS *ppc_text_csects;
-
-/* Next subsegment to allocate within the .data segment. */
-static subsegT ppc_data_subsegment = 2;
+ however, are all encompassed within the .text, .data or .bss sections
+ of the final output file. We handle this by using different
+ subsegments within these main segments.
+ .tdata and .tbss sections only have one type of csects for now,
+ but it's better to follow the same construction like the others. */
+
+struct ppc_xcoff_section ppc_xcoff_text_section;
+struct ppc_xcoff_section ppc_xcoff_data_section;
+struct ppc_xcoff_section ppc_xcoff_bss_section;
+struct ppc_xcoff_section ppc_xcoff_tdata_section;
+struct ppc_xcoff_section ppc_xcoff_tbss_section;
+
+/* Return true if the ppc_xcoff_section structure is already
+ initialized. */
+static bfd_boolean
+ppc_xcoff_section_is_initialized (struct ppc_xcoff_section *section)
+{
+ return section->segment != NULL;
+}
-/* Linked list of csects in the data section. */
-static symbolS *ppc_data_csects;
+/* Initialize a ppc_xcoff_section.
+ Dummy symbols are used to ensure the position of .text over .data
+ and .tdata. These symbols won't be output. */
+static void
+ppc_init_xcoff_section (struct ppc_xcoff_section *s, segT seg,
+ bfd_boolean need_dummy)
+{
+ s->segment = seg;
+ s->next_subsegment = 2;
+ if (need_dummy)
+ {
+ s->csects = symbol_make ("dummy\001");
+ symbol_get_tc (s->csects)->within = s->csects;
+ }
+}
/* The current csect. */
static symbolS *ppc_current_csect;
@@ -1858,13 +1878,12 @@ md_begin (void)
#ifdef OBJ_XCOFF
ppc_coff_debug_section = coff_section_from_bfd_index (stdoutput, N_DEBUG);
- /* Create dummy symbols to serve as initial csects. This forces the
- text csects to precede the data csects. These symbols will not
- be output. */
- ppc_text_csects = symbol_make ("dummy\001");
- symbol_get_tc (ppc_text_csects)->within = ppc_text_csects;
- ppc_data_csects = symbol_make ("dummy\001");
- symbol_get_tc (ppc_data_csects)->within = ppc_data_csects;
+ /* Create XCOFF sections with .text in first, as it's creating dummy symbols
+ to serve as initial csects. This forces the text csects to precede the
+ data csects. These symbols will not be output. */
+ ppc_init_xcoff_section (&ppc_xcoff_text_section, text_section, TRUE);
+ ppc_init_xcoff_section (&ppc_xcoff_data_section, data_section, TRUE);
+ ppc_init_xcoff_section (&ppc_xcoff_bss_section, bss_section, FALSE);
#endif
}
@@ -2674,6 +2693,16 @@ ppc_xcoff_suffix (char **str_p)
static const struct map_bfd mapping[] = {
MAP ("l", BFD_RELOC_PPC_TOC16_LO),
MAP ("u", BFD_RELOC_PPC_TOC16_HI),
+ MAP32 ("ie", BFD_RELOC_PPC_TLSIE),
+ MAP32 ("ld", BFD_RELOC_PPC_TLSLD),
+ MAP32 ("le", BFD_RELOC_PPC_TLSLE),
+ MAP32 ("m", BFD_RELOC_PPC_TLSM),
+ MAP32 ("ml", BFD_RELOC_PPC_TLSML),
+ MAP64 ("ie", BFD_RELOC_PPC64_TLSIE),
+ MAP64 ("ld", BFD_RELOC_PPC64_TLSLD),
+ MAP64 ("le", BFD_RELOC_PPC64_TLSLE),
+ MAP64 ("m", BFD_RELOC_PPC64_TLSM),
+ MAP64 ("ml", BFD_RELOC_PPC64_TLSML),
};
if (*str++ != '@')
@@ -2726,6 +2755,24 @@ ppc_xcoff_fixup_addis (char *rt_e, char *d_e, char *ra_e)
free (save_ra);
}
+/* Support @ie, etc. on constants emitted via .short, .int etc. */
+
+bfd_reloc_code_real_type
+ppc_xcoff_parse_cons (expressionS *exp, unsigned int nbytes)
+{
+ expression (exp);
+ if (nbytes >= 2 && *input_line_pointer == '@')
+ return ppc_xcoff_suffix (&input_line_pointer);
+
+ /* There isn't any @ symbol for default TLS relocations (R_TLS). */
+ if (exp->X_add_symbol != NULL
+ && (symbol_get_tc (exp->X_add_symbol)->symbol_class == XMC_TL
+ || symbol_get_tc (exp->X_add_symbol)->symbol_class == XMC_UL))
+ return (ppc_obj64 ? BFD_RELOC_PPC64_TLSGD: BFD_RELOC_PPC_TLSGD);
+
+ return BFD_RELOC_NONE;
+}
+
#endif /* OBJ_XCOFF */
#if defined (OBJ_XCOFF) || defined (OBJ_ELF)
@@ -3052,6 +3099,10 @@ fixup_size (bfd_reloc_code_real_type reloc, bfd_boolean *pc_relative)
case BFD_RELOC_PPC_TLS:
case BFD_RELOC_PPC_TLSGD:
case BFD_RELOC_PPC_TLSLD:
+ case BFD_RELOC_PPC_TLSLE:
+ case BFD_RELOC_PPC_TLSIE:
+ case BFD_RELOC_PPC_TLSM:
+ case BFD_RELOC_PPC_TLSML:
case BFD_RELOC_PPC_VLE_HA16A:
case BFD_RELOC_PPC_VLE_HA16D:
case BFD_RELOC_PPC_VLE_HI16A:
@@ -3111,6 +3162,12 @@ fixup_size (bfd_reloc_code_real_type reloc, bfd_boolean *pc_relative)
case BFD_RELOC_PPC64_TPREL34:
case BFD_RELOC_PPC64_DTPREL34:
case BFD_RELOC_PPC64_TOC:
+ case BFD_RELOC_PPC64_TLSGD:
+ case BFD_RELOC_PPC64_TLSLD:
+ case BFD_RELOC_PPC64_TLSLE:
+ case BFD_RELOC_PPC64_TLSIE:
+ case BFD_RELOC_PPC64_TLSM:
+ case BFD_RELOC_PPC64_TLSML:
size = 8;
break;
@@ -4205,7 +4262,9 @@ static bfd_boolean ppc_stab_symbol;
/* The .comm and .lcomm pseudo-ops for XCOFF. XCOFF puts common
symbols in the .bss segment as though they were local common
symbols, and uses a different smclas. The native Aix 4.3.3 assembler
- aligns .comm and .lcomm to 4 bytes. */
+ aligns .comm and .lcomm to 4 bytes.
+ Symbols having a XMC_UL storage class are uninialized thread-local
+ data. */
static void
ppc_comm (int lcomm)
@@ -4220,6 +4279,7 @@ ppc_comm (int lcomm)
symbolS *lcomm_sym = NULL;
symbolS *sym;
char *pfrag;
+ struct ppc_xcoff_section *section;
endc = get_symbol_name (&name);
end_name = input_line_pointer;
@@ -4312,7 +4372,23 @@ ppc_comm (int lcomm)
return;
}
- record_alignment (bss_section, align);
+ if (symbol_get_tc (sym)->symbol_class == XMC_UL
+ || (lcomm && symbol_get_tc (lcomm_sym)->symbol_class == XMC_UL))
+ {
+ section = &ppc_xcoff_tbss_section;
+ if (!ppc_xcoff_section_is_initialized (section))
+ {
+ ppc_init_xcoff_section (section,
+ subseg_new (".tbss", 0), FALSE);
+ bfd_set_section_flags (section->segment,
+ SEC_ALLOC | SEC_THREAD_LOCAL);
+ seg_info (section->segment)->bss = 1;
+ }
+ }
+ else
+ section = &ppc_xcoff_bss_section;
+
+ record_alignment (section->segment, align);
if (! lcomm
|| ! S_IS_DEFINED (lcomm_sym))
@@ -4333,14 +4409,14 @@ ppc_comm (int lcomm)
def_size = 0;
}
- subseg_set (bss_section, 1);
+ subseg_set (section->segment, 1);
frag_align (align, 0, 0);
symbol_set_frag (def_sym, frag_now);
pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, def_sym,
def_size, (char *) NULL);
*pfrag = 0;
- S_SET_SEGMENT (def_sym, bss_section);
+ S_SET_SEGMENT (def_sym, section->segment);
symbol_get_tc (def_sym)->align = align;
}
else if (lcomm)
@@ -4356,7 +4432,7 @@ ppc_comm (int lcomm)
if (lcomm)
{
/* Make sym an offset from lcomm_sym. */
- S_SET_SEGMENT (sym, bss_section);
+ S_SET_SEGMENT (sym, section->segment);
symbol_set_frag (sym, symbol_get_frag (lcomm_sym));
S_SET_VALUE (sym, symbol_get_frag (lcomm_sym)->fr_offset);
symbol_get_frag (lcomm_sym)->fr_offset += size;
@@ -4414,7 +4490,7 @@ ppc_change_csect (symbolS *sym, offsetT align)
subseg_set (S_GET_SEGMENT (sym), symbol_get_tc (sym)->subseg);
else
{
- symbolS **list_ptr;
+ struct ppc_xcoff_section *section;
int after_toc;
int hold_chunksize;
symbolS *list;
@@ -4436,10 +4512,7 @@ ppc_change_csect (symbolS *sym, offsetT align)
case XMC_SV:
case XMC_TI:
case XMC_TB:
- S_SET_SEGMENT (sym, text_section);
- symbol_get_tc (sym)->subseg = ppc_text_subsegment;
- ++ppc_text_subsegment;
- list_ptr = &ppc_text_csects;
+ section = &ppc_xcoff_text_section;
is_code = 1;
break;
case XMC_RW:
@@ -4448,21 +4521,48 @@ ppc_change_csect (symbolS *sym, offsetT align)
case XMC_TE:
case XMC_DS:
case XMC_UA:
- case XMC_BS:
case XMC_UC:
+ section = &ppc_xcoff_data_section;
if (ppc_toc_csect != NULL
&& (symbol_get_tc (ppc_toc_csect)->subseg + 1
- == ppc_data_subsegment))
+ == section->next_subsegment))
after_toc = 1;
- S_SET_SEGMENT (sym, data_section);
- symbol_get_tc (sym)->subseg = ppc_data_subsegment;
- ++ppc_data_subsegment;
- list_ptr = &ppc_data_csects;
+ break;
+ case XMC_BS:
+ section = &ppc_xcoff_bss_section;
+ break;
+ case XMC_TL:
+ section = &ppc_xcoff_tdata_section;
+ /* Create .tdata section if not yet done. */
+ if (!ppc_xcoff_section_is_initialized (section))
+ {
+ ppc_init_xcoff_section (section, subseg_new (".tdata", 0),
+ TRUE);
+ bfd_set_section_flags (section->segment, SEC_ALLOC
+ | SEC_LOAD | SEC_RELOC | SEC_DATA
+ | SEC_THREAD_LOCAL);
+ }
+ break;
+ case XMC_UL:
+ section = &ppc_xcoff_tbss_section;
+ /* Create .tbss section if not yet done. */
+ if (!ppc_xcoff_section_is_initialized (section))
+ {
+ ppc_init_xcoff_section (section, subseg_new (".tbss", 0),
+ FALSE);
+ bfd_set_section_flags (section->segment, SEC_ALLOC |
+ SEC_THREAD_LOCAL);
+ seg_info (section->segment)->bss = 1;
+ }
break;
default:
abort ();
}
+ S_SET_SEGMENT (sym, section->segment);
+ symbol_get_tc (sym)->subseg = section->next_subsegment;
+ ++section->next_subsegment;
+
/* We set the obstack chunk size to a small value before
changing subsegments, so that we don't use a lot of memory
space for what may be a small section. */
@@ -4490,7 +4590,7 @@ ppc_change_csect (symbolS *sym, offsetT align)
symbol_get_tc (sym)->output = 1;
symbol_get_tc (sym)->within = sym;
- for (list = *list_ptr;
+ for (list = section->csects;
symbol_get_tc (list)->next != (symbolS *) NULL;
list = symbol_get_tc (list)->next)
;
@@ -5329,8 +5429,8 @@ ppc_toc (int ignore ATTRIBUTE_UNUSED)
symbolS *sym;
symbolS *list;
- subseg = ppc_data_subsegment;
- ++ppc_data_subsegment;
+ subseg = ppc_xcoff_data_section.next_subsegment;
+ ++ppc_xcoff_data_section.next_subsegment;
subseg_new (segment_name (data_section), subseg);
ppc_toc_frag = frag_now;
@@ -5345,7 +5445,7 @@ ppc_toc (int ignore ATTRIBUTE_UNUSED)
ppc_toc_csect = sym;
- for (list = ppc_data_csects;
+ for (list = ppc_xcoff_data_section.csects;
symbol_get_tc (list)->next != (symbolS *) NULL;
list = symbol_get_tc (list)->next)
;
@@ -5711,12 +5811,16 @@ ppc_symbol_new_hook (symbolS *sym)
tc->symbol_class = XMC_TC0;
else if (strcmp (s, "TE]") == 0)
tc->symbol_class = XMC_TE;
+ else if (strcmp (s, "TL]") == 0)
+ tc->symbol_class = XMC_TL;
break;
case 'U':
if (strcmp (s, "UA]") == 0)
tc->symbol_class = XMC_UA;
else if (strcmp (s, "UC]") == 0)
tc->symbol_class = XMC_UC;
+ else if (strcmp (s, "UL]") == 0)
+ tc->symbol_class = XMC_UL;
break;
case 'X':
if (strcmp (s, "XO]") == 0)
@@ -5858,12 +5962,15 @@ ppc_frob_symbol (symbolS *sym)
}
a->x_csect.x_smtyp = (symbol_get_tc (sym)->align << 3) | XTY_SD;
}
- else if (S_GET_SEGMENT (sym) == bss_section)
+ else if (S_GET_SEGMENT (sym) == bss_section
+ || S_GET_SEGMENT (sym) == ppc_xcoff_tbss_section.segment)
{
/* This is a common symbol. */
a->x_csect.x_scnlen.l = symbol_get_frag (sym)->fr_offset;
a->x_csect.x_smtyp = (symbol_get_tc (sym)->align << 3) | XTY_CM;
- if (S_IS_EXTERNAL (sym))
+ if (S_GET_SEGMENT (sym) == ppc_xcoff_tbss_section.segment)
+ symbol_get_tc (sym)->symbol_class = XMC_UL;
+ else if (S_IS_EXTERNAL (sym))
symbol_get_tc (sym)->symbol_class = XMC_RW;
else
symbol_get_tc (sym)->symbol_class = XMC_BS;
@@ -5917,9 +6024,11 @@ ppc_frob_symbol (symbolS *sym)
/* This is a normal symbol definition. x_scnlen is the
symbol index of the containing csect. */
if (S_GET_SEGMENT (sym) == text_section)
- csect = ppc_text_csects;
+ csect = ppc_xcoff_text_section.csects;
else if (S_GET_SEGMENT (sym) == data_section)
- csect = ppc_data_csects;
+ csect = ppc_xcoff_data_section.csects;
+ else if (S_GET_SEGMENT (sym) == ppc_xcoff_tdata_section.segment)
+ csect = ppc_xcoff_tdata_section.csects;
else
abort ();
@@ -6201,6 +6310,7 @@ ppc_fix_adjustable (fixS *fix)
&& tc->symbol_class != XMC_TC
&& tc->symbol_class != XMC_TE
&& symseg != bss_section
+ && symseg != ppc_xcoff_tbss_section.segment
/* Don't adjust if this is a reloc in the toc section. */
&& (symseg != data_section
|| ppc_toc_csect == NULL
@@ -7134,6 +7244,37 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
#endif
#ifdef OBJ_XCOFF
+ case BFD_RELOC_PPC_TLSGD:
+ case BFD_RELOC_PPC_TLSLD:
+ case BFD_RELOC_PPC_TLSLE:
+ case BFD_RELOC_PPC_TLSIE:
+ case BFD_RELOC_PPC_TLSM:
+ case BFD_RELOC_PPC64_TLSGD:
+ case BFD_RELOC_PPC64_TLSLD:
+ case BFD_RELOC_PPC64_TLSLE:
+ case BFD_RELOC_PPC64_TLSIE:
+ case BFD_RELOC_PPC64_TLSM:
+ gas_assert (fixP->fx_addsy != NULL);
+ S_SET_THREAD_LOCAL (fixP->fx_addsy);
+ fieldval = 0;
+ break;
+
+ /* TLSML relocations are targeting a XMC_TC symbol named
+ "_$TLSML". We can't check earlier because the relocation
+ can target any symbol name which will be latter .rename
+ to "_$TLSML". */
+ case BFD_RELOC_PPC_TLSML:
+ case BFD_RELOC_PPC64_TLSML:
+ gas_assert (fixP->fx_addsy != NULL);
+ if (strcmp (symbol_get_tc (fixP->fx_addsy)->real_name, "_$TLSML") != 0)
+ {
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("R_TLSML relocation doesn't target a "
+ "symbol named \"_$TLSML\". %s"), S_GET_NAME(fixP->fx_addsy));
+ }
+ fieldval = 0;
+ break;
+
case BFD_RELOC_NONE:
#endif
case BFD_RELOC_CTOR:
diff --git a/gas/config/tc-ppc.h b/gas/config/tc-ppc.h
index 9e2f174..d38c7d4 100644
--- a/gas/config/tc-ppc.h
+++ b/gas/config/tc-ppc.h
@@ -189,6 +189,23 @@ do { \
extern void ppc_xcoff_end (void);
#define md_end ppc_xcoff_end
+#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) \
+ ppc_xcoff_parse_cons (EXP, NBYTES)
+extern bfd_reloc_code_real_type ppc_xcoff_parse_cons (expressionS *,
+ unsigned int);
+/* XCOFF format allows only few predefined sections. Gather all
+ information in a common structure. */
+struct ppc_xcoff_section {
+ /* Main segment of the section. */
+ segT segment;
+
+ /* Next subsegment to allocate within the segment. */
+ subsegT next_subsegment;
+
+ /* Linked list of csects in the section. */
+ symbolS *csects;
+};
+
#endif /* OBJ_XCOFF */
#define tc_new_dot_label(sym) ppc_new_dot_label (sym)
diff --git a/include/ChangeLog b/include/ChangeLog
index c736323..3a40b16 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,5 +1,17 @@
2021-03-12 Clément Chigot <clement.chigot@atos.net>
+ * coff/internal.h (struct internal_aouthdr): Add new fields.
+ * coff/rs6000.h (AOUTHDRÃ): Add new fields.
+ * coff/rs6k64.h (struct external_filehdr): Likewise.
+ * coff/xcoff.h (_TDATA), _TBSS): New defines
+ (RS6K_AOUTHDR_TLS_LE, RS6K_AOUTHDR_RAS, RS6K_AOUTHDR_ALGNTDATA,
+ RS6K_AOUTHDR_SHR_SYMTAB, RS6K_AOUTHDR_FORK_POLICY,
+ RS6K_AOUTHDR_FORK_COR): New defines.
+ (XMC_TU): Removed.
+ (XMC_UL): New define.
+
+2021-03-12 Clément Chigot <clement.chigot@atos.net>
+
* coff/xcoff.h (R_RTB): Remove.
(R_TRL): Fix value.
diff --git a/include/coff/internal.h b/include/coff/internal.h
index 1655181..1b5b45c 100644
--- a/include/coff/internal.h
+++ b/include/coff/internal.h
@@ -263,8 +263,13 @@ struct internal_aouthdr
short o_algndata; /* max alignment for data */
short o_modtype; /* Module type field, 1R,RE,RO */
short o_cputype; /* Encoded CPU type */
- bfd_vma o_maxstack; /* max stack size allowed. */
- bfd_vma o_maxdata; /* max data size allowed. */
+ bfd_vma o_maxstack; /* max stack size allowed. */
+ bfd_vma o_maxdata; /* max data size allowed. */
+ char o_flags; /* Flags and TLS alignment */
+ short o_sntdata; /* section number for tdata */
+ short o_sntbss; /* section number for tbss */
+ short o_x64flags; /* XCOFF64 flags */
+
/* ECOFF stuff */
bfd_vma bss_start; /* Base of bss section. */
diff --git a/include/coff/rs6000.h b/include/coff/rs6000.h
index 280a81f..ff2de53 100644
--- a/include/coff/rs6000.h
+++ b/include/coff/rs6000.h
@@ -48,28 +48,34 @@ struct external_filehdr {
typedef struct
{
- unsigned char magic[2]; /* type of file */
- unsigned char vstamp[2]; /* version stamp */
- unsigned char tsize[4]; /* text size in bytes, padded to FW bdry */
- unsigned char dsize[4]; /* initialized data " " */
- unsigned char bsize[4]; /* uninitialized data " " */
- unsigned char entry[4]; /* entry pt. */
- unsigned char text_start[4]; /* base of text used for this file */
- unsigned char data_start[4]; /* base of data used for this file */
- unsigned char o_toc[4]; /* address of TOC */
- unsigned char o_snentry[2]; /* section number of entry point */
- unsigned char o_sntext[2]; /* section number of .text section */
- unsigned char o_sndata[2]; /* section number of .data section */
- unsigned char o_sntoc[2]; /* section number of TOC */
- unsigned char o_snloader[2]; /* section number of .loader section */
- unsigned char o_snbss[2]; /* section number of .bss section */
- unsigned char o_algntext[2]; /* .text alignment */
- unsigned char o_algndata[2]; /* .data alignment */
- unsigned char o_modtype[2]; /* module type (??) */
- unsigned char o_cputype[2]; /* cpu type */
- unsigned char o_maxstack[4]; /* max stack size (??) */
- unsigned char o_maxdata[4]; /* max data size (??) */
- unsigned char o_resv2[12]; /* reserved */
+ unsigned char magic[2]; /* type of file */
+ unsigned char vstamp[2]; /* version stamp */
+ unsigned char tsize[4]; /* text size in bytes, padded to FW bdry */
+ unsigned char dsize[4]; /* initialized data " " */
+ unsigned char bsize[4]; /* uninitialized data " " */
+ unsigned char entry[4]; /* entry pt. */
+ unsigned char text_start[4]; /* base of text used for this file */
+ unsigned char data_start[4]; /* base of data used for this file */
+ unsigned char o_toc[4]; /* address of TOC */
+ unsigned char o_snentry[2]; /* section number of entry point */
+ unsigned char o_sntext[2]; /* section number of .text section */
+ unsigned char o_sndata[2]; /* section number of .data section */
+ unsigned char o_sntoc[2]; /* section number of TOC */
+ unsigned char o_snloader[2]; /* section number of .loader section */
+ unsigned char o_snbss[2]; /* section number of .bss section */
+ unsigned char o_algntext[2]; /* .text alignment */
+ unsigned char o_algndata[2]; /* .data alignment */
+ unsigned char o_modtype[2]; /* module type (??) */
+ unsigned char o_cputype[2]; /* cpu type */
+ unsigned char o_maxstack[4]; /* max stack size (??) */
+ unsigned char o_maxdata[4]; /* max data size (??) */
+ unsigned char o_debugger[4]; /* reserved */
+ unsigned char o_textpsize[1]; /* text page size */
+ unsigned char o_datapsize[1]; /* data page size */
+ unsigned char o_stackpsize[1]; /* stack page size */
+ unsigned char o_flags[1]; /* Flags and TLS alignment */
+ unsigned char o_sntdata[2]; /* section number of .tdata section */
+ unsigned char o_sntbss[2]; /* section number of .tbss section */
}
AOUTHDR;
diff --git a/include/coff/rs6k64.h b/include/coff/rs6k64.h
index 1faf8e5..53adf4b 100644
--- a/include/coff/rs6k64.h
+++ b/include/coff/rs6k64.h
@@ -39,32 +39,38 @@ struct external_filehdr
/********************** AOUT "OPTIONAL HEADER" **********************/
-typedef struct
+typedef struct
{
- unsigned char magic[2]; /* type of file */
- unsigned char vstamp[2]; /* version stamp */
- unsigned char o_debugger[4]; /* reserved */
- unsigned char text_start[8]; /* base of text used for this file */
- unsigned char data_start[8]; /* base of data used for this file */
- unsigned char o_toc[8]; /* address of TOC */
- unsigned char o_snentry[2]; /* section number of entry point */
- unsigned char o_sntext[2]; /* section number of .text section */
- unsigned char o_sndata[2]; /* section number of .data section */
- unsigned char o_sntoc[2]; /* section number of TOC */
- unsigned char o_snloader[2]; /* section number of .loader section */
- unsigned char o_snbss[2]; /* section number of .bss section */
- unsigned char o_algntext[2]; /* .text alignment */
- unsigned char o_algndata[2]; /* .data alignment */
- unsigned char o_modtype[2]; /* module type (??) */
+ unsigned char magic[2]; /* type of file */
+ unsigned char vstamp[2]; /* version stamp */
+ unsigned char o_debugger[4]; /* reserved */
+ unsigned char text_start[8]; /* base of text used for this file */
+ unsigned char data_start[8]; /* base of data used for this file */
+ unsigned char o_toc[8]; /* address of TOC */
+ unsigned char o_snentry[2]; /* section number of entry point */
+ unsigned char o_sntext[2]; /* section number of .text section */
+ unsigned char o_sndata[2]; /* section number of .data section */
+ unsigned char o_sntoc[2]; /* section number of TOC */
+ unsigned char o_snloader[2]; /* section number of .loader section */
+ unsigned char o_snbss[2]; /* section number of .bss section */
+ unsigned char o_algntext[2]; /* .text alignment */
+ unsigned char o_algndata[2]; /* .data alignment */
+ unsigned char o_modtype[2]; /* module type (??) */
unsigned char o_cputype[2]; /* cpu type */
- unsigned char o_resv2[4]; /* reserved */
- unsigned char tsize[8]; /* text size bytes, padded to FW bdry */
- unsigned char dsize[8]; /* initialized data " " */
- unsigned char bsize[8]; /* uninitialized data " " */
- unsigned char entry[8]; /* entry pt. */
- unsigned char o_maxstack[8]; /* max stack size (??) */
- unsigned char o_maxdata[8]; /* max data size (??) */
- unsigned char o_resv3[16]; /* reserved */
+ unsigned char o_textpsize[1]; /* text page size */
+ unsigned char o_datapsize[1]; /* data page size */
+ unsigned char o_stackpsize[1]; /* stack page size */
+ unsigned char o_flags[1]; /* Flags and TLS alignment */
+ unsigned char tsize[8]; /* text size bytes, padded to FW bdry */
+ unsigned char dsize[8]; /* initialized data " " */
+ unsigned char bsize[8]; /* uninitialized data " " */
+ unsigned char entry[8]; /* entry pt. */
+ unsigned char o_maxstack[8]; /* max stack size (??) */
+ unsigned char o_maxdata[8]; /* max data size (??) */
+ unsigned char o_sntdata[2]; /* section number of .tdata section */
+ unsigned char o_sntbss[2]; /* section number of .tbss section */
+ unsigned char o_x64flags[2]; /* XCOFF64 flags */
+ unsigned char o_resv3[10]; /* reserved */
}
AOUTHDR;
diff --git a/include/coff/xcoff.h b/include/coff/xcoff.h
index 36651d4..05e9160 100644
--- a/include/coff/xcoff.h
+++ b/include/coff/xcoff.h
@@ -46,6 +46,8 @@
#define _TEXT ".text"
#define _DATA ".data"
#define _BSS ".bss"
+#define _TDATA ".tdata"
+#define _TBSS ".tbss"
#define _PAD ".pad"
#define _LOADER ".loader"
#define _EXCEPT ".except"
@@ -93,8 +95,19 @@
#define RS6K_AOUTHDR_NMAGIC 0x0108 /* new: text r/o, data r/w */
#define RS6K_AOUTHDR_ZMAGIC 0x010B /* paged: text r/o, both page-aligned */
-/* XCOFF relocation types.
- The relocations are described in the function
+/* Flags for aouthdr o_flags */
+#define RS6K_AOUTHDR_TLS_LE 0x80 /* TLS local-exec code was generated */
+#define RS6K_AOUTHDR_RAS 0x40 /* kernel module is key & recovery safe */
+#define RS6K_AOUTHDR_ALGNTDATA 0xf /* TLS alignment */
+
+/* Flags for aouthdr o_x64flags */
+#define RS6K_AOUTHDR_SHR_SYMTAB 0x8000
+#define RS6K_AOUTHDR_FORK_POLICY 0x4000
+#define RS6K_AOUTHDR_FORK_COR 0x2000
+
+
+/* XCOFF relocation types.
+ The relocations are described in the function
xcoff[64]_ppc_relocate_section in coff64-rs6000.c and coff-rs6000.c */
#define R_POS (0x00)
@@ -171,7 +184,7 @@
#define XMC_SV3264 18 /* Read-only 32 or 64 bit supervisor call */
/* 19 ??? */
#define XMC_TL 20 /* Read-write initialized TLS data */
-#define XMC_TU 21 /* Read-write uninitialized TLS data */
+#define XMC_UL 21 /* Read-write uninitialized TLS data */
#define XMC_TE 22 /* Same as XMC_TC but mapped after it */
/* The ldhdr structure. This appears at the start of the .loader
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 024ea0d..35c5e20 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,5 +1,20 @@
2021-03-12 Clément Chigot <clement.chigot@atos.net>
+ * emultempl/aix.em: Ensure .tdata section is removed
+ if empty, even with -r flag.
+ * scripttempl/aix.sc: Handle TLS sections.
+ * testsuite/ld-powerpc/aix52.exp: Add new tests.
+ * testsuite/ld-powerpc/aix-tls-reloc-32.d: New test.
+ * testsuite/ld-powerpc/aix-tls-reloc-64.d: New test.
+ * testsuite/ld-powerpc/aix-tls-reloc.ex: New test.
+ * testsuite/ld-powerpc/aix-tls-reloc.s: New test.
+ * testsuite/ld-powerpc/aix-tls-section-32.d: New test.
+ * testsuite/ld-powerpc/aix-tls-section-64.d: New test.
+ * testsuite/ld-powerpc/aix-tls-section.ex: New test.
+ * testsuite/ld-powerpc/aix-tls-section.s: New test.
+
+2021-03-12 Clément Chigot <clement.chigot@atos.net>
+
* scripttempl/aix.sc: Add .te to .data section.
* testsuite/ld-powerpc/aix52.exp: Add test structure for AIX7+.
Add aix-largetoc-1 test.
diff --git a/ld/emultempl/aix.em b/ld/emultempl/aix.em
index d578b6e..e098f2a 100644
--- a/ld/emultempl/aix.em
+++ b/ld/emultempl/aix.em
@@ -969,6 +969,44 @@ gld${EMULATION_NAME}_before_allocation (void)
sec->flags |= SEC_KEEP;
}
+ /* Make sure .tdata is removed if empty, even with -r flag.
+ .tdata is always being generated because its size is needed
+ to cumpute .data address. */
+ if (bfd_link_relocatable (&link_info))
+ {
+ static const char *const thread_sections[] = {
+ ".tdata",
+ ".tbss"
+ };
+
+ /* Run lang_size_sections (if not already done). */
+ if (expld.phase != lang_mark_phase_enum)
+ {
+ expld.phase = lang_mark_phase_enum;
+ expld.dataseg.phase = exp_seg_none;
+ one_lang_size_sections_pass (NULL, FALSE);
+ lang_reset_memory_regions ();
+ }
+
+ for (i = 0; i < ARRAY_SIZE (thread_sections); i++)
+ {
+ asection *sec;
+
+ sec = bfd_get_section_by_name (link_info.output_bfd,
+ thread_sections[i]);
+
+ if (sec != NULL && sec->rawsize == 0
+ && (sec->flags & SEC_KEEP) == 0
+ && !bfd_section_removed_from_list (link_info.output_bfd,
+ sec))
+ {
+ sec->flags |= SEC_EXCLUDE;
+ bfd_section_list_remove (link_info.output_bfd, sec);
+ link_info.output_bfd->section_count--;
+ }
+ }
+ }
+
before_allocation_default ();
}
diff --git a/ld/scripttempl/aix.sc b/ld/scripttempl/aix.sc
index aa129d9..3e4d7c0 100644
--- a/ld/scripttempl/aix.sc
+++ b/ld/scripttempl/aix.sc
@@ -37,7 +37,35 @@ SECTIONS
${RELOCATING+PROVIDE (_etext = .);}
}
- . = ALIGN (ALIGN (0x10000000) + (. & 0xfff), 32);
+ /* .tdata and .tbss addresses are representing the offset from
+ the TLS pointer. It starts at -0x7800 for 64bit and -0x7c00
+ for 32bit.
+ TODO: 32bit should have -0x7c00 but it works like this for
+ now.
+ The other particularity is that they must be before .data
+ sections. But .data must be aligned correctly as if the
+ addresses were contiguous. This means that the correct
+ address must be restored, taking into account: the size of
+ .text, its alignment 2^5, the size of .tdata and its
+ aligment 2^4. */
+ .tdata -0x7800 : {
+ *(.tdata)
+ *(.tl)
+ }
+
+ .tbss : {
+ *(.tbss)
+ *(.ul)
+ }
+
+ . = ${RELOCATING+(ALIGN (0x10000000 + SIZEOF_HEADERS, 32)) + }SIZEOF(.text);
+ . = ALIGN (.,32);
+ . = . + SIZEOF(.tdata);
+ . = ALIGN (.,16);
+
+ /* .data starting address must be in a different segment than
+ the .text addresses. Thus, 0x10000000 is added. */
+ . = ALIGN (0x10000000) + (. & 0xfff);
.data . : {
${RELOCATING+PROVIDE (_data = .);}
*(.data)
diff --git a/ld/testsuite/ld-powerpc/aix-tls-reloc-32.d b/ld/testsuite/ld-powerpc/aix-tls-reloc-32.d
new file mode 100644
index 0000000..5103de5
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/aix-tls-reloc-32.d
@@ -0,0 +1,35 @@
+#source: aix-tls-reloc.s
+#as: -a32
+#ld: -b32 -shared -bE:aix-tls-reloc.ex
+#objdump: -dr
+#target: [is_xcoff_format]
+
+.*
+
+Disassembly of section \.text:
+
+.* <\.foo>:
+.*: 80 82 00 00 l r4,0\(r2\)
+.*: R_TOC gd-.*
+.*: 80 62 00 04 l r3,4\(r2\)
+.*: R_TOC .gd-.*
+.*: 48 00 00 03 bla 0 <\.foo-.*>
+.*: R_BA_26 __tls_get_addr
+.*: 80 62 00 0c l r3,12\(r2\)
+.*: R_TOC _\$TLSML-.*
+.*: 48 00 00 03 bla 0 <\.foo-.*>
+.*: R_BA_26 __tls_get_mod
+.*: 80 82 00 08 l r4,8\(r2\)
+.*: R_TOC ld-.*
+.*: 7c a3 22 14 cax r5,r3,r4
+.*: 48 00 00 03 bla 0 <\.foo-.*>
+.*: R_BA_26 __get_tpointer
+.*: 80 82 00 10 l r4,16\(r2\)
+.*: R_TOC ie-.*
+.*: 7c a3 22 14 cax r5,r3,r4
+.*: 48 00 00 03 bla 0 <\.foo-.*>
+.*: R_BA_26 __get_tpointer
+.*: 80 82 00 14 l r4,20\(r2\)
+.*: R_TOC le-.*
+.*: 7c a3 22 14 cax r5,r3,r4
+.*
diff --git a/ld/testsuite/ld-powerpc/aix-tls-reloc-64.d b/ld/testsuite/ld-powerpc/aix-tls-reloc-64.d
new file mode 100644
index 0000000..71f6302
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/aix-tls-reloc-64.d
@@ -0,0 +1,31 @@
+#source: aix-tls-reloc.s
+#as: -a32
+#ld: -b32 -shared -bE:aix-tls-reloc.ex
+#objdump: -dr
+#target: [is_xcoff_format]
+
+.*
+
+Disassembly of section \.text:
+
+.* <\.foo>:
+.*: e8 82 00 00 ld r4,0\(r2\)
+.*: R_TOC gd-.*
+.*: e8 62 00 08 ld r3,8\(r2\)
+.*: R_TOC .gd-.*
+.*: 48 00 00 03 bla 0 <\.foo-.*>
+.*: R_BA_26 __tls_get_addr
+.*: e8 62 00 18 ld r3,24\(r2\)
+.*: R_TOC _\$TLSML-.*
+.*: 48 00 00 03 bla 0 <\.foo-.*>
+.*: R_BA_26 __tls_get_mod
+.*: 80 82 00 10 lwz r4,16\(r2\)
+.*: R_TOC ld-.*
+.*: 7c a3 22 14 add r5,r3,r4
+.*: e8 82 00 20 ld r4,32\(r2\)
+.*: R_TOC ie-.*
+.*: 7c a4 6a 14 add r5,r4,r13
+.*: e8 82 00 28 ld r4,40\(r2\)
+.*: R_TOC le-.*
+.*: 7c a3 6a 14 add r5,r3,r13
+.*
diff --git a/ld/testsuite/ld-powerpc/aix-tls-reloc.ex b/ld/testsuite/ld-powerpc/aix-tls-reloc.ex
new file mode 100644
index 0000000..257cc56
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/aix-tls-reloc.ex
@@ -0,0 +1 @@
+foo
diff --git a/ld/testsuite/ld-powerpc/aix-tls-reloc.s b/ld/testsuite/ld-powerpc/aix-tls-reloc.s
new file mode 100644
index 0000000..62ef73c
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/aix-tls-reloc.s
@@ -0,0 +1,65 @@
+ .globl bar[TL]
+ .csect bar[TL]
+ .long 1
+
+ .toc
+ .tc gd[TC],bar[TL]
+ .tc .gd[TC],bar[TL]@m
+ .tc ld[TC],bar[TL]@ld
+ .tc mh[TC],mh[TC]@ml
+ .tc ie[TC],bar[TL]@ie
+ .tc le[TC],bar[TL]@le
+
+ .globl foo
+ .globl .foo
+ .csect foo[DS],3
+foo:
+ .if size == 32
+ .long .foo, TOC[tc0], 0
+ .else
+ .llong .foo, TOC[tc0], 0
+ .endif
+
+ .csect foo[PR]
+.foo:
+ #GD
+ .if size == 32
+ lwz 4, gd[TC](2)
+ lwz 3, .gd[TC](2)
+ .else
+ ld 4, gd[TC](2)
+ ld 3, .gd[TC](2)
+ .endif
+ bla __tls_get_addr
+
+ #LD
+ .if size == 32
+ lwz 3, mh[TC](2)
+ .else
+ ld 3, mh[TC](2)
+ .endif
+ bla __tls_get_mod
+ lwz 4, ld[TC](2)
+ add 5,3,4
+
+ #IE
+ .if size == 32
+ bla __get_tpointer
+ lwz 4, ie[TC](2)
+ add 5,3,4
+ .else
+ ld 4, ie[TC](2)
+ add 5,4,13
+ .endif
+
+ #LE
+ .if size == 32
+ bla __get_tpointer
+ lwz 4, le[TC](2)
+ add 5,3,4
+ .else
+ ld 4, le[TC](2)
+ add 5,3,13
+ .endif
+
+.rename mh[TC], "_$TLSML" # Symbol for the module handle
diff --git a/ld/testsuite/ld-powerpc/aix-tls-section-32.d b/ld/testsuite/ld-powerpc/aix-tls-section-32.d
new file mode 100644
index 0000000..16b9686
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/aix-tls-section-32.d
@@ -0,0 +1,15 @@
+#source: aix-tls-section.s
+#as: -a32
+#ld: -b32 -shared -bE:aix-tls-section.ex
+#objdump: -hw
+#target: [is_xcoff_format]
+
+.*
+
+Sections:
+.*
+ 0 \.text .* .* .* .* .* ALLOC, LOAD, CODE
+ 1 \.tdata 00000008 ffff8800 ffff8800 .* .* CONTENTS, ALLOC, LOAD, DATA, THREAD_LOCAL
+ 2 \.tbss 00000008 ffff8808 ffff8808 .* .* ALLOC, THREAD_LOCAL
+ 3 \.data .* .* .* .* .* ALLOC, LOAD, DATA
+#...
diff --git a/ld/testsuite/ld-powerpc/aix-tls-section-64.d b/ld/testsuite/ld-powerpc/aix-tls-section-64.d
new file mode 100644
index 0000000..dceeaaf
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/aix-tls-section-64.d
@@ -0,0 +1,15 @@
+#source: aix-tls-section.s
+#as: -a64
+#ld: -b64 -shared -bE:aix-tls-section.ex
+#objdump: -hw
+#target: [is_xcoff_format]
+
+.*
+
+Sections\:
+.*
+ 0 \.text .* .* .* .* .* ALLOC, LOAD, CODE
+ 1 \.tdata 00000008 ffffffffffff8800 ffffffffffff8800 .* .* CONTENTS, ALLOC, LOAD, DATA, THREAD_LOCAL
+ 2 \.tbss 00000008 ffffffffffff8808 ffffffffffff8808 .* .* ALLOC, THREAD_LOCAL
+ 3 \.data .* .* .* .* .* ALLOC, LOAD, DATA
+#...
diff --git a/ld/testsuite/ld-powerpc/aix-tls-section.ex b/ld/testsuite/ld-powerpc/aix-tls-section.ex
new file mode 100644
index 0000000..3bd1f0e
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/aix-tls-section.ex
@@ -0,0 +1,2 @@
+foo
+bar
diff --git a/ld/testsuite/ld-powerpc/aix-tls-section.s b/ld/testsuite/ld-powerpc/aix-tls-section.s
new file mode 100644
index 0000000..30c328f
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/aix-tls-section.s
@@ -0,0 +1,8 @@
+ /* .tbss */
+ .comm foo[UL],8
+ .lcomm foo2_l,8,foo2[UL]
+
+ /* .tdata */
+ .globl bar[TL]
+ .csect bar[TL]
+ .long 1
diff --git a/ld/testsuite/ld-powerpc/aix52.exp b/ld/testsuite/ld-powerpc/aix52.exp
index 3dfbae0..0e68b6a 100644
--- a/ld/testsuite/ld-powerpc/aix52.exp
+++ b/ld/testsuite/ld-powerpc/aix52.exp
@@ -275,6 +275,16 @@ set aix7tests {
"" {aix-largetoc-1.s}
{{objdump -dr aix-largetoc-1-SIZE.d}}
"aix-largetoc-1.so"}
+
+ {"TLS relocations" "-shared -bE:aix-tls-reloc.ex"
+ "" {aix-tls-reloc.s}
+ {{objdump -dr aix-tls-reloc-SIZE.d}}
+ "aix-tls-reloc.so"}
+
+ {"TLS section" "-shared -bE:aix-tls-section.ex"
+ "" {aix-tls-section.s}
+ {{objdump -hw aix-tls-section-SIZE.d}}
+ "aix-tls-section.so"}
}
foreach test $aix7tests {