From 2d0f3896005097776f6bd807c7df97bbb6c99dd9 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Wed, 18 Nov 2009 12:42:52 +0000 Subject: [PATCH] bfd/ * bfd-in.h (_bfd_elf_ppc_at_tls_transform): Declare. * bfd-in2.h: Regenerate. * elf64-ppc.c (ppc64_elf_relocate_section): Move code for R_PPC64_TLS insn optimisation to.. * elf32-ppc.c (_bfd_elf_ppc_at_tls_transform): ..here. New function. (ppc_elf_relocate_section): Use it. gas/ * config/tc-ppc.c (md_assemble): Report error on invalid @tls operands and opcode. --- bfd/ChangeLog | 9 ++++++ bfd/bfd-in.h | 4 +++ bfd/bfd-in2.h | 4 +++ bfd/elf32-ppc.c | 73 +++++++++++++++++++++++++++------------------ bfd/elf64-ppc.c | 31 ++----------------- gas/ChangeLog | 5 ++++ gas/config/tc-ppc.c | 11 +++++-- 7 files changed, 77 insertions(+), 60 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 9bc8a85c79b..d7d77bfeb47 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,12 @@ +2009-11-18 Alan Modra + + * bfd-in.h (_bfd_elf_ppc_at_tls_transform): Declare. + * bfd-in2.h: Regenerate. + * elf64-ppc.c (ppc64_elf_relocate_section): Move code for R_PPC64_TLS + insn optimisation to.. + * elf32-ppc.c (_bfd_elf_ppc_at_tls_transform): ..here. New function. + (ppc_elf_relocate_section): Use it. + 2009-11-18 Alan Modra * targets.c: Don't include alloca-conf.h. diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h index c3d2d978062..82bf0433544 100644 --- a/bfd/bfd-in.h +++ b/bfd/bfd-in.h @@ -908,6 +908,10 @@ extern bfd_boolean elf32_arm_build_stubs extern bfd_boolean elf32_arm_fix_exidx_coverage (struct bfd_section **, unsigned int, struct bfd_link_info *); +/* PowerPC @tls opcode transform/validate. */ +extern unsigned int _bfd_elf_ppc_at_tls_transform + (unsigned int, unsigned int); + /* TI COFF load page support. */ extern void bfd_ticoff_set_section_load_page (struct bfd_section *, int); diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 2cf3ba103d9..455ec5696fc 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -915,6 +915,10 @@ extern bfd_boolean elf32_arm_build_stubs extern bfd_boolean elf32_arm_fix_exidx_coverage (struct bfd_section **, unsigned int, struct bfd_link_info *); +/* PowerPC @tls opcode transform/validate. */ +extern unsigned int _bfd_elf_ppc_at_tls_transform + (unsigned int, unsigned int); + /* TI COFF load page support. */ extern void bfd_ticoff_set_section_load_page (struct bfd_section *, int); diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 95058a233db..e4fdc1ea231 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -6613,6 +6613,46 @@ is_static_defined (struct elf_link_hash_entry *h) && h->root.u.def.section->output_section != NULL); } +/* If INSN is an opcode that may be used with an @tls operand, return + the transformed insn for TLS optimisation, otherwise return 0. If + REG is non-zero only match an insn with RB or RA equal to REG. */ + +unsigned int +_bfd_elf_ppc_at_tls_transform (unsigned int insn, unsigned int reg) +{ + unsigned int rtra; + + if ((insn & (0x3f << 26)) != 31 << 26) + return 0; + + if (reg == 0 || ((insn >> 11) & 0x1f) == reg) + rtra = insn & ((1 << 26) - (1 << 16)); + else if (((insn >> 16) & 0x1f) == reg) + rtra = (insn & (0x1f << 21)) | ((insn & (0x1f << 11)) << 5); + else + return 0; + + if ((insn & (0x3ff << 1)) == 266 << 1) + /* add -> addi. */ + insn = 14 << 26; + else if ((insn & (0x1f << 1)) == 23 << 1 + && ((insn & (0x1f << 6)) < 14 << 6 + || ((insn & (0x1f << 6)) >= 16 << 6 + && (insn & (0x1f << 6)) < 24 << 6))) + /* load and store indexed -> dform. */ + insn = (32 | ((insn >> 6) & 0x1f)) << 26; + else if ((insn & (((0x1a << 5) | 0x1f) << 1)) == 21 << 1) + /* ldx, ldux, stdx, stdux -> ld, ldu, std, stdu. */ + insn = ((58 | ((insn >> 6) & 4)) << 26) | ((insn >> 6) & 1); + else if ((insn & (((0x1f << 5) | 0x1f) << 1)) == 341 << 1) + /* lwax -> lwa. */ + insn = (58 << 26) | 2; + else + return 0; + insn |= rtra; + return insn; +} + /* The RELOCATE_SECTION function is called by the ELF backend linker to handle the relocations for a section. @@ -6813,37 +6853,12 @@ ppc_elf_relocate_section (bfd *output_bfd, if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_TPREL) == 0) { - bfd_vma insn, rtra; + bfd_vma insn; + insn = bfd_get_32 (output_bfd, contents + rel->r_offset); - if ((insn & ((31 << 26) | (31 << 11))) - == ((31 << 26) | (2 << 11))) - rtra = insn & ((1 << 26) - (1 << 16)); - else if ((insn & ((31 << 26) | (31 << 16))) - == ((31 << 26) | (2 << 16))) - rtra = (insn & (31 << 21)) | ((insn & (31 << 11)) << 5); - else - abort (); - if ((insn & ((1 << 11) - (1 << 1))) == 266 << 1) - /* add -> addi. */ - insn = 14 << 26; - else if ((insn & (31 << 1)) == 23 << 1 - && ((insn & (31 << 6)) < 14 << 6 - || ((insn & (31 << 6)) >= 16 << 6 - && (insn & (31 << 6)) < 24 << 6))) - /* load and store indexed -> dform. */ - insn = (32 | ((insn >> 6) & 31)) << 26; - else if ((insn & (31 << 1)) == 21 << 1 - && (insn & (0x1a << 6)) == 0) - /* ldx, ldux, stdx, stdux -> ld, ldu, std, stdu. */ - insn = (((58 | ((insn >> 6) & 4)) << 26) - | ((insn >> 6) & 1)); - else if ((insn & (31 << 1)) == 21 << 1 - && (insn & ((1 << 11) - (1 << 1))) == 341 << 1) - /* lwax -> lwa. */ - insn = (58 << 26) | 2; - else + insn = _bfd_elf_ppc_at_tls_transform (insn, 2); + if (insn == 0) abort (); - insn |= rtra; bfd_put_32 (output_bfd, insn, contents + rel->r_offset); r_type = R_PPC_TPREL16_LO; rel->r_info = ELF32_R_INFO (r_symndx, r_type); diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 35757b85d5c..e748a41fcc2 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -11018,37 +11018,10 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (tls_mask != 0 && (tls_mask & TLS_TPREL) == 0) { - bfd_vma rtra; insn = bfd_get_32 (output_bfd, contents + rel->r_offset); - if ((insn & ((0x3f << 26) | (31 << 11))) - == ((31 << 26) | (13 << 11))) - rtra = insn & ((1 << 26) - (1 << 16)); - else if ((insn & ((0x3f << 26) | (31 << 16))) - == ((31 << 26) | (13 << 16))) - rtra = (insn & (31 << 21)) | ((insn & (31 << 11)) << 5); - else - abort (); - if ((insn & ((1 << 11) - (1 << 1))) == 266 << 1) - /* add -> addi. */ - insn = 14 << 26; - else if ((insn & (31 << 1)) == 23 << 1 - && ((insn & (31 << 6)) < 14 << 6 - || ((insn & (31 << 6)) >= 16 << 6 - && (insn & (31 << 6)) < 24 << 6))) - /* load and store indexed -> dform. */ - insn = (32 | ((insn >> 6) & 31)) << 26; - else if ((insn & (31 << 1)) == 21 << 1 - && (insn & (0x1a << 6)) == 0) - /* ldx, ldux, stdx, stdux -> ld, ldu, std, stdu. */ - insn = (((58 | ((insn >> 6) & 4)) << 26) - | ((insn >> 6) & 1)); - else if ((insn & (31 << 1)) == 21 << 1 - && (insn & ((1 << 11) - (1 << 1))) == 341 << 1) - /* lwax -> lwa. */ - insn = (58 << 26) | 2; - else + insn = _bfd_elf_ppc_at_tls_transform (insn, 13); + if (insn == 0) abort (); - insn |= rtra; bfd_put_32 (output_bfd, insn, contents + rel->r_offset); /* Was PPC64_TLS which sits on insn boundary, now PPC64_TPREL16_LO which is at low-order half-word. */ diff --git a/gas/ChangeLog b/gas/ChangeLog index deb12a486cc..15092c42e21 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,8 @@ +2009-11-18 Alan Modra + + * config/tc-ppc.c (md_assemble): Report error on invalid @tls operands + and opcode. + 2009-11-17 Sebastian Pop Quentin Neill diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c index 493bfe5546b..1d615e950a1 100644 --- a/gas/config/tc-ppc.c +++ b/gas/config/tc-ppc.c @@ -2732,8 +2732,15 @@ md_assemble (char *str) break; case BFD_RELOC_PPC_TLS: - insn = ppc_insert_operand (insn, operand, ppc_obj64 ? 13 : 2, - ppc_cpu, (char *) NULL, 0); + if (!_bfd_elf_ppc_at_tls_transform (opcode->opcode, 0)) + as_bad (_("@tls may not be used with \"%s\" operands"), + opcode->name); + else if (operand->shift != 11) + as_bad (_("@tls may only be used in last operand")); + else + insn = ppc_insert_operand (insn, operand, + ppc_obj64 ? 13 : 2, + ppc_cpu, (char *) NULL, 0); break; /* We'll only use the 32 (or 64) bit form of these relocations -- 2.30.2