[V5] x86: Add tls check in gas
Checks
Context |
Check |
Description |
linaro-tcwg-bot/tcwg_binutils_build--master-arm |
success
|
Build passed
|
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 |
success
|
Build passed
|
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 |
success
|
Test passed
|
linaro-tcwg-bot/tcwg_binutils_check--master-arm |
success
|
Test passed
|
Commit Message
Assembler shouldn't accept invalid TLS instructions, TLS relocations
can only be used with specific instructions as specified in TLS psABI
and linker issues an error when TLS relocations are used with wrong
instructions or format. It is inconvenient for gcc to rely on linker
to report errors, adding tls check in the assembler stage so that gcc
can know tls errors earlier.
----------------------
Changes in V5:
1. Separated the register size judgment of X32 and ILP64.
2. Added new x32 TLS relocation tests.
3. Adjusted comments and error types.
----------------------
gas/ChangeLog:
PR gas/32022
* config.in: Regenerate.
* config/tc-i386.c
*(enum x86_tls_error_type): New.
*(struct _i386_insn): Added has_gotrel to indicate whether tls relocations need to be checked.
(x86_check_tls_relocation): Added a new function to check tls relocation.
(x86_report_tls_error): Created a new function to report tls error.
(i386_assemble): Handle x86_check_tls_relocation.
(lex_got): Set i.has_gotrel.
(OPTION_MTLS_CHECK): Added a new option to contrl tls check.
(struct option): Ditto.
(md_parse_option): Ditto.
(md_show_usage): Ditto.
* configure: Added a new option to check tls relocation by default.
* configure.ac: Ditto.
* doc/c-i386.texi: Ditto.
* testsuite/gas/i386/i386.exp: Added new tests.
* testsuite/gas/i386/ilp32/ilp32.exp: Ditto.
* testsuite/gas/i386/ilp32/reloc64.d: Disable tls check for it.
* testsuite/gas/i386/ilp32/x32-tls.d: Ditto.
* testsuite/gas/i386/inval-tls.l: Added more test cases.
* testsuite/gas/i386/inval-tls.s: Ditto.
* testsuite/gas/i386/reloc32.d: Disable tls check for it.
* testsuite/gas/i386/reloc64.d: Ditto.
* testsuite/gas/i386/x86-64-inval-tls.l: Added more test cases.
* testsuite/gas/i386/x86-64-inval-tls.s: Ditto.
* testsuite/gas/i386/x86-64.exp: Added new tests.
* testsuite/gas/i386/ilp32/x32-inval-tls.l: New test.
* testsuite/gas/i386/ilp32/x32-inval-tls.s: Ditto.
* testsuite/gas/i386/ilp32/x86-64-tls.d: Ditto.
* testsuite/gas/i386/tls.d: Ditto.
* testsuite/gas/i386/tls.s: Ditto.
* testsuite/gas/i386/x86-64-tls.d: Ditto.
* testsuite/gas/i386/x86-64-tls.s: Ditto.
ld/ChangeLog:
PR gas/32022
* testsuite/ld-i386/tlsgdesc1.d: Disable tls check for it.
* testsuite/ld-i386/tlsgdesc2.d: Ditto.
* testsuite/ld-i386/tlsie2.d: Ditto.
* testsuite/ld-i386/tlsie3.d: Ditto.
* testsuite/ld-i386/tlsie4.d: Ditto.
* testsuite/ld-i386/tlsie5.d: Ditto.
* testsuite/ld-i386/tlsgdesc3.d: Ditto.
* testsuite/ld-x86-64/tlsdesc3.d: Ditto.
* testsuite/ld-x86-64/tlsdesc4.d: Ditto.
* testsuite/ld-x86-64/tlsie2.d: Ditto.
* testsuite/ld-x86-64/tlsie3.d: Ditto.
* testsuite/ld-x86-64/tlsie5.d: Ditto.
* testsuite/ld-x86-64/tlsdesc5.d: Ditto.
---
gas/config.in | 3 +
gas/config/tc-i386.c | 438 ++++++++++++++++++-
gas/configure | 26 +-
gas/configure.ac | 18 +
gas/doc/c-i386.texi | 10 +
gas/testsuite/gas/i386/i386.exp | 3 +-
gas/testsuite/gas/i386/ilp32/ilp32.exp | 3 +-
gas/testsuite/gas/i386/ilp32/reloc64.d | 2 +-
gas/testsuite/gas/i386/ilp32/x32-inval-tls.l | 38 ++
gas/testsuite/gas/i386/ilp32/x32-inval-tls.s | 1 +
gas/testsuite/gas/i386/ilp32/x32-tls.d | 1 +
gas/testsuite/gas/i386/ilp32/x86-64-tls.d | 4 +
gas/testsuite/gas/i386/inval-tls.l | 72 ++-
gas/testsuite/gas/i386/inval-tls.s | 82 ++++
gas/testsuite/gas/i386/reloc32.d | 2 +-
gas/testsuite/gas/i386/reloc64.d | 2 +-
gas/testsuite/gas/i386/tls.d | 25 ++
gas/testsuite/gas/i386/tls.s | 31 ++
gas/testsuite/gas/i386/x86-64-inval-tls.l | 36 ++
gas/testsuite/gas/i386/x86-64-inval-tls.s | 46 ++
gas/testsuite/gas/i386/x86-64-tls.d | 25 ++
gas/testsuite/gas/i386/x86-64-tls.s | 27 ++
gas/testsuite/gas/i386/x86-64.exp | 3 +-
ld/testsuite/ld-i386/tlsgdesc1.d | 2 +-
ld/testsuite/ld-i386/tlsgdesc2.d | 2 +-
ld/testsuite/ld-i386/tlsgdesc3.d | 2 +-
ld/testsuite/ld-i386/tlsie2.d | 2 +-
ld/testsuite/ld-i386/tlsie3.d | 2 +-
ld/testsuite/ld-i386/tlsie4.d | 2 +-
ld/testsuite/ld-i386/tlsie5.d | 2 +-
ld/testsuite/ld-x86-64/tlsdesc3.d | 2 +-
ld/testsuite/ld-x86-64/tlsdesc4.d | 2 +-
ld/testsuite/ld-x86-64/tlsdesc5.d | 2 +-
ld/testsuite/ld-x86-64/tlsie2.d | 2 +-
ld/testsuite/ld-x86-64/tlsie3.d | 2 +-
ld/testsuite/ld-x86-64/tlsie5.d | 2 +-
36 files changed, 879 insertions(+), 45 deletions(-)
create mode 100644 gas/testsuite/gas/i386/ilp32/x32-inval-tls.l
create mode 100644 gas/testsuite/gas/i386/ilp32/x32-inval-tls.s
create mode 100644 gas/testsuite/gas/i386/ilp32/x86-64-tls.d
create mode 100644 gas/testsuite/gas/i386/tls.d
create mode 100644 gas/testsuite/gas/i386/tls.s
create mode 100644 gas/testsuite/gas/i386/x86-64-tls.d
create mode 100644 gas/testsuite/gas/i386/x86-64-tls.s
Comments
On Thu, Sep 19, 2024 at 2:38 PM Cui, Lili <lili.cui@intel.com> wrote:
>
> Assembler shouldn't accept invalid TLS instructions, TLS relocations
> can only be used with specific instructions as specified in TLS psABI
> and linker issues an error when TLS relocations are used with wrong
> instructions or format. It is inconvenient for gcc to rely on linker
> to report errors, adding tls check in the assembler stage so that gcc
> can know tls errors earlier.
>
> ----------------------
> Changes in V5:
>
> 1. Separated the register size judgment of X32 and ILP64.
> 2. Added new x32 TLS relocation tests.
> 3. Adjusted comments and error types.
>
> ----------------------
>
> gas/ChangeLog:
>
> PR gas/32022
> * config.in: Regenerate.
> * config/tc-i386.c
> *(enum x86_tls_error_type): New.
> *(struct _i386_insn): Added has_gotrel to indicate whether tls relocations need to be checked.
LIne too long.
> (x86_check_tls_relocation): Added a new function to check tls relocation.
Line too long.
Also please use TLS, instead of tls, in the commit message and ChangeLog.
It looks OK to me. Please give Jan a day to comment before committing
it.
Thanks.
> (x86_report_tls_error): Created a new function to report tls error.
> (i386_assemble): Handle x86_check_tls_relocation.
> (lex_got): Set i.has_gotrel.
> (OPTION_MTLS_CHECK): Added a new option to contrl tls check.
> (struct option): Ditto.
> (md_parse_option): Ditto.
> (md_show_usage): Ditto.
> * configure: Added a new option to check tls relocation by default.
> * configure.ac: Ditto.
> * doc/c-i386.texi: Ditto.
> * testsuite/gas/i386/i386.exp: Added new tests.
> * testsuite/gas/i386/ilp32/ilp32.exp: Ditto.
> * testsuite/gas/i386/ilp32/reloc64.d: Disable tls check for it.
> * testsuite/gas/i386/ilp32/x32-tls.d: Ditto.
> * testsuite/gas/i386/inval-tls.l: Added more test cases.
> * testsuite/gas/i386/inval-tls.s: Ditto.
> * testsuite/gas/i386/reloc32.d: Disable tls check for it.
> * testsuite/gas/i386/reloc64.d: Ditto.
> * testsuite/gas/i386/x86-64-inval-tls.l: Added more test cases.
> * testsuite/gas/i386/x86-64-inval-tls.s: Ditto.
> * testsuite/gas/i386/x86-64.exp: Added new tests.
> * testsuite/gas/i386/ilp32/x32-inval-tls.l: New test.
> * testsuite/gas/i386/ilp32/x32-inval-tls.s: Ditto.
> * testsuite/gas/i386/ilp32/x86-64-tls.d: Ditto.
> * testsuite/gas/i386/tls.d: Ditto.
> * testsuite/gas/i386/tls.s: Ditto.
> * testsuite/gas/i386/x86-64-tls.d: Ditto.
> * testsuite/gas/i386/x86-64-tls.s: Ditto.
>
> ld/ChangeLog:
>
> PR gas/32022
> * testsuite/ld-i386/tlsgdesc1.d: Disable tls check for it.
> * testsuite/ld-i386/tlsgdesc2.d: Ditto.
> * testsuite/ld-i386/tlsie2.d: Ditto.
> * testsuite/ld-i386/tlsie3.d: Ditto.
> * testsuite/ld-i386/tlsie4.d: Ditto.
> * testsuite/ld-i386/tlsie5.d: Ditto.
> * testsuite/ld-i386/tlsgdesc3.d: Ditto.
> * testsuite/ld-x86-64/tlsdesc3.d: Ditto.
> * testsuite/ld-x86-64/tlsdesc4.d: Ditto.
> * testsuite/ld-x86-64/tlsie2.d: Ditto.
> * testsuite/ld-x86-64/tlsie3.d: Ditto.
> * testsuite/ld-x86-64/tlsie5.d: Ditto.
> * testsuite/ld-x86-64/tlsdesc5.d: Ditto.
> ---
> gas/config.in | 3 +
> gas/config/tc-i386.c | 438 ++++++++++++++++++-
> gas/configure | 26 +-
> gas/configure.ac | 18 +
> gas/doc/c-i386.texi | 10 +
> gas/testsuite/gas/i386/i386.exp | 3 +-
> gas/testsuite/gas/i386/ilp32/ilp32.exp | 3 +-
> gas/testsuite/gas/i386/ilp32/reloc64.d | 2 +-
> gas/testsuite/gas/i386/ilp32/x32-inval-tls.l | 38 ++
> gas/testsuite/gas/i386/ilp32/x32-inval-tls.s | 1 +
> gas/testsuite/gas/i386/ilp32/x32-tls.d | 1 +
> gas/testsuite/gas/i386/ilp32/x86-64-tls.d | 4 +
> gas/testsuite/gas/i386/inval-tls.l | 72 ++-
> gas/testsuite/gas/i386/inval-tls.s | 82 ++++
> gas/testsuite/gas/i386/reloc32.d | 2 +-
> gas/testsuite/gas/i386/reloc64.d | 2 +-
> gas/testsuite/gas/i386/tls.d | 25 ++
> gas/testsuite/gas/i386/tls.s | 31 ++
> gas/testsuite/gas/i386/x86-64-inval-tls.l | 36 ++
> gas/testsuite/gas/i386/x86-64-inval-tls.s | 46 ++
> gas/testsuite/gas/i386/x86-64-tls.d | 25 ++
> gas/testsuite/gas/i386/x86-64-tls.s | 27 ++
> gas/testsuite/gas/i386/x86-64.exp | 3 +-
> ld/testsuite/ld-i386/tlsgdesc1.d | 2 +-
> ld/testsuite/ld-i386/tlsgdesc2.d | 2 +-
> ld/testsuite/ld-i386/tlsgdesc3.d | 2 +-
> ld/testsuite/ld-i386/tlsie2.d | 2 +-
> ld/testsuite/ld-i386/tlsie3.d | 2 +-
> ld/testsuite/ld-i386/tlsie4.d | 2 +-
> ld/testsuite/ld-i386/tlsie5.d | 2 +-
> ld/testsuite/ld-x86-64/tlsdesc3.d | 2 +-
> ld/testsuite/ld-x86-64/tlsdesc4.d | 2 +-
> ld/testsuite/ld-x86-64/tlsdesc5.d | 2 +-
> ld/testsuite/ld-x86-64/tlsie2.d | 2 +-
> ld/testsuite/ld-x86-64/tlsie3.d | 2 +-
> ld/testsuite/ld-x86-64/tlsie5.d | 2 +-
> 36 files changed, 879 insertions(+), 45 deletions(-)
> create mode 100644 gas/testsuite/gas/i386/ilp32/x32-inval-tls.l
> create mode 100644 gas/testsuite/gas/i386/ilp32/x32-inval-tls.s
> create mode 100644 gas/testsuite/gas/i386/ilp32/x86-64-tls.d
> create mode 100644 gas/testsuite/gas/i386/tls.d
> create mode 100644 gas/testsuite/gas/i386/tls.s
> create mode 100644 gas/testsuite/gas/i386/x86-64-tls.d
> create mode 100644 gas/testsuite/gas/i386/x86-64-tls.s
>
> diff --git a/gas/config.in b/gas/config.in
> index a1f83499332..c32b46b93f5 100644
> --- a/gas/config.in
> +++ b/gas/config.in
> @@ -60,6 +60,9 @@
> /* Define default value for RISC-V -mpriv-spec */
> #undef DEFAULT_RISCV_PRIV_SPEC
>
> +/* Define to 1 if you want to check x86 TLS relocation by default. */
> +#undef DEFAULT_X86_TLS_CHECK
> +
> /* Define to 1 if you want to generate GNU x86 used ISA and feature properties
> by default. */
> #undef DEFAULT_X86_USED_NOTE
> diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
> index 4739a6d0c21..2b6b5ab5538 100644
> --- a/gas/config/tc-i386.c
> +++ b/gas/config/tc-i386.c
> @@ -274,6 +274,30 @@ enum i386_error
> internal_error,
> };
>
> +enum x86_tls_error_type
> +{
> + x86_tls_error_continue,
> + x86_tls_error_none,
> + x86_tls_error_insn,
> + x86_tls_error_opcode,
> + x86_tls_error_sib,
> + x86_tls_error_no_base_reg,
> + x86_tls_error_require_no_base_index_reg,
> + x86_tls_error_base_reg,
> + x86_tls_error_index_ebx,
> + x86_tls_error_eax,
> + x86_tls_error_RegA,
> + x86_tls_error_ebx,
> + x86_tls_error_rip,
> + x86_tls_error_dest_eax,
> + x86_tls_error_dest_rdi,
> + x86_tls_error_scale_factor,
> + x86_tls_error_base_reg_size,
> + x86_tls_error_dest_32bit_reg_size,
> + x86_tls_error_dest_64bit_reg_size,
> + x86_tls_error_dest_32bit_or_64bit_reg_size
> +};
> +
> struct _i386_insn
> {
> /* TM holds the template for the insn were currently assembling. */
> @@ -365,6 +389,9 @@ struct _i386_insn
> /* Has GOTPC or TLS relocation. */
> bool has_gotpc_tls_reloc;
>
> + /* Has relocation entry from the gotrel array. */
> + bool has_gotrel;
> +
> /* RM and SIB are the modrm byte and the sib byte where the
> addressing modes of this insn are encoded. */
> modrm_byte rm;
> @@ -717,6 +744,9 @@ lfence_before_ret;
> static int generate_relax_relocations
> = DEFAULT_GENERATE_X86_RELAX_RELOCATIONS;
>
> +/* 1 if the assembler should check tls relocation. */
> +static bool tls_check = DEFAULT_X86_TLS_CHECK;
> +
> static enum check_kind
> {
> check_none = 0,
> @@ -6357,6 +6387,356 @@ static INLINE bool may_need_pass2 (const insn_template *t)
> && (t->base_opcode | 8) == 0x2c);
> }
>
> +static enum x86_tls_error_type
> +x86_check_tls_relocation (enum bfd_reloc_code_real r_type)
> +{
> + switch (r_type)
> + {
> + case BFD_RELOC_386_TLS_GOTDESC:
> + /* Check GDesc access model:
> +
> + leal x@tlsdesc(%ebx), %reg32 --> Memory reg must be %ebx and
> + SIB is not supported.
> + */
> + if (i.tm.mnem_off != MN_lea)
> + return x86_tls_error_insn;
> + if (i.index_reg)
> + return x86_tls_error_sib;
> + if (!i.base_reg)
> + return x86_tls_error_no_base_reg;
> + if (i.base_reg->reg_type.bitfield.instance != RegB)
> + return x86_tls_error_ebx;
> + if (!i.op[1].regs->reg_type.bitfield.dword)
> + return x86_tls_error_dest_32bit_reg_size;
> + break;
> +
> + case BFD_RELOC_386_TLS_GD:
> + /* Check GD access model:
> +
> + leal foo@tlsgd(,%ebx,1), %eax --> Only this fixed format is supported.
> + leal foo@tlsgd(%reg32), %eax --> Dest reg must be '%eax'
> + Memory reg can't be %eax.
> + */
> + if (i.tm.mnem_off != MN_lea)
> + return x86_tls_error_insn;
> + if (i.op[1].regs->reg_type.bitfield.instance != Accum)
> + return x86_tls_error_dest_eax;
> + if (!i.op[1].regs->reg_type.bitfield.dword)
> + return x86_tls_error_dest_32bit_reg_size;
> + if (i.index_reg)
> + {
> + if (i.base_reg)
> + return x86_tls_error_base_reg;
> + if (i.index_reg->reg_type.bitfield.instance != RegB)
> + return x86_tls_error_index_ebx;
> + if (i.log2_scale_factor)
> + return x86_tls_error_scale_factor;
> + }
> + else
> + {
> + if (!i.base_reg)
> + return x86_tls_error_no_base_reg;
> + if (i.base_reg->reg_type.bitfield.instance == Accum)
> + return x86_tls_error_eax;
> + }
> + break;
> +
> + case BFD_RELOC_386_TLS_LDM:
> + /* Check LDM access model:
> +
> + leal foo@tlsldm(%reg32), %eax --> Dest reg must be '%eax'
> + Memory reg can't be %eax and SIB
> + is not supported.
> + */
> + if (i.tm.mnem_off != MN_lea)
> + return x86_tls_error_insn;
> + if (i.index_reg)
> + return x86_tls_error_sib;
> + if (!i.base_reg)
> + return x86_tls_error_no_base_reg;
> + if (i.base_reg->reg_type.bitfield.instance == Accum)
> + return x86_tls_error_eax;
> + if (i.op[1].regs->reg_type.bitfield.instance != Accum)
> + return x86_tls_error_dest_eax;
> + if (!i.op[1].regs->reg_type.bitfield.dword)
> + return x86_tls_error_dest_32bit_reg_size;
> + break;
> +
> + case BFD_RELOC_X86_64_GOTPC32_TLSDESC:
> + /* Check GOTPC32 TLSDESC access model:
> +
> + --- LP64 mode ---
> + leaq x@tlsdesc(%rip), %reg64 --> Memory reg must be %rip.
> +
> + --- X32 mode ---
> + rex/rex2 leal x@tlsdesc(%rip), %reg32 --> Memory reg must be %rip.
> +
> + In X32 mode, gas will add rex/rex2 for it later, no need to check
> + here.
> + */
> + if (i.tm.mnem_off != MN_lea)
> + return x86_tls_error_insn;
> + if (!i.base_reg)
> + return x86_tls_error_no_base_reg;
> + if (i.base_reg->reg_num != RegIP
> + || !i.base_reg->reg_type.bitfield.qword)
> + return x86_tls_error_rip;
> + if (x86_elf_abi == X86_64_ABI)
> + {
> + if (!i.op[1].regs->reg_type.bitfield.qword)
> + return x86_tls_error_dest_64bit_reg_size;
> + }
> + else if (!i.op[1].regs->reg_type.bitfield.dword
> + && !i.op[1].regs->reg_type.bitfield.qword)
> + return x86_tls_error_dest_32bit_or_64bit_reg_size;
> + break;
> +
> + case BFD_RELOC_X86_64_TLSGD:
> + /* Check GD access model:
> +
> + leaq foo@tlsgd(%rip), %rdi --> Only this fixed format is supported.
> + */
> + case BFD_RELOC_X86_64_TLSLD:
> + /* Check LD access model:
> +
> + leaq foo@tlsld(%rip), %rdi --> Only this fixed format is supported.
> + */
> + if (i.tm.mnem_off != MN_lea)
> + return x86_tls_error_insn;
> + if (!i.base_reg)
> + return x86_tls_error_no_base_reg;
> + if (i.base_reg->reg_num != RegIP
> + || !i.base_reg->reg_type.bitfield.qword)
> + return x86_tls_error_rip;
> + if (!i.op[1].regs->reg_type.bitfield.qword
> + || i.op[1].regs->reg_num != EDI_REG_NUM
> + || i.op[1].regs->reg_flags)
> + return x86_tls_error_dest_rdi;
> + break;
> +
> + case BFD_RELOC_386_TLS_GOTIE:
> + /* Check GOTIE access model:
> +
> + subl foo@gotntpoff(%reg1), %reg2
> + movl foo@gotntpoff(%reg1), %reg2
> + addl foo@gotntpoff(%reg1), %reg2
> +
> + Memory operand: SIB is not supported.
> + */
> + case BFD_RELOC_386_TLS_IE_32:
> + /* Check IE_32 access model:
> +
> + subl foo@gottpoff(%reg1), %reg2
> + movl foo@gottpoff(%reg1), %reg2
> + addl foo@gottpoff(%reg1), %reg2
> +
> + Memory operand: SIB is not supported.
> + */
> + if (i.tm.mnem_off != MN_sub
> + && i.tm.mnem_off != MN_add
> + && i.tm.mnem_off != MN_mov)
> + return x86_tls_error_insn;
> + if (i.op[1].regs->reg_type.bitfield.class != Reg
> + || i.op[0].regs->reg_type.bitfield.class
> + || i.imm_operands)
> + return x86_tls_error_opcode;
> + if (!i.base_reg)
> + return x86_tls_error_no_base_reg;
> + if (i.index_reg)
> + return x86_tls_error_sib;
> + if (!i.base_reg->reg_type.bitfield.dword)
> + return x86_tls_error_base_reg_size;
> + if (!i.op[1].regs->reg_type.bitfield.dword)
> + return x86_tls_error_dest_32bit_reg_size;
> + break;
> +
> + case BFD_RELOC_386_TLS_IE:
> + /* Check IE access model:
> +
> + movl foo@indntpoff, %reg32 --> Mod == 00 && r/m == 5
> + addl foo@indntpoff, %reg32 --> Mod == 00 && r/m == 5
> + */
> + if (i.tm.mnem_off != MN_add && i.tm.mnem_off != MN_mov)
> + return x86_tls_error_insn;
> + if (i.op[1].regs->reg_type.bitfield.class != Reg
> + || i.op[0].regs->reg_type.bitfield.class
> + || i.imm_operands)
> + return x86_tls_error_opcode;
> + if (i.base_reg || i.index_reg)
> + return x86_tls_error_require_no_base_index_reg;
> + if (!i.op[1].regs->reg_type.bitfield.dword)
> + return x86_tls_error_dest_32bit_reg_size;
> + break;
> +
> + case BFD_RELOC_X86_64_GOTTPOFF:
> + /* Check GOTTPOFF access model:
> +
> + mov foo@gottpoff(%rip), %reg --> Memory Reg must be %rip.
> + add foo@gottpoff(%rip), %reg --> Memory Reg must be %rip.
> + add %reg1, foo@gottpoff(%rip), %reg2 --> Memory Reg must be %rip.
> + add foo@gottpoff(%rip), %reg1, %reg2 --> Memory Reg must be %rip.
> + */
> + if (i.tm.mnem_off != MN_add && i.tm.mnem_off != MN_mov)
> + return x86_tls_error_insn;
> + if (i.op[i.operands - 1].regs->reg_type.bitfield.class != Reg
> + || (i.op[0].regs->reg_type.bitfield.class
> + && i.tm.opcode_modifier.vexvvvv != VexVVVV_DST)
> + || i.imm_operands)
> + return x86_tls_error_opcode;
> + if (!i.base_reg)
> + return x86_tls_error_no_base_reg;
> + if (i.base_reg->reg_num != RegIP
> + || !i.base_reg->reg_type.bitfield.qword)
> + return x86_tls_error_rip;
> + if (x86_elf_abi == X86_64_ABI)
> + {
> + if (!i.op[i.operands - 1].regs->reg_type.bitfield.qword)
> + return x86_tls_error_dest_64bit_reg_size;
> + }
> + else if (!i.op[i.operands - 1].regs->reg_type.bitfield.dword
> + && !i.op[i.operands - 1].regs->reg_type.bitfield.qword)
> + return x86_tls_error_dest_32bit_or_64bit_reg_size;
> + break;
> +
> + case BFD_RELOC_386_TLS_DESC_CALL:
> + /* Check GDesc access model:
> +
> + call *x@tlscall(%eax) --> Memory reg must be %eax and
> + SIB is not supported.
> + */
> + case BFD_RELOC_X86_64_TLSDESC_CALL:
> + /* Check GDesc access model:
> +
> + call *x@tlscall(%rax) <--- LP64 mode.
> + call *x@tlscall(%eax) <--- X32 mode.
> +
> + Only these fixed formats are supported.
> + */
> + if (i.tm.mnem_off != MN_call)
> + return x86_tls_error_insn;
> + if (i.index_reg)
> + return x86_tls_error_sib;
> + if (!i.base_reg)
> + return x86_tls_error_no_base_reg;
> + if (i.base_reg->reg_type.bitfield.instance != Accum)
> + return x86_tls_error_RegA;
> + break;
> +
> + case BFD_RELOC_NONE:
> + /* This isn't a relocation. */
> + return x86_tls_error_continue;
> +
> + default:
> + break;
> + }
> +
> + /* This relocation is OK. */
> + return x86_tls_error_none;
> +}
> +
> +static void
> +x86_report_tls_error (enum x86_tls_error_type tls_error,
> + enum bfd_reloc_code_real r_type)
> +{
> + unsigned int k;
> + for (k = 0; k < ARRAY_SIZE (gotrel); k++)
> + if (gotrel[k].rel[object_64bit] == r_type)
> + break;
> +
> + switch (tls_error)
> + {
> + case x86_tls_error_insn:
> + as_bad (_("@%s operator cannot be used with `%s'"),
> + gotrel[k].str, insn_name (&i.tm));
> + return;
> +
> + case x86_tls_error_opcode:
> + as_bad (_("@%s operator can be used with `%s', but format is wrong"),
> + gotrel[k].str, insn_name (&i.tm));
> + return;
> +
> + case x86_tls_error_sib:
> + as_bad (_("@%s operator requires no SIB"), gotrel[k].str);
> + return;
> +
> + case x86_tls_error_no_base_reg:
> + as_bad (_("@%s operator requires base register"), gotrel[k].str);
> + return;
> +
> + case x86_tls_error_require_no_base_index_reg:
> + as_bad (_("@%s operator requires no base/index register"),
> + gotrel[k].str);
> + return;
> +
> + case x86_tls_error_base_reg:
> + as_bad (_("@%s operator requires no base register"), gotrel[k].str);
> + return;
> +
> + case x86_tls_error_index_ebx:
> + as_bad (_("@%s operator requires `%sebx' as index register"),
> + gotrel[k].str, register_prefix);
> + return;
> +
> + case x86_tls_error_eax:
> + as_bad (_("@%s operator requires `%seax' as base register"),
> + gotrel[k].str, register_prefix);
> + return;
> +
> + case x86_tls_error_RegA:
> + as_bad (_("@%s operator requires `%seax/%srax' as base register"),
> + gotrel[k].str, register_prefix, register_prefix);
> + return;
> +
> + case x86_tls_error_ebx:
> + as_bad (_("@%s operator requires `%sebx' as base register"),
> + gotrel[k].str, register_prefix);
> + return;
> +
> + case x86_tls_error_rip:
> + as_bad (_("@%s operator requires `%srip' as base register"),
> + gotrel[k].str, register_prefix);
> + return;
> +
> + case x86_tls_error_dest_eax:
> + as_bad (_("@%s operator requires `%seax' as dest register"),
> + gotrel[k].str, register_prefix);
> + return;
> +
> + case x86_tls_error_dest_rdi:
> + as_bad (_("@%s operator requires `%srdi' as dest register"),
> + gotrel[k].str, register_prefix);
> + return;
> +
> + case x86_tls_error_scale_factor:
> + as_bad (_("@%s operator requires scale factor of 1"),
> + gotrel[k].str);
> + return;
> +
> + case x86_tls_error_base_reg_size:
> + as_bad (_("@%s operator requires 32-bit base register"),
> + gotrel[k].str);
> + return;
> +
> + case x86_tls_error_dest_32bit_reg_size:
> + as_bad (_("@%s operator requires 32-bit dest register"),
> + gotrel[k].str);
> + return;
> +
> + case x86_tls_error_dest_64bit_reg_size:
> + as_bad (_("@%s operator requires 64-bit dest register"),
> + gotrel[k].str);
> + return;
> +
> + case x86_tls_error_dest_32bit_or_64bit_reg_size:
> + as_bad (_("@%s operator requires 32-bit or 64-bit dest register"),
> + gotrel[k].str);
> + return;
> +
> + default:
> + abort ();
> + }
> +}
> +
> /* This is the guts of the machine-dependent assembler. LINE points to a
> machine dependent instruction. This function is supposed to emit
> the frags/bytes it assembles to. */
> @@ -6695,6 +7075,21 @@ i386_assemble (char *line)
> i.prefix[LOCK_PREFIX] = 0;
> }
>
> + if (i.has_gotrel && tls_check)
> + {
> + enum x86_tls_error_type tls_error;
> + for (j = 0; j < i.operands; ++j)
> + {
> + tls_error = x86_check_tls_relocation (i.reloc[j]);
> + if (tls_error == x86_tls_error_continue)
> + continue;
> +
> + if (tls_error != x86_tls_error_none)
> + x86_report_tls_error (tls_error, i.reloc[j]);
> + break;
> + }
> + }
> +
> if ((is_any_vex_encoding (&i.tm) && i.tm.opcode_space != SPACE_EVEXMAP4)
> || i.tm.operand_types[i.imm_operands].bitfield.class >= RegMMX
> || i.tm.operand_types[i.imm_operands + 1].bitfield.class >= RegMMX)
> @@ -6705,28 +7100,6 @@ i386_assemble (char *line)
> as_bad (_("data size prefix invalid with `%s'"), insn_name (&i.tm));
> return;
> }
> -
> - /* Don't allow e.g. KMOV in TLS code sequences which will trigger
> - linker error later. */
> - for (j = i.imm_operands; j < i.operands; ++j)
> - switch (i.reloc[j])
> - {
> - case BFD_RELOC_X86_64_GOTTPOFF:
> - case BFD_RELOC_386_TLS_GOTIE:
> - case BFD_RELOC_X86_64_TLSLD:
> - for (unsigned int k = 0; k < ARRAY_SIZE (gotrel); k++)
> - {
> - if (gotrel[k].rel[object_64bit] == i.reloc[j])
> - {
> - as_bad (_("@%s operator cannot be used with `%s'"),
> - gotrel[k].str, insn_name (&i.tm));
> - return;
> - }
> - }
> - abort ();
> - default:
> - break;
> - }
> }
>
> /* Check if HLE prefix is OK. */
> @@ -12496,6 +12869,7 @@ lex_got (enum bfd_reloc_code_real *rel,
> int first, second;
> char *tmpbuf, *past_reloc;
>
> + i.has_gotrel = true;
> *rel = gotrel[j].rel[object_64bit];
>
> if (types)
> @@ -16229,6 +16603,7 @@ const char *md_shortopts = "qnO::";
> #define OPTION_MLFENCE_BEFORE_INDIRECT_BRANCH (OPTION_MD_BASE + 32)
> #define OPTION_MLFENCE_BEFORE_RET (OPTION_MD_BASE + 33)
> #define OPTION_MUSE_UNALIGNED_VECTOR_MOVE (OPTION_MD_BASE + 34)
> +#define OPTION_MTLS_CHECK (OPTION_MD_BASE + 35)
>
> struct option md_longopts[] =
> {
> @@ -16275,6 +16650,7 @@ struct option md_longopts[] =
> {"mlfence-before-ret", required_argument, NULL, OPTION_MLFENCE_BEFORE_RET},
> {"mamd64", no_argument, NULL, OPTION_MAMD64},
> {"mintel64", no_argument, NULL, OPTION_MINTEL64},
> + {"mtls-check", required_argument, NULL, OPTION_MTLS_CHECK},
> {NULL, no_argument, NULL, 0}
> };
> size_t md_longopts_size = sizeof (md_longopts);
> @@ -16831,6 +17207,14 @@ md_parse_option (int c, const char *arg)
> optimize_for_space = 0;
> }
> break;
> + case OPTION_MTLS_CHECK:
> + if (strcasecmp (arg, "yes") == 0)
> + tls_check = true;
> + else if (strcasecmp (arg, "no") == 0)
> + tls_check = false;
> + else
> + as_fatal (_("invalid -mtls-check= option: `%s'"), arg);
> + break;
>
> default:
> return 0;
> @@ -17073,6 +17457,16 @@ md_show_usage (FILE *stream)
> fprintf (stream, _("(default: no)\n"));
> fprintf (stream, _("\
> generate relax relocations\n"));
> +
> + fprintf (stream, _("\
> + -mtls-check=[no|yes] "));
> + if (DEFAULT_X86_TLS_CHECK)
> + fprintf (stream, _("(default: yes)\n"));
> + else
> + fprintf (stream, _("(default: no)\n"));
> + fprintf (stream, _("\
> + check TLS relocation\n"));
> +
> fprintf (stream, _("\
> -malign-branch-boundary=NUM (default: 0)\n\
> align branches within NUM byte boundary\n"));
> diff --git a/gas/configure b/gas/configure
> index 6b96d3a4e0c..be37f31e1af 100755
> --- a/gas/configure
> +++ b/gas/configure
> @@ -818,6 +818,7 @@ enable_checking
> enable_compressed_debug_sections
> enable_default_compressed_debug_sections_algorithm
> enable_x86_relax_relocations
> +enable_x86_tls_check
> enable_elf_stt_common
> enable_generate_build_notes
> enable_mips_fix_loongson3_llsc
> @@ -1493,6 +1494,7 @@ Optional Features:
> --enable-compressed-debug-sections.
> --enable-x86-relax-relocations
> generate x86 relax relocations by default
> + --enable-x86-tls-check check x86 TLS relocation by default
> --enable-elf-stt-common generate ELF common symbols with STT_COMMON type by
> default
> --enable-generate-build-notes
> @@ -10775,7 +10777,7 @@ else
> lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
> lt_status=$lt_dlunknown
> cat > conftest.$ac_ext <<_LT_EOF
> -#line 10778 "configure"
> +#line 10780 "configure"
> #include "confdefs.h"
>
> #if HAVE_DLFCN_H
> @@ -10881,7 +10883,7 @@ else
> lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
> lt_status=$lt_dlunknown
> cat > conftest.$ac_ext <<_LT_EOF
> -#line 10884 "configure"
> +#line 10886 "configure"
> #include "confdefs.h"
>
> #if HAVE_DLFCN_H
> @@ -11575,6 +11577,17 @@ if test "${enable_x86_relax_relocations+set}" = set; then :
> esac
> fi
>
> +# PR gas/32022
> +# Decide if x86 assembler should check TLS relocation.
> +ac_default_x86_tls_check=unset
> +# Provide a configure time option to override our default.
> +# Check whether --enable-x86_tls_check was given.
> +if test "${enable_x86_tls_check+set}" = set; then :
> + enableval=$enable_x86_tls_check; case "${enableval}" in
> + no) ac_default_x86_tls_check=0 ;;
> +esac
> +fi
> +
> # Decide if ELF assembler should generate common symbols with the
> # STT_COMMON type.
> ac_default_elf_stt_common=unset
> @@ -12698,6 +12711,15 @@ cat >>confdefs.h <<_ACEOF
> _ACEOF
>
>
> +if test ${ac_default_x86_tls_check} = unset; then
> + ac_default_x86_tls_check=1
> +fi
> +
> +cat >>confdefs.h <<_ACEOF
> +#define DEFAULT_X86_TLS_CHECK $ac_default_x86_tls_check
> +_ACEOF
> +
> +
> if test ${ac_default_elf_stt_common} = unset; then
> ac_default_elf_stt_common=0
> fi
> diff --git a/gas/configure.ac b/gas/configure.ac
> index 6b978aae3f7..bf3f9b5b6fa 100644
> --- a/gas/configure.ac
> +++ b/gas/configure.ac
> @@ -95,6 +95,17 @@ AC_ARG_ENABLE(x86_relax_relocations,
> no) ac_default_x86_relax_relocations=0 ;;
> esac])dnl
>
> +# PR gas/32022
> +# Decide if x86 assembler should check TLS relocation.
> +ac_default_x86_tls_check=unset
> +# Provide a configure time option to override our default.
> +AC_ARG_ENABLE(x86_tls_check,
> + AS_HELP_STRING([--enable-x86-tls-check],
> + [check x86 TLS relocation by default]),
> +[case "${enableval}" in
> + no) ac_default_x86_tls_check=0 ;;
> +esac])dnl
> +
> # Decide if ELF assembler should generate common symbols with the
> # STT_COMMON type.
> ac_default_elf_stt_common=unset
> @@ -737,6 +748,13 @@ AC_DEFINE_UNQUOTED(DEFAULT_GENERATE_X86_RELAX_RELOCATIONS,
> $ac_default_x86_relax_relocations,
> [Define to 1 if you want to generate x86 relax relocations by default.])
>
> +if test ${ac_default_x86_tls_check} = unset; then
> + ac_default_x86_tls_check=1
> +fi
> +AC_DEFINE_UNQUOTED(DEFAULT_X86_TLS_CHECK,
> + $ac_default_x86_tls_check,
> + [Define to 1 if you want to check x86 TLS relocation by default.])
> +
> if test ${ac_default_elf_stt_common} = unset; then
> ac_default_elf_stt_common=0
> fi
> diff --git a/gas/doc/c-i386.texi b/gas/doc/c-i386.texi
> index a9e43560aea..9667061752d 100644
> --- a/gas/doc/c-i386.texi
> +++ b/gas/doc/c-i386.texi
> @@ -467,6 +467,16 @@ R_X86_64_REX_GOTPCRELX, in 64-bit mode.
> relocations. The default can be controlled by a configure option
> @option{--enable-x86-relax-relocations}.
>
> +@cindex @samp{-mtls-check=} option, i386
> +@cindex @samp{-mtls-check=} option, x86-64
> +@item -mtls-check=@var{no}
> +@itemx -mtls-check=@var{yes}
> +These options control whether the assembler check tls relocation.
> +@option{-mtls-check=@var{yes}} will check tls relocation.
> +@option{-mtls-check=@var{no}} will not check tls relocation
> +The default can be controlled by a configure option
> +@option{--enable-x86-tls-check}.
> +
> @cindex @samp{-malign-branch-boundary=} option, i386
> @cindex @samp{-malign-branch-boundary=} option, x86-64
> @item -malign-branch-boundary=@var{NUM}
> diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp
> index 75ad061b32c..6710a56d64a 100644
> --- a/gas/testsuite/gas/i386/i386.exp
> +++ b/gas/testsuite/gas/i386/i386.exp
> @@ -699,10 +699,11 @@ if [gas_32_check] then {
> run_dump_test "tlsd"
> run_dump_test "tlspic"
> run_dump_test "tlsnopic"
> + run_dump_test "tls"
> run_list_test "inval-tls"
> run_dump_test "bss"
> run_dump_test "reloc32"
> - run_list_test "reloc32" "--defsym _bad_=1"
> + run_list_test "reloc32" "--defsym _bad_=1 -mtls-check=no"
> run_dump_test "intel-got32"
> run_dump_test "intel-movs32"
> run_dump_test "intel-movs16"
> diff --git a/gas/testsuite/gas/i386/ilp32/ilp32.exp b/gas/testsuite/gas/i386/ilp32/ilp32.exp
> index a3017388934..18befccf5ff 100644
> --- a/gas/testsuite/gas/i386/ilp32/ilp32.exp
> +++ b/gas/testsuite/gas/i386/ilp32/ilp32.exp
> @@ -37,8 +37,9 @@ if [expr ([istarget "i*86-*-*"] || [istarget "x86_64-*-*"]) && [gas_x32_check] &
> }
> }
>
> - run_list_test "reloc64" "--defsym _bad_=1"
> + run_list_test "reloc64" "--defsym _bad_=1 -mtls-check=no"
> run_list_test "reloc-2"
> + run_list_test "x32-inval-tls" "-I${srcdir}/$subdir"
>
> set ASFLAGS "$old_ASFLAGS"
> }
> diff --git a/gas/testsuite/gas/i386/ilp32/reloc64.d b/gas/testsuite/gas/i386/ilp32/reloc64.d
> index e2c461f24e8..84b6aaccc01 100644
> --- a/gas/testsuite/gas/i386/ilp32/reloc64.d
> +++ b/gas/testsuite/gas/i386/ilp32/reloc64.d
> @@ -1,4 +1,4 @@
> -#as: -mx86-used-note=no --generate-missing-build-notes=no
> +#as: -mx86-used-note=no --generate-missing-build-notes=no -mtls-check=no
> #objdump: -Drw
> #name: x86-64 (ILP32) relocs
>
> diff --git a/gas/testsuite/gas/i386/ilp32/x32-inval-tls.l b/gas/testsuite/gas/i386/ilp32/x32-inval-tls.l
> new file mode 100644
> index 00000000000..f3807c8b69d
> --- /dev/null
> +++ b/gas/testsuite/gas/i386/ilp32/x32-inval-tls.l
> @@ -0,0 +1,38 @@
> +.*: Assembler messages:
> +.*:3: Error: @GOTTPOFF operator cannot be used with `kmovq'
> +.*:4: Error: @TLSLD operator cannot be used with `kmovq'
> +.*:7: Error: @TLSGD operator cannot be used with `add'
> +.*:8: Error: @TLSGD operator requires `%rdi' as dest register
> +.*:9: Error: @TLSGD operator requires `%rip' as base register
> +.*:10: Error: @TLSGD operator requires base register
> +.*:11: Error: @TLSGD operator requires `%rip' as base register
> +.*:12: Error: @TLSGD operator requires `%rdi' as dest register
> +.*:15: Error: @TLSLD operator cannot be used with `add'
> +.*:16: Error: @TLSLD operator requires `%rdi' as dest register
> +.*:17: Error: @TLSLD operator requires `%rip' as base register
> +.*:18: Error: @TLSLD operator requires base register
> +.*:19: Error: @TLSLD operator requires `%rip' as base register
> +.*:20: Error: @TLSLD operator requires `%rdi' as dest register
> +.*:23: Error: @TLSDESC operator cannot be used with `add'
> +.*:24: Error: @TLSDESC operator requires `%rip' as base register
> +.*:25: Error: @TLSDESC operator requires `%rip' as base register
> +.*:27: Error: @TLSDESC operator requires 32-bit or 64-bit dest register
> +.*:30: Error: @GOTTPOFF operator cannot be used with `sub'
> +.*:31: Error: @GOTTPOFF operator cannot be used with `xor'
> +.*:32: Error: @GOTTPOFF operator requires `%rip' as base register
> +.*:33: Error: @GOTTPOFF operator requires `%rip' as base register
> +.*:34: Error: @GOTTPOFF operator requires 32-bit or 64-bit dest register
> +.*:35: Error: @GOTTPOFF operator can be used with `add', but format is wrong
> +.*:36: Error: @GOTTPOFF operator can be used with `add', but format is wrong
> +.*:37: Error: @GOTTPOFF operator can be used with `add', but format is wrong
> +.*:38: Error: @GOTTPOFF operator can be used with `add', but format is wrong
> +.*:39: Error: @GOTTPOFF operator requires `%rip' as base register
> +.*:40: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
> +.*:41: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
> +.*:42: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
> +.*:43: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
> +.*:44: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
> +.*:48: Error: @TLSCALL operator cannot be used with `lea'
> +.*:49: Error: @TLSCALL operator requires `%eax/%rax' as base register
> +.*:49: Error: 0-byte relocation cannot be applied to 4-byte field
> +.*:50: Error: `\*foo@tlscall\(%ax\)' is not a valid base/index expression
> diff --git a/gas/testsuite/gas/i386/ilp32/x32-inval-tls.s b/gas/testsuite/gas/i386/ilp32/x32-inval-tls.s
> new file mode 100644
> index 00000000000..b1d967f88db
> --- /dev/null
> +++ b/gas/testsuite/gas/i386/ilp32/x32-inval-tls.s
> @@ -0,0 +1 @@
> +.include "../x86-64-inval-tls.s"
> diff --git a/gas/testsuite/gas/i386/ilp32/x32-tls.d b/gas/testsuite/gas/i386/ilp32/x32-tls.d
> index ab4da5c730b..ac7d136c1ac 100644
> --- a/gas/testsuite/gas/i386/ilp32/x32-tls.d
> +++ b/gas/testsuite/gas/i386/ilp32/x32-tls.d
> @@ -1,3 +1,4 @@
> +#as: -mtls-check=no
> #objdump: -dw
> #name: x86-64 (ILP32) TLS
>
> diff --git a/gas/testsuite/gas/i386/ilp32/x86-64-tls.d b/gas/testsuite/gas/i386/ilp32/x86-64-tls.d
> new file mode 100644
> index 00000000000..a2261f5cdcb
> --- /dev/null
> +++ b/gas/testsuite/gas/i386/ilp32/x86-64-tls.d
> @@ -0,0 +1,4 @@
> +#source: ../x86-64-tls.s
> +#objdump: -drw
> +#name: x86-64 (ILP32) TLS
> +#dump: ../x86-64-tls.d
> diff --git a/gas/testsuite/gas/i386/inval-tls.l b/gas/testsuite/gas/i386/inval-tls.l
> index 98f7a29f1ab..e20ba7a4316 100644
> --- a/gas/testsuite/gas/i386/inval-tls.l
> +++ b/gas/testsuite/gas/i386/inval-tls.l
> @@ -1,2 +1,70 @@
> -.*: Assembler messages:
> -.*:3: Error: @GOTNTPOFF operator cannot be used with `kmovd'
> +.*ssembler messages:
> +.* Error: @GOTNTPOFF operator cannot be used with `kmovd'
> +.* Error: @TLSGD operator cannot be used with `add'
> +.* Error: @TLSGD operator requires `%ebx' as index register
> +.* Error: @TLSGD operator requires scale factor of 1
> +.* Error: @TLSGD operator requires no base register
> +.*: Error: @TLSGD operator requires `%eax' as dest register
> +.*: Error: @TLSGD operator requires `%eax' as dest register
> +.*: Error: @TLSGD operator requires `%eax' as base register
> +.*: Error: @TLSGD operator requires 32-bit dest register
> +.*: Error: @TLSLDM operator cannot be used with `add'
> +.*: Error: @TLSLDM operator requires `%eax' as dest register
> +.*: Error: @TLSLDM operator requires `%eax' as base register
> +.*: Error: @TLSLDM operator requires no SIB
> +.*: Error: @TLSLDM operator requires 32-bit dest register
> +.*: Error: @TLSDESC operator cannot be used with `add'
> +.*: Error: @TLSDESC operator requires `%ebx' as base register
> +.*: Error: @TLSDESC operator requires no SIB
> +.*: Error: @TLSDESC operator requires 32-bit dest register
> +.*: Error: @INDNTPOFF operator cannot be used with `sub'
> +.*: Error: @INDNTPOFF operator requires no base/index register
> +.*: Error: @INDNTPOFF operator requires no base/index register
> +.*: Error: @INDNTPOFF operator requires 32-bit dest register
> +.*: Error: @INDNTPOFF operator can be used with `add', but format is wrong
> +.*: Error: @INDNTPOFF operator can be used with `add', but format is wrong
> +.*: Error: @INDNTPOFF operator can be used with `add', but format is wrong
> +.*: Error: @INDNTPOFF operator can be used with `add', but format is wrong
> +.*: Error: @INDNTPOFF operator can be used with `mov', but format is wrong
> +.*: Error: @INDNTPOFF operator can be used with `mov', but format is wrong
> +.*: Error: @INDNTPOFF operator can be used with `mov', but format is wrong
> +.*: Error: @INDNTPOFF operator can be used with `mov', but format is wrong
> +.*: Error: @INDNTPOFF operator can be used with `mov', but format is wrong
> +.*: Error: @GOTNTPOFF operator cannot be used with `lea'
> +.*: Error: @GOTNTPOFF operator requires base register
> +.*: Error: @GOTNTPOFF operator cannot be used with `lea'
> +.*: Error: @GOTNTPOFF operator can be used with `sub', but format is wrong
> +.*: Error: @GOTNTPOFF operator can be used with `sub', but format is wrong
> +.*: Error: @GOTNTPOFF operator can be used with `sub', but format is wrong
> +.*: Error: @GOTNTPOFF operator can be used with `sub', but format is wrong
> +.*: Error: @GOTNTPOFF operator can be used with `add', but format is wrong
> +.*: Error: @GOTNTPOFF operator can be used with `add', but format is wrong
> +.*: Error: @GOTNTPOFF operator can be used with `add', but format is wrong
> +.*: Error: @GOTNTPOFF operator can be used with `add', but format is wrong
> +.*: Error: @GOTNTPOFF operator requires base register
> +.*: Error: @GOTNTPOFF operator can be used with `mov', but format is wrong
> +.*: Error: @GOTNTPOFF operator can be used with `mov', but format is wrong
> +.*: Error: @GOTNTPOFF operator can be used with `mov', but format is wrong
> +.*: Error: @GOTNTPOFF operator can be used with `mov', but format is wrong
> +.*: Error: @GOTNTPOFF operator can be used with `mov', but format is wrong
> +.*: Error: @GOTTPOFF operator cannot be used with `lea'
> +.*: Error: @GOTTPOFF operator requires base register
> +.*: Error: @GOTTPOFF operator requires 32-bit dest register
> +.*: Error: @GOTTPOFF operator can be used with `sub', but format is wrong
> +.*: Error: @GOTTPOFF operator can be used with `sub', but format is wrong
> +.*: Error: @GOTTPOFF operator can be used with `sub', but format is wrong
> +.*: Error: @GOTTPOFF operator can be used with `sub', but format is wrong
> +.*: Error: @GOTTPOFF operator can be used with `add', but format is wrong
> +.*: Error: @GOTTPOFF operator can be used with `add', but format is wrong
> +.*: Error: @GOTTPOFF operator can be used with `add', but format is wrong
> +.*: Error: @GOTTPOFF operator requires base register
> +.*: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
> +.*: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
> +.*: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
> +.*: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
> +.*: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
> +.*: Error: @TLSCALL operator cannot be used with `lea'
> +.*: Error: @TLSCALL operator requires `%eax/%rax' as base register
> +.*: Error: @TLSCALL operator requires no SIB
> +.*: Error: 0-byte relocation cannot be applied to 4-byte field
> +.*: Error: @TLSCALL operator requires `%eax/%rax' as base register
> diff --git a/gas/testsuite/gas/i386/inval-tls.s b/gas/testsuite/gas/i386/inval-tls.s
> index ba0e1b81dc9..067e9b4cbdf 100644
> --- a/gas/testsuite/gas/i386/inval-tls.s
> +++ b/gas/testsuite/gas/i386/inval-tls.s
> @@ -1,3 +1,85 @@
> .text
> # All the following should be illegal
> kmovd foo@gotntpoff(%eax), %k0
> +
> + /* Invalid testcase for R_386_TLS_GD. */
> + addl foo@tlsgd(,%ebx,1), %eax
> + leal foo@tlsgd(,%ecx,1), %eax
> + leal foo@tlsgd(,%ebx,2), %eax
> + leal foo@tlsgd(%ecx,%ebx,1), %eax
> + leal foo@tlsgd(,%ebx,1), %ecx
> + leal foo@tlsgd(%ebx), %ecx
> + leal foo@tlsgd(%eax), %eax
> + lea foo@tlsgd(%ebx), %ax
> +
> + /* Invalid testcase for R_386_TLS_LDM. */
> + addl foo@tlsldm(%ebx), %eax
> + leal foo@tlsldm(%ebx), %ecx
> + leal foo@tlsldm(%eax), %eax
> + leal foo@tlsldm(,%ebx,1), %eax
> + lea foo@tlsldm(%ebx), %ax
> +
> + /* Invalid testcase for R_386_TLS_GOTDESC. */
> + addl x@tlsdesc(%ebx), %eax
> + leal x@tlsdesc(%ecx), %eax
> + leal x@tlsdesc(,%ecx,1), %eax
> + lea x@tlsdesc(%ebx), %ax
> +
> + /* Invalid testcase for R_386_TLS_IE. */
> + subl foo@indntpoff, %ecx
> + addl foo@indntpoff(%ebx), %ecx
> + movl foo@indntpoff(%ebx), %ecx
> + add foo@indntpoff, %cx
> + addl $foo@indntpoff, %eax
> + addl %ecx, foo@indntpoff
> + addl $0x9090,foo@indntpoff
> + addl $0x90909090,foo@indntpoff
> + movl foo@indntpoff,%eax
> + movl %edx,foo@indntpoff(%eax)
> + movw %ss,foo@indntpoff(%eax)
> + movw foo@indntpoff(%eax),%ss
> + movl $0x90909090,foo@indntpoff(%eax)
> + movl $foo@indntpoff, %eax
> +
> + /* Invalid testcase for R_386_TLS_GOTIE. */
> + leal foo@gotntpoff(%ebx), %ecx
> + subl foo@gotntpoff(,%ebx,1), %ecx
> + lea foo@gotntpoff(%ebx), %cx
> + subl %ecx, foo@gotntpoff(%ebx)
> + subl $0x9090,foo@gotntpoff(%ebx)
> + subl $0x90909090,foo@gotntpoff(%eax)
> + subl $foo@gotntpoff, %eax
> + addl %ecx, foo@gotntpoff(%ebx)
> + addl $0x9090,foo@gotntpoff(%ebx)
> + addl $0x90909090,foo@gotntpoff(%eax)
> + addl $foo@gotntpoff, %eax
> + movl foo@gotntpoff,%eax
> + movl %edx,foo@gotntpoff(%eax)
> + movw %ss,foo@gotntpoff(%eax)
> + movw foo@gotntpoff(%eax),%ss
> + movl $0x90909090,foo@gotntpoff(%eax)
> + movl $foo@gotntpoff, %eax
> +
> + /* Invalid testcase for R_386_TLS_IE_32. */
> + leal foo@gottpoff(%ebx), %ecx
> + subl foo@gottpoff(,%ebx,1), %ecx
> + add foo@gottpoff(%ebx), %cx
> + subl %ecx, foo@gottpoff(%ebx)
> + subl $0x9090,foo@gottpoff(%ebx)
> + subl $0x90909090,foo@gottpoff(%eax)
> + subl $foo@gottpoff, %eax
> + addl %ecx, foo@gottpoff(%ebx)
> + addl $0x9090,foo@gottpoff(%ebx)
> + addl $0x90909090,foo@gottpoff(%eax)
> + movl foo@gottpoff,%eax
> + movl %edx,foo@gottpoff(%eax)
> + movw %ss,foo@gottpoff(%eax)
> + movw foo@gottpoff(%eax),%ss
> + movl $0x90909090,foo@gottpoff(%eax)
> + movl $foo@gottpoff, %eax
> +
> + /* Invalid testcase for R_386_TLS_DESC_CALL. */
> + leal foo@tlscall(%eax), %ebx
> + call *x@tlscall(%ebx)
> + call *x@tlscall(,%eax,1)
> + call *x@tlscall(%bx)
> diff --git a/gas/testsuite/gas/i386/reloc32.d b/gas/testsuite/gas/i386/reloc32.d
> index 263a742022e..7d1b1ba2ae0 100644
> --- a/gas/testsuite/gas/i386/reloc32.d
> +++ b/gas/testsuite/gas/i386/reloc32.d
> @@ -1,4 +1,4 @@
> -#as: -mrelax-relocations=yes
> +#as: -mrelax-relocations=yes -mtls-check=no
> #objdump: -Drw
> #name: i386 relocs
>
> diff --git a/gas/testsuite/gas/i386/reloc64.d b/gas/testsuite/gas/i386/reloc64.d
> index 540a9b77d35..f4e44a627c5 100644
> --- a/gas/testsuite/gas/i386/reloc64.d
> +++ b/gas/testsuite/gas/i386/reloc64.d
> @@ -1,4 +1,4 @@
> -#as: -mx86-used-note=no --generate-missing-build-notes=no
> +#as: -mx86-used-note=no --generate-missing-build-notes=no -mtls-check=no
> #objdump: -Drw
> #name: x86-64 relocs
> #notarget: *-*-solaris*
> diff --git a/gas/testsuite/gas/i386/tls.d b/gas/testsuite/gas/i386/tls.d
> new file mode 100644
> index 00000000000..adfe7ce9551
> --- /dev/null
> +++ b/gas/testsuite/gas/i386/tls.d
> @@ -0,0 +1,25 @@
> +#as:
> +#objdump: -drw
> +#name: Check tls relocation 32 bit-mode
> +
> +.*: +file format .*
> +
> +
> +Disassembly of section .text:
> +
> +00000000 <_start>:
> +\s*[a-f0-9]+:\s*8d 04 1d 00 00 00 00[ ]+lea 0x0\(,%ebx,1\),%eax 3: R_386_TLS_GD foo
> +\s*[a-f0-9]+:\s*8d 81 00 00 00 00[ ]+lea 0x0\(%ecx\),%eax 9: R_386_TLS_GD foo
> +\s*[a-f0-9]+:\s*8d 83 00 00 00 00[ ]+lea 0x0\(%ebx\),%eax f: R_386_TLS_LDM foo
> +\s*[a-f0-9]+:\s*8d 83 00 00 00 00[ ]+lea 0x0\(%ebx\),%eax 15: R_386_TLS_GOTDESC x
> +\s*[a-f0-9]+:\s*a1 00 00 00 00[ ]+mov 0x0,%eax 1a: R_386_TLS_IE foo
> +\s*[a-f0-9]+:\s*8b 1d 00 00 00 00[ ]+mov 0x0,%ebx 20: R_386_TLS_IE foo
> +\s*[a-f0-9]+:\s*03 15 00 00 00 00[ ]+add 0x0,%edx 26: R_386_TLS_IE foo
> +\s*[a-f0-9]+:\s*2b 8b 00 00 00 00[ ]+sub 0x0\(%ebx\),%ecx 2c: R_386_TLS_GOTIE foo
> +\s*[a-f0-9]+:\s*8b 8b 00 00 00 00[ ]+mov 0x0\(%ebx\),%ecx 32: R_386_TLS_GOTIE foo
> +\s*[a-f0-9]+:\s*03 8b 00 00 00 00[ ]+add 0x0\(%ebx\),%ecx 38: R_386_TLS_GOTIE foo
> +\s*[a-f0-9]+:\s*2b 8b 00 00 00 00[ ]+sub 0x0\(%ebx\),%ecx 3e: R_386_TLS_IE_32 foo
> +\s*[a-f0-9]+:\s*8b 8b 00 00 00 00[ ]+mov 0x0\(%ebx\),%ecx 44: R_386_TLS_IE_32 foo
> +\s*[a-f0-9]+:\s*03 8b 00 00 00 00[ ]+add 0x0\(%ebx\),%ecx 4a: R_386_TLS_IE_32 foo
> +\s*[a-f0-9]+:\s*ff 10[ ]+call \*\(%eax\) 4e: R_386_TLS_DESC_CALL foo
> +#pass
> diff --git a/gas/testsuite/gas/i386/tls.s b/gas/testsuite/gas/i386/tls.s
> new file mode 100644
> index 00000000000..6c077ee48fb
> --- /dev/null
> +++ b/gas/testsuite/gas/i386/tls.s
> @@ -0,0 +1,31 @@
> +# Check tls relocation 32-bit mode
> +
> + .text
> +_start:
> + /* R_386_TLS_GD. */
> + leal foo@tlsgd(,%ebx,1), %eax
> + leal foo@tlsgd(%ecx), %eax
> +
> + /* R_386_TLS_LDM. */
> + leal foo@tlsldm(%ebx), %eax
> +
> + /* R_386_TLS_GOTDESC. */
> + leal x@tlsdesc(%ebx), %eax
> +
> + /* R_386_TLS_IE. */
> + movl foo@indntpoff, %eax
> + movl foo@indntpoff, %ebx
> + addl foo@indntpoff, %edx
> +
> + /* R_386_TLS_GOTIE. */
> + subl foo@gotntpoff(%ebx), %ecx
> + movl foo@gotntpoff(%ebx), %ecx
> + addl foo@gotntpoff(%ebx), %ecx
> +
> + /* R_386_TLS_IE_32. */
> + subl foo@gottpoff(%ebx), %ecx
> + movl foo@gottpoff(%ebx), %ecx
> + addl foo@gottpoff(%ebx), %ecx
> +
> + /* R_386_TLS_DESC_CALL. */
> + call *foo@tlscall(%eax)
> diff --git a/gas/testsuite/gas/i386/x86-64-inval-tls.l b/gas/testsuite/gas/i386/x86-64-inval-tls.l
> index da8ac19f869..134d96bf383 100644
> --- a/gas/testsuite/gas/i386/x86-64-inval-tls.l
> +++ b/gas/testsuite/gas/i386/x86-64-inval-tls.l
> @@ -1,3 +1,39 @@
> .*: Assembler messages:
> .*:3: Error: @GOTTPOFF operator cannot be used with `kmovq'
> .*:4: Error: @TLSLD operator cannot be used with `kmovq'
> +.*:7: Error: @TLSGD operator cannot be used with `add'
> +.*:8: Error: @TLSGD operator requires `%rdi' as dest register
> +.*:9: Error: @TLSGD operator requires `%rip' as base register
> +.*:10: Error: @TLSGD operator requires base register
> +.*:11: Error: @TLSGD operator requires `%rip' as base register
> +.*:12: Error: @TLSGD operator requires `%rdi' as dest register
> +.*:15: Error: @TLSLD operator cannot be used with `add'
> +.*:16: Error: @TLSLD operator requires `%rdi' as dest register
> +.*:17: Error: @TLSLD operator requires `%rip' as base register
> +.*:18: Error: @TLSLD operator requires base register
> +.*:19: Error: @TLSLD operator requires `%rip' as base register
> +.*:20: Error: @TLSLD operator requires `%rdi' as dest register
> +.*:23: Error: @TLSDESC operator cannot be used with `add'
> +.*:24: Error: @TLSDESC operator requires `%rip' as base register
> +.*:25: Error: @TLSDESC operator requires `%rip' as base register
> +.*:26: Error: @TLSDESC operator requires 64-bit dest register
> +.*:27: Error: @TLSDESC operator requires 64-bit dest register
> +.*:30: Error: @GOTTPOFF operator cannot be used with `sub'
> +.*:31: Error: @GOTTPOFF operator cannot be used with `xor'
> +.*:32: Error: @GOTTPOFF operator requires `%rip' as base register
> +.*:33: Error: @GOTTPOFF operator requires `%rip' as base register
> +.*:34: Error: @GOTTPOFF operator requires 64-bit dest register
> +.*:35: Error: @GOTTPOFF operator can be used with `add', but format is wrong
> +.*:36: Error: @GOTTPOFF operator can be used with `add', but format is wrong
> +.*:37: Error: @GOTTPOFF operator can be used with `add', but format is wrong
> +.*:38: Error: @GOTTPOFF operator can be used with `add', but format is wrong
> +.*:39: Error: @GOTTPOFF operator requires `%rip' as base register
> +.*:40: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
> +.*:41: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
> +.*:42: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
> +.*:43: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
> +.*:44: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
> +.*:48: Error: @TLSCALL operator cannot be used with `lea'
> +.*:49: Error: @TLSCALL operator requires `%eax/%rax' as base register
> +.*:49: Error: 0-byte relocation cannot be applied to 4-byte field
> +.*:50: Error: `\*foo@tlscall\(%ax\)' is not a valid base/index expression
> diff --git a/gas/testsuite/gas/i386/x86-64-inval-tls.s b/gas/testsuite/gas/i386/x86-64-inval-tls.s
> index 71e19272ba9..8783530a423 100644
> --- a/gas/testsuite/gas/i386/x86-64-inval-tls.s
> +++ b/gas/testsuite/gas/i386/x86-64-inval-tls.s
> @@ -2,3 +2,49 @@
> # All the following should be illegal
> kmovq foo@gottpoff(%rip), %k0
> kmovq foo@tlsld(%rip), %k0
> +
> + /* Invalid testcase for R_X86_64_TLSGD. */
> + addq foo@tlsgd(%rip), %rdi
> + leaq foo@tlsgd(%rip), %rax
> + leaq foo@tlsgd(%rax), %rdi
> + leaq foo@tlsgd(,%rax,1), %rdi
> + leaq foo@tlsgd(%eip), %rdi
> + leal foo@tlsgd(%rip), %edi
> +
> + /* Invalid testcase for R_X86_64_TLSLD. */
> + addq foo@tlsld(%rip), %rdi
> + leaq foo@tlsld(%rip), %rax
> + leaq foo@tlsld(%rax), %rdi
> + leaq foo@tlsld(,%rax,1), %rdi
> + leaq foo@tlsld(%eip), %rdi
> + leal foo@tlsld(%rip), %edi
> +
> + /* Invalid testcase for R_X86_64_GOTPC32_TLSDESC. */
> + addq x@tlsdesc(%rip), %rax
> + leaq x@tlsdesc(%rbx), %rax
> + lea x@tlsdesc(%eip), %rdi
> + lea x@tlsdesc(%rip), %eax
> + lea x@tlsdesc(%rip), %ax
> +
> + /* Invalid testcase for R_X86_64_GOTTPOFF. */
> + subq foo@gottpoff(%rip), %r12
> + xorq foo@gottpoff(%rip), %rax
> + addq foo@gottpoff(%rbx), %rax
> + addq foo@gottpoff(%eip), %rax
> + add foo@gottpoff(%rip), %ax
> + addq %rax, foo@gottpoff(%rip)
> + addl $0x90909090, foo@gottpoff(%rip)
> + add $0x90, foo@gottpoff(%rip), %rax
> + add $0xffffffffffffffff, foo@gottpoff(%rip), %rax
> + movq foo@gottpoff(%rbx), %rax
> + movq %rax, foo@gottpoff(%rip)
> + mov %ss,foo@gottpoff(%rip)
> + mov foo@gottpoff(%rip),%ss
> + movl $0x90909090,foo@gottpoff(%rip)
> + mov $foo@gottpoff, %rax
> +
> +
> + /* Invalid testcase for R_X86_64_TLSDESC_CALL. */
> + leaq foo@tlscall(%rax), %rbx
> + call *foo@tlscall(%rip)
> + call *foo@tlscall(%ax)
> diff --git a/gas/testsuite/gas/i386/x86-64-tls.d b/gas/testsuite/gas/i386/x86-64-tls.d
> new file mode 100644
> index 00000000000..1c30496e227
> --- /dev/null
> +++ b/gas/testsuite/gas/i386/x86-64-tls.d
> @@ -0,0 +1,25 @@
> +#as:
> +#objdump: -drw
> +#name: Check tls relocation x86-64
> +
> +.*: +file format .*
> +
> +
> +Disassembly of section .text:
> +
> +0+ <_start>:
> + +[a-f0-9]+: 48 8d 3d 00 00 00 00 lea 0x0\(%rip\),%rdi # 7 <_start\+0x7> 3: R_X86_64_TLSGD foo-0x4
> + +[a-f0-9]+: 48 8d 3d 00 00 00 00 lea 0x0\(%rip\),%rdi # e <_start\+0xe> a: R_X86_64_TLSLD foo-0x4
> + +[a-f0-9]+: 48 8d 05 00 00 00 00 lea 0x0\(%rip\),%rax # 15 <_start\+0x15> 11: R_X86_64_GOTPC32_TLSDESC x-0x4
> + +[a-f0-9]+: 4c 03 25 00 00 00 00 add 0x0\(%rip\),%r12 # 1c <_start\+0x1c> 18: R_X86_64_GOTTPOFF foo-0x4
> + +[a-f0-9]+: 48 8b 05 00 00 00 00 mov 0x0\(%rip\),%rax # 23 <_start\+0x23> 1f: R_X86_64_GOTTPOFF foo-0x4
> + +[a-f0-9]+: d5 48 03 05 00 00 00 00 add 0x0\(%rip\),%r16 # 2b <_start\+0x2b> 27: R_X86_64_CODE_4_GOTTPOFF foo-0x4
> + +[a-f0-9]+: d5 48 8b 25 00 00 00 00 mov 0x0\(%rip\),%r20 # 33 <_start\+0x33> 2f: R_X86_64_CODE_4_GOTTPOFF foo-0x4
> + +[a-f0-9]+: 62 64 bc 18 01 35 00 00 00 00 add %r30,0x0\(%rip\),%r8 # 3d <_start\+0x3d> 39: R_X86_64_CODE_6_GOTTPOFF foo-0x4
> + +[a-f0-9]+: 62 f4 dc 10 03 05 00 00 00 00 add 0x0\(%rip\),%rax,%r20 # 47 <_start\+0x47> 43: R_X86_64_CODE_6_GOTTPOFF foo-0x4
> + +[a-f0-9]+: 62 e4 fc 0c 03 05 00 00 00 00 \{nf\} add 0x0\(%rip\),%r16 # 51 <_start\+0x51> 4d: R_X86_64_CODE_6_GOTTPOFF foo-0x4
> + +[a-f0-9]+: 62 64 bc 1c 01 35 00 00 00 00 \{nf\} add %r30,0x0\(%rip\),%r8 # 5b <_start\+0x5b> 57: R_X86_64_CODE_6_GOTTPOFF foo-0x4
> + +[a-f0-9]+: 62 f4 dc 14 03 05 00 00 00 00 \{nf\} add 0x0\(%rip\),%rax,%r20 # 65 <_start\+0x65> 61: R_X86_64_CODE_6_GOTTPOFF foo-0x4
> + +[a-f0-9]+: ff 10 call \*\(%rax\) 65: R_X86_64_TLSDESC_CALL x
> + +[a-f0-9]+: 67 ff 10 call \*\(%eax\) 67: R_X86_64_TLSDESC_CALL x
> +#pass
> diff --git a/gas/testsuite/gas/i386/x86-64-tls.s b/gas/testsuite/gas/i386/x86-64-tls.s
> new file mode 100644
> index 00000000000..7c3bd4a982c
> --- /dev/null
> +++ b/gas/testsuite/gas/i386/x86-64-tls.s
> @@ -0,0 +1,27 @@
> +# Check tls relocation 64-bit mode
> +
> + .text
> +_start:
> + /* R_X86_64_TLSGD. */
> + leaq foo@tlsgd(%rip), %rdi
> +
> + /* R_X86_64_TLSLD. */
> + leaq foo@tlsld(%rip), %rdi
> +
> + /* R_X86_64_GOTPC32_TLSDESC. */
> + leaq x@tlsdesc(%rip), %rax
> +
> + /* R_X86_64_GOTTPOFF. */
> + addq foo@gottpoff(%rip), %r12
> + movq foo@gottpoff(%rip), %rax
> + addq foo@gottpoff(%rip), %r16
> + movq foo@gottpoff(%rip), %r20
> + addq %r30, foo@gottpoff(%rip), %r8
> + addq foo@gottpoff(%rip), %rax, %r20
> + {nf} addq foo@gottpoff(%rip), %r16
> + {nf} addq %r30, foo@gottpoff(%rip), %r8
> + {nf} addq foo@gottpoff(%rip), %rax, %r20
> +
> + /* R_X86_64_TLSDESC_CALL. */
> + call *x@tlscall(%rax)
> + call *x@tlscall(%eax)
> diff --git a/gas/testsuite/gas/i386/x86-64.exp b/gas/testsuite/gas/i386/x86-64.exp
> index 86e7f4a75b3..740f5268de3 100644
> --- a/gas/testsuite/gas/i386/x86-64.exp
> +++ b/gas/testsuite/gas/i386/x86-64.exp
> @@ -653,7 +653,8 @@ if [is_elf_format] then {
> run_dump_test "x86-64-unwind"
>
> run_dump_test "reloc64"
> - run_list_test "reloc64" "--defsym _bad_=1"
> + run_list_test "reloc64" "--defsym _bad_=1 -mtls-check=no"
> + run_dump_test "x86-64-tls"
> run_list_test "x86-64-inval-tls"
> run_dump_test "mixed-mode-reloc64"
> run_dump_test "rela"
> diff --git a/ld/testsuite/ld-i386/tlsgdesc1.d b/ld/testsuite/ld-i386/tlsgdesc1.d
> index 2a70e81c444..0c853ab0a67 100644
> --- a/ld/testsuite/ld-i386/tlsgdesc1.d
> +++ b/ld/testsuite/ld-i386/tlsgdesc1.d
> @@ -1,4 +1,4 @@
> #name: TLS GDesc->LE transition check (LEA)
> -#as: --32
> +#as: --32 -mtls-check=no
> #ld: -melf_i386
> #error: .*: relocation R_386_TLS_GOTDESC against `foo' must be used in LEA only
> diff --git a/ld/testsuite/ld-i386/tlsgdesc2.d b/ld/testsuite/ld-i386/tlsgdesc2.d
> index bbf93bef767..99e1b18b1ea 100644
> --- a/ld/testsuite/ld-i386/tlsgdesc2.d
> +++ b/ld/testsuite/ld-i386/tlsgdesc2.d
> @@ -1,4 +1,4 @@
> #name: TLS GDesc->LE transition check (indirect CALL)
> -#as: --32
> +#as: --32 -mtls-check=no
> #ld: -melf_i386
> #error: .*: relocation R_386_TLS_DESC_CALL against `foo' must be used in indirect CALL with EAX register only
> diff --git a/ld/testsuite/ld-i386/tlsgdesc3.d b/ld/testsuite/ld-i386/tlsgdesc3.d
> index f2c29d880f2..4bb99c4422b 100644
> --- a/ld/testsuite/ld-i386/tlsgdesc3.d
> +++ b/ld/testsuite/ld-i386/tlsgdesc3.d
> @@ -1,5 +1,5 @@
> #source: tlsgdesc2.s
> #name: TLS GDesc call (indirect CALL)
> -#as: --32
> +#as: --32 -mtls-check=no
> #ld: -shared -melf_i386
> #error: .*: relocation R_386_TLS_DESC_CALL against `foo' must be used in indirect CALL with EAX register only
> diff --git a/ld/testsuite/ld-i386/tlsie2.d b/ld/testsuite/ld-i386/tlsie2.d
> index 9f9e63029d6..4e7dc6ea56e 100644
> --- a/ld/testsuite/ld-i386/tlsie2.d
> +++ b/ld/testsuite/ld-i386/tlsie2.d
> @@ -1,4 +1,4 @@
> #name: TLS IE->LE transition check (R_386_TLS_GOTIE with %eax)
> -#as: --32
> +#as: --32 -mtls-check=no
> #ld: -melf_i386
> #error: .*: relocation R_386_TLS_GOTIE against `foo' must be used in ADD, SUB or MOV only
> diff --git a/ld/testsuite/ld-i386/tlsie3.d b/ld/testsuite/ld-i386/tlsie3.d
> index 506f1a02605..6bfc78e0b49 100644
> --- a/ld/testsuite/ld-i386/tlsie3.d
> +++ b/ld/testsuite/ld-i386/tlsie3.d
> @@ -1,4 +1,4 @@
> #name: TLS IE->LE transition check (R_386_TLS_GOTIE)
> -#as: --32
> +#as: --32 -mtls-check=no
> #ld: -melf_i386
> #error: .*: relocation R_386_TLS_GOTIE against `foo' must be used in ADD, SUB or MOV only
> diff --git a/ld/testsuite/ld-i386/tlsie4.d b/ld/testsuite/ld-i386/tlsie4.d
> index a516d002660..98293f4b36a 100644
> --- a/ld/testsuite/ld-i386/tlsie4.d
> +++ b/ld/testsuite/ld-i386/tlsie4.d
> @@ -1,4 +1,4 @@
> #name: TLS IE->LE transition check (R_386_TLS_IE with %eax)
> -#as: --32
> +#as: --32 -mtls-check=no
> #ld: -melf_i386
> #error: .*: relocation R_386_TLS_IE against `foo' must be used in ADD or MOV only
> diff --git a/ld/testsuite/ld-i386/tlsie5.d b/ld/testsuite/ld-i386/tlsie5.d
> index d3447182e19..4e9c9a8f74a 100644
> --- a/ld/testsuite/ld-i386/tlsie5.d
> +++ b/ld/testsuite/ld-i386/tlsie5.d
> @@ -1,4 +1,4 @@
> #name: TLS IE->LE transition check (R_386_TLS_IE)
> -#as: --32
> +#as: --32 -mtls-check=no
> #ld: -melf_i386
> #error: .*: relocation R_386_TLS_IE against `foo' must be used in ADD or MOV only
> diff --git a/ld/testsuite/ld-x86-64/tlsdesc3.d b/ld/testsuite/ld-x86-64/tlsdesc3.d
> index bbf22ebeafe..955884885d7 100644
> --- a/ld/testsuite/ld-x86-64/tlsdesc3.d
> +++ b/ld/testsuite/ld-x86-64/tlsdesc3.d
> @@ -1,4 +1,4 @@
> #name: TLS GDesc->LE transition check (LEA)
> -#as: --64
> +#as: --64 -mtls-check=no
> #ld: -melf_x86_64
> #error: .*: relocation R_X86_64_GOTPC32_TLSDESC against `foo' must be used in LEA only
> diff --git a/ld/testsuite/ld-x86-64/tlsdesc4.d b/ld/testsuite/ld-x86-64/tlsdesc4.d
> index c882c877ae3..ccaa525c74b 100644
> --- a/ld/testsuite/ld-x86-64/tlsdesc4.d
> +++ b/ld/testsuite/ld-x86-64/tlsdesc4.d
> @@ -1,4 +1,4 @@
> #name: TLS GDesc->LE transition check (indirect CALL)
> -#as: --64
> +#as: --64 -mtls-check=no
> #ld: -melf_x86_64
> #error: .*: relocation R_X86_64_TLSDESC_CALL against `foo' must be used in indirect CALL with RAX register only
> diff --git a/ld/testsuite/ld-x86-64/tlsdesc5.d b/ld/testsuite/ld-x86-64/tlsdesc5.d
> index 6a0158b44b7..0876993bca3 100644
> --- a/ld/testsuite/ld-x86-64/tlsdesc5.d
> +++ b/ld/testsuite/ld-x86-64/tlsdesc5.d
> @@ -1,5 +1,5 @@
> #source: tlsdesc4.s
> #name: TLS GDesc call (indirect CALL)
> -#as: --64
> +#as: --64 -mtls-check=no
> #ld: -shared -melf_x86_64
> #error: .*: relocation R_X86_64_TLSDESC_CALL against `foo' must be used in indirect CALL with RAX register only
> diff --git a/ld/testsuite/ld-x86-64/tlsie2.d b/ld/testsuite/ld-x86-64/tlsie2.d
> index bf8a8198b5b..2e6d41ccf61 100644
> --- a/ld/testsuite/ld-x86-64/tlsie2.d
> +++ b/ld/testsuite/ld-x86-64/tlsie2.d
> @@ -1,4 +1,4 @@
> #name: TLS IE->LE transition check
> -#as: --64
> +#as: --64 -mtls-check=no
> #ld: -melf_x86_64
> #error: .*: relocation R_X86_64_GOTTPOFF against `foo' must be used in ADD or MOV only
> diff --git a/ld/testsuite/ld-x86-64/tlsie3.d b/ld/testsuite/ld-x86-64/tlsie3.d
> index 49d8464fbaf..b59cc6429de 100644
> --- a/ld/testsuite/ld-x86-64/tlsie3.d
> +++ b/ld/testsuite/ld-x86-64/tlsie3.d
> @@ -1,4 +1,4 @@
> #name: TLS IE->LE transition check (%r12)
> -#as: --64
> +#as: --64 -mtls-check=no
> #ld: -melf_x86_64
> #error: .*: relocation R_X86_64_GOTTPOFF against `foo' must be used in ADD or MOV only
> diff --git a/ld/testsuite/ld-x86-64/tlsie5.d b/ld/testsuite/ld-x86-64/tlsie5.d
> index 29de1cebf8e..d7ab5ab7b32 100644
> --- a/ld/testsuite/ld-x86-64/tlsie5.d
> +++ b/ld/testsuite/ld-x86-64/tlsie5.d
> @@ -1,4 +1,4 @@
> #name: TLS IE->LE transition check (APX)
> -#as: --64
> +#as: --64 -mtls-check=no
> #ld: -melf_x86_64
> #error: .*: relocation R_X86_64_CODE_6_GOTTPOFF against `foo' must be used in ADD only
> --
> 2.34.1
>
> -----Original Message-----
> From: H.J. Lu <hjl.tools@gmail.com>
> Sent: Thursday, September 19, 2024 2:50 PM
> To: Cui, Lili <lili.cui@intel.com>
> Cc: Beulich, Jan <JBeulich@suse.com>; binutils@sourceware.org
> Subject: Re: [PATCH V5] x86: Add tls check in gas
>
> On Thu, Sep 19, 2024 at 2:38 PM Cui, Lili <lili.cui@intel.com> wrote:
> >
> > Assembler shouldn't accept invalid TLS instructions, TLS relocations
> > can only be used with specific instructions as specified in TLS psABI
> > and linker issues an error when TLS relocations are used with wrong
> > instructions or format. It is inconvenient for gcc to rely on linker
> > to report errors, adding tls check in the assembler stage so that gcc
> > can know tls errors earlier.
> >
> > ----------------------
> > Changes in V5:
> >
> > 1. Separated the register size judgment of X32 and ILP64.
> > 2. Added new x32 TLS relocation tests.
> > 3. Adjusted comments and error types.
> >
> > ----------------------
> >
> > gas/ChangeLog:
> >
> > PR gas/32022
> > * config.in: Regenerate.
> > * config/tc-i386.c
> > *(enum x86_tls_error_type): New.
> > *(struct _i386_insn): Added has_gotrel to indicate whether tls relocations
> need to be checked.
>
> LIne too long.
>
Done.
> > (x86_check_tls_relocation): Added a new function to check tls relocation.
>
> Line too long.
>
Done.
> Also please use TLS, instead of tls, in the commit message and ChangeLog.
>
> It looks OK to me. Please give Jan a day to comment before committing
> it.
>
Ok.
Thanks,
Lili.
> Thanks.
>
> > (x86_report_tls_error): Created a new function to report tls error.
> > (i386_assemble): Handle x86_check_tls_relocation.
> > (lex_got): Set i.has_gotrel.
> > (OPTION_MTLS_CHECK): Added a new option to contrl tls check.
> > (struct option): Ditto.
> > (md_parse_option): Ditto.
> > (md_show_usage): Ditto.
> > * configure: Added a new option to check tls relocation by default.
> > * configure.ac: Ditto.
> > * doc/c-i386.texi: Ditto.
> > * testsuite/gas/i386/i386.exp: Added new tests.
> > * testsuite/gas/i386/ilp32/ilp32.exp: Ditto.
> > * testsuite/gas/i386/ilp32/reloc64.d: Disable tls check for it.
> > * testsuite/gas/i386/ilp32/x32-tls.d: Ditto.
> > * testsuite/gas/i386/inval-tls.l: Added more test cases.
> > * testsuite/gas/i386/inval-tls.s: Ditto.
> > * testsuite/gas/i386/reloc32.d: Disable tls check for it.
> > * testsuite/gas/i386/reloc64.d: Ditto.
> > * testsuite/gas/i386/x86-64-inval-tls.l: Added more test cases.
> > * testsuite/gas/i386/x86-64-inval-tls.s: Ditto.
> > * testsuite/gas/i386/x86-64.exp: Added new tests.
> > * testsuite/gas/i386/ilp32/x32-inval-tls.l: New test.
> > * testsuite/gas/i386/ilp32/x32-inval-tls.s: Ditto.
> > * testsuite/gas/i386/ilp32/x86-64-tls.d: Ditto.
> > * testsuite/gas/i386/tls.d: Ditto.
> > * testsuite/gas/i386/tls.s: Ditto.
> > * testsuite/gas/i386/x86-64-tls.d: Ditto.
> > * testsuite/gas/i386/x86-64-tls.s: Ditto.
> >
> > ld/ChangeLog:
> >
> > PR gas/32022
> > * testsuite/ld-i386/tlsgdesc1.d: Disable tls check for it.
> > * testsuite/ld-i386/tlsgdesc2.d: Ditto.
> > * testsuite/ld-i386/tlsie2.d: Ditto.
> > * testsuite/ld-i386/tlsie3.d: Ditto.
> > * testsuite/ld-i386/tlsie4.d: Ditto.
> > * testsuite/ld-i386/tlsie5.d: Ditto.
> > * testsuite/ld-i386/tlsgdesc3.d: Ditto.
> > * testsuite/ld-x86-64/tlsdesc3.d: Ditto.
> > * testsuite/ld-x86-64/tlsdesc4.d: Ditto.
> > * testsuite/ld-x86-64/tlsie2.d: Ditto.
> > * testsuite/ld-x86-64/tlsie3.d: Ditto.
> > * testsuite/ld-x86-64/tlsie5.d: Ditto.
> > * testsuite/ld-x86-64/tlsdesc5.d: Ditto.
> > ---
> > gas/config.in | 3 +
> > gas/config/tc-i386.c | 438 ++++++++++++++++++-
> > gas/configure | 26 +-
> > gas/configure.ac | 18 +
> > gas/doc/c-i386.texi | 10 +
> > gas/testsuite/gas/i386/i386.exp | 3 +-
> > gas/testsuite/gas/i386/ilp32/ilp32.exp | 3 +-
> > gas/testsuite/gas/i386/ilp32/reloc64.d | 2 +-
> > gas/testsuite/gas/i386/ilp32/x32-inval-tls.l | 38 ++
> > gas/testsuite/gas/i386/ilp32/x32-inval-tls.s | 1 +
> > gas/testsuite/gas/i386/ilp32/x32-tls.d | 1 +
> > gas/testsuite/gas/i386/ilp32/x86-64-tls.d | 4 +
> > gas/testsuite/gas/i386/inval-tls.l | 72 ++-
> > gas/testsuite/gas/i386/inval-tls.s | 82 ++++
> > gas/testsuite/gas/i386/reloc32.d | 2 +-
> > gas/testsuite/gas/i386/reloc64.d | 2 +-
> > gas/testsuite/gas/i386/tls.d | 25 ++
> > gas/testsuite/gas/i386/tls.s | 31 ++
> > gas/testsuite/gas/i386/x86-64-inval-tls.l | 36 ++
> > gas/testsuite/gas/i386/x86-64-inval-tls.s | 46 ++
> > gas/testsuite/gas/i386/x86-64-tls.d | 25 ++
> > gas/testsuite/gas/i386/x86-64-tls.s | 27 ++
> > gas/testsuite/gas/i386/x86-64.exp | 3 +-
> > ld/testsuite/ld-i386/tlsgdesc1.d | 2 +-
> > ld/testsuite/ld-i386/tlsgdesc2.d | 2 +-
> > ld/testsuite/ld-i386/tlsgdesc3.d | 2 +-
> > ld/testsuite/ld-i386/tlsie2.d | 2 +-
> > ld/testsuite/ld-i386/tlsie3.d | 2 +-
> > ld/testsuite/ld-i386/tlsie4.d | 2 +-
> > ld/testsuite/ld-i386/tlsie5.d | 2 +-
> > ld/testsuite/ld-x86-64/tlsdesc3.d | 2 +-
> > ld/testsuite/ld-x86-64/tlsdesc4.d | 2 +-
> > ld/testsuite/ld-x86-64/tlsdesc5.d | 2 +-
> > ld/testsuite/ld-x86-64/tlsie2.d | 2 +-
> > ld/testsuite/ld-x86-64/tlsie3.d | 2 +-
> > ld/testsuite/ld-x86-64/tlsie5.d | 2 +-
> > 36 files changed, 879 insertions(+), 45 deletions(-)
> > create mode 100644 gas/testsuite/gas/i386/ilp32/x32-inval-tls.l
> > create mode 100644 gas/testsuite/gas/i386/ilp32/x32-inval-tls.s
> > create mode 100644 gas/testsuite/gas/i386/ilp32/x86-64-tls.d
> > create mode 100644 gas/testsuite/gas/i386/tls.d
> > create mode 100644 gas/testsuite/gas/i386/tls.s
> > create mode 100644 gas/testsuite/gas/i386/x86-64-tls.d
> > create mode 100644 gas/testsuite/gas/i386/x86-64-tls.s
> >
> > diff --git a/gas/config.in b/gas/config.in
> > index a1f83499332..c32b46b93f5 100644
> > --- a/gas/config.in
> > +++ b/gas/config.in
> > @@ -60,6 +60,9 @@
> > /* Define default value for RISC-V -mpriv-spec */
> > #undef DEFAULT_RISCV_PRIV_SPEC
> >
> > +/* Define to 1 if you want to check x86 TLS relocation by default. */
> > +#undef DEFAULT_X86_TLS_CHECK
> > +
> > /* Define to 1 if you want to generate GNU x86 used ISA and feature
> properties
> > by default. */
> > #undef DEFAULT_X86_USED_NOTE
> > diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
> > index 4739a6d0c21..2b6b5ab5538 100644
> > --- a/gas/config/tc-i386.c
> > +++ b/gas/config/tc-i386.c
> > @@ -274,6 +274,30 @@ enum i386_error
> > internal_error,
> > };
> >
> > +enum x86_tls_error_type
> > +{
> > + x86_tls_error_continue,
> > + x86_tls_error_none,
> > + x86_tls_error_insn,
> > + x86_tls_error_opcode,
> > + x86_tls_error_sib,
> > + x86_tls_error_no_base_reg,
> > + x86_tls_error_require_no_base_index_reg,
> > + x86_tls_error_base_reg,
> > + x86_tls_error_index_ebx,
> > + x86_tls_error_eax,
> > + x86_tls_error_RegA,
> > + x86_tls_error_ebx,
> > + x86_tls_error_rip,
> > + x86_tls_error_dest_eax,
> > + x86_tls_error_dest_rdi,
> > + x86_tls_error_scale_factor,
> > + x86_tls_error_base_reg_size,
> > + x86_tls_error_dest_32bit_reg_size,
> > + x86_tls_error_dest_64bit_reg_size,
> > + x86_tls_error_dest_32bit_or_64bit_reg_size
> > +};
> > +
> > struct _i386_insn
> > {
> > /* TM holds the template for the insn were currently assembling. */
> > @@ -365,6 +389,9 @@ struct _i386_insn
> > /* Has GOTPC or TLS relocation. */
> > bool has_gotpc_tls_reloc;
> >
> > + /* Has relocation entry from the gotrel array. */
> > + bool has_gotrel;
> > +
> > /* RM and SIB are the modrm byte and the sib byte where the
> > addressing modes of this insn are encoded. */
> > modrm_byte rm;
> > @@ -717,6 +744,9 @@ lfence_before_ret;
> > static int generate_relax_relocations
> > = DEFAULT_GENERATE_X86_RELAX_RELOCATIONS;
> >
> > +/* 1 if the assembler should check tls relocation. */
> > +static bool tls_check = DEFAULT_X86_TLS_CHECK;
> > +
> > static enum check_kind
> > {
> > check_none = 0,
> > @@ -6357,6 +6387,356 @@ static INLINE bool may_need_pass2 (const
> insn_template *t)
> > && (t->base_opcode | 8) == 0x2c);
> > }
> >
> > +static enum x86_tls_error_type
> > +x86_check_tls_relocation (enum bfd_reloc_code_real r_type)
> > +{
> > + switch (r_type)
> > + {
> > + case BFD_RELOC_386_TLS_GOTDESC:
> > + /* Check GDesc access model:
> > +
> > + leal x@tlsdesc(%ebx), %reg32 --> Memory reg must be %ebx and
> > + SIB is not supported.
> > + */
> > + if (i.tm.mnem_off != MN_lea)
> > + return x86_tls_error_insn;
> > + if (i.index_reg)
> > + return x86_tls_error_sib;
> > + if (!i.base_reg)
> > + return x86_tls_error_no_base_reg;
> > + if (i.base_reg->reg_type.bitfield.instance != RegB)
> > + return x86_tls_error_ebx;
> > + if (!i.op[1].regs->reg_type.bitfield.dword)
> > + return x86_tls_error_dest_32bit_reg_size;
> > + break;
> > +
> > + case BFD_RELOC_386_TLS_GD:
> > + /* Check GD access model:
> > +
> > + leal foo@tlsgd(,%ebx,1), %eax --> Only this fixed format is supported.
> > + leal foo@tlsgd(%reg32), %eax --> Dest reg must be '%eax'
> > + Memory reg can't be %eax.
> > + */
> > + if (i.tm.mnem_off != MN_lea)
> > + return x86_tls_error_insn;
> > + if (i.op[1].regs->reg_type.bitfield.instance != Accum)
> > + return x86_tls_error_dest_eax;
> > + if (!i.op[1].regs->reg_type.bitfield.dword)
> > + return x86_tls_error_dest_32bit_reg_size;
> > + if (i.index_reg)
> > + {
> > + if (i.base_reg)
> > + return x86_tls_error_base_reg;
> > + if (i.index_reg->reg_type.bitfield.instance != RegB)
> > + return x86_tls_error_index_ebx;
> > + if (i.log2_scale_factor)
> > + return x86_tls_error_scale_factor;
> > + }
> > + else
> > + {
> > + if (!i.base_reg)
> > + return x86_tls_error_no_base_reg;
> > + if (i.base_reg->reg_type.bitfield.instance == Accum)
> > + return x86_tls_error_eax;
> > + }
> > + break;
> > +
> > + case BFD_RELOC_386_TLS_LDM:
> > + /* Check LDM access model:
> > +
> > + leal foo@tlsldm(%reg32), %eax --> Dest reg must be '%eax'
> > + Memory reg can't be %eax and SIB
> > + is not supported.
> > + */
> > + if (i.tm.mnem_off != MN_lea)
> > + return x86_tls_error_insn;
> > + if (i.index_reg)
> > + return x86_tls_error_sib;
> > + if (!i.base_reg)
> > + return x86_tls_error_no_base_reg;
> > + if (i.base_reg->reg_type.bitfield.instance == Accum)
> > + return x86_tls_error_eax;
> > + if (i.op[1].regs->reg_type.bitfield.instance != Accum)
> > + return x86_tls_error_dest_eax;
> > + if (!i.op[1].regs->reg_type.bitfield.dword)
> > + return x86_tls_error_dest_32bit_reg_size;
> > + break;
> > +
> > + case BFD_RELOC_X86_64_GOTPC32_TLSDESC:
> > + /* Check GOTPC32 TLSDESC access model:
> > +
> > + --- LP64 mode ---
> > + leaq x@tlsdesc(%rip), %reg64 --> Memory reg must be %rip.
> > +
> > + --- X32 mode ---
> > + rex/rex2 leal x@tlsdesc(%rip), %reg32 --> Memory reg must be %rip.
> > +
> > + In X32 mode, gas will add rex/rex2 for it later, no need to check
> > + here.
> > + */
> > + if (i.tm.mnem_off != MN_lea)
> > + return x86_tls_error_insn;
> > + if (!i.base_reg)
> > + return x86_tls_error_no_base_reg;
> > + if (i.base_reg->reg_num != RegIP
> > + || !i.base_reg->reg_type.bitfield.qword)
> > + return x86_tls_error_rip;
> > + if (x86_elf_abi == X86_64_ABI)
> > + {
> > + if (!i.op[1].regs->reg_type.bitfield.qword)
> > + return x86_tls_error_dest_64bit_reg_size;
> > + }
> > + else if (!i.op[1].regs->reg_type.bitfield.dword
> > + && !i.op[1].regs->reg_type.bitfield.qword)
> > + return x86_tls_error_dest_32bit_or_64bit_reg_size;
> > + break;
> > +
> > + case BFD_RELOC_X86_64_TLSGD:
> > + /* Check GD access model:
> > +
> > + leaq foo@tlsgd(%rip), %rdi --> Only this fixed format is supported.
> > + */
> > + case BFD_RELOC_X86_64_TLSLD:
> > + /* Check LD access model:
> > +
> > + leaq foo@tlsld(%rip), %rdi --> Only this fixed format is supported.
> > + */
> > + if (i.tm.mnem_off != MN_lea)
> > + return x86_tls_error_insn;
> > + if (!i.base_reg)
> > + return x86_tls_error_no_base_reg;
> > + if (i.base_reg->reg_num != RegIP
> > + || !i.base_reg->reg_type.bitfield.qword)
> > + return x86_tls_error_rip;
> > + if (!i.op[1].regs->reg_type.bitfield.qword
> > + || i.op[1].regs->reg_num != EDI_REG_NUM
> > + || i.op[1].regs->reg_flags)
> > + return x86_tls_error_dest_rdi;
> > + break;
> > +
> > + case BFD_RELOC_386_TLS_GOTIE:
> > + /* Check GOTIE access model:
> > +
> > + subl foo@gotntpoff(%reg1), %reg2
> > + movl foo@gotntpoff(%reg1), %reg2
> > + addl foo@gotntpoff(%reg1), %reg2
> > +
> > + Memory operand: SIB is not supported.
> > + */
> > + case BFD_RELOC_386_TLS_IE_32:
> > + /* Check IE_32 access model:
> > +
> > + subl foo@gottpoff(%reg1), %reg2
> > + movl foo@gottpoff(%reg1), %reg2
> > + addl foo@gottpoff(%reg1), %reg2
> > +
> > + Memory operand: SIB is not supported.
> > + */
> > + if (i.tm.mnem_off != MN_sub
> > + && i.tm.mnem_off != MN_add
> > + && i.tm.mnem_off != MN_mov)
> > + return x86_tls_error_insn;
> > + if (i.op[1].regs->reg_type.bitfield.class != Reg
> > + || i.op[0].regs->reg_type.bitfield.class
> > + || i.imm_operands)
> > + return x86_tls_error_opcode;
> > + if (!i.base_reg)
> > + return x86_tls_error_no_base_reg;
> > + if (i.index_reg)
> > + return x86_tls_error_sib;
> > + if (!i.base_reg->reg_type.bitfield.dword)
> > + return x86_tls_error_base_reg_size;
> > + if (!i.op[1].regs->reg_type.bitfield.dword)
> > + return x86_tls_error_dest_32bit_reg_size;
> > + break;
> > +
> > + case BFD_RELOC_386_TLS_IE:
> > + /* Check IE access model:
> > +
> > + movl foo@indntpoff, %reg32 --> Mod == 00 && r/m == 5
> > + addl foo@indntpoff, %reg32 --> Mod == 00 && r/m == 5
> > + */
> > + if (i.tm.mnem_off != MN_add && i.tm.mnem_off != MN_mov)
> > + return x86_tls_error_insn;
> > + if (i.op[1].regs->reg_type.bitfield.class != Reg
> > + || i.op[0].regs->reg_type.bitfield.class
> > + || i.imm_operands)
> > + return x86_tls_error_opcode;
> > + if (i.base_reg || i.index_reg)
> > + return x86_tls_error_require_no_base_index_reg;
> > + if (!i.op[1].regs->reg_type.bitfield.dword)
> > + return x86_tls_error_dest_32bit_reg_size;
> > + break;
> > +
> > + case BFD_RELOC_X86_64_GOTTPOFF:
> > + /* Check GOTTPOFF access model:
> > +
> > + mov foo@gottpoff(%rip), %reg --> Memory Reg must be %rip.
> > + add foo@gottpoff(%rip), %reg --> Memory Reg must be %rip.
> > + add %reg1, foo@gottpoff(%rip), %reg2 --> Memory Reg must be %rip.
> > + add foo@gottpoff(%rip), %reg1, %reg2 --> Memory Reg must be %rip.
> > + */
> > + if (i.tm.mnem_off != MN_add && i.tm.mnem_off != MN_mov)
> > + return x86_tls_error_insn;
> > + if (i.op[i.operands - 1].regs->reg_type.bitfield.class != Reg
> > + || (i.op[0].regs->reg_type.bitfield.class
> > + && i.tm.opcode_modifier.vexvvvv != VexVVVV_DST)
> > + || i.imm_operands)
> > + return x86_tls_error_opcode;
> > + if (!i.base_reg)
> > + return x86_tls_error_no_base_reg;
> > + if (i.base_reg->reg_num != RegIP
> > + || !i.base_reg->reg_type.bitfield.qword)
> > + return x86_tls_error_rip;
> > + if (x86_elf_abi == X86_64_ABI)
> > + {
> > + if (!i.op[i.operands - 1].regs->reg_type.bitfield.qword)
> > + return x86_tls_error_dest_64bit_reg_size;
> > + }
> > + else if (!i.op[i.operands - 1].regs->reg_type.bitfield.dword
> > + && !i.op[i.operands - 1].regs->reg_type.bitfield.qword)
> > + return x86_tls_error_dest_32bit_or_64bit_reg_size;
> > + break;
> > +
> > + case BFD_RELOC_386_TLS_DESC_CALL:
> > + /* Check GDesc access model:
> > +
> > + call *x@tlscall(%eax) --> Memory reg must be %eax and
> > + SIB is not supported.
> > + */
> > + case BFD_RELOC_X86_64_TLSDESC_CALL:
> > + /* Check GDesc access model:
> > +
> > + call *x@tlscall(%rax) <--- LP64 mode.
> > + call *x@tlscall(%eax) <--- X32 mode.
> > +
> > + Only these fixed formats are supported.
> > + */
> > + if (i.tm.mnem_off != MN_call)
> > + return x86_tls_error_insn;
> > + if (i.index_reg)
> > + return x86_tls_error_sib;
> > + if (!i.base_reg)
> > + return x86_tls_error_no_base_reg;
> > + if (i.base_reg->reg_type.bitfield.instance != Accum)
> > + return x86_tls_error_RegA;
> > + break;
> > +
> > + case BFD_RELOC_NONE:
> > + /* This isn't a relocation. */
> > + return x86_tls_error_continue;
> > +
> > + default:
> > + break;
> > + }
> > +
> > + /* This relocation is OK. */
> > + return x86_tls_error_none;
> > +}
> > +
> > +static void
> > +x86_report_tls_error (enum x86_tls_error_type tls_error,
> > + enum bfd_reloc_code_real r_type)
> > +{
> > + unsigned int k;
> > + for (k = 0; k < ARRAY_SIZE (gotrel); k++)
> > + if (gotrel[k].rel[object_64bit] == r_type)
> > + break;
> > +
> > + switch (tls_error)
> > + {
> > + case x86_tls_error_insn:
> > + as_bad (_("@%s operator cannot be used with `%s'"),
> > + gotrel[k].str, insn_name (&i.tm));
> > + return;
> > +
> > + case x86_tls_error_opcode:
> > + as_bad (_("@%s operator can be used with `%s', but format is wrong"),
> > + gotrel[k].str, insn_name (&i.tm));
> > + return;
> > +
> > + case x86_tls_error_sib:
> > + as_bad (_("@%s operator requires no SIB"), gotrel[k].str);
> > + return;
> > +
> > + case x86_tls_error_no_base_reg:
> > + as_bad (_("@%s operator requires base register"), gotrel[k].str);
> > + return;
> > +
> > + case x86_tls_error_require_no_base_index_reg:
> > + as_bad (_("@%s operator requires no base/index register"),
> > + gotrel[k].str);
> > + return;
> > +
> > + case x86_tls_error_base_reg:
> > + as_bad (_("@%s operator requires no base register"), gotrel[k].str);
> > + return;
> > +
> > + case x86_tls_error_index_ebx:
> > + as_bad (_("@%s operator requires `%sebx' as index register"),
> > + gotrel[k].str, register_prefix);
> > + return;
> > +
> > + case x86_tls_error_eax:
> > + as_bad (_("@%s operator requires `%seax' as base register"),
> > + gotrel[k].str, register_prefix);
> > + return;
> > +
> > + case x86_tls_error_RegA:
> > + as_bad (_("@%s operator requires `%seax/%srax' as base register"),
> > + gotrel[k].str, register_prefix, register_prefix);
> > + return;
> > +
> > + case x86_tls_error_ebx:
> > + as_bad (_("@%s operator requires `%sebx' as base register"),
> > + gotrel[k].str, register_prefix);
> > + return;
> > +
> > + case x86_tls_error_rip:
> > + as_bad (_("@%s operator requires `%srip' as base register"),
> > + gotrel[k].str, register_prefix);
> > + return;
> > +
> > + case x86_tls_error_dest_eax:
> > + as_bad (_("@%s operator requires `%seax' as dest register"),
> > + gotrel[k].str, register_prefix);
> > + return;
> > +
> > + case x86_tls_error_dest_rdi:
> > + as_bad (_("@%s operator requires `%srdi' as dest register"),
> > + gotrel[k].str, register_prefix);
> > + return;
> > +
> > + case x86_tls_error_scale_factor:
> > + as_bad (_("@%s operator requires scale factor of 1"),
> > + gotrel[k].str);
> > + return;
> > +
> > + case x86_tls_error_base_reg_size:
> > + as_bad (_("@%s operator requires 32-bit base register"),
> > + gotrel[k].str);
> > + return;
> > +
> > + case x86_tls_error_dest_32bit_reg_size:
> > + as_bad (_("@%s operator requires 32-bit dest register"),
> > + gotrel[k].str);
> > + return;
> > +
> > + case x86_tls_error_dest_64bit_reg_size:
> > + as_bad (_("@%s operator requires 64-bit dest register"),
> > + gotrel[k].str);
> > + return;
> > +
> > + case x86_tls_error_dest_32bit_or_64bit_reg_size:
> > + as_bad (_("@%s operator requires 32-bit or 64-bit dest register"),
> > + gotrel[k].str);
> > + return;
> > +
> > + default:
> > + abort ();
> > + }
> > +}
> > +
> > /* This is the guts of the machine-dependent assembler. LINE points to a
> > machine dependent instruction. This function is supposed to emit
> > the frags/bytes it assembles to. */
> > @@ -6695,6 +7075,21 @@ i386_assemble (char *line)
> > i.prefix[LOCK_PREFIX] = 0;
> > }
> >
> > + if (i.has_gotrel && tls_check)
> > + {
> > + enum x86_tls_error_type tls_error;
> > + for (j = 0; j < i.operands; ++j)
> > + {
> > + tls_error = x86_check_tls_relocation (i.reloc[j]);
> > + if (tls_error == x86_tls_error_continue)
> > + continue;
> > +
> > + if (tls_error != x86_tls_error_none)
> > + x86_report_tls_error (tls_error, i.reloc[j]);
> > + break;
> > + }
> > + }
> > +
> > if ((is_any_vex_encoding (&i.tm) && i.tm.opcode_space !=
> SPACE_EVEXMAP4)
> > || i.tm.operand_types[i.imm_operands].bitfield.class >= RegMMX
> > || i.tm.operand_types[i.imm_operands + 1].bitfield.class >= RegMMX)
> > @@ -6705,28 +7100,6 @@ i386_assemble (char *line)
> > as_bad (_("data size prefix invalid with `%s'"), insn_name (&i.tm));
> > return;
> > }
> > -
> > - /* Don't allow e.g. KMOV in TLS code sequences which will trigger
> > - linker error later. */
> > - for (j = i.imm_operands; j < i.operands; ++j)
> > - switch (i.reloc[j])
> > - {
> > - case BFD_RELOC_X86_64_GOTTPOFF:
> > - case BFD_RELOC_386_TLS_GOTIE:
> > - case BFD_RELOC_X86_64_TLSLD:
> > - for (unsigned int k = 0; k < ARRAY_SIZE (gotrel); k++)
> > - {
> > - if (gotrel[k].rel[object_64bit] == i.reloc[j])
> > - {
> > - as_bad (_("@%s operator cannot be used with `%s'"),
> > - gotrel[k].str, insn_name (&i.tm));
> > - return;
> > - }
> > - }
> > - abort ();
> > - default:
> > - break;
> > - }
> > }
> >
> > /* Check if HLE prefix is OK. */
> > @@ -12496,6 +12869,7 @@ lex_got (enum bfd_reloc_code_real *rel,
> > int first, second;
> > char *tmpbuf, *past_reloc;
> >
> > + i.has_gotrel = true;
> > *rel = gotrel[j].rel[object_64bit];
> >
> > if (types)
> > @@ -16229,6 +16603,7 @@ const char *md_shortopts = "qnO::";
> > #define OPTION_MLFENCE_BEFORE_INDIRECT_BRANCH (OPTION_MD_BASE
> + 32)
> > #define OPTION_MLFENCE_BEFORE_RET (OPTION_MD_BASE + 33)
> > #define OPTION_MUSE_UNALIGNED_VECTOR_MOVE (OPTION_MD_BASE +
> 34)
> > +#define OPTION_MTLS_CHECK (OPTION_MD_BASE + 35)
> >
> > struct option md_longopts[] =
> > {
> > @@ -16275,6 +16650,7 @@ struct option md_longopts[] =
> > {"mlfence-before-ret", required_argument, NULL,
> OPTION_MLFENCE_BEFORE_RET},
> > {"mamd64", no_argument, NULL, OPTION_MAMD64},
> > {"mintel64", no_argument, NULL, OPTION_MINTEL64},
> > + {"mtls-check", required_argument, NULL, OPTION_MTLS_CHECK},
> > {NULL, no_argument, NULL, 0}
> > };
> > size_t md_longopts_size = sizeof (md_longopts);
> > @@ -16831,6 +17207,14 @@ md_parse_option (int c, const char *arg)
> > optimize_for_space = 0;
> > }
> > break;
> > + case OPTION_MTLS_CHECK:
> > + if (strcasecmp (arg, "yes") == 0)
> > + tls_check = true;
> > + else if (strcasecmp (arg, "no") == 0)
> > + tls_check = false;
> > + else
> > + as_fatal (_("invalid -mtls-check= option: `%s'"), arg);
> > + break;
> >
> > default:
> > return 0;
> > @@ -17073,6 +17457,16 @@ md_show_usage (FILE *stream)
> > fprintf (stream, _("(default: no)\n"));
> > fprintf (stream, _("\
> > generate relax relocations\n"));
> > +
> > + fprintf (stream, _("\
> > + -mtls-check=[no|yes] "));
> > + if (DEFAULT_X86_TLS_CHECK)
> > + fprintf (stream, _("(default: yes)\n"));
> > + else
> > + fprintf (stream, _("(default: no)\n"));
> > + fprintf (stream, _("\
> > + check TLS relocation\n"));
> > +
> > fprintf (stream, _("\
> > -malign-branch-boundary=NUM (default: 0)\n\
> > align branches within NUM byte boundary\n"));
> > diff --git a/gas/configure b/gas/configure
> > index 6b96d3a4e0c..be37f31e1af 100755
> > --- a/gas/configure
> > +++ b/gas/configure
> > @@ -818,6 +818,7 @@ enable_checking
> > enable_compressed_debug_sections
> > enable_default_compressed_debug_sections_algorithm
> > enable_x86_relax_relocations
> > +enable_x86_tls_check
> > enable_elf_stt_common
> > enable_generate_build_notes
> > enable_mips_fix_loongson3_llsc
> > @@ -1493,6 +1494,7 @@ Optional Features:
> > --enable-compressed-debug-sections.
> > --enable-x86-relax-relocations
> > generate x86 relax relocations by default
> > + --enable-x86-tls-check check x86 TLS relocation by default
> > --enable-elf-stt-common generate ELF common symbols with STT_COMMON
> type by
> > default
> > --enable-generate-build-notes
> > @@ -10775,7 +10777,7 @@ else
> > lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
> > lt_status=$lt_dlunknown
> > cat > conftest.$ac_ext <<_LT_EOF
> > -#line 10778 "configure"
> > +#line 10780 "configure"
> > #include "confdefs.h"
> >
> > #if HAVE_DLFCN_H
> > @@ -10881,7 +10883,7 @@ else
> > lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
> > lt_status=$lt_dlunknown
> > cat > conftest.$ac_ext <<_LT_EOF
> > -#line 10884 "configure"
> > +#line 10886 "configure"
> > #include "confdefs.h"
> >
> > #if HAVE_DLFCN_H
> > @@ -11575,6 +11577,17 @@ if test "${enable_x86_relax_relocations+set}" =
> set; then :
> > esac
> > fi
> >
> > +# PR gas/32022
> > +# Decide if x86 assembler should check TLS relocation.
> > +ac_default_x86_tls_check=unset
> > +# Provide a configure time option to override our default.
> > +# Check whether --enable-x86_tls_check was given.
> > +if test "${enable_x86_tls_check+set}" = set; then :
> > + enableval=$enable_x86_tls_check; case "${enableval}" in
> > + no) ac_default_x86_tls_check=0 ;;
> > +esac
> > +fi
> > +
> > # Decide if ELF assembler should generate common symbols with the
> > # STT_COMMON type.
> > ac_default_elf_stt_common=unset
> > @@ -12698,6 +12711,15 @@ cat >>confdefs.h <<_ACEOF
> > _ACEOF
> >
> >
> > +if test ${ac_default_x86_tls_check} = unset; then
> > + ac_default_x86_tls_check=1
> > +fi
> > +
> > +cat >>confdefs.h <<_ACEOF
> > +#define DEFAULT_X86_TLS_CHECK $ac_default_x86_tls_check
> > +_ACEOF
> > +
> > +
> > if test ${ac_default_elf_stt_common} = unset; then
> > ac_default_elf_stt_common=0
> > fi
> > diff --git a/gas/configure.ac b/gas/configure.ac
> > index 6b978aae3f7..bf3f9b5b6fa 100644
> > --- a/gas/configure.ac
> > +++ b/gas/configure.ac
> > @@ -95,6 +95,17 @@ AC_ARG_ENABLE(x86_relax_relocations,
> > no) ac_default_x86_relax_relocations=0 ;;
> > esac])dnl
> >
> > +# PR gas/32022
> > +# Decide if x86 assembler should check TLS relocation.
> > +ac_default_x86_tls_check=unset
> > +# Provide a configure time option to override our default.
> > +AC_ARG_ENABLE(x86_tls_check,
> > + AS_HELP_STRING([--enable-x86-tls-check],
> > + [check x86 TLS relocation by default]),
> > +[case "${enableval}" in
> > + no) ac_default_x86_tls_check=0 ;;
> > +esac])dnl
> > +
> > # Decide if ELF assembler should generate common symbols with the
> > # STT_COMMON type.
> > ac_default_elf_stt_common=unset
> > @@ -737,6 +748,13 @@
> AC_DEFINE_UNQUOTED(DEFAULT_GENERATE_X86_RELAX_RELOCATIONS,
> > $ac_default_x86_relax_relocations,
> > [Define to 1 if you want to generate x86 relax relocations by default.])
> >
> > +if test ${ac_default_x86_tls_check} = unset; then
> > + ac_default_x86_tls_check=1
> > +fi
> > +AC_DEFINE_UNQUOTED(DEFAULT_X86_TLS_CHECK,
> > + $ac_default_x86_tls_check,
> > + [Define to 1 if you want to check x86 TLS relocation by default.])
> > +
> > if test ${ac_default_elf_stt_common} = unset; then
> > ac_default_elf_stt_common=0
> > fi
> > diff --git a/gas/doc/c-i386.texi b/gas/doc/c-i386.texi
> > index a9e43560aea..9667061752d 100644
> > --- a/gas/doc/c-i386.texi
> > +++ b/gas/doc/c-i386.texi
> > @@ -467,6 +467,16 @@ R_X86_64_REX_GOTPCRELX, in 64-bit mode.
> > relocations. The default can be controlled by a configure option
> > @option{--enable-x86-relax-relocations}.
> >
> > +@cindex @samp{-mtls-check=} option, i386
> > +@cindex @samp{-mtls-check=} option, x86-64
> > +@item -mtls-check=@var{no}
> > +@itemx -mtls-check=@var{yes}
> > +These options control whether the assembler check tls relocation.
> > +@option{-mtls-check=@var{yes}} will check tls relocation.
> > +@option{-mtls-check=@var{no}} will not check tls relocation
> > +The default can be controlled by a configure option
> > +@option{--enable-x86-tls-check}.
> > +
> > @cindex @samp{-malign-branch-boundary=} option, i386
> > @cindex @samp{-malign-branch-boundary=} option, x86-64
> > @item -malign-branch-boundary=@var{NUM}
> > diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp
> > index 75ad061b32c..6710a56d64a 100644
> > --- a/gas/testsuite/gas/i386/i386.exp
> > +++ b/gas/testsuite/gas/i386/i386.exp
> > @@ -699,10 +699,11 @@ if [gas_32_check] then {
> > run_dump_test "tlsd"
> > run_dump_test "tlspic"
> > run_dump_test "tlsnopic"
> > + run_dump_test "tls"
> > run_list_test "inval-tls"
> > run_dump_test "bss"
> > run_dump_test "reloc32"
> > - run_list_test "reloc32" "--defsym _bad_=1"
> > + run_list_test "reloc32" "--defsym _bad_=1 -mtls-check=no"
> > run_dump_test "intel-got32"
> > run_dump_test "intel-movs32"
> > run_dump_test "intel-movs16"
> > diff --git a/gas/testsuite/gas/i386/ilp32/ilp32.exp
> b/gas/testsuite/gas/i386/ilp32/ilp32.exp
> > index a3017388934..18befccf5ff 100644
> > --- a/gas/testsuite/gas/i386/ilp32/ilp32.exp
> > +++ b/gas/testsuite/gas/i386/ilp32/ilp32.exp
> > @@ -37,8 +37,9 @@ if [expr ([istarget "i*86-*-*"] || [istarget "x86_64-*-*"])
> && [gas_x32_check] &
> > }
> > }
> >
> > - run_list_test "reloc64" "--defsym _bad_=1"
> > + run_list_test "reloc64" "--defsym _bad_=1 -mtls-check=no"
> > run_list_test "reloc-2"
> > + run_list_test "x32-inval-tls" "-I${srcdir}/$subdir"
> >
> > set ASFLAGS "$old_ASFLAGS"
> > }
> > diff --git a/gas/testsuite/gas/i386/ilp32/reloc64.d
> b/gas/testsuite/gas/i386/ilp32/reloc64.d
> > index e2c461f24e8..84b6aaccc01 100644
> > --- a/gas/testsuite/gas/i386/ilp32/reloc64.d
> > +++ b/gas/testsuite/gas/i386/ilp32/reloc64.d
> > @@ -1,4 +1,4 @@
> > -#as: -mx86-used-note=no --generate-missing-build-notes=no
> > +#as: -mx86-used-note=no --generate-missing-build-notes=no -mtls-check=no
> > #objdump: -Drw
> > #name: x86-64 (ILP32) relocs
> >
> > diff --git a/gas/testsuite/gas/i386/ilp32/x32-inval-tls.l
> b/gas/testsuite/gas/i386/ilp32/x32-inval-tls.l
> > new file mode 100644
> > index 00000000000..f3807c8b69d
> > --- /dev/null
> > +++ b/gas/testsuite/gas/i386/ilp32/x32-inval-tls.l
> > @@ -0,0 +1,38 @@
> > +.*: Assembler messages:
> > +.*:3: Error: @GOTTPOFF operator cannot be used with `kmovq'
> > +.*:4: Error: @TLSLD operator cannot be used with `kmovq'
> > +.*:7: Error: @TLSGD operator cannot be used with `add'
> > +.*:8: Error: @TLSGD operator requires `%rdi' as dest register
> > +.*:9: Error: @TLSGD operator requires `%rip' as base register
> > +.*:10: Error: @TLSGD operator requires base register
> > +.*:11: Error: @TLSGD operator requires `%rip' as base register
> > +.*:12: Error: @TLSGD operator requires `%rdi' as dest register
> > +.*:15: Error: @TLSLD operator cannot be used with `add'
> > +.*:16: Error: @TLSLD operator requires `%rdi' as dest register
> > +.*:17: Error: @TLSLD operator requires `%rip' as base register
> > +.*:18: Error: @TLSLD operator requires base register
> > +.*:19: Error: @TLSLD operator requires `%rip' as base register
> > +.*:20: Error: @TLSLD operator requires `%rdi' as dest register
> > +.*:23: Error: @TLSDESC operator cannot be used with `add'
> > +.*:24: Error: @TLSDESC operator requires `%rip' as base register
> > +.*:25: Error: @TLSDESC operator requires `%rip' as base register
> > +.*:27: Error: @TLSDESC operator requires 32-bit or 64-bit dest register
> > +.*:30: Error: @GOTTPOFF operator cannot be used with `sub'
> > +.*:31: Error: @GOTTPOFF operator cannot be used with `xor'
> > +.*:32: Error: @GOTTPOFF operator requires `%rip' as base register
> > +.*:33: Error: @GOTTPOFF operator requires `%rip' as base register
> > +.*:34: Error: @GOTTPOFF operator requires 32-bit or 64-bit dest register
> > +.*:35: Error: @GOTTPOFF operator can be used with `add', but format is
> wrong
> > +.*:36: Error: @GOTTPOFF operator can be used with `add', but format is
> wrong
> > +.*:37: Error: @GOTTPOFF operator can be used with `add', but format is
> wrong
> > +.*:38: Error: @GOTTPOFF operator can be used with `add', but format is
> wrong
> > +.*:39: Error: @GOTTPOFF operator requires `%rip' as base register
> > +.*:40: Error: @GOTTPOFF operator can be used with `mov', but format is
> wrong
> > +.*:41: Error: @GOTTPOFF operator can be used with `mov', but format is
> wrong
> > +.*:42: Error: @GOTTPOFF operator can be used with `mov', but format is
> wrong
> > +.*:43: Error: @GOTTPOFF operator can be used with `mov', but format is
> wrong
> > +.*:44: Error: @GOTTPOFF operator can be used with `mov', but format is
> wrong
> > +.*:48: Error: @TLSCALL operator cannot be used with `lea'
> > +.*:49: Error: @TLSCALL operator requires `%eax/%rax' as base register
> > +.*:49: Error: 0-byte relocation cannot be applied to 4-byte field
> > +.*:50: Error: `\*foo@tlscall\(%ax\)' is not a valid base/index expression
> > diff --git a/gas/testsuite/gas/i386/ilp32/x32-inval-tls.s
> b/gas/testsuite/gas/i386/ilp32/x32-inval-tls.s
> > new file mode 100644
> > index 00000000000..b1d967f88db
> > --- /dev/null
> > +++ b/gas/testsuite/gas/i386/ilp32/x32-inval-tls.s
> > @@ -0,0 +1 @@
> > +.include "../x86-64-inval-tls.s"
> > diff --git a/gas/testsuite/gas/i386/ilp32/x32-tls.d
> b/gas/testsuite/gas/i386/ilp32/x32-tls.d
> > index ab4da5c730b..ac7d136c1ac 100644
> > --- a/gas/testsuite/gas/i386/ilp32/x32-tls.d
> > +++ b/gas/testsuite/gas/i386/ilp32/x32-tls.d
> > @@ -1,3 +1,4 @@
> > +#as: -mtls-check=no
> > #objdump: -dw
> > #name: x86-64 (ILP32) TLS
> >
> > diff --git a/gas/testsuite/gas/i386/ilp32/x86-64-tls.d
> b/gas/testsuite/gas/i386/ilp32/x86-64-tls.d
> > new file mode 100644
> > index 00000000000..a2261f5cdcb
> > --- /dev/null
> > +++ b/gas/testsuite/gas/i386/ilp32/x86-64-tls.d
> > @@ -0,0 +1,4 @@
> > +#source: ../x86-64-tls.s
> > +#objdump: -drw
> > +#name: x86-64 (ILP32) TLS
> > +#dump: ../x86-64-tls.d
> > diff --git a/gas/testsuite/gas/i386/inval-tls.l b/gas/testsuite/gas/i386/inval-tls.l
> > index 98f7a29f1ab..e20ba7a4316 100644
> > --- a/gas/testsuite/gas/i386/inval-tls.l
> > +++ b/gas/testsuite/gas/i386/inval-tls.l
> > @@ -1,2 +1,70 @@
> > -.*: Assembler messages:
> > -.*:3: Error: @GOTNTPOFF operator cannot be used with `kmovd'
> > +.*ssembler messages:
> > +.* Error: @GOTNTPOFF operator cannot be used with `kmovd'
> > +.* Error: @TLSGD operator cannot be used with `add'
> > +.* Error: @TLSGD operator requires `%ebx' as index register
> > +.* Error: @TLSGD operator requires scale factor of 1
> > +.* Error: @TLSGD operator requires no base register
> > +.*: Error: @TLSGD operator requires `%eax' as dest register
> > +.*: Error: @TLSGD operator requires `%eax' as dest register
> > +.*: Error: @TLSGD operator requires `%eax' as base register
> > +.*: Error: @TLSGD operator requires 32-bit dest register
> > +.*: Error: @TLSLDM operator cannot be used with `add'
> > +.*: Error: @TLSLDM operator requires `%eax' as dest register
> > +.*: Error: @TLSLDM operator requires `%eax' as base register
> > +.*: Error: @TLSLDM operator requires no SIB
> > +.*: Error: @TLSLDM operator requires 32-bit dest register
> > +.*: Error: @TLSDESC operator cannot be used with `add'
> > +.*: Error: @TLSDESC operator requires `%ebx' as base register
> > +.*: Error: @TLSDESC operator requires no SIB
> > +.*: Error: @TLSDESC operator requires 32-bit dest register
> > +.*: Error: @INDNTPOFF operator cannot be used with `sub'
> > +.*: Error: @INDNTPOFF operator requires no base/index register
> > +.*: Error: @INDNTPOFF operator requires no base/index register
> > +.*: Error: @INDNTPOFF operator requires 32-bit dest register
> > +.*: Error: @INDNTPOFF operator can be used with `add', but format is wrong
> > +.*: Error: @INDNTPOFF operator can be used with `add', but format is wrong
> > +.*: Error: @INDNTPOFF operator can be used with `add', but format is wrong
> > +.*: Error: @INDNTPOFF operator can be used with `add', but format is wrong
> > +.*: Error: @INDNTPOFF operator can be used with `mov', but format is wrong
> > +.*: Error: @INDNTPOFF operator can be used with `mov', but format is wrong
> > +.*: Error: @INDNTPOFF operator can be used with `mov', but format is wrong
> > +.*: Error: @INDNTPOFF operator can be used with `mov', but format is wrong
> > +.*: Error: @INDNTPOFF operator can be used with `mov', but format is wrong
> > +.*: Error: @GOTNTPOFF operator cannot be used with `lea'
> > +.*: Error: @GOTNTPOFF operator requires base register
> > +.*: Error: @GOTNTPOFF operator cannot be used with `lea'
> > +.*: Error: @GOTNTPOFF operator can be used with `sub', but format is wrong
> > +.*: Error: @GOTNTPOFF operator can be used with `sub', but format is wrong
> > +.*: Error: @GOTNTPOFF operator can be used with `sub', but format is wrong
> > +.*: Error: @GOTNTPOFF operator can be used with `sub', but format is wrong
> > +.*: Error: @GOTNTPOFF operator can be used with `add', but format is wrong
> > +.*: Error: @GOTNTPOFF operator can be used with `add', but format is wrong
> > +.*: Error: @GOTNTPOFF operator can be used with `add', but format is wrong
> > +.*: Error: @GOTNTPOFF operator can be used with `add', but format is wrong
> > +.*: Error: @GOTNTPOFF operator requires base register
> > +.*: Error: @GOTNTPOFF operator can be used with `mov', but format is
> wrong
> > +.*: Error: @GOTNTPOFF operator can be used with `mov', but format is
> wrong
> > +.*: Error: @GOTNTPOFF operator can be used with `mov', but format is
> wrong
> > +.*: Error: @GOTNTPOFF operator can be used with `mov', but format is
> wrong
> > +.*: Error: @GOTNTPOFF operator can be used with `mov', but format is
> wrong
> > +.*: Error: @GOTTPOFF operator cannot be used with `lea'
> > +.*: Error: @GOTTPOFF operator requires base register
> > +.*: Error: @GOTTPOFF operator requires 32-bit dest register
> > +.*: Error: @GOTTPOFF operator can be used with `sub', but format is wrong
> > +.*: Error: @GOTTPOFF operator can be used with `sub', but format is wrong
> > +.*: Error: @GOTTPOFF operator can be used with `sub', but format is wrong
> > +.*: Error: @GOTTPOFF operator can be used with `sub', but format is wrong
> > +.*: Error: @GOTTPOFF operator can be used with `add', but format is wrong
> > +.*: Error: @GOTTPOFF operator can be used with `add', but format is wrong
> > +.*: Error: @GOTTPOFF operator can be used with `add', but format is wrong
> > +.*: Error: @GOTTPOFF operator requires base register
> > +.*: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
> > +.*: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
> > +.*: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
> > +.*: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
> > +.*: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
> > +.*: Error: @TLSCALL operator cannot be used with `lea'
> > +.*: Error: @TLSCALL operator requires `%eax/%rax' as base register
> > +.*: Error: @TLSCALL operator requires no SIB
> > +.*: Error: 0-byte relocation cannot be applied to 4-byte field
> > +.*: Error: @TLSCALL operator requires `%eax/%rax' as base register
> > diff --git a/gas/testsuite/gas/i386/inval-tls.s b/gas/testsuite/gas/i386/inval-tls.s
> > index ba0e1b81dc9..067e9b4cbdf 100644
> > --- a/gas/testsuite/gas/i386/inval-tls.s
> > +++ b/gas/testsuite/gas/i386/inval-tls.s
> > @@ -1,3 +1,85 @@
> > .text
> > # All the following should be illegal
> > kmovd foo@gotntpoff(%eax), %k0
> > +
> > + /* Invalid testcase for R_386_TLS_GD. */
> > + addl foo@tlsgd(,%ebx,1), %eax
> > + leal foo@tlsgd(,%ecx,1), %eax
> > + leal foo@tlsgd(,%ebx,2), %eax
> > + leal foo@tlsgd(%ecx,%ebx,1), %eax
> > + leal foo@tlsgd(,%ebx,1), %ecx
> > + leal foo@tlsgd(%ebx), %ecx
> > + leal foo@tlsgd(%eax), %eax
> > + lea foo@tlsgd(%ebx), %ax
> > +
> > + /* Invalid testcase for R_386_TLS_LDM. */
> > + addl foo@tlsldm(%ebx), %eax
> > + leal foo@tlsldm(%ebx), %ecx
> > + leal foo@tlsldm(%eax), %eax
> > + leal foo@tlsldm(,%ebx,1), %eax
> > + lea foo@tlsldm(%ebx), %ax
> > +
> > + /* Invalid testcase for R_386_TLS_GOTDESC. */
> > + addl x@tlsdesc(%ebx), %eax
> > + leal x@tlsdesc(%ecx), %eax
> > + leal x@tlsdesc(,%ecx,1), %eax
> > + lea x@tlsdesc(%ebx), %ax
> > +
> > + /* Invalid testcase for R_386_TLS_IE. */
> > + subl foo@indntpoff, %ecx
> > + addl foo@indntpoff(%ebx), %ecx
> > + movl foo@indntpoff(%ebx), %ecx
> > + add foo@indntpoff, %cx
> > + addl $foo@indntpoff, %eax
> > + addl %ecx, foo@indntpoff
> > + addl $0x9090,foo@indntpoff
> > + addl $0x90909090,foo@indntpoff
> > + movl foo@indntpoff,%eax
> > + movl %edx,foo@indntpoff(%eax)
> > + movw %ss,foo@indntpoff(%eax)
> > + movw foo@indntpoff(%eax),%ss
> > + movl $0x90909090,foo@indntpoff(%eax)
> > + movl $foo@indntpoff, %eax
> > +
> > + /* Invalid testcase for R_386_TLS_GOTIE. */
> > + leal foo@gotntpoff(%ebx), %ecx
> > + subl foo@gotntpoff(,%ebx,1), %ecx
> > + lea foo@gotntpoff(%ebx), %cx
> > + subl %ecx, foo@gotntpoff(%ebx)
> > + subl $0x9090,foo@gotntpoff(%ebx)
> > + subl $0x90909090,foo@gotntpoff(%eax)
> > + subl $foo@gotntpoff, %eax
> > + addl %ecx, foo@gotntpoff(%ebx)
> > + addl $0x9090,foo@gotntpoff(%ebx)
> > + addl $0x90909090,foo@gotntpoff(%eax)
> > + addl $foo@gotntpoff, %eax
> > + movl foo@gotntpoff,%eax
> > + movl %edx,foo@gotntpoff(%eax)
> > + movw %ss,foo@gotntpoff(%eax)
> > + movw foo@gotntpoff(%eax),%ss
> > + movl $0x90909090,foo@gotntpoff(%eax)
> > + movl $foo@gotntpoff, %eax
> > +
> > + /* Invalid testcase for R_386_TLS_IE_32. */
> > + leal foo@gottpoff(%ebx), %ecx
> > + subl foo@gottpoff(,%ebx,1), %ecx
> > + add foo@gottpoff(%ebx), %cx
> > + subl %ecx, foo@gottpoff(%ebx)
> > + subl $0x9090,foo@gottpoff(%ebx)
> > + subl $0x90909090,foo@gottpoff(%eax)
> > + subl $foo@gottpoff, %eax
> > + addl %ecx, foo@gottpoff(%ebx)
> > + addl $0x9090,foo@gottpoff(%ebx)
> > + addl $0x90909090,foo@gottpoff(%eax)
> > + movl foo@gottpoff,%eax
> > + movl %edx,foo@gottpoff(%eax)
> > + movw %ss,foo@gottpoff(%eax)
> > + movw foo@gottpoff(%eax),%ss
> > + movl $0x90909090,foo@gottpoff(%eax)
> > + movl $foo@gottpoff, %eax
> > +
> > + /* Invalid testcase for R_386_TLS_DESC_CALL. */
> > + leal foo@tlscall(%eax), %ebx
> > + call *x@tlscall(%ebx)
> > + call *x@tlscall(,%eax,1)
> > + call *x@tlscall(%bx)
> > diff --git a/gas/testsuite/gas/i386/reloc32.d b/gas/testsuite/gas/i386/reloc32.d
> > index 263a742022e..7d1b1ba2ae0 100644
> > --- a/gas/testsuite/gas/i386/reloc32.d
> > +++ b/gas/testsuite/gas/i386/reloc32.d
> > @@ -1,4 +1,4 @@
> > -#as: -mrelax-relocations=yes
> > +#as: -mrelax-relocations=yes -mtls-check=no
> > #objdump: -Drw
> > #name: i386 relocs
> >
> > diff --git a/gas/testsuite/gas/i386/reloc64.d b/gas/testsuite/gas/i386/reloc64.d
> > index 540a9b77d35..f4e44a627c5 100644
> > --- a/gas/testsuite/gas/i386/reloc64.d
> > +++ b/gas/testsuite/gas/i386/reloc64.d
> > @@ -1,4 +1,4 @@
> > -#as: -mx86-used-note=no --generate-missing-build-notes=no
> > +#as: -mx86-used-note=no --generate-missing-build-notes=no -mtls-check=no
> > #objdump: -Drw
> > #name: x86-64 relocs
> > #notarget: *-*-solaris*
> > diff --git a/gas/testsuite/gas/i386/tls.d b/gas/testsuite/gas/i386/tls.d
> > new file mode 100644
> > index 00000000000..adfe7ce9551
> > --- /dev/null
> > +++ b/gas/testsuite/gas/i386/tls.d
> > @@ -0,0 +1,25 @@
> > +#as:
> > +#objdump: -drw
> > +#name: Check tls relocation 32 bit-mode
> > +
> > +.*: +file format .*
> > +
> > +
> > +Disassembly of section .text:
> > +
> > +00000000 <_start>:
> > +\s*[a-f0-9]+:\s*8d 04 1d 00 00 00 00[ ]+lea 0x0\(,%ebx,1\),%eax 3:
> R_386_TLS_GD foo
> > +\s*[a-f0-9]+:\s*8d 81 00 00 00 00[ ]+lea 0x0\(%ecx\),%eax 9:
> R_386_TLS_GD foo
> > +\s*[a-f0-9]+:\s*8d 83 00 00 00 00[ ]+lea 0x0\(%ebx\),%eax f:
> R_386_TLS_LDM foo
> > +\s*[a-f0-9]+:\s*8d 83 00 00 00 00[ ]+lea 0x0\(%ebx\),%eax 15:
> R_386_TLS_GOTDESC x
> > +\s*[a-f0-9]+:\s*a1 00 00 00 00[ ]+mov 0x0,%eax 1a: R_386_TLS_IE
> foo
> > +\s*[a-f0-9]+:\s*8b 1d 00 00 00 00[ ]+mov 0x0,%ebx 20: R_386_TLS_IE
> foo
> > +\s*[a-f0-9]+:\s*03 15 00 00 00 00[ ]+add 0x0,%edx 26: R_386_TLS_IE
> foo
> > +\s*[a-f0-9]+:\s*2b 8b 00 00 00 00[ ]+sub 0x0\(%ebx\),%ecx 2c:
> R_386_TLS_GOTIE foo
> > +\s*[a-f0-9]+:\s*8b 8b 00 00 00 00[ ]+mov 0x0\(%ebx\),%ecx 32:
> R_386_TLS_GOTIE foo
> > +\s*[a-f0-9]+:\s*03 8b 00 00 00 00[ ]+add 0x0\(%ebx\),%ecx 38:
> R_386_TLS_GOTIE foo
> > +\s*[a-f0-9]+:\s*2b 8b 00 00 00 00[ ]+sub 0x0\(%ebx\),%ecx 3e:
> R_386_TLS_IE_32 foo
> > +\s*[a-f0-9]+:\s*8b 8b 00 00 00 00[ ]+mov 0x0\(%ebx\),%ecx 44:
> R_386_TLS_IE_32 foo
> > +\s*[a-f0-9]+:\s*03 8b 00 00 00 00[ ]+add 0x0\(%ebx\),%ecx 4a:
> R_386_TLS_IE_32 foo
> > +\s*[a-f0-9]+:\s*ff 10[ ]+call \*\(%eax\) 4e: R_386_TLS_DESC_CALL foo
> > +#pass
> > diff --git a/gas/testsuite/gas/i386/tls.s b/gas/testsuite/gas/i386/tls.s
> > new file mode 100644
> > index 00000000000..6c077ee48fb
> > --- /dev/null
> > +++ b/gas/testsuite/gas/i386/tls.s
> > @@ -0,0 +1,31 @@
> > +# Check tls relocation 32-bit mode
> > +
> > + .text
> > +_start:
> > + /* R_386_TLS_GD. */
> > + leal foo@tlsgd(,%ebx,1), %eax
> > + leal foo@tlsgd(%ecx), %eax
> > +
> > + /* R_386_TLS_LDM. */
> > + leal foo@tlsldm(%ebx), %eax
> > +
> > + /* R_386_TLS_GOTDESC. */
> > + leal x@tlsdesc(%ebx), %eax
> > +
> > + /* R_386_TLS_IE. */
> > + movl foo@indntpoff, %eax
> > + movl foo@indntpoff, %ebx
> > + addl foo@indntpoff, %edx
> > +
> > + /* R_386_TLS_GOTIE. */
> > + subl foo@gotntpoff(%ebx), %ecx
> > + movl foo@gotntpoff(%ebx), %ecx
> > + addl foo@gotntpoff(%ebx), %ecx
> > +
> > + /* R_386_TLS_IE_32. */
> > + subl foo@gottpoff(%ebx), %ecx
> > + movl foo@gottpoff(%ebx), %ecx
> > + addl foo@gottpoff(%ebx), %ecx
> > +
> > + /* R_386_TLS_DESC_CALL. */
> > + call *foo@tlscall(%eax)
> > diff --git a/gas/testsuite/gas/i386/x86-64-inval-tls.l
> b/gas/testsuite/gas/i386/x86-64-inval-tls.l
> > index da8ac19f869..134d96bf383 100644
> > --- a/gas/testsuite/gas/i386/x86-64-inval-tls.l
> > +++ b/gas/testsuite/gas/i386/x86-64-inval-tls.l
> > @@ -1,3 +1,39 @@
> > .*: Assembler messages:
> > .*:3: Error: @GOTTPOFF operator cannot be used with `kmovq'
> > .*:4: Error: @TLSLD operator cannot be used with `kmovq'
> > +.*:7: Error: @TLSGD operator cannot be used with `add'
> > +.*:8: Error: @TLSGD operator requires `%rdi' as dest register
> > +.*:9: Error: @TLSGD operator requires `%rip' as base register
> > +.*:10: Error: @TLSGD operator requires base register
> > +.*:11: Error: @TLSGD operator requires `%rip' as base register
> > +.*:12: Error: @TLSGD operator requires `%rdi' as dest register
> > +.*:15: Error: @TLSLD operator cannot be used with `add'
> > +.*:16: Error: @TLSLD operator requires `%rdi' as dest register
> > +.*:17: Error: @TLSLD operator requires `%rip' as base register
> > +.*:18: Error: @TLSLD operator requires base register
> > +.*:19: Error: @TLSLD operator requires `%rip' as base register
> > +.*:20: Error: @TLSLD operator requires `%rdi' as dest register
> > +.*:23: Error: @TLSDESC operator cannot be used with `add'
> > +.*:24: Error: @TLSDESC operator requires `%rip' as base register
> > +.*:25: Error: @TLSDESC operator requires `%rip' as base register
> > +.*:26: Error: @TLSDESC operator requires 64-bit dest register
> > +.*:27: Error: @TLSDESC operator requires 64-bit dest register
> > +.*:30: Error: @GOTTPOFF operator cannot be used with `sub'
> > +.*:31: Error: @GOTTPOFF operator cannot be used with `xor'
> > +.*:32: Error: @GOTTPOFF operator requires `%rip' as base register
> > +.*:33: Error: @GOTTPOFF operator requires `%rip' as base register
> > +.*:34: Error: @GOTTPOFF operator requires 64-bit dest register
> > +.*:35: Error: @GOTTPOFF operator can be used with `add', but format is
> wrong
> > +.*:36: Error: @GOTTPOFF operator can be used with `add', but format is
> wrong
> > +.*:37: Error: @GOTTPOFF operator can be used with `add', but format is
> wrong
> > +.*:38: Error: @GOTTPOFF operator can be used with `add', but format is
> wrong
> > +.*:39: Error: @GOTTPOFF operator requires `%rip' as base register
> > +.*:40: Error: @GOTTPOFF operator can be used with `mov', but format is
> wrong
> > +.*:41: Error: @GOTTPOFF operator can be used with `mov', but format is
> wrong
> > +.*:42: Error: @GOTTPOFF operator can be used with `mov', but format is
> wrong
> > +.*:43: Error: @GOTTPOFF operator can be used with `mov', but format is
> wrong
> > +.*:44: Error: @GOTTPOFF operator can be used with `mov', but format is
> wrong
> > +.*:48: Error: @TLSCALL operator cannot be used with `lea'
> > +.*:49: Error: @TLSCALL operator requires `%eax/%rax' as base register
> > +.*:49: Error: 0-byte relocation cannot be applied to 4-byte field
> > +.*:50: Error: `\*foo@tlscall\(%ax\)' is not a valid base/index expression
> > diff --git a/gas/testsuite/gas/i386/x86-64-inval-tls.s
> b/gas/testsuite/gas/i386/x86-64-inval-tls.s
> > index 71e19272ba9..8783530a423 100644
> > --- a/gas/testsuite/gas/i386/x86-64-inval-tls.s
> > +++ b/gas/testsuite/gas/i386/x86-64-inval-tls.s
> > @@ -2,3 +2,49 @@
> > # All the following should be illegal
> > kmovq foo@gottpoff(%rip), %k0
> > kmovq foo@tlsld(%rip), %k0
> > +
> > + /* Invalid testcase for R_X86_64_TLSGD. */
> > + addq foo@tlsgd(%rip), %rdi
> > + leaq foo@tlsgd(%rip), %rax
> > + leaq foo@tlsgd(%rax), %rdi
> > + leaq foo@tlsgd(,%rax,1), %rdi
> > + leaq foo@tlsgd(%eip), %rdi
> > + leal foo@tlsgd(%rip), %edi
> > +
> > + /* Invalid testcase for R_X86_64_TLSLD. */
> > + addq foo@tlsld(%rip), %rdi
> > + leaq foo@tlsld(%rip), %rax
> > + leaq foo@tlsld(%rax), %rdi
> > + leaq foo@tlsld(,%rax,1), %rdi
> > + leaq foo@tlsld(%eip), %rdi
> > + leal foo@tlsld(%rip), %edi
> > +
> > + /* Invalid testcase for R_X86_64_GOTPC32_TLSDESC. */
> > + addq x@tlsdesc(%rip), %rax
> > + leaq x@tlsdesc(%rbx), %rax
> > + lea x@tlsdesc(%eip), %rdi
> > + lea x@tlsdesc(%rip), %eax
> > + lea x@tlsdesc(%rip), %ax
> > +
> > + /* Invalid testcase for R_X86_64_GOTTPOFF. */
> > + subq foo@gottpoff(%rip), %r12
> > + xorq foo@gottpoff(%rip), %rax
> > + addq foo@gottpoff(%rbx), %rax
> > + addq foo@gottpoff(%eip), %rax
> > + add foo@gottpoff(%rip), %ax
> > + addq %rax, foo@gottpoff(%rip)
> > + addl $0x90909090, foo@gottpoff(%rip)
> > + add $0x90, foo@gottpoff(%rip), %rax
> > + add $0xffffffffffffffff, foo@gottpoff(%rip), %rax
> > + movq foo@gottpoff(%rbx), %rax
> > + movq %rax, foo@gottpoff(%rip)
> > + mov %ss,foo@gottpoff(%rip)
> > + mov foo@gottpoff(%rip),%ss
> > + movl $0x90909090,foo@gottpoff(%rip)
> > + mov $foo@gottpoff, %rax
> > +
> > +
> > + /* Invalid testcase for R_X86_64_TLSDESC_CALL. */
> > + leaq foo@tlscall(%rax), %rbx
> > + call *foo@tlscall(%rip)
> > + call *foo@tlscall(%ax)
> > diff --git a/gas/testsuite/gas/i386/x86-64-tls.d b/gas/testsuite/gas/i386/x86-
> 64-tls.d
> > new file mode 100644
> > index 00000000000..1c30496e227
> > --- /dev/null
> > +++ b/gas/testsuite/gas/i386/x86-64-tls.d
> > @@ -0,0 +1,25 @@
> > +#as:
> > +#objdump: -drw
> > +#name: Check tls relocation x86-64
> > +
> > +.*: +file format .*
> > +
> > +
> > +Disassembly of section .text:
> > +
> > +0+ <_start>:
> > + +[a-f0-9]+: 48 8d 3d 00 00 00 00 lea 0x0\(%rip\),%rdi # 7
> <_start\+0x7> 3: R_X86_64_TLSGD foo-0x4
> > + +[a-f0-9]+: 48 8d 3d 00 00 00 00 lea 0x0\(%rip\),%rdi # e
> <_start\+0xe> a: R_X86_64_TLSLD foo-0x4
> > + +[a-f0-9]+: 48 8d 05 00 00 00 00 lea 0x0\(%rip\),%rax # 15
> <_start\+0x15> 11: R_X86_64_GOTPC32_TLSDESC x-0x4
> > + +[a-f0-9]+: 4c 03 25 00 00 00 00 add 0x0\(%rip\),%r12 # 1c
> <_start\+0x1c> 18: R_X86_64_GOTTPOFF foo-0x4
> > + +[a-f0-9]+: 48 8b 05 00 00 00 00 mov 0x0\(%rip\),%rax # 23
> <_start\+0x23> 1f: R_X86_64_GOTTPOFF foo-0x4
> > + +[a-f0-9]+: d5 48 03 05 00 00 00 00 add 0x0\(%rip\),%r16 # 2b
> <_start\+0x2b> 27: R_X86_64_CODE_4_GOTTPOFF foo-0x4
> > + +[a-f0-9]+: d5 48 8b 25 00 00 00 00 mov 0x0\(%rip\),%r20 # 33
> <_start\+0x33> 2f: R_X86_64_CODE_4_GOTTPOFF foo-0x4
> > + +[a-f0-9]+: 62 64 bc 18 01 35 00 00 00 00 add %r30,0x0\(%rip\),%r8
> # 3d <_start\+0x3d> 39: R_X86_64_CODE_6_GOTTPOFF foo-0x4
> > + +[a-f0-9]+: 62 f4 dc 10 03 05 00 00 00 00 add 0x0\(%rip\),%rax,%r20
> # 47 <_start\+0x47> 43: R_X86_64_CODE_6_GOTTPOFF foo-0x4
> > + +[a-f0-9]+: 62 e4 fc 0c 03 05 00 00 00 00 \{nf\} add 0x0\(%rip\),%r16
> # 51 <_start\+0x51> 4d: R_X86_64_CODE_6_GOTTPOFF foo-0x4
> > + +[a-f0-9]+: 62 64 bc 1c 01 35 00 00 00 00 \{nf\}
> add %r30,0x0\(%rip\),%r8 # 5b <_start\+0x5b> 57:
> R_X86_64_CODE_6_GOTTPOFF foo-0x4
> > + +[a-f0-9]+: 62 f4 dc 14 03 05 00 00 00 00 \{nf\} add
> 0x0\(%rip\),%rax,%r20 # 65 <_start\+0x65> 61:
> R_X86_64_CODE_6_GOTTPOFF foo-0x4
> > + +[a-f0-9]+: ff 10 call \*\(%rax\) 65: R_X86_64_TLSDESC_CALL
> x
> > + +[a-f0-9]+: 67 ff 10 call \*\(%eax\) 67:
> R_X86_64_TLSDESC_CALL x
> > +#pass
> > diff --git a/gas/testsuite/gas/i386/x86-64-tls.s b/gas/testsuite/gas/i386/x86-
> 64-tls.s
> > new file mode 100644
> > index 00000000000..7c3bd4a982c
> > --- /dev/null
> > +++ b/gas/testsuite/gas/i386/x86-64-tls.s
> > @@ -0,0 +1,27 @@
> > +# Check tls relocation 64-bit mode
> > +
> > + .text
> > +_start:
> > + /* R_X86_64_TLSGD. */
> > + leaq foo@tlsgd(%rip), %rdi
> > +
> > + /* R_X86_64_TLSLD. */
> > + leaq foo@tlsld(%rip), %rdi
> > +
> > + /* R_X86_64_GOTPC32_TLSDESC. */
> > + leaq x@tlsdesc(%rip), %rax
> > +
> > + /* R_X86_64_GOTTPOFF. */
> > + addq foo@gottpoff(%rip), %r12
> > + movq foo@gottpoff(%rip), %rax
> > + addq foo@gottpoff(%rip), %r16
> > + movq foo@gottpoff(%rip), %r20
> > + addq %r30, foo@gottpoff(%rip), %r8
> > + addq foo@gottpoff(%rip), %rax, %r20
> > + {nf} addq foo@gottpoff(%rip), %r16
> > + {nf} addq %r30, foo@gottpoff(%rip), %r8
> > + {nf} addq foo@gottpoff(%rip), %rax, %r20
> > +
> > + /* R_X86_64_TLSDESC_CALL. */
> > + call *x@tlscall(%rax)
> > + call *x@tlscall(%eax)
> > diff --git a/gas/testsuite/gas/i386/x86-64.exp b/gas/testsuite/gas/i386/x86-
> 64.exp
> > index 86e7f4a75b3..740f5268de3 100644
> > --- a/gas/testsuite/gas/i386/x86-64.exp
> > +++ b/gas/testsuite/gas/i386/x86-64.exp
> > @@ -653,7 +653,8 @@ if [is_elf_format] then {
> > run_dump_test "x86-64-unwind"
> >
> > run_dump_test "reloc64"
> > - run_list_test "reloc64" "--defsym _bad_=1"
> > + run_list_test "reloc64" "--defsym _bad_=1 -mtls-check=no"
> > + run_dump_test "x86-64-tls"
> > run_list_test "x86-64-inval-tls"
> > run_dump_test "mixed-mode-reloc64"
> > run_dump_test "rela"
> > diff --git a/ld/testsuite/ld-i386/tlsgdesc1.d b/ld/testsuite/ld-i386/tlsgdesc1.d
> > index 2a70e81c444..0c853ab0a67 100644
> > --- a/ld/testsuite/ld-i386/tlsgdesc1.d
> > +++ b/ld/testsuite/ld-i386/tlsgdesc1.d
> > @@ -1,4 +1,4 @@
> > #name: TLS GDesc->LE transition check (LEA)
> > -#as: --32
> > +#as: --32 -mtls-check=no
> > #ld: -melf_i386
> > #error: .*: relocation R_386_TLS_GOTDESC against `foo' must be used in LEA
> only
> > diff --git a/ld/testsuite/ld-i386/tlsgdesc2.d b/ld/testsuite/ld-i386/tlsgdesc2.d
> > index bbf93bef767..99e1b18b1ea 100644
> > --- a/ld/testsuite/ld-i386/tlsgdesc2.d
> > +++ b/ld/testsuite/ld-i386/tlsgdesc2.d
> > @@ -1,4 +1,4 @@
> > #name: TLS GDesc->LE transition check (indirect CALL)
> > -#as: --32
> > +#as: --32 -mtls-check=no
> > #ld: -melf_i386
> > #error: .*: relocation R_386_TLS_DESC_CALL against `foo' must be used in
> indirect CALL with EAX register only
> > diff --git a/ld/testsuite/ld-i386/tlsgdesc3.d b/ld/testsuite/ld-i386/tlsgdesc3.d
> > index f2c29d880f2..4bb99c4422b 100644
> > --- a/ld/testsuite/ld-i386/tlsgdesc3.d
> > +++ b/ld/testsuite/ld-i386/tlsgdesc3.d
> > @@ -1,5 +1,5 @@
> > #source: tlsgdesc2.s
> > #name: TLS GDesc call (indirect CALL)
> > -#as: --32
> > +#as: --32 -mtls-check=no
> > #ld: -shared -melf_i386
> > #error: .*: relocation R_386_TLS_DESC_CALL against `foo' must be used in
> indirect CALL with EAX register only
> > diff --git a/ld/testsuite/ld-i386/tlsie2.d b/ld/testsuite/ld-i386/tlsie2.d
> > index 9f9e63029d6..4e7dc6ea56e 100644
> > --- a/ld/testsuite/ld-i386/tlsie2.d
> > +++ b/ld/testsuite/ld-i386/tlsie2.d
> > @@ -1,4 +1,4 @@
> > #name: TLS IE->LE transition check (R_386_TLS_GOTIE with %eax)
> > -#as: --32
> > +#as: --32 -mtls-check=no
> > #ld: -melf_i386
> > #error: .*: relocation R_386_TLS_GOTIE against `foo' must be used in ADD,
> SUB or MOV only
> > diff --git a/ld/testsuite/ld-i386/tlsie3.d b/ld/testsuite/ld-i386/tlsie3.d
> > index 506f1a02605..6bfc78e0b49 100644
> > --- a/ld/testsuite/ld-i386/tlsie3.d
> > +++ b/ld/testsuite/ld-i386/tlsie3.d
> > @@ -1,4 +1,4 @@
> > #name: TLS IE->LE transition check (R_386_TLS_GOTIE)
> > -#as: --32
> > +#as: --32 -mtls-check=no
> > #ld: -melf_i386
> > #error: .*: relocation R_386_TLS_GOTIE against `foo' must be used in ADD,
> SUB or MOV only
> > diff --git a/ld/testsuite/ld-i386/tlsie4.d b/ld/testsuite/ld-i386/tlsie4.d
> > index a516d002660..98293f4b36a 100644
> > --- a/ld/testsuite/ld-i386/tlsie4.d
> > +++ b/ld/testsuite/ld-i386/tlsie4.d
> > @@ -1,4 +1,4 @@
> > #name: TLS IE->LE transition check (R_386_TLS_IE with %eax)
> > -#as: --32
> > +#as: --32 -mtls-check=no
> > #ld: -melf_i386
> > #error: .*: relocation R_386_TLS_IE against `foo' must be used in ADD or MOV
> only
> > diff --git a/ld/testsuite/ld-i386/tlsie5.d b/ld/testsuite/ld-i386/tlsie5.d
> > index d3447182e19..4e9c9a8f74a 100644
> > --- a/ld/testsuite/ld-i386/tlsie5.d
> > +++ b/ld/testsuite/ld-i386/tlsie5.d
> > @@ -1,4 +1,4 @@
> > #name: TLS IE->LE transition check (R_386_TLS_IE)
> > -#as: --32
> > +#as: --32 -mtls-check=no
> > #ld: -melf_i386
> > #error: .*: relocation R_386_TLS_IE against `foo' must be used in ADD or MOV
> only
> > diff --git a/ld/testsuite/ld-x86-64/tlsdesc3.d b/ld/testsuite/ld-x86-64/tlsdesc3.d
> > index bbf22ebeafe..955884885d7 100644
> > --- a/ld/testsuite/ld-x86-64/tlsdesc3.d
> > +++ b/ld/testsuite/ld-x86-64/tlsdesc3.d
> > @@ -1,4 +1,4 @@
> > #name: TLS GDesc->LE transition check (LEA)
> > -#as: --64
> > +#as: --64 -mtls-check=no
> > #ld: -melf_x86_64
> > #error: .*: relocation R_X86_64_GOTPC32_TLSDESC against `foo' must be
> used in LEA only
> > diff --git a/ld/testsuite/ld-x86-64/tlsdesc4.d b/ld/testsuite/ld-x86-64/tlsdesc4.d
> > index c882c877ae3..ccaa525c74b 100644
> > --- a/ld/testsuite/ld-x86-64/tlsdesc4.d
> > +++ b/ld/testsuite/ld-x86-64/tlsdesc4.d
> > @@ -1,4 +1,4 @@
> > #name: TLS GDesc->LE transition check (indirect CALL)
> > -#as: --64
> > +#as: --64 -mtls-check=no
> > #ld: -melf_x86_64
> > #error: .*: relocation R_X86_64_TLSDESC_CALL against `foo' must be used in
> indirect CALL with RAX register only
> > diff --git a/ld/testsuite/ld-x86-64/tlsdesc5.d b/ld/testsuite/ld-x86-64/tlsdesc5.d
> > index 6a0158b44b7..0876993bca3 100644
> > --- a/ld/testsuite/ld-x86-64/tlsdesc5.d
> > +++ b/ld/testsuite/ld-x86-64/tlsdesc5.d
> > @@ -1,5 +1,5 @@
> > #source: tlsdesc4.s
> > #name: TLS GDesc call (indirect CALL)
> > -#as: --64
> > +#as: --64 -mtls-check=no
> > #ld: -shared -melf_x86_64
> > #error: .*: relocation R_X86_64_TLSDESC_CALL against `foo' must be used in
> indirect CALL with RAX register only
> > diff --git a/ld/testsuite/ld-x86-64/tlsie2.d b/ld/testsuite/ld-x86-64/tlsie2.d
> > index bf8a8198b5b..2e6d41ccf61 100644
> > --- a/ld/testsuite/ld-x86-64/tlsie2.d
> > +++ b/ld/testsuite/ld-x86-64/tlsie2.d
> > @@ -1,4 +1,4 @@
> > #name: TLS IE->LE transition check
> > -#as: --64
> > +#as: --64 -mtls-check=no
> > #ld: -melf_x86_64
> > #error: .*: relocation R_X86_64_GOTTPOFF against `foo' must be used in ADD
> or MOV only
> > diff --git a/ld/testsuite/ld-x86-64/tlsie3.d b/ld/testsuite/ld-x86-64/tlsie3.d
> > index 49d8464fbaf..b59cc6429de 100644
> > --- a/ld/testsuite/ld-x86-64/tlsie3.d
> > +++ b/ld/testsuite/ld-x86-64/tlsie3.d
> > @@ -1,4 +1,4 @@
> > #name: TLS IE->LE transition check (%r12)
> > -#as: --64
> > +#as: --64 -mtls-check=no
> > #ld: -melf_x86_64
> > #error: .*: relocation R_X86_64_GOTTPOFF against `foo' must be used in ADD
> or MOV only
> > diff --git a/ld/testsuite/ld-x86-64/tlsie5.d b/ld/testsuite/ld-x86-64/tlsie5.d
> > index 29de1cebf8e..d7ab5ab7b32 100644
> > --- a/ld/testsuite/ld-x86-64/tlsie5.d
> > +++ b/ld/testsuite/ld-x86-64/tlsie5.d
> > @@ -1,4 +1,4 @@
> > #name: TLS IE->LE transition check (APX)
> > -#as: --64
> > +#as: --64 -mtls-check=no
> > #ld: -melf_x86_64
> > #error: .*: relocation R_X86_64_CODE_6_GOTTPOFF against `foo' must be
> used in ADD only
> > --
> > 2.34.1
> >
>
>
> --
> H.J.
I've grabbed the newest tls.pdf I could find (still over 10 years old,
from Ulrich Drepper's site as referenced by the Thread-Local Storage
section in gcc14 doc), and that raises questions:
On 19.09.2024 08:38, Cui, Lili wrote:
> @@ -6357,6 +6387,356 @@ static INLINE bool may_need_pass2 (const insn_template *t)
> && (t->base_opcode | 8) == 0x2c);
> }
>
> +static enum x86_tls_error_type
> +x86_check_tls_relocation (enum bfd_reloc_code_real r_type)
> +{
> + switch (r_type)
> + {
> + case BFD_RELOC_386_TLS_GOTDESC:
> + /* Check GDesc access model:
What's "GDesc access model"? I can't find anything named like this, nor
mention of ...
> + leal x@tlsdesc(%ebx), %reg32 --> Memory reg must be %ebx and
> + SIB is not supported.
> + */
... @tlsdesc.
> + if (i.tm.mnem_off != MN_lea)
> + return x86_tls_error_insn;
> + if (i.index_reg)
> + return x86_tls_error_sib;
> + if (!i.base_reg)
> + return x86_tls_error_no_base_reg;
> + if (i.base_reg->reg_type.bitfield.instance != RegB)
> + return x86_tls_error_ebx;
> + if (!i.op[1].regs->reg_type.bitfield.dword)
> + return x86_tls_error_dest_32bit_reg_size;
> + break;
> +
> + case BFD_RELOC_386_TLS_GD:
> + /* Check GD access model:
> +
> + leal foo@tlsgd(,%ebx,1), %eax --> Only this fixed format is supported.
> + leal foo@tlsgd(%reg32), %eax --> Dest reg must be '%eax'
> + Memory reg can't be %eax.
> + */
Where's this 2nd form coming from? The doc says the SIB form must be
used, and the converted-to code sequence would require one more byte
than the non-SIB form provides space for.
The doc doesn't say that the index reg has to be %ebx, it merely
mentions that in the example, for being the commonly used GOT reg.
This is the same ...
> + if (i.tm.mnem_off != MN_lea)
> + return x86_tls_error_insn;
> + if (i.op[1].regs->reg_type.bitfield.instance != Accum)
> + return x86_tls_error_dest_eax;
> + if (!i.op[1].regs->reg_type.bitfield.dword)
> + return x86_tls_error_dest_32bit_reg_size;
> + if (i.index_reg)
> + {
> + if (i.base_reg)
> + return x86_tls_error_base_reg;
> + if (i.index_reg->reg_type.bitfield.instance != RegB)
> + return x86_tls_error_index_ebx;
> + if (i.log2_scale_factor)
> + return x86_tls_error_scale_factor;
> + }
> + else
> + {
> + if (!i.base_reg)
> + return x86_tls_error_no_base_reg;
> + if (i.base_reg->reg_type.bitfield.instance == Accum)
> + return x86_tls_error_eax;
> + }
> + break;
> +
> + case BFD_RELOC_386_TLS_LDM:
> + /* Check LDM access model:
> +
> + leal foo@tlsldm(%reg32), %eax --> Dest reg must be '%eax'
> + Memory reg can't be %eax and SIB
> + is not supported.
> + */
... for this case, and surprisingly any register is permitted here.
I'll stop here for now, as this is all unclear enough already. I'm
getting the impression that gas is being made match ld without
regard to whether ld is actually correct. Checks in gas - if we
already have any - should be tied to what the spec demands, not
how a particular linker is implemented. As said before - people may
be using different linkers.
Jan
> I've grabbed the newest tls.pdf I could find (still over 10 years old, from Ulrich
> Drepper's site as referenced by the Thread-Local Storage section in gcc14 doc),
> and that raises questions:
>
Jan, you can find the latest TLS in ABI chapter 10 (https://gitlab.com/x86-psABIs/x86-64-ABI) and some TLS doc linkers there (e.g. http://www.akkadia.org/drepper/tls.pdf)
> On 19.09.2024 08:38, Cui, Lili wrote:
> > @@ -6357,6 +6387,356 @@ static INLINE bool may_need_pass2 (const
> insn_template *t)
> > && (t->base_opcode | 8) == 0x2c); }
> >
> > +static enum x86_tls_error_type
> > +x86_check_tls_relocation (enum bfd_reloc_code_real r_type) {
> > + switch (r_type)
> > + {
> > + case BFD_RELOC_386_TLS_GOTDESC:
> > + /* Check GDesc access model:
>
> What's "GDesc access model"? I can't find anything named like this, nor mention
> of ...
> > + leal x@tlsdesc(%ebx), %reg32 --> Memory reg must be %ebx and
> > + SIB is not supported.
> > + */
>
> ... @tlsdesc.
>
It is defined in ABI doc.
> > + if (i.tm.mnem_off != MN_lea)
> > + return x86_tls_error_insn;
> > + if (i.index_reg)
> > + return x86_tls_error_sib;
> > + if (!i.base_reg)
> > + return x86_tls_error_no_base_reg;
> > + if (i.base_reg->reg_type.bitfield.instance != RegB)
> > + return x86_tls_error_ebx;
> > + if (!i.op[1].regs->reg_type.bitfield.dword)
> > + return x86_tls_error_dest_32bit_reg_size;
> > + break;
> > +
> > + case BFD_RELOC_386_TLS_GD:
> > + /* Check GD access model:
> > +
> > + leal foo@tlsgd(,%ebx,1), %eax --> Only this fixed format is supported.
> > + leal foo@tlsgd(%reg32), %eax --> Dest reg must be '%eax'
> > + Memory reg can't be %eax.
> > + */
>
> Where's this 2nd form coming from? The doc says the SIB form must be used,
> and the converted-to code sequence would require one more byte than the non-
> SIB form provides space for.
>
> The doc doesn't say that the index reg has to be %ebx, it merely mentions that in
> the example, for being the commonly used GOT reg.
> This is the same ...
>
It is mentioned in 4.1 of tls.pdf.
> > + if (i.tm.mnem_off != MN_lea)
> > + return x86_tls_error_insn;
> > + if (i.op[1].regs->reg_type.bitfield.instance != Accum)
> > + return x86_tls_error_dest_eax;
> > + if (!i.op[1].regs->reg_type.bitfield.dword)
> > + return x86_tls_error_dest_32bit_reg_size;
> > + if (i.index_reg)
> > + {
> > + if (i.base_reg)
> > + return x86_tls_error_base_reg;
> > + if (i.index_reg->reg_type.bitfield.instance != RegB)
> > + return x86_tls_error_index_ebx;
> > + if (i.log2_scale_factor)
> > + return x86_tls_error_scale_factor;
> > + }
> > + else
> > + {
> > + if (!i.base_reg)
> > + return x86_tls_error_no_base_reg;
> > + if (i.base_reg->reg_type.bitfield.instance == Accum)
> > + return x86_tls_error_eax;
> > + }
> > + break;
> > +
> > + case BFD_RELOC_386_TLS_LDM:
> > + /* Check LDM access model:
> > +
> > + leal foo@tlsldm(%reg32), %eax --> Dest reg must be '%eax'
> > + Memory reg can't be %eax and SIB
> > + is not supported.
> > + */
>
> ... for this case, and surprisingly any register is permitted here.
>
There are two types of sequence listings in linker comments:
/* Check transition from LD access model. Only
leal foo@tlsldm(%ebx), %eax
call ___tls_get_addr@PLT
or
leal foo@tlsldm(%reg), %eax
call *___tls_get_addr@GOT(%reg)
which may be converted to
addr32 call ___tls_get_addr
can transit to different access model. */
They may be related to 4.2 of tls.pdf.
Thanks,
Lili.
> I'll stop here for now, as this is all unclear enough already. I'm getting the
> impression that gas is being made match ld without regard to whether ld is
> actually correct. Checks in gas - if we already have any - should be tied to what
> the spec demands, not how a particular linker is implemented. As said before -
> people may be using different linkers.
>
> Jan
On 25.09.2024 05:32, Cui, Lili wrote:
>> I've grabbed the newest tls.pdf I could find (still over 10 years old, from Ulrich
>> Drepper's site as referenced by the Thread-Local Storage section in gcc14 doc),
>> and that raises questions:
>
> Jan, you can find the latest TLS in ABI chapter 10 (https://gitlab.com/x86-psABIs/x86-64-ABI)
So far all my questions were on the i386 side of things, which isn't covered
there.
> and some TLS doc linkers there (e.g. http://www.akkadia.org/drepper/tls.pdf)
This is the doc I was referring to.
As an aside - of course it shouldn't really take two docs to get a complete
picture.
>> On 19.09.2024 08:38, Cui, Lili wrote:
>>> @@ -6357,6 +6387,356 @@ static INLINE bool may_need_pass2 (const
>> insn_template *t)
>>> && (t->base_opcode | 8) == 0x2c); }
>>>
>>> +static enum x86_tls_error_type
>>> +x86_check_tls_relocation (enum bfd_reloc_code_real r_type) {
>>> + switch (r_type)
>>> + {
>>> + case BFD_RELOC_386_TLS_GOTDESC:
>>> + /* Check GDesc access model:
>>
>> What's "GDesc access model"? I can't find anything named like this, nor mention
>> of ...
>>> + leal x@tlsdesc(%ebx), %reg32 --> Memory reg must be %ebx and
>>> + SIB is not supported.
>>> + */
>>
>> ... @tlsdesc.
>
> It is defined in ABI doc.
As per above - where? I can see the 64-bit counterpart of this being
described in the x86-64 psABI, but that's not covering the case here.
>>> + if (i.tm.mnem_off != MN_lea)
>>> + return x86_tls_error_insn;
>>> + if (i.index_reg)
>>> + return x86_tls_error_sib;
>>> + if (!i.base_reg)
>>> + return x86_tls_error_no_base_reg;
>>> + if (i.base_reg->reg_type.bitfield.instance != RegB)
>>> + return x86_tls_error_ebx;
>>> + if (!i.op[1].regs->reg_type.bitfield.dword)
>>> + return x86_tls_error_dest_32bit_reg_size;
>>> + break;
>>> +
>>> + case BFD_RELOC_386_TLS_GD:
>>> + /* Check GD access model:
>>> +
>>> + leal foo@tlsgd(,%ebx,1), %eax --> Only this fixed format is supported.
>>> + leal foo@tlsgd(%reg32), %eax --> Dest reg must be '%eax'
>>> + Memory reg can't be %eax.
>>> + */
>>
>> Where's this 2nd form coming from? The doc says the SIB form must be used,
>> and the converted-to code sequence would require one more byte than the non-
>> SIB form provides space for.
>>
>> The doc doesn't say that the index reg has to be %ebx, it merely mentions that in
>> the example, for being the commonly used GOT reg.
>> This is the same ...
>
> It is mentioned in 4.1 of tls.pdf.
Where? Please quote the sentence. I can't spot anything saying that it has to
be %ebx. And similarly I can't spot anything indicating the non-SIB form would
be okay to use; to the contrary it says "Note the form of the first operand of
leal which forces the use of the SIB form ...". While that leaves open the use
of a NOP (or address size override on the associated CALL, as per the checking
the linker does) together with the non-SIB form,
- constraints on register use then still ought to be the same between both
variants,
- the presence of the NOP then would also need checking (as the linker does,
or else it might corrupt code).
>>> + if (i.tm.mnem_off != MN_lea)
>>> + return x86_tls_error_insn;
>>> + if (i.op[1].regs->reg_type.bitfield.instance != Accum)
>>> + return x86_tls_error_dest_eax;
>>> + if (!i.op[1].regs->reg_type.bitfield.dword)
>>> + return x86_tls_error_dest_32bit_reg_size;
>>> + if (i.index_reg)
>>> + {
>>> + if (i.base_reg)
>>> + return x86_tls_error_base_reg;
>>> + if (i.index_reg->reg_type.bitfield.instance != RegB)
>>> + return x86_tls_error_index_ebx;
>>> + if (i.log2_scale_factor)
>>> + return x86_tls_error_scale_factor;
>>> + }
>>> + else
>>> + {
>>> + if (!i.base_reg)
>>> + return x86_tls_error_no_base_reg;
>>> + if (i.base_reg->reg_type.bitfield.instance == Accum)
>>> + return x86_tls_error_eax;
>>> + }
>>> + break;
>>> +
>>> + case BFD_RELOC_386_TLS_LDM:
>>> + /* Check LDM access model:
>>> +
>>> + leal foo@tlsldm(%reg32), %eax --> Dest reg must be '%eax'
>>> + Memory reg can't be %eax and SIB
>>> + is not supported.
>>> + */
>>
>> ... for this case, and surprisingly any register is permitted here.
>
> There are two types of sequence listings in linker comments:
>
> /* Check transition from LD access model. Only
> leal foo@tlsldm(%ebx), %eax
> call ___tls_get_addr@PLT
> or
> leal foo@tlsldm(%reg), %eax
> call *___tls_get_addr@GOT(%reg)
> which may be converted to
> addr32 call ___tls_get_addr
> can transit to different access model. */
>
> They may be related to 4.2 of tls.pdf.
They are corresponding to that section, yes, but they don't match it.
Also note how all uses of addr32 in those comments are fishy: We're talking
about 32-bit mode code there, so the 0x67 prefix is addr16.
The recurring "%eax can't be used as the GOT base register since it
is used to pass parameter to ___tls_get_addr" in linker comments are also
unclear to me: The transitions eliminate the calls, and hence no arguments
are passed anyway. Locally and transiently establishing the GOT pointer in
%eax therefore looks entirely acceptable to me. It is clear from both the
original and the transitioned-to code sequences that %eax would no longer
hold the GOT pointer after these sequences. What instead is the case is
that in e.g.
leal foo@tlsldm(%reg), %eax
call *___tls_get_addr@GOT(%reg)
%reg is used again after the LEA, and hence its clobbering would be a
problem. Yet that's nowhere near what those comments say.
Jan
> Subject: Re: [PATCH V5] x86: Add tls check in gas
>
> On 25.09.2024 05:32, Cui, Lili wrote:
> >> I've grabbed the newest tls.pdf I could find (still over 10 years
> >> old, from Ulrich Drepper's site as referenced by the Thread-Local
> >> Storage section in gcc14 doc), and that raises questions:
> >
> > Jan, you can find the latest TLS in ABI chapter 10
> > (https://gitlab.com/x86-psABIs/x86-64-ABI)
>
> So far all my questions were on the i386 side of things, which isn't covered there.
>
> > and some TLS doc linkers there (e.g.
> > http://www.akkadia.org/drepper/tls.pdf)
>
> This is the doc I was referring to.
>
> As an aside - of course it shouldn't really take two docs to get a complete picture.
>
At least you can find " GDesc access model " in ABI doc.
> >> On 19.09.2024 08:38, Cui, Lili wrote:
> >>> @@ -6357,6 +6387,356 @@ static INLINE bool may_need_pass2 (const
> >> insn_template *t)
> >>> && (t->base_opcode | 8) == 0x2c); }
> >>>
> >>> +static enum x86_tls_error_type
> >>> +x86_check_tls_relocation (enum bfd_reloc_code_real r_type) {
> >>> + switch (r_type)
> >>> + {
> >>> + case BFD_RELOC_386_TLS_GOTDESC:
> >>> + /* Check GDesc access model:
> >>
> >> What's "GDesc access model"? I can't find anything named like this,
> >> nor mention of ...
> >>> + leal x@tlsdesc(%ebx), %reg32 --> Memory reg must be %ebx and
> >>> + SIB is not supported.
> >>> + */
> >>
> >> ... @tlsdesc.
> >
> > It is defined in ABI doc.
>
> As per above - where? I can see the 64-bit counterpart of this being described in
> the x86-64 psABI, but that's not covering the case here.
>
> >>> + if (i.tm.mnem_off != MN_lea)
> >>> + return x86_tls_error_insn;
> >>> + if (i.index_reg)
> >>> + return x86_tls_error_sib;
> >>> + if (!i.base_reg)
> >>> + return x86_tls_error_no_base_reg;
> >>> + if (i.base_reg->reg_type.bitfield.instance != RegB)
> >>> + return x86_tls_error_ebx;
> >>> + if (!i.op[1].regs->reg_type.bitfield.dword)
> >>> + return x86_tls_error_dest_32bit_reg_size;
> >>> + break;
> >>> +
> >>> + case BFD_RELOC_386_TLS_GD:
> >>> + /* Check GD access model:
> >>> +
> >>> + leal foo@tlsgd(,%ebx,1), %eax --> Only this fixed format is supported.
> >>> + leal foo@tlsgd(%reg32), %eax --> Dest reg must be '%eax'
> >>> + Memory reg can't be %eax.
> >>> + */
> >>
> >> Where's this 2nd form coming from? The doc says the SIB form must be
> >> used, and the converted-to code sequence would require one more byte
> >> than the non- SIB form provides space for.
> >>
> >> The doc doesn't say that the index reg has to be %ebx, it merely
> >> mentions that in the example, for being the commonly used GOT reg.
> >> This is the same ...
> >
> > It is mentioned in 4.1 of tls.pdf.
>
> Where? Please quote the sentence. I can't spot anything saying that it has to
> be %ebx. And similarly I can't spot anything indicating the non-SIB form would
> be okay to use; to the contrary it says "Note the form of the first operand of leal
> which forces the use of the SIB form ...". While that leaves open the use of a NOP
> (or address size override on the associated CALL, as per the checking the linker
> does) together with the non-SIB form,
This is the place, tls.pdf is encrypted and cannot be copied. I typed a sentence.
"To signal that this instruction is for the GNU variant of the access model the syntax @tlsgd(%ebx) is used."
It mentioned @tlsgd(%ebx), but I think the details are not clear enough, after all, the documentation has not been updated for 10 years. This place needs to be confirmed with the author.
> - constraints on register use then still ought to be the same between both
> variants,
> - the presence of the NOP then would also need checking (as the linker does,
> or else it might corrupt code).
>
I'll confirm this later.
> >>> + if (i.tm.mnem_off != MN_lea)
> >>> + return x86_tls_error_insn;
> >>> + if (i.op[1].regs->reg_type.bitfield.instance != Accum)
> >>> + return x86_tls_error_dest_eax;
> >>> + if (!i.op[1].regs->reg_type.bitfield.dword)
> >>> + return x86_tls_error_dest_32bit_reg_size;
> >>> + if (i.index_reg)
> >>> + {
> >>> + if (i.base_reg)
> >>> + return x86_tls_error_base_reg;
> >>> + if (i.index_reg->reg_type.bitfield.instance != RegB)
> >>> + return x86_tls_error_index_ebx;
> >>> + if (i.log2_scale_factor)
> >>> + return x86_tls_error_scale_factor;
> >>> + }
> >>> + else
> >>> + {
> >>> + if (!i.base_reg)
> >>> + return x86_tls_error_no_base_reg;
> >>> + if (i.base_reg->reg_type.bitfield.instance == Accum)
> >>> + return x86_tls_error_eax;
> >>> + }
> >>> + break;
> >>> +
> >>> + case BFD_RELOC_386_TLS_LDM:
> >>> + /* Check LDM access model:
> >>> +
> >>> + leal foo@tlsldm(%reg32), %eax --> Dest reg must be '%eax'
> >>> + Memory reg can't be %eax and SIB
> >>> + is not supported.
> >>> + */
> >>
> >> ... for this case, and surprisingly any register is permitted here.
> >
> > There are two types of sequence listings in linker comments:
> >
> > /* Check transition from LD access model. Only
> > leal foo@tlsldm(%ebx), %eax
> > call ___tls_get_addr@PLT
> > or
> > leal foo@tlsldm(%reg), %eax
> > call *___tls_get_addr@GOT(%reg)
> > which may be converted to
> > addr32 call ___tls_get_addr
> > can transit to different access model. */
> >
> > They may be related to 4.2 of tls.pdf.
>
> They are corresponding to that section, yes, but they don't match it.
>
> Also note how all uses of addr32 in those comments are fishy: We're talking
> about 32-bit mode code there, so the 0x67 prefix is addr16.
>
> The recurring "%eax can't be used as the GOT base register since it is used to pass
> parameter to ___tls_get_addr" in linker comments are also unclear to me: The
> transitions eliminate the calls, and hence no arguments are passed anyway.
> Locally and transiently establishing the GOT pointer in %eax therefore looks
> entirely acceptable to me. It is clear from both the original and the transitioned-
> to code sequences that %eax would no longer hold the GOT pointer after these
> sequences. What instead is the case is that in e.g.
>
> leal foo@tlsldm(%reg), %eax
> call *___tls_get_addr@GOT(%reg)
>
> %reg is used again after the LEA, and hence its clobbering would be a problem.
> Yet that's nowhere near what those comments say.
>
This place needs to be confirmed with the author.
Thanks,
Lili.
> Jan
On 25.09.2024 14:45, Cui, Lili wrote:
>> Subject: Re: [PATCH V5] x86: Add tls check in gas
>>
>> On 25.09.2024 05:32, Cui, Lili wrote:
>>>> I've grabbed the newest tls.pdf I could find (still over 10 years
>>>> old, from Ulrich Drepper's site as referenced by the Thread-Local
>>>> Storage section in gcc14 doc), and that raises questions:
>>>
>>> Jan, you can find the latest TLS in ABI chapter 10
>>> (https://gitlab.com/x86-psABIs/x86-64-ABI)
>>
>> So far all my questions were on the i386 side of things, which isn't covered there.
>>
>>> and some TLS doc linkers there (e.g.
>>> http://www.akkadia.org/drepper/tls.pdf)
>>
>> This is the doc I was referring to.
>>
>> As an aside - of course it shouldn't really take two docs to get a complete picture.
>
> At least you can find " GDesc access model " in ABI doc.
But not what exactly it means on i386. Are we here dealing with private,
undocumented extensions to the TLS spec?
>>>> On 19.09.2024 08:38, Cui, Lili wrote:
>>>>> @@ -6357,6 +6387,356 @@ static INLINE bool may_need_pass2 (const
>>>> insn_template *t)
>>>>> && (t->base_opcode | 8) == 0x2c); }
>>>>>
>>>>> +static enum x86_tls_error_type
>>>>> +x86_check_tls_relocation (enum bfd_reloc_code_real r_type) {
>>>>> + switch (r_type)
>>>>> + {
>>>>> + case BFD_RELOC_386_TLS_GOTDESC:
>>>>> + /* Check GDesc access model:
>>>>
>>>> What's "GDesc access model"? I can't find anything named like this,
>>>> nor mention of ...
>>>>> + leal x@tlsdesc(%ebx), %reg32 --> Memory reg must be %ebx and
>>>>> + SIB is not supported.
>>>>> + */
>>>>
>>>> ... @tlsdesc.
>>>
>>> It is defined in ABI doc.
>>
>> As per above - where? I can see the 64-bit counterpart of this being described in
>> the x86-64 psABI, but that's not covering the case here.
>>
>>>>> + if (i.tm.mnem_off != MN_lea)
>>>>> + return x86_tls_error_insn;
>>>>> + if (i.index_reg)
>>>>> + return x86_tls_error_sib;
>>>>> + if (!i.base_reg)
>>>>> + return x86_tls_error_no_base_reg;
>>>>> + if (i.base_reg->reg_type.bitfield.instance != RegB)
>>>>> + return x86_tls_error_ebx;
>>>>> + if (!i.op[1].regs->reg_type.bitfield.dword)
>>>>> + return x86_tls_error_dest_32bit_reg_size;
>>>>> + break;
>>>>> +
>>>>> + case BFD_RELOC_386_TLS_GD:
>>>>> + /* Check GD access model:
>>>>> +
>>>>> + leal foo@tlsgd(,%ebx,1), %eax --> Only this fixed format is supported.
>>>>> + leal foo@tlsgd(%reg32), %eax --> Dest reg must be '%eax'
>>>>> + Memory reg can't be %eax.
>>>>> + */
>>>>
>>>> Where's this 2nd form coming from? The doc says the SIB form must be
>>>> used, and the converted-to code sequence would require one more byte
>>>> than the non- SIB form provides space for.
>>>>
>>>> The doc doesn't say that the index reg has to be %ebx, it merely
>>>> mentions that in the example, for being the commonly used GOT reg.
>>>> This is the same ...
>>>
>>> It is mentioned in 4.1 of tls.pdf.
>>
>> Where? Please quote the sentence. I can't spot anything saying that it has to
>> be %ebx. And similarly I can't spot anything indicating the non-SIB form would
>> be okay to use; to the contrary it says "Note the form of the first operand of leal
>> which forces the use of the SIB form ...". While that leaves open the use of a NOP
>> (or address size override on the associated CALL, as per the checking the linker
>> does) together with the non-SIB form,
>
> This is the place, tls.pdf is encrypted and cannot be copied. I typed a sentence.
>
> "To signal that this instruction is for the GNU variant of the access model the syntax @tlsgd(%ebx) is used."
>
> It mentioned @tlsgd(%ebx),
As you say - mentions. It doesn't say that's the only valid form. Instead ...
> but I think the details are not clear enough, after all, the documentation has not been updated for 10 years.
... it seems pretty obvious that if any reg other than %eax is fine for the
non-SIB form, the same is true for the SIB one. The two forms are solely
different encodings of the same EA.
> This place needs to be confirmed with the author.
First of all I'd like to understand the origin of the non-SIB form, and
thus (hopefully) why that permits more registers than the SIB one.
Jan
On Wed, Sep 25, 2024 at 10:29 PM Jan Beulich <jbeulich@suse.com> wrote:
>
> On 25.09.2024 14:45, Cui, Lili wrote:
> >> Subject: Re: [PATCH V5] x86: Add tls check in gas
> >>
> >> On 25.09.2024 05:32, Cui, Lili wrote:
> >>>> I've grabbed the newest tls.pdf I could find (still over 10 years
> >>>> old, from Ulrich Drepper's site as referenced by the Thread-Local
> >>>> Storage section in gcc14 doc), and that raises questions:
> >>>
> >>> Jan, you can find the latest TLS in ABI chapter 10
> >>> (https://gitlab.com/x86-psABIs/x86-64-ABI)
> >>
> >> So far all my questions were on the i386 side of things, which isn't covered there.
> >>
> >>> and some TLS doc linkers there (e.g.
> >>> http://www.akkadia.org/drepper/tls.pdf)
> >>
> >> This is the doc I was referring to.
> >>
> >> As an aside - of course it shouldn't really take two docs to get a complete picture.
> >
> > At least you can find " GDesc access model " in ABI doc.
>
> But not what exactly it means on i386. Are we here dealing with private,
> undocumented extensions to the TLS spec?
>
> >>>> On 19.09.2024 08:38, Cui, Lili wrote:
> >>>>> @@ -6357,6 +6387,356 @@ static INLINE bool may_need_pass2 (const
> >>>> insn_template *t)
> >>>>> && (t->base_opcode | 8) == 0x2c); }
> >>>>>
> >>>>> +static enum x86_tls_error_type
> >>>>> +x86_check_tls_relocation (enum bfd_reloc_code_real r_type) {
> >>>>> + switch (r_type)
> >>>>> + {
> >>>>> + case BFD_RELOC_386_TLS_GOTDESC:
> >>>>> + /* Check GDesc access model:
> >>>>
> >>>> What's "GDesc access model"? I can't find anything named like this,
> >>>> nor mention of ...
> >>>>> + leal x@tlsdesc(%ebx), %reg32 --> Memory reg must be %ebx and
> >>>>> + SIB is not supported.
> >>>>> + */
> >>>>
> >>>> ... @tlsdesc.
> >>>
> >>> It is defined in ABI doc.
> >>
> >> As per above - where? I can see the 64-bit counterpart of this being described in
> >> the x86-64 psABI, but that's not covering the case here.
> >>
> >>>>> + if (i.tm.mnem_off != MN_lea)
> >>>>> + return x86_tls_error_insn;
> >>>>> + if (i.index_reg)
> >>>>> + return x86_tls_error_sib;
> >>>>> + if (!i.base_reg)
> >>>>> + return x86_tls_error_no_base_reg;
> >>>>> + if (i.base_reg->reg_type.bitfield.instance != RegB)
> >>>>> + return x86_tls_error_ebx;
> >>>>> + if (!i.op[1].regs->reg_type.bitfield.dword)
> >>>>> + return x86_tls_error_dest_32bit_reg_size;
> >>>>> + break;
> >>>>> +
> >>>>> + case BFD_RELOC_386_TLS_GD:
> >>>>> + /* Check GD access model:
> >>>>> +
> >>>>> + leal foo@tlsgd(,%ebx,1), %eax --> Only this fixed format is supported.
> >>>>> + leal foo@tlsgd(%reg32), %eax --> Dest reg must be '%eax'
> >>>>> + Memory reg can't be %eax.
> >>>>> + */
> >>>>
> >>>> Where's this 2nd form coming from? The doc says the SIB form must be
> >>>> used, and the converted-to code sequence would require one more byte
> >>>> than the non- SIB form provides space for.
> >>>>
> >>>> The doc doesn't say that the index reg has to be %ebx, it merely
> >>>> mentions that in the example, for being the commonly used GOT reg.
> >>>> This is the same ...
> >>>
> >>> It is mentioned in 4.1 of tls.pdf.
> >>
> >> Where? Please quote the sentence. I can't spot anything saying that it has to
> >> be %ebx. And similarly I can't spot anything indicating the non-SIB form would
> >> be okay to use; to the contrary it says "Note the form of the first operand of leal
> >> which forces the use of the SIB form ...". While that leaves open the use of a NOP
> >> (or address size override on the associated CALL, as per the checking the linker
> >> does) together with the non-SIB form,
> >
> > This is the place, tls.pdf is encrypted and cannot be copied. I typed a sentence.
> >
> > "To signal that this instruction is for the GNU variant of the access model the syntax @tlsgd(%ebx) is used."
> >
> > It mentioned @tlsgd(%ebx),
>
> As you say - mentions. It doesn't say that's the only valid form. Instead ...
>
> > but I think the details are not clear enough, after all, the documentation has not been updated for 10 years.
>
> ... it seems pretty obvious that if any reg other than %eax is fine for the
> non-SIB form, the same is true for the SIB one. The two forms are solely
> different encodings of the same EA.
>
> > This place needs to be confirmed with the author.
>
> First of all I'd like to understand the origin of the non-SIB form, and
> thus (hopefully) why that permits more registers than the SIB one.
>
> Jan
These assembler checks are the same as the linker checks.
Unless there is a real workload to show the linker check is
incorrect, I don't believe we should check the linker.
On 27.09.2024 01:12, H.J. Lu wrote:
> On Wed, Sep 25, 2024 at 10:29 PM Jan Beulich <jbeulich@suse.com> wrote:
>>
>> On 25.09.2024 14:45, Cui, Lili wrote:
>>>> Subject: Re: [PATCH V5] x86: Add tls check in gas
>>>>
>>>> On 25.09.2024 05:32, Cui, Lili wrote:
>>>>>> I've grabbed the newest tls.pdf I could find (still over 10 years
>>>>>> old, from Ulrich Drepper's site as referenced by the Thread-Local
>>>>>> Storage section in gcc14 doc), and that raises questions:
>>>>>
>>>>> Jan, you can find the latest TLS in ABI chapter 10
>>>>> (https://gitlab.com/x86-psABIs/x86-64-ABI)
>>>>
>>>> So far all my questions were on the i386 side of things, which isn't covered there.
>>>>
>>>>> and some TLS doc linkers there (e.g.
>>>>> http://www.akkadia.org/drepper/tls.pdf)
>>>>
>>>> This is the doc I was referring to.
>>>>
>>>> As an aside - of course it shouldn't really take two docs to get a complete picture.
>>>
>>> At least you can find " GDesc access model " in ABI doc.
>>
>> But not what exactly it means on i386. Are we here dealing with private,
>> undocumented extensions to the TLS spec?
>>
>>>>>> On 19.09.2024 08:38, Cui, Lili wrote:
>>>>>>> @@ -6357,6 +6387,356 @@ static INLINE bool may_need_pass2 (const
>>>>>> insn_template *t)
>>>>>>> && (t->base_opcode | 8) == 0x2c); }
>>>>>>>
>>>>>>> +static enum x86_tls_error_type
>>>>>>> +x86_check_tls_relocation (enum bfd_reloc_code_real r_type) {
>>>>>>> + switch (r_type)
>>>>>>> + {
>>>>>>> + case BFD_RELOC_386_TLS_GOTDESC:
>>>>>>> + /* Check GDesc access model:
>>>>>>
>>>>>> What's "GDesc access model"? I can't find anything named like this,
>>>>>> nor mention of ...
>>>>>>> + leal x@tlsdesc(%ebx), %reg32 --> Memory reg must be %ebx and
>>>>>>> + SIB is not supported.
>>>>>>> + */
>>>>>>
>>>>>> ... @tlsdesc.
>>>>>
>>>>> It is defined in ABI doc.
>>>>
>>>> As per above - where? I can see the 64-bit counterpart of this being described in
>>>> the x86-64 psABI, but that's not covering the case here.
>>>>
>>>>>>> + if (i.tm.mnem_off != MN_lea)
>>>>>>> + return x86_tls_error_insn;
>>>>>>> + if (i.index_reg)
>>>>>>> + return x86_tls_error_sib;
>>>>>>> + if (!i.base_reg)
>>>>>>> + return x86_tls_error_no_base_reg;
>>>>>>> + if (i.base_reg->reg_type.bitfield.instance != RegB)
>>>>>>> + return x86_tls_error_ebx;
>>>>>>> + if (!i.op[1].regs->reg_type.bitfield.dword)
>>>>>>> + return x86_tls_error_dest_32bit_reg_size;
>>>>>>> + break;
>>>>>>> +
>>>>>>> + case BFD_RELOC_386_TLS_GD:
>>>>>>> + /* Check GD access model:
>>>>>>> +
>>>>>>> + leal foo@tlsgd(,%ebx,1), %eax --> Only this fixed format is supported.
>>>>>>> + leal foo@tlsgd(%reg32), %eax --> Dest reg must be '%eax'
>>>>>>> + Memory reg can't be %eax.
>>>>>>> + */
>>>>>>
>>>>>> Where's this 2nd form coming from? The doc says the SIB form must be
>>>>>> used, and the converted-to code sequence would require one more byte
>>>>>> than the non- SIB form provides space for.
>>>>>>
>>>>>> The doc doesn't say that the index reg has to be %ebx, it merely
>>>>>> mentions that in the example, for being the commonly used GOT reg.
>>>>>> This is the same ...
>>>>>
>>>>> It is mentioned in 4.1 of tls.pdf.
>>>>
>>>> Where? Please quote the sentence. I can't spot anything saying that it has to
>>>> be %ebx. And similarly I can't spot anything indicating the non-SIB form would
>>>> be okay to use; to the contrary it says "Note the form of the first operand of leal
>>>> which forces the use of the SIB form ...". While that leaves open the use of a NOP
>>>> (or address size override on the associated CALL, as per the checking the linker
>>>> does) together with the non-SIB form,
>>>
>>> This is the place, tls.pdf is encrypted and cannot be copied. I typed a sentence.
>>>
>>> "To signal that this instruction is for the GNU variant of the access model the syntax @tlsgd(%ebx) is used."
>>>
>>> It mentioned @tlsgd(%ebx),
>>
>> As you say - mentions. It doesn't say that's the only valid form. Instead ...
>>
>>> but I think the details are not clear enough, after all, the documentation has not been updated for 10 years.
>>
>> ... it seems pretty obvious that if any reg other than %eax is fine for the
>> non-SIB form, the same is true for the SIB one. The two forms are solely
>> different encodings of the same EA.
>>
>>> This place needs to be confirmed with the author.
>>
>> First of all I'd like to understand the origin of the non-SIB form, and
>> thus (hopefully) why that permits more registers than the SIB one.
>
> These assembler checks are the same as the linker checks.
> Unless there is a real workload to show the linker check is
> incorrect, I don't believe we should check the linker.
Here we go again - you apply personal preferences. For those APX insn
promotions you've insisted on us sticking to the spec. Here you say you
want to keep the linker as is, no matter whether it matches the spec
(wherever the missing parts thereof are). I'm afraid I'd like to ask
that you make up your mind in a consistent way: Do specs matter, or can
we take arbitrary liberties? My view is that in both cases we could
permit sensible extensions, as long as those are sufficiently clear to
be in line with the original intentions of the spec. In the case here
that of course would first mean to properly identify what the extension
parts are. And then any extensions of course want to be consistent with
the original spec as well as self-consistent.
Jan
On Fri, Sep 27, 2024, 3:25 PM Jan Beulich <jbeulich@suse.com> wrote:
> On 27.09.2024 01:12, H.J. Lu wrote:
> > On Wed, Sep 25, 2024 at 10:29 PM Jan Beulich <jbeulich@suse.com> wrote:
> >>
> >> On 25.09.2024 14:45, Cui, Lili wrote:
> >>>> Subject: Re: [PATCH V5] x86: Add tls check in gas
> >>>>
> >>>> On 25.09.2024 05:32, Cui, Lili wrote:
> >>>>>> I've grabbed the newest tls.pdf I could find (still over 10 years
> >>>>>> old, from Ulrich Drepper's site as referenced by the Thread-Local
> >>>>>> Storage section in gcc14 doc), and that raises questions:
> >>>>>
> >>>>> Jan, you can find the latest TLS in ABI chapter 10
> >>>>> (https://gitlab.com/x86-psABIs/x86-64-ABI)
> >>>>
> >>>> So far all my questions were on the i386 side of things, which isn't
> covered there.
> >>>>
> >>>>> and some TLS doc linkers there (e.g.
> >>>>> http://www.akkadia.org/drepper/tls.pdf)
> >>>>
> >>>> This is the doc I was referring to.
> >>>>
> >>>> As an aside - of course it shouldn't really take two docs to get a
> complete picture.
> >>>
> >>> At least you can find " GDesc access model " in ABI doc.
> >>
> >> But not what exactly it means on i386. Are we here dealing with private,
> >> undocumented extensions to the TLS spec?
> >>
> >>>>>> On 19.09.2024 08:38, Cui, Lili wrote:
> >>>>>>> @@ -6357,6 +6387,356 @@ static INLINE bool may_need_pass2 (const
> >>>>>> insn_template *t)
> >>>>>>> && (t->base_opcode | 8) == 0x2c); }
> >>>>>>>
> >>>>>>> +static enum x86_tls_error_type
> >>>>>>> +x86_check_tls_relocation (enum bfd_reloc_code_real r_type) {
> >>>>>>> + switch (r_type)
> >>>>>>> + {
> >>>>>>> + case BFD_RELOC_386_TLS_GOTDESC:
> >>>>>>> + /* Check GDesc access model:
> >>>>>>
> >>>>>> What's "GDesc access model"? I can't find anything named like this,
> >>>>>> nor mention of ...
> >>>>>>> + leal x@tlsdesc(%ebx), %reg32 --> Memory reg must be %ebx and
> >>>>>>> + SIB is not supported.
> >>>>>>> + */
> >>>>>>
> >>>>>> ... @tlsdesc.
> >>>>>
> >>>>> It is defined in ABI doc.
> >>>>
> >>>> As per above - where? I can see the 64-bit counterpart of this being
> described in
> >>>> the x86-64 psABI, but that's not covering the case here.
> >>>>
> >>>>>>> + if (i.tm.mnem_off != MN_lea)
> >>>>>>> + return x86_tls_error_insn;
> >>>>>>> + if (i.index_reg)
> >>>>>>> + return x86_tls_error_sib;
> >>>>>>> + if (!i.base_reg)
> >>>>>>> + return x86_tls_error_no_base_reg;
> >>>>>>> + if (i.base_reg->reg_type.bitfield.instance != RegB)
> >>>>>>> + return x86_tls_error_ebx;
> >>>>>>> + if (!i.op[1].regs->reg_type.bitfield.dword)
> >>>>>>> + return x86_tls_error_dest_32bit_reg_size;
> >>>>>>> + break;
> >>>>>>> +
> >>>>>>> + case BFD_RELOC_386_TLS_GD:
> >>>>>>> + /* Check GD access model:
> >>>>>>> +
> >>>>>>> + leal foo@tlsgd(,%ebx,1), %eax --> Only this fixed format is
> supported.
> >>>>>>> + leal foo@tlsgd(%reg32), %eax --> Dest reg must be '%eax'
> >>>>>>> + Memory reg can't be %eax.
> >>>>>>> + */
> >>>>>>
> >>>>>> Where's this 2nd form coming from? The doc says the SIB form must be
> >>>>>> used, and the converted-to code sequence would require one more byte
> >>>>>> than the non- SIB form provides space for.
> >>>>>>
> >>>>>> The doc doesn't say that the index reg has to be %ebx, it merely
> >>>>>> mentions that in the example, for being the commonly used GOT reg.
> >>>>>> This is the same ...
> >>>>>
> >>>>> It is mentioned in 4.1 of tls.pdf.
> >>>>
> >>>> Where? Please quote the sentence. I can't spot anything saying that
> it has to
> >>>> be %ebx. And similarly I can't spot anything indicating the non-SIB
> form would
> >>>> be okay to use; to the contrary it says "Note the form of the first
> operand of leal
> >>>> which forces the use of the SIB form ...". While that leaves open the
> use of a NOP
> >>>> (or address size override on the associated CALL, as per the checking
> the linker
> >>>> does) together with the non-SIB form,
> >>>
> >>> This is the place, tls.pdf is encrypted and cannot be copied. I typed
> a sentence.
> >>>
> >>> "To signal that this instruction is for the GNU variant of the access
> model the syntax @tlsgd(%ebx) is used."
> >>>
> >>> It mentioned @tlsgd(%ebx),
> >>
> >> As you say - mentions. It doesn't say that's the only valid form.
> Instead ...
> >>
> >>> but I think the details are not clear enough, after all, the
> documentation has not been updated for 10 years.
> >>
> >> ... it seems pretty obvious that if any reg other than %eax is fine for
> the
> >> non-SIB form, the same is true for the SIB one. The two forms are solely
> >> different encodings of the same EA.
> >>
> >>> This place needs to be confirmed with the author.
> >>
> >> First of all I'd like to understand the origin of the non-SIB form, and
> >> thus (hopefully) why that permits more registers than the SIB one.
> >
> > These assembler checks are the same as the linker checks.
> > Unless there is a real workload to show the linker check is
> > incorrect, I don't believe we should check the linker.
>
> Here we go again - you apply personal preferences. For those APX insn
> promotions you've insisted on us sticking to the spec. Here you say you
> want to keep the linker as is, no matter whether it matches the spec
> (wherever the missing parts thereof are). I'm afraid I'd like to ask
> that you make up your mind in a consistent way: Do specs matter, or can
> we take arbitrary liberties? My view is that in both cases we could
> permit sensible extensions, as long as those are sufficiently clear to
> be in line with the original intentions of the spec. In the case here
> that of course would first mean to properly identify what the extension
> parts are. And then any extensions of course want to be consistent with
> the original spec as well as self-consistent.
>
Linker and assembler are different.
Linker check was added for a reason.
You can ask the author of such linker
check. He or she may remember the reason.
> Jan
>
>
On 27.09.2024 09:53, H.J. Lu wrote:
> On Fri, Sep 27, 2024, 3:25 PM Jan Beulich <jbeulich@suse.com> wrote:
>
>> On 27.09.2024 01:12, H.J. Lu wrote:
>>> On Wed, Sep 25, 2024 at 10:29 PM Jan Beulich <jbeulich@suse.com> wrote:
>>>>
>>>> On 25.09.2024 14:45, Cui, Lili wrote:
>>>>>> Subject: Re: [PATCH V5] x86: Add tls check in gas
>>>>>>
>>>>>> On 25.09.2024 05:32, Cui, Lili wrote:
>>>>>>>> I've grabbed the newest tls.pdf I could find (still over 10 years
>>>>>>>> old, from Ulrich Drepper's site as referenced by the Thread-Local
>>>>>>>> Storage section in gcc14 doc), and that raises questions:
>>>>>>>
>>>>>>> Jan, you can find the latest TLS in ABI chapter 10
>>>>>>> (https://gitlab.com/x86-psABIs/x86-64-ABI)
>>>>>>
>>>>>> So far all my questions were on the i386 side of things, which isn't
>> covered there.
>>>>>>
>>>>>>> and some TLS doc linkers there (e.g.
>>>>>>> http://www.akkadia.org/drepper/tls.pdf)
>>>>>>
>>>>>> This is the doc I was referring to.
>>>>>>
>>>>>> As an aside - of course it shouldn't really take two docs to get a
>> complete picture.
>>>>>
>>>>> At least you can find " GDesc access model " in ABI doc.
>>>>
>>>> But not what exactly it means on i386. Are we here dealing with private,
>>>> undocumented extensions to the TLS spec?
>>>>
>>>>>>>> On 19.09.2024 08:38, Cui, Lili wrote:
>>>>>>>>> @@ -6357,6 +6387,356 @@ static INLINE bool may_need_pass2 (const
>>>>>>>> insn_template *t)
>>>>>>>>> && (t->base_opcode | 8) == 0x2c); }
>>>>>>>>>
>>>>>>>>> +static enum x86_tls_error_type
>>>>>>>>> +x86_check_tls_relocation (enum bfd_reloc_code_real r_type) {
>>>>>>>>> + switch (r_type)
>>>>>>>>> + {
>>>>>>>>> + case BFD_RELOC_386_TLS_GOTDESC:
>>>>>>>>> + /* Check GDesc access model:
>>>>>>>>
>>>>>>>> What's "GDesc access model"? I can't find anything named like this,
>>>>>>>> nor mention of ...
>>>>>>>>> + leal x@tlsdesc(%ebx), %reg32 --> Memory reg must be %ebx and
>>>>>>>>> + SIB is not supported.
>>>>>>>>> + */
>>>>>>>>
>>>>>>>> ... @tlsdesc.
>>>>>>>
>>>>>>> It is defined in ABI doc.
>>>>>>
>>>>>> As per above - where? I can see the 64-bit counterpart of this being
>> described in
>>>>>> the x86-64 psABI, but that's not covering the case here.
>>>>>>
>>>>>>>>> + if (i.tm.mnem_off != MN_lea)
>>>>>>>>> + return x86_tls_error_insn;
>>>>>>>>> + if (i.index_reg)
>>>>>>>>> + return x86_tls_error_sib;
>>>>>>>>> + if (!i.base_reg)
>>>>>>>>> + return x86_tls_error_no_base_reg;
>>>>>>>>> + if (i.base_reg->reg_type.bitfield.instance != RegB)
>>>>>>>>> + return x86_tls_error_ebx;
>>>>>>>>> + if (!i.op[1].regs->reg_type.bitfield.dword)
>>>>>>>>> + return x86_tls_error_dest_32bit_reg_size;
>>>>>>>>> + break;
>>>>>>>>> +
>>>>>>>>> + case BFD_RELOC_386_TLS_GD:
>>>>>>>>> + /* Check GD access model:
>>>>>>>>> +
>>>>>>>>> + leal foo@tlsgd(,%ebx,1), %eax --> Only this fixed format is
>> supported.
>>>>>>>>> + leal foo@tlsgd(%reg32), %eax --> Dest reg must be '%eax'
>>>>>>>>> + Memory reg can't be %eax.
>>>>>>>>> + */
>>>>>>>>
>>>>>>>> Where's this 2nd form coming from? The doc says the SIB form must be
>>>>>>>> used, and the converted-to code sequence would require one more byte
>>>>>>>> than the non- SIB form provides space for.
>>>>>>>>
>>>>>>>> The doc doesn't say that the index reg has to be %ebx, it merely
>>>>>>>> mentions that in the example, for being the commonly used GOT reg.
>>>>>>>> This is the same ...
>>>>>>>
>>>>>>> It is mentioned in 4.1 of tls.pdf.
>>>>>>
>>>>>> Where? Please quote the sentence. I can't spot anything saying that
>> it has to
>>>>>> be %ebx. And similarly I can't spot anything indicating the non-SIB
>> form would
>>>>>> be okay to use; to the contrary it says "Note the form of the first
>> operand of leal
>>>>>> which forces the use of the SIB form ...". While that leaves open the
>> use of a NOP
>>>>>> (or address size override on the associated CALL, as per the checking
>> the linker
>>>>>> does) together with the non-SIB form,
>>>>>
>>>>> This is the place, tls.pdf is encrypted and cannot be copied. I typed
>> a sentence.
>>>>>
>>>>> "To signal that this instruction is for the GNU variant of the access
>> model the syntax @tlsgd(%ebx) is used."
>>>>>
>>>>> It mentioned @tlsgd(%ebx),
>>>>
>>>> As you say - mentions. It doesn't say that's the only valid form.
>> Instead ...
>>>>
>>>>> but I think the details are not clear enough, after all, the
>> documentation has not been updated for 10 years.
>>>>
>>>> ... it seems pretty obvious that if any reg other than %eax is fine for
>> the
>>>> non-SIB form, the same is true for the SIB one. The two forms are solely
>>>> different encodings of the same EA.
>>>>
>>>>> This place needs to be confirmed with the author.
>>>>
>>>> First of all I'd like to understand the origin of the non-SIB form, and
>>>> thus (hopefully) why that permits more registers than the SIB one.
>>>
>>> These assembler checks are the same as the linker checks.
>>> Unless there is a real workload to show the linker check is
>>> incorrect, I don't believe we should check the linker.
>>
>> Here we go again - you apply personal preferences. For those APX insn
>> promotions you've insisted on us sticking to the spec. Here you say you
>> want to keep the linker as is, no matter whether it matches the spec
>> (wherever the missing parts thereof are). I'm afraid I'd like to ask
>> that you make up your mind in a consistent way: Do specs matter, or can
>> we take arbitrary liberties? My view is that in both cases we could
>> permit sensible extensions, as long as those are sufficiently clear to
>> be in line with the original intentions of the spec. In the case here
>> that of course would first mean to properly identify what the extension
>> parts are. And then any extensions of course want to be consistent with
>> the original spec as well as self-consistent.
>>
>
> Linker and assembler are different.
Well. Of course they're different, yet that doesn't mean one needs to adhere
to specs and the other can do whatever it wants.
> Linker check was added for a reason.
> You can ask the author of such linker
> check. He or she may remember the reason.
Have I not been doing this all the time? You're the author of 6eaa7fb59b32
("Support i386 TLS code sequences without PLT"), which switched R_386_TLS_GD
handling from any-reg to %ebx-only.
Jan
On Fri, Sep 27, 2024 at 8:54 PM Jan Beulich <jbeulich@suse.com> wrote:
>
> On 27.09.2024 09:53, H.J. Lu wrote:
> > On Fri, Sep 27, 2024, 3:25 PM Jan Beulich <jbeulich@suse.com> wrote:
> >
> >> On 27.09.2024 01:12, H.J. Lu wrote:
> >>> On Wed, Sep 25, 2024 at 10:29 PM Jan Beulich <jbeulich@suse.com> wrote:
> >>>>
> >>>> On 25.09.2024 14:45, Cui, Lili wrote:
> >>>>>> Subject: Re: [PATCH V5] x86: Add tls check in gas
> >>>>>>
> >>>>>> On 25.09.2024 05:32, Cui, Lili wrote:
> >>>>>>>> I've grabbed the newest tls.pdf I could find (still over 10 years
> >>>>>>>> old, from Ulrich Drepper's site as referenced by the Thread-Local
> >>>>>>>> Storage section in gcc14 doc), and that raises questions:
> >>>>>>>
> >>>>>>> Jan, you can find the latest TLS in ABI chapter 10
> >>>>>>> (https://gitlab.com/x86-psABIs/x86-64-ABI)
> >>>>>>
> >>>>>> So far all my questions were on the i386 side of things, which isn't
> >> covered there.
> >>>>>>
> >>>>>>> and some TLS doc linkers there (e.g.
> >>>>>>> http://www.akkadia.org/drepper/tls.pdf)
> >>>>>>
> >>>>>> This is the doc I was referring to.
> >>>>>>
> >>>>>> As an aside - of course it shouldn't really take two docs to get a
> >> complete picture.
> >>>>>
> >>>>> At least you can find " GDesc access model " in ABI doc.
> >>>>
> >>>> But not what exactly it means on i386. Are we here dealing with private,
> >>>> undocumented extensions to the TLS spec?
> >>>>
> >>>>>>>> On 19.09.2024 08:38, Cui, Lili wrote:
> >>>>>>>>> @@ -6357,6 +6387,356 @@ static INLINE bool may_need_pass2 (const
> >>>>>>>> insn_template *t)
> >>>>>>>>> && (t->base_opcode | 8) == 0x2c); }
> >>>>>>>>>
> >>>>>>>>> +static enum x86_tls_error_type
> >>>>>>>>> +x86_check_tls_relocation (enum bfd_reloc_code_real r_type) {
> >>>>>>>>> + switch (r_type)
> >>>>>>>>> + {
> >>>>>>>>> + case BFD_RELOC_386_TLS_GOTDESC:
> >>>>>>>>> + /* Check GDesc access model:
> >>>>>>>>
> >>>>>>>> What's "GDesc access model"? I can't find anything named like this,
> >>>>>>>> nor mention of ...
> >>>>>>>>> + leal x@tlsdesc(%ebx), %reg32 --> Memory reg must be %ebx and
> >>>>>>>>> + SIB is not supported.
> >>>>>>>>> + */
> >>>>>>>>
> >>>>>>>> ... @tlsdesc.
> >>>>>>>
> >>>>>>> It is defined in ABI doc.
> >>>>>>
> >>>>>> As per above - where? I can see the 64-bit counterpart of this being
> >> described in
> >>>>>> the x86-64 psABI, but that's not covering the case here.
> >>>>>>
> >>>>>>>>> + if (i.tm.mnem_off != MN_lea)
> >>>>>>>>> + return x86_tls_error_insn;
> >>>>>>>>> + if (i.index_reg)
> >>>>>>>>> + return x86_tls_error_sib;
> >>>>>>>>> + if (!i.base_reg)
> >>>>>>>>> + return x86_tls_error_no_base_reg;
> >>>>>>>>> + if (i.base_reg->reg_type.bitfield.instance != RegB)
> >>>>>>>>> + return x86_tls_error_ebx;
> >>>>>>>>> + if (!i.op[1].regs->reg_type.bitfield.dword)
> >>>>>>>>> + return x86_tls_error_dest_32bit_reg_size;
> >>>>>>>>> + break;
> >>>>>>>>> +
> >>>>>>>>> + case BFD_RELOC_386_TLS_GD:
> >>>>>>>>> + /* Check GD access model:
> >>>>>>>>> +
> >>>>>>>>> + leal foo@tlsgd(,%ebx,1), %eax --> Only this fixed format is
> >> supported.
> >>>>>>>>> + leal foo@tlsgd(%reg32), %eax --> Dest reg must be '%eax'
> >>>>>>>>> + Memory reg can't be %eax.
> >>>>>>>>> + */
> >>>>>>>>
> >>>>>>>> Where's this 2nd form coming from? The doc says the SIB form must be
> >>>>>>>> used, and the converted-to code sequence would require one more byte
> >>>>>>>> than the non- SIB form provides space for.
> >>>>>>>>
> >>>>>>>> The doc doesn't say that the index reg has to be %ebx, it merely
> >>>>>>>> mentions that in the example, for being the commonly used GOT reg.
> >>>>>>>> This is the same ...
> >>>>>>>
> >>>>>>> It is mentioned in 4.1 of tls.pdf.
> >>>>>>
> >>>>>> Where? Please quote the sentence. I can't spot anything saying that
> >> it has to
> >>>>>> be %ebx. And similarly I can't spot anything indicating the non-SIB
> >> form would
> >>>>>> be okay to use; to the contrary it says "Note the form of the first
> >> operand of leal
> >>>>>> which forces the use of the SIB form ...". While that leaves open the
> >> use of a NOP
> >>>>>> (or address size override on the associated CALL, as per the checking
> >> the linker
> >>>>>> does) together with the non-SIB form,
> >>>>>
> >>>>> This is the place, tls.pdf is encrypted and cannot be copied. I typed
> >> a sentence.
> >>>>>
> >>>>> "To signal that this instruction is for the GNU variant of the access
> >> model the syntax @tlsgd(%ebx) is used."
> >>>>>
> >>>>> It mentioned @tlsgd(%ebx),
> >>>>
> >>>> As you say - mentions. It doesn't say that's the only valid form.
> >> Instead ...
> >>>>
> >>>>> but I think the details are not clear enough, after all, the
> >> documentation has not been updated for 10 years.
> >>>>
> >>>> ... it seems pretty obvious that if any reg other than %eax is fine for
> >> the
> >>>> non-SIB form, the same is true for the SIB one. The two forms are solely
> >>>> different encodings of the same EA.
> >>>>
> >>>>> This pl ace needs to be confirmed with the author.
> >>>>
> >>>> First of all I'd like to understand the origin of the non-SIB form, and
> >>>> thus (hopefully) why that permits more registers than the SIB one.
> >>>
> >>> These assembler checks are the same as the linker checks.
> >>> Unless there is a real workload to show the linker check is
> >>> incorrect, I don't believe we should check the linker.
> >>
> >> Here we go again - you apply personal preferences. For those APX insn
> >> promotions you've insisted on us sticking to the spec. Here you say you
> >> want to keep the linker as is, no matter whether it matches the spec
> >> (wherever the missing parts thereof are). I'm afraid I'd like to ask
> >> that you make up your mind in a consistent way: Do specs matter, or can
> >> we take arbitrary liberties? My view is that in both cases we could
> >> permit sensible extensions, as long as those are sufficiently clear to
> >> be in line with the original intentions of the spec. In the case here
> >> that of course would first mean to properly identify what the extension
> >> parts are. And then any extensions of course want to be consistent with
> >> the original spec as well as self-consistent.
> >>
> >
> > Linker and assembler are different.
>
> Well. Of course they're different, yet that doesn't mean one needs to adhere
> to specs and the other can do whatever it wants.
>
> > Linker check was added for a reason.
> > You can ask the author of such linker
> > check. He or she may remember the reason.
>
> Have I not been doing this all the time? You're the author of 6eaa7fb59b32
> ("Support i386 TLS code sequences without PLT"), which switched R_386_TLS_GD
> handling from any-reg to %ebx-only.
>
For call via PLT like, "call ___tls_get_addr@PLT", GOT register
must be EBX due to PLT entry:
00001010 <realloc@plt>:
1010: ff a3 0c 00 00 00 jmp *0xc(%ebx)
1016: 68 00 00 00 00 push $0x0
101b: e9 e0 ff ff ff jmp 1000 <thread_rpc_vars+0xfb4>
The R_386_TLS_GD patter in GCC is
(define_insn "*tls_global_dynamic_32_gnu"
[(set (match_operand:SI 0 "register_operand" "=a")
(unspec:SI
[(match_operand:SI 1 "register_operand" "Yb")
(match_operand 2 "tls_symbolic_operand")
(match_operand 3 "constant_call_address_operand" "Bz")
(reg:SI SP_REG)]
UNSPEC_TLS_GD))
(clobber (match_scratch:SI 4 "=d"))
(clobber (match_scratch:SI 5 "=c"))
(clobber (reg:CC FLAGS_REG))]
"!TARGET_64BIT && TARGET_GNU_TLS"
{
if (TARGET_SUN_TLS || flag_plt || !HAVE_AS_IX86_TLS_GET_ADDR_GOT)
output_asm_insn
("lea{l}\t{%E2@tlsgd(,%1,1), %0|%0, %E2@tlsgd[%1*1]}", operands);
else
output_asm_insn
("lea{l}\t{%E2@tlsgd(%1), %0|%0, %E2@tlsgd[%1]}", operands);
if (TARGET_SUN_TLS)
#ifdef HAVE_AS_IX86_TLSGDPLT
return "call\t%a2@tlsgdplt";
#else
return "call\t%p3@plt";
#endif
if (flag_plt || !HAVE_AS_IX86_TLS_GET_ADDR_GOT)
return "call\t%P3";
return "call\t{*%p3@GOT(%1)|[DWORD PTR %p3@GOT[%1]]}";
}
[(set_attr "type" "multi")
(set_attr "length" "12")])
where Yb is defined as
(define_register_constraint "Yb"
"(!flag_plt && HAVE_AS_IX86_TLS_GET_ADDR_GOT) ? TLS_GOTBASE_REGS : BREG"
"@internal Any register that can be used as the GOT base when calling
___tls_get_addr: that is, any general register except @code{a} and
@code{sp} registers, for -fno-plt if linker supports it. Otherwise,
@code{b} register.")
For this case, EBX should be used.
On 28.09.2024 05:30, H.J. Lu wrote:
> On Fri, Sep 27, 2024 at 8:54 PM Jan Beulich <jbeulich@suse.com> wrote:
>>
>> On 27.09.2024 09:53, H.J. Lu wrote:
>>> On Fri, Sep 27, 2024, 3:25 PM Jan Beulich <jbeulich@suse.com> wrote:
>>>
>>>> On 27.09.2024 01:12, H.J. Lu wrote:
>>>>> On Wed, Sep 25, 2024 at 10:29 PM Jan Beulich <jbeulich@suse.com> wrote:
>>>>>>
>>>>>> On 25.09.2024 14:45, Cui, Lili wrote:
>>>>>>>> Subject: Re: [PATCH V5] x86: Add tls check in gas
>>>>>>>>
>>>>>>>> On 25.09.2024 05:32, Cui, Lili wrote:
>>>>>>>>>> I've grabbed the newest tls.pdf I could find (still over 10 years
>>>>>>>>>> old, from Ulrich Drepper's site as referenced by the Thread-Local
>>>>>>>>>> Storage section in gcc14 doc), and that raises questions:
>>>>>>>>>
>>>>>>>>> Jan, you can find the latest TLS in ABI chapter 10
>>>>>>>>> (https://gitlab.com/x86-psABIs/x86-64-ABI)
>>>>>>>>
>>>>>>>> So far all my questions were on the i386 side of things, which isn't
>>>> covered there.
>>>>>>>>
>>>>>>>>> and some TLS doc linkers there (e.g.
>>>>>>>>> http://www.akkadia.org/drepper/tls.pdf)
>>>>>>>>
>>>>>>>> This is the doc I was referring to.
>>>>>>>>
>>>>>>>> As an aside - of course it shouldn't really take two docs to get a
>>>> complete picture.
>>>>>>>
>>>>>>> At least you can find " GDesc access model " in ABI doc.
>>>>>>
>>>>>> But not what exactly it means on i386. Are we here dealing with private,
>>>>>> undocumented extensions to the TLS spec?
>>>>>>
>>>>>>>>>> On 19.09.2024 08:38, Cui, Lili wrote:
>>>>>>>>>>> @@ -6357,6 +6387,356 @@ static INLINE bool may_need_pass2 (const
>>>>>>>>>> insn_template *t)
>>>>>>>>>>> && (t->base_opcode | 8) == 0x2c); }
>>>>>>>>>>>
>>>>>>>>>>> +static enum x86_tls_error_type
>>>>>>>>>>> +x86_check_tls_relocation (enum bfd_reloc_code_real r_type) {
>>>>>>>>>>> + switch (r_type)
>>>>>>>>>>> + {
>>>>>>>>>>> + case BFD_RELOC_386_TLS_GOTDESC:
>>>>>>>>>>> + /* Check GDesc access model:
>>>>>>>>>>
>>>>>>>>>> What's "GDesc access model"? I can't find anything named like this,
>>>>>>>>>> nor mention of ...
>>>>>>>>>>> + leal x@tlsdesc(%ebx), %reg32 --> Memory reg must be %ebx and
>>>>>>>>>>> + SIB is not supported.
>>>>>>>>>>> + */
>>>>>>>>>>
>>>>>>>>>> ... @tlsdesc.
>>>>>>>>>
>>>>>>>>> It is defined in ABI doc.
>>>>>>>>
>>>>>>>> As per above - where? I can see the 64-bit counterpart of this being
>>>> described in
>>>>>>>> the x86-64 psABI, but that's not covering the case here.
>>>>>>>>
>>>>>>>>>>> + if (i.tm.mnem_off != MN_lea)
>>>>>>>>>>> + return x86_tls_error_insn;
>>>>>>>>>>> + if (i.index_reg)
>>>>>>>>>>> + return x86_tls_error_sib;
>>>>>>>>>>> + if (!i.base_reg)
>>>>>>>>>>> + return x86_tls_error_no_base_reg;
>>>>>>>>>>> + if (i.base_reg->reg_type.bitfield.instance != RegB)
>>>>>>>>>>> + return x86_tls_error_ebx;
>>>>>>>>>>> + if (!i.op[1].regs->reg_type.bitfield.dword)
>>>>>>>>>>> + return x86_tls_error_dest_32bit_reg_size;
>>>>>>>>>>> + break;
>>>>>>>>>>> +
>>>>>>>>>>> + case BFD_RELOC_386_TLS_GD:
>>>>>>>>>>> + /* Check GD access model:
>>>>>>>>>>> +
>>>>>>>>>>> + leal foo@tlsgd(,%ebx,1), %eax --> Only this fixed format is
>>>> supported.
>>>>>>>>>>> + leal foo@tlsgd(%reg32), %eax --> Dest reg must be '%eax'
>>>>>>>>>>> + Memory reg can't be %eax.
>>>>>>>>>>> + */
>>>>>>>>>>
>>>>>>>>>> Where's this 2nd form coming from? The doc says the SIB form must be
>>>>>>>>>> used, and the converted-to code sequence would require one more byte
>>>>>>>>>> than the non- SIB form provides space for.
>>>>>>>>>>
>>>>>>>>>> The doc doesn't say that the index reg has to be %ebx, it merely
>>>>>>>>>> mentions that in the example, for being the commonly used GOT reg.
>>>>>>>>>> This is the same ...
>>>>>>>>>
>>>>>>>>> It is mentioned in 4.1 of tls.pdf.
>>>>>>>>
>>>>>>>> Where? Please quote the sentence. I can't spot anything saying that
>>>> it has to
>>>>>>>> be %ebx. And similarly I can't spot anything indicating the non-SIB
>>>> form would
>>>>>>>> be okay to use; to the contrary it says "Note the form of the first
>>>> operand of leal
>>>>>>>> which forces the use of the SIB form ...". While that leaves open the
>>>> use of a NOP
>>>>>>>> (or address size override on the associated CALL, as per the checking
>>>> the linker
>>>>>>>> does) together with the non-SIB form,
>>>>>>>
>>>>>>> This is the place, tls.pdf is encrypted and cannot be copied. I typed
>>>> a sentence.
>>>>>>>
>>>>>>> "To signal that this instruction is for the GNU variant of the access
>>>> model the syntax @tlsgd(%ebx) is used."
>>>>>>>
>>>>>>> It mentioned @tlsgd(%ebx),
>>>>>>
>>>>>> As you say - mentions. It doesn't say that's the only valid form.
>>>> Instead ...
>>>>>>
>>>>>>> but I think the details are not clear enough, after all, the
>>>> documentation has not been updated for 10 years.
>>>>>>
>>>>>> ... it seems pretty obvious that if any reg other than %eax is fine for
>>>> the
>>>>>> non-SIB form, the same is true for the SIB one. The two forms are solely
>>>>>> different encodings of the same EA.
>>>>>>
>>>>>>> This pl ace needs to be confirmed with the author.
>>>>>>
>>>>>> First of all I'd like to understand the origin of the non-SIB form, and
>>>>>> thus (hopefully) why that permits more registers than the SIB one.
>>>>>
>>>>> These assembler checks are the same as the linker checks.
>>>>> Unless there is a real workload to show the linker check is
>>>>> incorrect, I don't believe we should check the linker.
>>>>
>>>> Here we go again - you apply personal preferences. For those APX insn
>>>> promotions you've insisted on us sticking to the spec. Here you say you
>>>> want to keep the linker as is, no matter whether it matches the spec
>>>> (wherever the missing parts thereof are). I'm afraid I'd like to ask
>>>> that you make up your mind in a consistent way: Do specs matter, or can
>>>> we take arbitrary liberties? My view is that in both cases we could
>>>> permit sensible extensions, as long as those are sufficiently clear to
>>>> be in line with the original intentions of the spec. In the case here
>>>> that of course would first mean to properly identify what the extension
>>>> parts are. And then any extensions of course want to be consistent with
>>>> the original spec as well as self-consistent.
>>>>
>>>
>>> Linker and assembler are different.
>>
>> Well. Of course they're different, yet that doesn't mean one needs to adhere
>> to specs and the other can do whatever it wants.
>>
>>> Linker check was added for a reason.
>>> You can ask the author of such linker
>>> check. He or she may remember the reason.
>>
>> Have I not been doing this all the time? You're the author of 6eaa7fb59b32
>> ("Support i386 TLS code sequences without PLT"), which switched R_386_TLS_GD
>> handling from any-reg to %ebx-only.
>>
>
> For call via PLT like, "call ___tls_get_addr@PLT", GOT register
> must be EBX due to PLT entry:
>
> 00001010 <realloc@plt>:
> 1010: ff a3 0c 00 00 00 jmp *0xc(%ebx)
> 1016: 68 00 00 00 00 push $0x0
> 101b: e9 e0 ff ff ff jmp 1000 <thread_rpc_vars+0xfb4>
Okay, finally some pieces fall into place (and I'm now able to comment some
more on the original patch).
But - where are the ix86 x@tlsdesc and x@tlscall forms specified?
Jan
On 19.09.2024 08:38, Cui, Lili wrote:
> + case BFD_RELOC_386_TLS_GOTIE:
> + /* Check GOTIE access model:
> +
> + subl foo@gotntpoff(%reg1), %reg2
> + movl foo@gotntpoff(%reg1), %reg2
> + addl foo@gotntpoff(%reg1), %reg2
> +
> + Memory operand: SIB is not supported.
> + */
> + case BFD_RELOC_386_TLS_IE_32:
> + /* Check IE_32 access model:
> +
> + subl foo@gottpoff(%reg1), %reg2
> + movl foo@gottpoff(%reg1), %reg2
> + addl foo@gottpoff(%reg1), %reg2
> +
> + Memory operand: SIB is not supported.
> + */
> + if (i.tm.mnem_off != MN_sub
> + && i.tm.mnem_off != MN_add
> + && i.tm.mnem_off != MN_mov)
> + return x86_tls_error_insn;
> + if (i.op[1].regs->reg_type.bitfield.class != Reg
> + || i.op[0].regs->reg_type.bitfield.class
> + || i.imm_operands)
You may not de-reference i.op[0].regs for the intended forms at all. If
anything, i.op[0].disps may be de-referenced there.
You may also not de-reference i.op[1].regs until you've checked that
operand 1 actually is a register. There are insn forms after all where
operand 1 is a memory one.
Which member of the union is valid to de-reference can only be told by
inspecting i.types[] and/or i.tm.operand_types[] (when insns are more
constrained than mov/add/sub are, going from just
i.{reg,imm,mem,disp}_operands may also be possible, just to mention it).
I expect you want to check for operand counts first: No immediate one,
a single disp one, and a single register one. Then check that it's the
destination that's the register one. There may then not be any need to
access any i.op[<n>].reg anymore.
> + return x86_tls_error_opcode;
> + if (!i.base_reg)
> + return x86_tls_error_no_base_reg;
> + if (i.index_reg)
> + return x86_tls_error_sib;
> + if (!i.base_reg->reg_type.bitfield.dword)
> + return x86_tls_error_base_reg_size;
> + if (!i.op[1].regs->reg_type.bitfield.dword)
> + return x86_tls_error_dest_32bit_reg_size;
> + break;
> +
> + case BFD_RELOC_386_TLS_IE:
> + /* Check IE access model:
> +
> + movl foo@indntpoff, %reg32 --> Mod == 00 && r/m == 5
> + addl foo@indntpoff, %reg32 --> Mod == 00 && r/m == 5
> + */
> + if (i.tm.mnem_off != MN_add && i.tm.mnem_off != MN_mov)
> + return x86_tls_error_insn;
> + if (i.op[1].regs->reg_type.bitfield.class != Reg
> + || i.op[0].regs->reg_type.bitfield.class
> + || i.imm_operands)
Similar concerns here and ...
> + return x86_tls_error_opcode;
> + if (i.base_reg || i.index_reg)
> + return x86_tls_error_require_no_base_index_reg;
> + if (!i.op[1].regs->reg_type.bitfield.dword)
> + return x86_tls_error_dest_32bit_reg_size;
> + break;
> +
> + case BFD_RELOC_X86_64_GOTTPOFF:
> + /* Check GOTTPOFF access model:
> +
> + mov foo@gottpoff(%rip), %reg --> Memory Reg must be %rip.
> + add foo@gottpoff(%rip), %reg --> Memory Reg must be %rip.
> + add %reg1, foo@gottpoff(%rip), %reg2 --> Memory Reg must be %rip.
> + add foo@gottpoff(%rip), %reg1, %reg2 --> Memory Reg must be %rip.
> + */
> + if (i.tm.mnem_off != MN_add && i.tm.mnem_off != MN_mov)
> + return x86_tls_error_insn;
> + if (i.op[i.operands - 1].regs->reg_type.bitfield.class != Reg
> + || (i.op[0].regs->reg_type.bitfield.class
> + && i.tm.opcode_modifier.vexvvvv != VexVVVV_DST)
> + || i.imm_operands)
... here.
Jan
On Mon, Sep 30, 2024, 2:48 PM Jan Beulich <jbeulich@suse.com> wrote:
> On 28.09.2024 05:30, H.J. Lu wrote:
> > On Fri, Sep 27, 2024 at 8:54 PM Jan Beulich <jbeulich@suse.com> wrote:
> >>
> >> On 27.09.2024 09:53, H.J. Lu wrote:
> >>> On Fri, Sep 27, 2024, 3:25 PM Jan Beulich <jbeulich@suse.com> wrote:
> >>>
> >>>> On 27.09.2024 01:12, H.J. Lu wrote:
> >>>>> On Wed, Sep 25, 2024 at 10:29 PM Jan Beulich <jbeulich@suse.com>
> wrote:
> >>>>>>
> >>>>>> On 25.09.2024 14:45, Cui, Lili wrote:
> >>>>>>>> Subject: Re: [PATCH V5] x86: Add tls check in gas
> >>>>>>>>
> >>>>>>>> On 25.09.2024 05:32, Cui, Lili wrote:
> >>>>>>>>>> I've grabbed the newest tls.pdf I could find (still over 10
> years
> >>>>>>>>>> old, from Ulrich Drepper's site as referenced by the
> Thread-Local
> >>>>>>>>>> Storage section in gcc14 doc), and that raises questions:
> >>>>>>>>>
> >>>>>>>>> Jan, you can find the latest TLS in ABI chapter 10
> >>>>>>>>> (https://gitlab.com/x86-psABIs/x86-64-ABI)
> >>>>>>>>
> >>>>>>>> So far all my questions were on the i386 side of things, which
> isn't
> >>>> covered there.
> >>>>>>>>
> >>>>>>>>> and some TLS doc linkers there (e.g.
> >>>>>>>>> http://www.akkadia.org/drepper/tls.pdf)
> >>>>>>>>
> >>>>>>>> This is the doc I was referring to.
> >>>>>>>>
> >>>>>>>> As an aside - of course it shouldn't really take two docs to get a
> >>>> complete picture.
> >>>>>>>
> >>>>>>> At least you can find " GDesc access model " in ABI doc.
> >>>>>>
> >>>>>> But not what exactly it means on i386. Are we here dealing with
> private,
> >>>>>> undocumented extensions to the TLS spec?
> >>>>>>
> >>>>>>>>>> On 19.09.2024 08:38, Cui, Lili wrote:
> >>>>>>>>>>> @@ -6357,6 +6387,356 @@ static INLINE bool may_need_pass2
> (const
> >>>>>>>>>> insn_template *t)
> >>>>>>>>>>> && (t->base_opcode | 8) == 0x2c); }
> >>>>>>>>>>>
> >>>>>>>>>>> +static enum x86_tls_error_type
> >>>>>>>>>>> +x86_check_tls_relocation (enum bfd_reloc_code_real r_type) {
> >>>>>>>>>>> + switch (r_type)
> >>>>>>>>>>> + {
> >>>>>>>>>>> + case BFD_RELOC_386_TLS_GOTDESC:
> >>>>>>>>>>> + /* Check GDesc access model:
> >>>>>>>>>>
> >>>>>>>>>> What's "GDesc access model"? I can't find anything named like
> this,
> >>>>>>>>>> nor mention of ...
> >>>>>>>>>>> + leal x@tlsdesc(%ebx), %reg32 --> Memory reg must be %ebx
> and
> >>>>>>>>>>> + SIB is not supported.
> >>>>>>>>>>> + */
> >>>>>>>>>>
> >>>>>>>>>> ... @tlsdesc.
> >>>>>>>>>
> >>>>>>>>> It is defined in ABI doc.
> >>>>>>>>
> >>>>>>>> As per above - where? I can see the 64-bit counterpart of this
> being
> >>>> described in
> >>>>>>>> the x86-64 psABI, but that's not covering the case here.
> >>>>>>>>
> >>>>>>>>>>> + if (i.tm.mnem_off != MN_lea)
> >>>>>>>>>>> + return x86_tls_error_insn;
> >>>>>>>>>>> + if (i.index_reg)
> >>>>>>>>>>> + return x86_tls_error_sib;
> >>>>>>>>>>> + if (!i.base_reg)
> >>>>>>>>>>> + return x86_tls_error_no_base_reg;
> >>>>>>>>>>> + if (i.base_reg->reg_type.bitfield.instance != RegB)
> >>>>>>>>>>> + return x86_tls_error_ebx;
> >>>>>>>>>>> + if (!i.op[1].regs->reg_type.bitfield.dword)
> >>>>>>>>>>> + return x86_tls_error_dest_32bit_reg_size;
> >>>>>>>>>>> + break;
> >>>>>>>>>>> +
> >>>>>>>>>>> + case BFD_RELOC_386_TLS_GD:
> >>>>>>>>>>> + /* Check GD access model:
> >>>>>>>>>>> +
> >>>>>>>>>>> + leal foo@tlsgd(,%ebx,1), %eax --> Only this fixed format
> is
> >>>> supported.
> >>>>>>>>>>> + leal foo@tlsgd(%reg32), %eax --> Dest reg must be '%eax'
> >>>>>>>>>>> + Memory reg can't be
> %eax.
> >>>>>>>>>>> + */
> >>>>>>>>>>
> >>>>>>>>>> Where's this 2nd form coming from? The doc says the SIB form
> must be
> >>>>>>>>>> used, and the converted-to code sequence would require one more
> byte
> >>>>>>>>>> than the non- SIB form provides space for.
> >>>>>>>>>>
> >>>>>>>>>> The doc doesn't say that the index reg has to be %ebx, it merely
> >>>>>>>>>> mentions that in the example, for being the commonly used GOT
> reg.
> >>>>>>>>>> This is the same ...
> >>>>>>>>>
> >>>>>>>>> It is mentioned in 4.1 of tls.pdf.
> >>>>>>>>
> >>>>>>>> Where? Please quote the sentence. I can't spot anything saying
> that
> >>>> it has to
> >>>>>>>> be %ebx. And similarly I can't spot anything indicating the
> non-SIB
> >>>> form would
> >>>>>>>> be okay to use; to the contrary it says "Note the form of the
> first
> >>>> operand of leal
> >>>>>>>> which forces the use of the SIB form ...". While that leaves open
> the
> >>>> use of a NOP
> >>>>>>>> (or address size override on the associated CALL, as per the
> checking
> >>>> the linker
> >>>>>>>> does) together with the non-SIB form,
> >>>>>>>
> >>>>>>> This is the place, tls.pdf is encrypted and cannot be copied. I
> typed
> >>>> a sentence.
> >>>>>>>
> >>>>>>> "To signal that this instruction is for the GNU variant of the
> access
> >>>> model the syntax @tlsgd(%ebx) is used."
> >>>>>>>
> >>>>>>> It mentioned @tlsgd(%ebx),
> >>>>>>
> >>>>>> As you say - mentions. It doesn't say that's the only valid form.
> >>>> Instead ...
> >>>>>>
> >>>>>>> but I think the details are not clear enough, after all, the
> >>>> documentation has not been updated for 10 years.
> >>>>>>
> >>>>>> ... it seems pretty obvious that if any reg other than %eax is fine
> for
> >>>> the
> >>>>>> non-SIB form, the same is true for the SIB one. The two forms are
> solely
> >>>>>> different encodings of the same EA.
> >>>>>>
> >>>>>>> This pl ace needs to be confirmed with the author.
> >>>>>>
> >>>>>> First of all I'd like to understand the origin of the non-SIB form,
> and
> >>>>>> thus (hopefully) why that permits more registers than the SIB one.
> >>>>>
> >>>>> These assembler checks are the same as the linker checks.
> >>>>> Unless there is a real workload to show the linker check is
> >>>>> incorrect, I don't believe we should check the linker.
> >>>>
> >>>> Here we go again - you apply personal preferences. For those APX insn
> >>>> promotions you've insisted on us sticking to the spec. Here you say
> you
> >>>> want to keep the linker as is, no matter whether it matches the spec
> >>>> (wherever the missing parts thereof are). I'm afraid I'd like to ask
> >>>> that you make up your mind in a consistent way: Do specs matter, or
> can
> >>>> we take arbitrary liberties? My view is that in both cases we could
> >>>> permit sensible extensions, as long as those are sufficiently clear to
> >>>> be in line with the original intentions of the spec. In the case here
> >>>> that of course would first mean to properly identify what the
> extension
> >>>> parts are. And then any extensions of course want to be consistent
> with
> >>>> the original spec as well as self-consistent.
> >>>>
> >>>
> >>> Linker and assembler are different.
> >>
> >> Well. Of course they're different, yet that doesn't mean one needs to
> adhere
> >> to specs and the other can do whatever it wants.
> >>
> >>> Linker check was added for a reason.
> >>> You can ask the author of such linker
> >>> check. He or she may remember the reason.
> >>
> >> Have I not been doing this all the time? You're the author of
> 6eaa7fb59b32
> >> ("Support i386 TLS code sequences without PLT"), which switched
> R_386_TLS_GD
> >> handling from any-reg to %ebx-only.
> >>
> >
> > For call via PLT like, "call ___tls_get_addr@PLT", GOT register
> > must be EBX due to PLT entry:
> >
> > 00001010 <realloc@plt>:
> > 1010: ff a3 0c 00 00 00 jmp *0xc(%ebx)
> > 1016: 68 00 00 00 00 push $0x0
> > 101b: e9 e0 ff ff ff jmp 1000 <thread_rpc_vars+0xfb4>
>
> Okay, finally some pieces fall into place (and I'm now able to comment some
> more on the original patch).
>
> But - where are the ix86 x@tlsdesc and x@tlscall forms specified?
>
There are 2 links for TLS specs in the x86-64 psABI.
One of them has the description.
> Jan
>
>
@@ -60,6 +60,9 @@
/* Define default value for RISC-V -mpriv-spec */
#undef DEFAULT_RISCV_PRIV_SPEC
+/* Define to 1 if you want to check x86 TLS relocation by default. */
+#undef DEFAULT_X86_TLS_CHECK
+
/* Define to 1 if you want to generate GNU x86 used ISA and feature properties
by default. */
#undef DEFAULT_X86_USED_NOTE
@@ -274,6 +274,30 @@ enum i386_error
internal_error,
};
+enum x86_tls_error_type
+{
+ x86_tls_error_continue,
+ x86_tls_error_none,
+ x86_tls_error_insn,
+ x86_tls_error_opcode,
+ x86_tls_error_sib,
+ x86_tls_error_no_base_reg,
+ x86_tls_error_require_no_base_index_reg,
+ x86_tls_error_base_reg,
+ x86_tls_error_index_ebx,
+ x86_tls_error_eax,
+ x86_tls_error_RegA,
+ x86_tls_error_ebx,
+ x86_tls_error_rip,
+ x86_tls_error_dest_eax,
+ x86_tls_error_dest_rdi,
+ x86_tls_error_scale_factor,
+ x86_tls_error_base_reg_size,
+ x86_tls_error_dest_32bit_reg_size,
+ x86_tls_error_dest_64bit_reg_size,
+ x86_tls_error_dest_32bit_or_64bit_reg_size
+};
+
struct _i386_insn
{
/* TM holds the template for the insn were currently assembling. */
@@ -365,6 +389,9 @@ struct _i386_insn
/* Has GOTPC or TLS relocation. */
bool has_gotpc_tls_reloc;
+ /* Has relocation entry from the gotrel array. */
+ bool has_gotrel;
+
/* RM and SIB are the modrm byte and the sib byte where the
addressing modes of this insn are encoded. */
modrm_byte rm;
@@ -717,6 +744,9 @@ lfence_before_ret;
static int generate_relax_relocations
= DEFAULT_GENERATE_X86_RELAX_RELOCATIONS;
+/* 1 if the assembler should check tls relocation. */
+static bool tls_check = DEFAULT_X86_TLS_CHECK;
+
static enum check_kind
{
check_none = 0,
@@ -6357,6 +6387,356 @@ static INLINE bool may_need_pass2 (const insn_template *t)
&& (t->base_opcode | 8) == 0x2c);
}
+static enum x86_tls_error_type
+x86_check_tls_relocation (enum bfd_reloc_code_real r_type)
+{
+ switch (r_type)
+ {
+ case BFD_RELOC_386_TLS_GOTDESC:
+ /* Check GDesc access model:
+
+ leal x@tlsdesc(%ebx), %reg32 --> Memory reg must be %ebx and
+ SIB is not supported.
+ */
+ if (i.tm.mnem_off != MN_lea)
+ return x86_tls_error_insn;
+ if (i.index_reg)
+ return x86_tls_error_sib;
+ if (!i.base_reg)
+ return x86_tls_error_no_base_reg;
+ if (i.base_reg->reg_type.bitfield.instance != RegB)
+ return x86_tls_error_ebx;
+ if (!i.op[1].regs->reg_type.bitfield.dword)
+ return x86_tls_error_dest_32bit_reg_size;
+ break;
+
+ case BFD_RELOC_386_TLS_GD:
+ /* Check GD access model:
+
+ leal foo@tlsgd(,%ebx,1), %eax --> Only this fixed format is supported.
+ leal foo@tlsgd(%reg32), %eax --> Dest reg must be '%eax'
+ Memory reg can't be %eax.
+ */
+ if (i.tm.mnem_off != MN_lea)
+ return x86_tls_error_insn;
+ if (i.op[1].regs->reg_type.bitfield.instance != Accum)
+ return x86_tls_error_dest_eax;
+ if (!i.op[1].regs->reg_type.bitfield.dword)
+ return x86_tls_error_dest_32bit_reg_size;
+ if (i.index_reg)
+ {
+ if (i.base_reg)
+ return x86_tls_error_base_reg;
+ if (i.index_reg->reg_type.bitfield.instance != RegB)
+ return x86_tls_error_index_ebx;
+ if (i.log2_scale_factor)
+ return x86_tls_error_scale_factor;
+ }
+ else
+ {
+ if (!i.base_reg)
+ return x86_tls_error_no_base_reg;
+ if (i.base_reg->reg_type.bitfield.instance == Accum)
+ return x86_tls_error_eax;
+ }
+ break;
+
+ case BFD_RELOC_386_TLS_LDM:
+ /* Check LDM access model:
+
+ leal foo@tlsldm(%reg32), %eax --> Dest reg must be '%eax'
+ Memory reg can't be %eax and SIB
+ is not supported.
+ */
+ if (i.tm.mnem_off != MN_lea)
+ return x86_tls_error_insn;
+ if (i.index_reg)
+ return x86_tls_error_sib;
+ if (!i.base_reg)
+ return x86_tls_error_no_base_reg;
+ if (i.base_reg->reg_type.bitfield.instance == Accum)
+ return x86_tls_error_eax;
+ if (i.op[1].regs->reg_type.bitfield.instance != Accum)
+ return x86_tls_error_dest_eax;
+ if (!i.op[1].regs->reg_type.bitfield.dword)
+ return x86_tls_error_dest_32bit_reg_size;
+ break;
+
+ case BFD_RELOC_X86_64_GOTPC32_TLSDESC:
+ /* Check GOTPC32 TLSDESC access model:
+
+ --- LP64 mode ---
+ leaq x@tlsdesc(%rip), %reg64 --> Memory reg must be %rip.
+
+ --- X32 mode ---
+ rex/rex2 leal x@tlsdesc(%rip), %reg32 --> Memory reg must be %rip.
+
+ In X32 mode, gas will add rex/rex2 for it later, no need to check
+ here.
+ */
+ if (i.tm.mnem_off != MN_lea)
+ return x86_tls_error_insn;
+ if (!i.base_reg)
+ return x86_tls_error_no_base_reg;
+ if (i.base_reg->reg_num != RegIP
+ || !i.base_reg->reg_type.bitfield.qword)
+ return x86_tls_error_rip;
+ if (x86_elf_abi == X86_64_ABI)
+ {
+ if (!i.op[1].regs->reg_type.bitfield.qword)
+ return x86_tls_error_dest_64bit_reg_size;
+ }
+ else if (!i.op[1].regs->reg_type.bitfield.dword
+ && !i.op[1].regs->reg_type.bitfield.qword)
+ return x86_tls_error_dest_32bit_or_64bit_reg_size;
+ break;
+
+ case BFD_RELOC_X86_64_TLSGD:
+ /* Check GD access model:
+
+ leaq foo@tlsgd(%rip), %rdi --> Only this fixed format is supported.
+ */
+ case BFD_RELOC_X86_64_TLSLD:
+ /* Check LD access model:
+
+ leaq foo@tlsld(%rip), %rdi --> Only this fixed format is supported.
+ */
+ if (i.tm.mnem_off != MN_lea)
+ return x86_tls_error_insn;
+ if (!i.base_reg)
+ return x86_tls_error_no_base_reg;
+ if (i.base_reg->reg_num != RegIP
+ || !i.base_reg->reg_type.bitfield.qword)
+ return x86_tls_error_rip;
+ if (!i.op[1].regs->reg_type.bitfield.qword
+ || i.op[1].regs->reg_num != EDI_REG_NUM
+ || i.op[1].regs->reg_flags)
+ return x86_tls_error_dest_rdi;
+ break;
+
+ case BFD_RELOC_386_TLS_GOTIE:
+ /* Check GOTIE access model:
+
+ subl foo@gotntpoff(%reg1), %reg2
+ movl foo@gotntpoff(%reg1), %reg2
+ addl foo@gotntpoff(%reg1), %reg2
+
+ Memory operand: SIB is not supported.
+ */
+ case BFD_RELOC_386_TLS_IE_32:
+ /* Check IE_32 access model:
+
+ subl foo@gottpoff(%reg1), %reg2
+ movl foo@gottpoff(%reg1), %reg2
+ addl foo@gottpoff(%reg1), %reg2
+
+ Memory operand: SIB is not supported.
+ */
+ if (i.tm.mnem_off != MN_sub
+ && i.tm.mnem_off != MN_add
+ && i.tm.mnem_off != MN_mov)
+ return x86_tls_error_insn;
+ if (i.op[1].regs->reg_type.bitfield.class != Reg
+ || i.op[0].regs->reg_type.bitfield.class
+ || i.imm_operands)
+ return x86_tls_error_opcode;
+ if (!i.base_reg)
+ return x86_tls_error_no_base_reg;
+ if (i.index_reg)
+ return x86_tls_error_sib;
+ if (!i.base_reg->reg_type.bitfield.dword)
+ return x86_tls_error_base_reg_size;
+ if (!i.op[1].regs->reg_type.bitfield.dword)
+ return x86_tls_error_dest_32bit_reg_size;
+ break;
+
+ case BFD_RELOC_386_TLS_IE:
+ /* Check IE access model:
+
+ movl foo@indntpoff, %reg32 --> Mod == 00 && r/m == 5
+ addl foo@indntpoff, %reg32 --> Mod == 00 && r/m == 5
+ */
+ if (i.tm.mnem_off != MN_add && i.tm.mnem_off != MN_mov)
+ return x86_tls_error_insn;
+ if (i.op[1].regs->reg_type.bitfield.class != Reg
+ || i.op[0].regs->reg_type.bitfield.class
+ || i.imm_operands)
+ return x86_tls_error_opcode;
+ if (i.base_reg || i.index_reg)
+ return x86_tls_error_require_no_base_index_reg;
+ if (!i.op[1].regs->reg_type.bitfield.dword)
+ return x86_tls_error_dest_32bit_reg_size;
+ break;
+
+ case BFD_RELOC_X86_64_GOTTPOFF:
+ /* Check GOTTPOFF access model:
+
+ mov foo@gottpoff(%rip), %reg --> Memory Reg must be %rip.
+ add foo@gottpoff(%rip), %reg --> Memory Reg must be %rip.
+ add %reg1, foo@gottpoff(%rip), %reg2 --> Memory Reg must be %rip.
+ add foo@gottpoff(%rip), %reg1, %reg2 --> Memory Reg must be %rip.
+ */
+ if (i.tm.mnem_off != MN_add && i.tm.mnem_off != MN_mov)
+ return x86_tls_error_insn;
+ if (i.op[i.operands - 1].regs->reg_type.bitfield.class != Reg
+ || (i.op[0].regs->reg_type.bitfield.class
+ && i.tm.opcode_modifier.vexvvvv != VexVVVV_DST)
+ || i.imm_operands)
+ return x86_tls_error_opcode;
+ if (!i.base_reg)
+ return x86_tls_error_no_base_reg;
+ if (i.base_reg->reg_num != RegIP
+ || !i.base_reg->reg_type.bitfield.qword)
+ return x86_tls_error_rip;
+ if (x86_elf_abi == X86_64_ABI)
+ {
+ if (!i.op[i.operands - 1].regs->reg_type.bitfield.qword)
+ return x86_tls_error_dest_64bit_reg_size;
+ }
+ else if (!i.op[i.operands - 1].regs->reg_type.bitfield.dword
+ && !i.op[i.operands - 1].regs->reg_type.bitfield.qword)
+ return x86_tls_error_dest_32bit_or_64bit_reg_size;
+ break;
+
+ case BFD_RELOC_386_TLS_DESC_CALL:
+ /* Check GDesc access model:
+
+ call *x@tlscall(%eax) --> Memory reg must be %eax and
+ SIB is not supported.
+ */
+ case BFD_RELOC_X86_64_TLSDESC_CALL:
+ /* Check GDesc access model:
+
+ call *x@tlscall(%rax) <--- LP64 mode.
+ call *x@tlscall(%eax) <--- X32 mode.
+
+ Only these fixed formats are supported.
+ */
+ if (i.tm.mnem_off != MN_call)
+ return x86_tls_error_insn;
+ if (i.index_reg)
+ return x86_tls_error_sib;
+ if (!i.base_reg)
+ return x86_tls_error_no_base_reg;
+ if (i.base_reg->reg_type.bitfield.instance != Accum)
+ return x86_tls_error_RegA;
+ break;
+
+ case BFD_RELOC_NONE:
+ /* This isn't a relocation. */
+ return x86_tls_error_continue;
+
+ default:
+ break;
+ }
+
+ /* This relocation is OK. */
+ return x86_tls_error_none;
+}
+
+static void
+x86_report_tls_error (enum x86_tls_error_type tls_error,
+ enum bfd_reloc_code_real r_type)
+{
+ unsigned int k;
+ for (k = 0; k < ARRAY_SIZE (gotrel); k++)
+ if (gotrel[k].rel[object_64bit] == r_type)
+ break;
+
+ switch (tls_error)
+ {
+ case x86_tls_error_insn:
+ as_bad (_("@%s operator cannot be used with `%s'"),
+ gotrel[k].str, insn_name (&i.tm));
+ return;
+
+ case x86_tls_error_opcode:
+ as_bad (_("@%s operator can be used with `%s', but format is wrong"),
+ gotrel[k].str, insn_name (&i.tm));
+ return;
+
+ case x86_tls_error_sib:
+ as_bad (_("@%s operator requires no SIB"), gotrel[k].str);
+ return;
+
+ case x86_tls_error_no_base_reg:
+ as_bad (_("@%s operator requires base register"), gotrel[k].str);
+ return;
+
+ case x86_tls_error_require_no_base_index_reg:
+ as_bad (_("@%s operator requires no base/index register"),
+ gotrel[k].str);
+ return;
+
+ case x86_tls_error_base_reg:
+ as_bad (_("@%s operator requires no base register"), gotrel[k].str);
+ return;
+
+ case x86_tls_error_index_ebx:
+ as_bad (_("@%s operator requires `%sebx' as index register"),
+ gotrel[k].str, register_prefix);
+ return;
+
+ case x86_tls_error_eax:
+ as_bad (_("@%s operator requires `%seax' as base register"),
+ gotrel[k].str, register_prefix);
+ return;
+
+ case x86_tls_error_RegA:
+ as_bad (_("@%s operator requires `%seax/%srax' as base register"),
+ gotrel[k].str, register_prefix, register_prefix);
+ return;
+
+ case x86_tls_error_ebx:
+ as_bad (_("@%s operator requires `%sebx' as base register"),
+ gotrel[k].str, register_prefix);
+ return;
+
+ case x86_tls_error_rip:
+ as_bad (_("@%s operator requires `%srip' as base register"),
+ gotrel[k].str, register_prefix);
+ return;
+
+ case x86_tls_error_dest_eax:
+ as_bad (_("@%s operator requires `%seax' as dest register"),
+ gotrel[k].str, register_prefix);
+ return;
+
+ case x86_tls_error_dest_rdi:
+ as_bad (_("@%s operator requires `%srdi' as dest register"),
+ gotrel[k].str, register_prefix);
+ return;
+
+ case x86_tls_error_scale_factor:
+ as_bad (_("@%s operator requires scale factor of 1"),
+ gotrel[k].str);
+ return;
+
+ case x86_tls_error_base_reg_size:
+ as_bad (_("@%s operator requires 32-bit base register"),
+ gotrel[k].str);
+ return;
+
+ case x86_tls_error_dest_32bit_reg_size:
+ as_bad (_("@%s operator requires 32-bit dest register"),
+ gotrel[k].str);
+ return;
+
+ case x86_tls_error_dest_64bit_reg_size:
+ as_bad (_("@%s operator requires 64-bit dest register"),
+ gotrel[k].str);
+ return;
+
+ case x86_tls_error_dest_32bit_or_64bit_reg_size:
+ as_bad (_("@%s operator requires 32-bit or 64-bit dest register"),
+ gotrel[k].str);
+ return;
+
+ default:
+ abort ();
+ }
+}
+
/* This is the guts of the machine-dependent assembler. LINE points to a
machine dependent instruction. This function is supposed to emit
the frags/bytes it assembles to. */
@@ -6695,6 +7075,21 @@ i386_assemble (char *line)
i.prefix[LOCK_PREFIX] = 0;
}
+ if (i.has_gotrel && tls_check)
+ {
+ enum x86_tls_error_type tls_error;
+ for (j = 0; j < i.operands; ++j)
+ {
+ tls_error = x86_check_tls_relocation (i.reloc[j]);
+ if (tls_error == x86_tls_error_continue)
+ continue;
+
+ if (tls_error != x86_tls_error_none)
+ x86_report_tls_error (tls_error, i.reloc[j]);
+ break;
+ }
+ }
+
if ((is_any_vex_encoding (&i.tm) && i.tm.opcode_space != SPACE_EVEXMAP4)
|| i.tm.operand_types[i.imm_operands].bitfield.class >= RegMMX
|| i.tm.operand_types[i.imm_operands + 1].bitfield.class >= RegMMX)
@@ -6705,28 +7100,6 @@ i386_assemble (char *line)
as_bad (_("data size prefix invalid with `%s'"), insn_name (&i.tm));
return;
}
-
- /* Don't allow e.g. KMOV in TLS code sequences which will trigger
- linker error later. */
- for (j = i.imm_operands; j < i.operands; ++j)
- switch (i.reloc[j])
- {
- case BFD_RELOC_X86_64_GOTTPOFF:
- case BFD_RELOC_386_TLS_GOTIE:
- case BFD_RELOC_X86_64_TLSLD:
- for (unsigned int k = 0; k < ARRAY_SIZE (gotrel); k++)
- {
- if (gotrel[k].rel[object_64bit] == i.reloc[j])
- {
- as_bad (_("@%s operator cannot be used with `%s'"),
- gotrel[k].str, insn_name (&i.tm));
- return;
- }
- }
- abort ();
- default:
- break;
- }
}
/* Check if HLE prefix is OK. */
@@ -12496,6 +12869,7 @@ lex_got (enum bfd_reloc_code_real *rel,
int first, second;
char *tmpbuf, *past_reloc;
+ i.has_gotrel = true;
*rel = gotrel[j].rel[object_64bit];
if (types)
@@ -16229,6 +16603,7 @@ const char *md_shortopts = "qnO::";
#define OPTION_MLFENCE_BEFORE_INDIRECT_BRANCH (OPTION_MD_BASE + 32)
#define OPTION_MLFENCE_BEFORE_RET (OPTION_MD_BASE + 33)
#define OPTION_MUSE_UNALIGNED_VECTOR_MOVE (OPTION_MD_BASE + 34)
+#define OPTION_MTLS_CHECK (OPTION_MD_BASE + 35)
struct option md_longopts[] =
{
@@ -16275,6 +16650,7 @@ struct option md_longopts[] =
{"mlfence-before-ret", required_argument, NULL, OPTION_MLFENCE_BEFORE_RET},
{"mamd64", no_argument, NULL, OPTION_MAMD64},
{"mintel64", no_argument, NULL, OPTION_MINTEL64},
+ {"mtls-check", required_argument, NULL, OPTION_MTLS_CHECK},
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof (md_longopts);
@@ -16831,6 +17207,14 @@ md_parse_option (int c, const char *arg)
optimize_for_space = 0;
}
break;
+ case OPTION_MTLS_CHECK:
+ if (strcasecmp (arg, "yes") == 0)
+ tls_check = true;
+ else if (strcasecmp (arg, "no") == 0)
+ tls_check = false;
+ else
+ as_fatal (_("invalid -mtls-check= option: `%s'"), arg);
+ break;
default:
return 0;
@@ -17073,6 +17457,16 @@ md_show_usage (FILE *stream)
fprintf (stream, _("(default: no)\n"));
fprintf (stream, _("\
generate relax relocations\n"));
+
+ fprintf (stream, _("\
+ -mtls-check=[no|yes] "));
+ if (DEFAULT_X86_TLS_CHECK)
+ fprintf (stream, _("(default: yes)\n"));
+ else
+ fprintf (stream, _("(default: no)\n"));
+ fprintf (stream, _("\
+ check TLS relocation\n"));
+
fprintf (stream, _("\
-malign-branch-boundary=NUM (default: 0)\n\
align branches within NUM byte boundary\n"));
@@ -818,6 +818,7 @@ enable_checking
enable_compressed_debug_sections
enable_default_compressed_debug_sections_algorithm
enable_x86_relax_relocations
+enable_x86_tls_check
enable_elf_stt_common
enable_generate_build_notes
enable_mips_fix_loongson3_llsc
@@ -1493,6 +1494,7 @@ Optional Features:
--enable-compressed-debug-sections.
--enable-x86-relax-relocations
generate x86 relax relocations by default
+ --enable-x86-tls-check check x86 TLS relocation by default
--enable-elf-stt-common generate ELF common symbols with STT_COMMON type by
default
--enable-generate-build-notes
@@ -10775,7 +10777,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 10778 "configure"
+#line 10780 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -10881,7 +10883,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 10884 "configure"
+#line 10886 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11575,6 +11577,17 @@ if test "${enable_x86_relax_relocations+set}" = set; then :
esac
fi
+# PR gas/32022
+# Decide if x86 assembler should check TLS relocation.
+ac_default_x86_tls_check=unset
+# Provide a configure time option to override our default.
+# Check whether --enable-x86_tls_check was given.
+if test "${enable_x86_tls_check+set}" = set; then :
+ enableval=$enable_x86_tls_check; case "${enableval}" in
+ no) ac_default_x86_tls_check=0 ;;
+esac
+fi
+
# Decide if ELF assembler should generate common symbols with the
# STT_COMMON type.
ac_default_elf_stt_common=unset
@@ -12698,6 +12711,15 @@ cat >>confdefs.h <<_ACEOF
_ACEOF
+if test ${ac_default_x86_tls_check} = unset; then
+ ac_default_x86_tls_check=1
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_X86_TLS_CHECK $ac_default_x86_tls_check
+_ACEOF
+
+
if test ${ac_default_elf_stt_common} = unset; then
ac_default_elf_stt_common=0
fi
@@ -95,6 +95,17 @@ AC_ARG_ENABLE(x86_relax_relocations,
no) ac_default_x86_relax_relocations=0 ;;
esac])dnl
+# PR gas/32022
+# Decide if x86 assembler should check TLS relocation.
+ac_default_x86_tls_check=unset
+# Provide a configure time option to override our default.
+AC_ARG_ENABLE(x86_tls_check,
+ AS_HELP_STRING([--enable-x86-tls-check],
+ [check x86 TLS relocation by default]),
+[case "${enableval}" in
+ no) ac_default_x86_tls_check=0 ;;
+esac])dnl
+
# Decide if ELF assembler should generate common symbols with the
# STT_COMMON type.
ac_default_elf_stt_common=unset
@@ -737,6 +748,13 @@ AC_DEFINE_UNQUOTED(DEFAULT_GENERATE_X86_RELAX_RELOCATIONS,
$ac_default_x86_relax_relocations,
[Define to 1 if you want to generate x86 relax relocations by default.])
+if test ${ac_default_x86_tls_check} = unset; then
+ ac_default_x86_tls_check=1
+fi
+AC_DEFINE_UNQUOTED(DEFAULT_X86_TLS_CHECK,
+ $ac_default_x86_tls_check,
+ [Define to 1 if you want to check x86 TLS relocation by default.])
+
if test ${ac_default_elf_stt_common} = unset; then
ac_default_elf_stt_common=0
fi
@@ -467,6 +467,16 @@ R_X86_64_REX_GOTPCRELX, in 64-bit mode.
relocations. The default can be controlled by a configure option
@option{--enable-x86-relax-relocations}.
+@cindex @samp{-mtls-check=} option, i386
+@cindex @samp{-mtls-check=} option, x86-64
+@item -mtls-check=@var{no}
+@itemx -mtls-check=@var{yes}
+These options control whether the assembler check tls relocation.
+@option{-mtls-check=@var{yes}} will check tls relocation.
+@option{-mtls-check=@var{no}} will not check tls relocation
+The default can be controlled by a configure option
+@option{--enable-x86-tls-check}.
+
@cindex @samp{-malign-branch-boundary=} option, i386
@cindex @samp{-malign-branch-boundary=} option, x86-64
@item -malign-branch-boundary=@var{NUM}
@@ -699,10 +699,11 @@ if [gas_32_check] then {
run_dump_test "tlsd"
run_dump_test "tlspic"
run_dump_test "tlsnopic"
+ run_dump_test "tls"
run_list_test "inval-tls"
run_dump_test "bss"
run_dump_test "reloc32"
- run_list_test "reloc32" "--defsym _bad_=1"
+ run_list_test "reloc32" "--defsym _bad_=1 -mtls-check=no"
run_dump_test "intel-got32"
run_dump_test "intel-movs32"
run_dump_test "intel-movs16"
@@ -37,8 +37,9 @@ if [expr ([istarget "i*86-*-*"] || [istarget "x86_64-*-*"]) && [gas_x32_check] &
}
}
- run_list_test "reloc64" "--defsym _bad_=1"
+ run_list_test "reloc64" "--defsym _bad_=1 -mtls-check=no"
run_list_test "reloc-2"
+ run_list_test "x32-inval-tls" "-I${srcdir}/$subdir"
set ASFLAGS "$old_ASFLAGS"
}
@@ -1,4 +1,4 @@
-#as: -mx86-used-note=no --generate-missing-build-notes=no
+#as: -mx86-used-note=no --generate-missing-build-notes=no -mtls-check=no
#objdump: -Drw
#name: x86-64 (ILP32) relocs
new file mode 100644
@@ -0,0 +1,38 @@
+.*: Assembler messages:
+.*:3: Error: @GOTTPOFF operator cannot be used with `kmovq'
+.*:4: Error: @TLSLD operator cannot be used with `kmovq'
+.*:7: Error: @TLSGD operator cannot be used with `add'
+.*:8: Error: @TLSGD operator requires `%rdi' as dest register
+.*:9: Error: @TLSGD operator requires `%rip' as base register
+.*:10: Error: @TLSGD operator requires base register
+.*:11: Error: @TLSGD operator requires `%rip' as base register
+.*:12: Error: @TLSGD operator requires `%rdi' as dest register
+.*:15: Error: @TLSLD operator cannot be used with `add'
+.*:16: Error: @TLSLD operator requires `%rdi' as dest register
+.*:17: Error: @TLSLD operator requires `%rip' as base register
+.*:18: Error: @TLSLD operator requires base register
+.*:19: Error: @TLSLD operator requires `%rip' as base register
+.*:20: Error: @TLSLD operator requires `%rdi' as dest register
+.*:23: Error: @TLSDESC operator cannot be used with `add'
+.*:24: Error: @TLSDESC operator requires `%rip' as base register
+.*:25: Error: @TLSDESC operator requires `%rip' as base register
+.*:27: Error: @TLSDESC operator requires 32-bit or 64-bit dest register
+.*:30: Error: @GOTTPOFF operator cannot be used with `sub'
+.*:31: Error: @GOTTPOFF operator cannot be used with `xor'
+.*:32: Error: @GOTTPOFF operator requires `%rip' as base register
+.*:33: Error: @GOTTPOFF operator requires `%rip' as base register
+.*:34: Error: @GOTTPOFF operator requires 32-bit or 64-bit dest register
+.*:35: Error: @GOTTPOFF operator can be used with `add', but format is wrong
+.*:36: Error: @GOTTPOFF operator can be used with `add', but format is wrong
+.*:37: Error: @GOTTPOFF operator can be used with `add', but format is wrong
+.*:38: Error: @GOTTPOFF operator can be used with `add', but format is wrong
+.*:39: Error: @GOTTPOFF operator requires `%rip' as base register
+.*:40: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
+.*:41: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
+.*:42: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
+.*:43: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
+.*:44: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
+.*:48: Error: @TLSCALL operator cannot be used with `lea'
+.*:49: Error: @TLSCALL operator requires `%eax/%rax' as base register
+.*:49: Error: 0-byte relocation cannot be applied to 4-byte field
+.*:50: Error: `\*foo@tlscall\(%ax\)' is not a valid base/index expression
new file mode 100644
@@ -0,0 +1 @@
+.include "../x86-64-inval-tls.s"
@@ -1,3 +1,4 @@
+#as: -mtls-check=no
#objdump: -dw
#name: x86-64 (ILP32) TLS
new file mode 100644
@@ -0,0 +1,4 @@
+#source: ../x86-64-tls.s
+#objdump: -drw
+#name: x86-64 (ILP32) TLS
+#dump: ../x86-64-tls.d
@@ -1,2 +1,70 @@
-.*: Assembler messages:
-.*:3: Error: @GOTNTPOFF operator cannot be used with `kmovd'
+.*ssembler messages:
+.* Error: @GOTNTPOFF operator cannot be used with `kmovd'
+.* Error: @TLSGD operator cannot be used with `add'
+.* Error: @TLSGD operator requires `%ebx' as index register
+.* Error: @TLSGD operator requires scale factor of 1
+.* Error: @TLSGD operator requires no base register
+.*: Error: @TLSGD operator requires `%eax' as dest register
+.*: Error: @TLSGD operator requires `%eax' as dest register
+.*: Error: @TLSGD operator requires `%eax' as base register
+.*: Error: @TLSGD operator requires 32-bit dest register
+.*: Error: @TLSLDM operator cannot be used with `add'
+.*: Error: @TLSLDM operator requires `%eax' as dest register
+.*: Error: @TLSLDM operator requires `%eax' as base register
+.*: Error: @TLSLDM operator requires no SIB
+.*: Error: @TLSLDM operator requires 32-bit dest register
+.*: Error: @TLSDESC operator cannot be used with `add'
+.*: Error: @TLSDESC operator requires `%ebx' as base register
+.*: Error: @TLSDESC operator requires no SIB
+.*: Error: @TLSDESC operator requires 32-bit dest register
+.*: Error: @INDNTPOFF operator cannot be used with `sub'
+.*: Error: @INDNTPOFF operator requires no base/index register
+.*: Error: @INDNTPOFF operator requires no base/index register
+.*: Error: @INDNTPOFF operator requires 32-bit dest register
+.*: Error: @INDNTPOFF operator can be used with `add', but format is wrong
+.*: Error: @INDNTPOFF operator can be used with `add', but format is wrong
+.*: Error: @INDNTPOFF operator can be used with `add', but format is wrong
+.*: Error: @INDNTPOFF operator can be used with `add', but format is wrong
+.*: Error: @INDNTPOFF operator can be used with `mov', but format is wrong
+.*: Error: @INDNTPOFF operator can be used with `mov', but format is wrong
+.*: Error: @INDNTPOFF operator can be used with `mov', but format is wrong
+.*: Error: @INDNTPOFF operator can be used with `mov', but format is wrong
+.*: Error: @INDNTPOFF operator can be used with `mov', but format is wrong
+.*: Error: @GOTNTPOFF operator cannot be used with `lea'
+.*: Error: @GOTNTPOFF operator requires base register
+.*: Error: @GOTNTPOFF operator cannot be used with `lea'
+.*: Error: @GOTNTPOFF operator can be used with `sub', but format is wrong
+.*: Error: @GOTNTPOFF operator can be used with `sub', but format is wrong
+.*: Error: @GOTNTPOFF operator can be used with `sub', but format is wrong
+.*: Error: @GOTNTPOFF operator can be used with `sub', but format is wrong
+.*: Error: @GOTNTPOFF operator can be used with `add', but format is wrong
+.*: Error: @GOTNTPOFF operator can be used with `add', but format is wrong
+.*: Error: @GOTNTPOFF operator can be used with `add', but format is wrong
+.*: Error: @GOTNTPOFF operator can be used with `add', but format is wrong
+.*: Error: @GOTNTPOFF operator requires base register
+.*: Error: @GOTNTPOFF operator can be used with `mov', but format is wrong
+.*: Error: @GOTNTPOFF operator can be used with `mov', but format is wrong
+.*: Error: @GOTNTPOFF operator can be used with `mov', but format is wrong
+.*: Error: @GOTNTPOFF operator can be used with `mov', but format is wrong
+.*: Error: @GOTNTPOFF operator can be used with `mov', but format is wrong
+.*: Error: @GOTTPOFF operator cannot be used with `lea'
+.*: Error: @GOTTPOFF operator requires base register
+.*: Error: @GOTTPOFF operator requires 32-bit dest register
+.*: Error: @GOTTPOFF operator can be used with `sub', but format is wrong
+.*: Error: @GOTTPOFF operator can be used with `sub', but format is wrong
+.*: Error: @GOTTPOFF operator can be used with `sub', but format is wrong
+.*: Error: @GOTTPOFF operator can be used with `sub', but format is wrong
+.*: Error: @GOTTPOFF operator can be used with `add', but format is wrong
+.*: Error: @GOTTPOFF operator can be used with `add', but format is wrong
+.*: Error: @GOTTPOFF operator can be used with `add', but format is wrong
+.*: Error: @GOTTPOFF operator requires base register
+.*: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
+.*: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
+.*: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
+.*: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
+.*: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
+.*: Error: @TLSCALL operator cannot be used with `lea'
+.*: Error: @TLSCALL operator requires `%eax/%rax' as base register
+.*: Error: @TLSCALL operator requires no SIB
+.*: Error: 0-byte relocation cannot be applied to 4-byte field
+.*: Error: @TLSCALL operator requires `%eax/%rax' as base register
@@ -1,3 +1,85 @@
.text
# All the following should be illegal
kmovd foo@gotntpoff(%eax), %k0
+
+ /* Invalid testcase for R_386_TLS_GD. */
+ addl foo@tlsgd(,%ebx,1), %eax
+ leal foo@tlsgd(,%ecx,1), %eax
+ leal foo@tlsgd(,%ebx,2), %eax
+ leal foo@tlsgd(%ecx,%ebx,1), %eax
+ leal foo@tlsgd(,%ebx,1), %ecx
+ leal foo@tlsgd(%ebx), %ecx
+ leal foo@tlsgd(%eax), %eax
+ lea foo@tlsgd(%ebx), %ax
+
+ /* Invalid testcase for R_386_TLS_LDM. */
+ addl foo@tlsldm(%ebx), %eax
+ leal foo@tlsldm(%ebx), %ecx
+ leal foo@tlsldm(%eax), %eax
+ leal foo@tlsldm(,%ebx,1), %eax
+ lea foo@tlsldm(%ebx), %ax
+
+ /* Invalid testcase for R_386_TLS_GOTDESC. */
+ addl x@tlsdesc(%ebx), %eax
+ leal x@tlsdesc(%ecx), %eax
+ leal x@tlsdesc(,%ecx,1), %eax
+ lea x@tlsdesc(%ebx), %ax
+
+ /* Invalid testcase for R_386_TLS_IE. */
+ subl foo@indntpoff, %ecx
+ addl foo@indntpoff(%ebx), %ecx
+ movl foo@indntpoff(%ebx), %ecx
+ add foo@indntpoff, %cx
+ addl $foo@indntpoff, %eax
+ addl %ecx, foo@indntpoff
+ addl $0x9090,foo@indntpoff
+ addl $0x90909090,foo@indntpoff
+ movl foo@indntpoff,%eax
+ movl %edx,foo@indntpoff(%eax)
+ movw %ss,foo@indntpoff(%eax)
+ movw foo@indntpoff(%eax),%ss
+ movl $0x90909090,foo@indntpoff(%eax)
+ movl $foo@indntpoff, %eax
+
+ /* Invalid testcase for R_386_TLS_GOTIE. */
+ leal foo@gotntpoff(%ebx), %ecx
+ subl foo@gotntpoff(,%ebx,1), %ecx
+ lea foo@gotntpoff(%ebx), %cx
+ subl %ecx, foo@gotntpoff(%ebx)
+ subl $0x9090,foo@gotntpoff(%ebx)
+ subl $0x90909090,foo@gotntpoff(%eax)
+ subl $foo@gotntpoff, %eax
+ addl %ecx, foo@gotntpoff(%ebx)
+ addl $0x9090,foo@gotntpoff(%ebx)
+ addl $0x90909090,foo@gotntpoff(%eax)
+ addl $foo@gotntpoff, %eax
+ movl foo@gotntpoff,%eax
+ movl %edx,foo@gotntpoff(%eax)
+ movw %ss,foo@gotntpoff(%eax)
+ movw foo@gotntpoff(%eax),%ss
+ movl $0x90909090,foo@gotntpoff(%eax)
+ movl $foo@gotntpoff, %eax
+
+ /* Invalid testcase for R_386_TLS_IE_32. */
+ leal foo@gottpoff(%ebx), %ecx
+ subl foo@gottpoff(,%ebx,1), %ecx
+ add foo@gottpoff(%ebx), %cx
+ subl %ecx, foo@gottpoff(%ebx)
+ subl $0x9090,foo@gottpoff(%ebx)
+ subl $0x90909090,foo@gottpoff(%eax)
+ subl $foo@gottpoff, %eax
+ addl %ecx, foo@gottpoff(%ebx)
+ addl $0x9090,foo@gottpoff(%ebx)
+ addl $0x90909090,foo@gottpoff(%eax)
+ movl foo@gottpoff,%eax
+ movl %edx,foo@gottpoff(%eax)
+ movw %ss,foo@gottpoff(%eax)
+ movw foo@gottpoff(%eax),%ss
+ movl $0x90909090,foo@gottpoff(%eax)
+ movl $foo@gottpoff, %eax
+
+ /* Invalid testcase for R_386_TLS_DESC_CALL. */
+ leal foo@tlscall(%eax), %ebx
+ call *x@tlscall(%ebx)
+ call *x@tlscall(,%eax,1)
+ call *x@tlscall(%bx)
@@ -1,4 +1,4 @@
-#as: -mrelax-relocations=yes
+#as: -mrelax-relocations=yes -mtls-check=no
#objdump: -Drw
#name: i386 relocs
@@ -1,4 +1,4 @@
-#as: -mx86-used-note=no --generate-missing-build-notes=no
+#as: -mx86-used-note=no --generate-missing-build-notes=no -mtls-check=no
#objdump: -Drw
#name: x86-64 relocs
#notarget: *-*-solaris*
new file mode 100644
@@ -0,0 +1,25 @@
+#as:
+#objdump: -drw
+#name: Check tls relocation 32 bit-mode
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+00000000 <_start>:
+\s*[a-f0-9]+:\s*8d 04 1d 00 00 00 00[ ]+lea 0x0\(,%ebx,1\),%eax 3: R_386_TLS_GD foo
+\s*[a-f0-9]+:\s*8d 81 00 00 00 00[ ]+lea 0x0\(%ecx\),%eax 9: R_386_TLS_GD foo
+\s*[a-f0-9]+:\s*8d 83 00 00 00 00[ ]+lea 0x0\(%ebx\),%eax f: R_386_TLS_LDM foo
+\s*[a-f0-9]+:\s*8d 83 00 00 00 00[ ]+lea 0x0\(%ebx\),%eax 15: R_386_TLS_GOTDESC x
+\s*[a-f0-9]+:\s*a1 00 00 00 00[ ]+mov 0x0,%eax 1a: R_386_TLS_IE foo
+\s*[a-f0-9]+:\s*8b 1d 00 00 00 00[ ]+mov 0x0,%ebx 20: R_386_TLS_IE foo
+\s*[a-f0-9]+:\s*03 15 00 00 00 00[ ]+add 0x0,%edx 26: R_386_TLS_IE foo
+\s*[a-f0-9]+:\s*2b 8b 00 00 00 00[ ]+sub 0x0\(%ebx\),%ecx 2c: R_386_TLS_GOTIE foo
+\s*[a-f0-9]+:\s*8b 8b 00 00 00 00[ ]+mov 0x0\(%ebx\),%ecx 32: R_386_TLS_GOTIE foo
+\s*[a-f0-9]+:\s*03 8b 00 00 00 00[ ]+add 0x0\(%ebx\),%ecx 38: R_386_TLS_GOTIE foo
+\s*[a-f0-9]+:\s*2b 8b 00 00 00 00[ ]+sub 0x0\(%ebx\),%ecx 3e: R_386_TLS_IE_32 foo
+\s*[a-f0-9]+:\s*8b 8b 00 00 00 00[ ]+mov 0x0\(%ebx\),%ecx 44: R_386_TLS_IE_32 foo
+\s*[a-f0-9]+:\s*03 8b 00 00 00 00[ ]+add 0x0\(%ebx\),%ecx 4a: R_386_TLS_IE_32 foo
+\s*[a-f0-9]+:\s*ff 10[ ]+call \*\(%eax\) 4e: R_386_TLS_DESC_CALL foo
+#pass
new file mode 100644
@@ -0,0 +1,31 @@
+# Check tls relocation 32-bit mode
+
+ .text
+_start:
+ /* R_386_TLS_GD. */
+ leal foo@tlsgd(,%ebx,1), %eax
+ leal foo@tlsgd(%ecx), %eax
+
+ /* R_386_TLS_LDM. */
+ leal foo@tlsldm(%ebx), %eax
+
+ /* R_386_TLS_GOTDESC. */
+ leal x@tlsdesc(%ebx), %eax
+
+ /* R_386_TLS_IE. */
+ movl foo@indntpoff, %eax
+ movl foo@indntpoff, %ebx
+ addl foo@indntpoff, %edx
+
+ /* R_386_TLS_GOTIE. */
+ subl foo@gotntpoff(%ebx), %ecx
+ movl foo@gotntpoff(%ebx), %ecx
+ addl foo@gotntpoff(%ebx), %ecx
+
+ /* R_386_TLS_IE_32. */
+ subl foo@gottpoff(%ebx), %ecx
+ movl foo@gottpoff(%ebx), %ecx
+ addl foo@gottpoff(%ebx), %ecx
+
+ /* R_386_TLS_DESC_CALL. */
+ call *foo@tlscall(%eax)
@@ -1,3 +1,39 @@
.*: Assembler messages:
.*:3: Error: @GOTTPOFF operator cannot be used with `kmovq'
.*:4: Error: @TLSLD operator cannot be used with `kmovq'
+.*:7: Error: @TLSGD operator cannot be used with `add'
+.*:8: Error: @TLSGD operator requires `%rdi' as dest register
+.*:9: Error: @TLSGD operator requires `%rip' as base register
+.*:10: Error: @TLSGD operator requires base register
+.*:11: Error: @TLSGD operator requires `%rip' as base register
+.*:12: Error: @TLSGD operator requires `%rdi' as dest register
+.*:15: Error: @TLSLD operator cannot be used with `add'
+.*:16: Error: @TLSLD operator requires `%rdi' as dest register
+.*:17: Error: @TLSLD operator requires `%rip' as base register
+.*:18: Error: @TLSLD operator requires base register
+.*:19: Error: @TLSLD operator requires `%rip' as base register
+.*:20: Error: @TLSLD operator requires `%rdi' as dest register
+.*:23: Error: @TLSDESC operator cannot be used with `add'
+.*:24: Error: @TLSDESC operator requires `%rip' as base register
+.*:25: Error: @TLSDESC operator requires `%rip' as base register
+.*:26: Error: @TLSDESC operator requires 64-bit dest register
+.*:27: Error: @TLSDESC operator requires 64-bit dest register
+.*:30: Error: @GOTTPOFF operator cannot be used with `sub'
+.*:31: Error: @GOTTPOFF operator cannot be used with `xor'
+.*:32: Error: @GOTTPOFF operator requires `%rip' as base register
+.*:33: Error: @GOTTPOFF operator requires `%rip' as base register
+.*:34: Error: @GOTTPOFF operator requires 64-bit dest register
+.*:35: Error: @GOTTPOFF operator can be used with `add', but format is wrong
+.*:36: Error: @GOTTPOFF operator can be used with `add', but format is wrong
+.*:37: Error: @GOTTPOFF operator can be used with `add', but format is wrong
+.*:38: Error: @GOTTPOFF operator can be used with `add', but format is wrong
+.*:39: Error: @GOTTPOFF operator requires `%rip' as base register
+.*:40: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
+.*:41: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
+.*:42: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
+.*:43: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
+.*:44: Error: @GOTTPOFF operator can be used with `mov', but format is wrong
+.*:48: Error: @TLSCALL operator cannot be used with `lea'
+.*:49: Error: @TLSCALL operator requires `%eax/%rax' as base register
+.*:49: Error: 0-byte relocation cannot be applied to 4-byte field
+.*:50: Error: `\*foo@tlscall\(%ax\)' is not a valid base/index expression
@@ -2,3 +2,49 @@
# All the following should be illegal
kmovq foo@gottpoff(%rip), %k0
kmovq foo@tlsld(%rip), %k0
+
+ /* Invalid testcase for R_X86_64_TLSGD. */
+ addq foo@tlsgd(%rip), %rdi
+ leaq foo@tlsgd(%rip), %rax
+ leaq foo@tlsgd(%rax), %rdi
+ leaq foo@tlsgd(,%rax,1), %rdi
+ leaq foo@tlsgd(%eip), %rdi
+ leal foo@tlsgd(%rip), %edi
+
+ /* Invalid testcase for R_X86_64_TLSLD. */
+ addq foo@tlsld(%rip), %rdi
+ leaq foo@tlsld(%rip), %rax
+ leaq foo@tlsld(%rax), %rdi
+ leaq foo@tlsld(,%rax,1), %rdi
+ leaq foo@tlsld(%eip), %rdi
+ leal foo@tlsld(%rip), %edi
+
+ /* Invalid testcase for R_X86_64_GOTPC32_TLSDESC. */
+ addq x@tlsdesc(%rip), %rax
+ leaq x@tlsdesc(%rbx), %rax
+ lea x@tlsdesc(%eip), %rdi
+ lea x@tlsdesc(%rip), %eax
+ lea x@tlsdesc(%rip), %ax
+
+ /* Invalid testcase for R_X86_64_GOTTPOFF. */
+ subq foo@gottpoff(%rip), %r12
+ xorq foo@gottpoff(%rip), %rax
+ addq foo@gottpoff(%rbx), %rax
+ addq foo@gottpoff(%eip), %rax
+ add foo@gottpoff(%rip), %ax
+ addq %rax, foo@gottpoff(%rip)
+ addl $0x90909090, foo@gottpoff(%rip)
+ add $0x90, foo@gottpoff(%rip), %rax
+ add $0xffffffffffffffff, foo@gottpoff(%rip), %rax
+ movq foo@gottpoff(%rbx), %rax
+ movq %rax, foo@gottpoff(%rip)
+ mov %ss,foo@gottpoff(%rip)
+ mov foo@gottpoff(%rip),%ss
+ movl $0x90909090,foo@gottpoff(%rip)
+ mov $foo@gottpoff, %rax
+
+
+ /* Invalid testcase for R_X86_64_TLSDESC_CALL. */
+ leaq foo@tlscall(%rax), %rbx
+ call *foo@tlscall(%rip)
+ call *foo@tlscall(%ax)
new file mode 100644
@@ -0,0 +1,25 @@
+#as:
+#objdump: -drw
+#name: Check tls relocation x86-64
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <_start>:
+ +[a-f0-9]+: 48 8d 3d 00 00 00 00 lea 0x0\(%rip\),%rdi # 7 <_start\+0x7> 3: R_X86_64_TLSGD foo-0x4
+ +[a-f0-9]+: 48 8d 3d 00 00 00 00 lea 0x0\(%rip\),%rdi # e <_start\+0xe> a: R_X86_64_TLSLD foo-0x4
+ +[a-f0-9]+: 48 8d 05 00 00 00 00 lea 0x0\(%rip\),%rax # 15 <_start\+0x15> 11: R_X86_64_GOTPC32_TLSDESC x-0x4
+ +[a-f0-9]+: 4c 03 25 00 00 00 00 add 0x0\(%rip\),%r12 # 1c <_start\+0x1c> 18: R_X86_64_GOTTPOFF foo-0x4
+ +[a-f0-9]+: 48 8b 05 00 00 00 00 mov 0x0\(%rip\),%rax # 23 <_start\+0x23> 1f: R_X86_64_GOTTPOFF foo-0x4
+ +[a-f0-9]+: d5 48 03 05 00 00 00 00 add 0x0\(%rip\),%r16 # 2b <_start\+0x2b> 27: R_X86_64_CODE_4_GOTTPOFF foo-0x4
+ +[a-f0-9]+: d5 48 8b 25 00 00 00 00 mov 0x0\(%rip\),%r20 # 33 <_start\+0x33> 2f: R_X86_64_CODE_4_GOTTPOFF foo-0x4
+ +[a-f0-9]+: 62 64 bc 18 01 35 00 00 00 00 add %r30,0x0\(%rip\),%r8 # 3d <_start\+0x3d> 39: R_X86_64_CODE_6_GOTTPOFF foo-0x4
+ +[a-f0-9]+: 62 f4 dc 10 03 05 00 00 00 00 add 0x0\(%rip\),%rax,%r20 # 47 <_start\+0x47> 43: R_X86_64_CODE_6_GOTTPOFF foo-0x4
+ +[a-f0-9]+: 62 e4 fc 0c 03 05 00 00 00 00 \{nf\} add 0x0\(%rip\),%r16 # 51 <_start\+0x51> 4d: R_X86_64_CODE_6_GOTTPOFF foo-0x4
+ +[a-f0-9]+: 62 64 bc 1c 01 35 00 00 00 00 \{nf\} add %r30,0x0\(%rip\),%r8 # 5b <_start\+0x5b> 57: R_X86_64_CODE_6_GOTTPOFF foo-0x4
+ +[a-f0-9]+: 62 f4 dc 14 03 05 00 00 00 00 \{nf\} add 0x0\(%rip\),%rax,%r20 # 65 <_start\+0x65> 61: R_X86_64_CODE_6_GOTTPOFF foo-0x4
+ +[a-f0-9]+: ff 10 call \*\(%rax\) 65: R_X86_64_TLSDESC_CALL x
+ +[a-f0-9]+: 67 ff 10 call \*\(%eax\) 67: R_X86_64_TLSDESC_CALL x
+#pass
new file mode 100644
@@ -0,0 +1,27 @@
+# Check tls relocation 64-bit mode
+
+ .text
+_start:
+ /* R_X86_64_TLSGD. */
+ leaq foo@tlsgd(%rip), %rdi
+
+ /* R_X86_64_TLSLD. */
+ leaq foo@tlsld(%rip), %rdi
+
+ /* R_X86_64_GOTPC32_TLSDESC. */
+ leaq x@tlsdesc(%rip), %rax
+
+ /* R_X86_64_GOTTPOFF. */
+ addq foo@gottpoff(%rip), %r12
+ movq foo@gottpoff(%rip), %rax
+ addq foo@gottpoff(%rip), %r16
+ movq foo@gottpoff(%rip), %r20
+ addq %r30, foo@gottpoff(%rip), %r8
+ addq foo@gottpoff(%rip), %rax, %r20
+ {nf} addq foo@gottpoff(%rip), %r16
+ {nf} addq %r30, foo@gottpoff(%rip), %r8
+ {nf} addq foo@gottpoff(%rip), %rax, %r20
+
+ /* R_X86_64_TLSDESC_CALL. */
+ call *x@tlscall(%rax)
+ call *x@tlscall(%eax)
@@ -653,7 +653,8 @@ if [is_elf_format] then {
run_dump_test "x86-64-unwind"
run_dump_test "reloc64"
- run_list_test "reloc64" "--defsym _bad_=1"
+ run_list_test "reloc64" "--defsym _bad_=1 -mtls-check=no"
+ run_dump_test "x86-64-tls"
run_list_test "x86-64-inval-tls"
run_dump_test "mixed-mode-reloc64"
run_dump_test "rela"
@@ -1,4 +1,4 @@
#name: TLS GDesc->LE transition check (LEA)
-#as: --32
+#as: --32 -mtls-check=no
#ld: -melf_i386
#error: .*: relocation R_386_TLS_GOTDESC against `foo' must be used in LEA only
@@ -1,4 +1,4 @@
#name: TLS GDesc->LE transition check (indirect CALL)
-#as: --32
+#as: --32 -mtls-check=no
#ld: -melf_i386
#error: .*: relocation R_386_TLS_DESC_CALL against `foo' must be used in indirect CALL with EAX register only
@@ -1,5 +1,5 @@
#source: tlsgdesc2.s
#name: TLS GDesc call (indirect CALL)
-#as: --32
+#as: --32 -mtls-check=no
#ld: -shared -melf_i386
#error: .*: relocation R_386_TLS_DESC_CALL against `foo' must be used in indirect CALL with EAX register only
@@ -1,4 +1,4 @@
#name: TLS IE->LE transition check (R_386_TLS_GOTIE with %eax)
-#as: --32
+#as: --32 -mtls-check=no
#ld: -melf_i386
#error: .*: relocation R_386_TLS_GOTIE against `foo' must be used in ADD, SUB or MOV only
@@ -1,4 +1,4 @@
#name: TLS IE->LE transition check (R_386_TLS_GOTIE)
-#as: --32
+#as: --32 -mtls-check=no
#ld: -melf_i386
#error: .*: relocation R_386_TLS_GOTIE against `foo' must be used in ADD, SUB or MOV only
@@ -1,4 +1,4 @@
#name: TLS IE->LE transition check (R_386_TLS_IE with %eax)
-#as: --32
+#as: --32 -mtls-check=no
#ld: -melf_i386
#error: .*: relocation R_386_TLS_IE against `foo' must be used in ADD or MOV only
@@ -1,4 +1,4 @@
#name: TLS IE->LE transition check (R_386_TLS_IE)
-#as: --32
+#as: --32 -mtls-check=no
#ld: -melf_i386
#error: .*: relocation R_386_TLS_IE against `foo' must be used in ADD or MOV only
@@ -1,4 +1,4 @@
#name: TLS GDesc->LE transition check (LEA)
-#as: --64
+#as: --64 -mtls-check=no
#ld: -melf_x86_64
#error: .*: relocation R_X86_64_GOTPC32_TLSDESC against `foo' must be used in LEA only
@@ -1,4 +1,4 @@
#name: TLS GDesc->LE transition check (indirect CALL)
-#as: --64
+#as: --64 -mtls-check=no
#ld: -melf_x86_64
#error: .*: relocation R_X86_64_TLSDESC_CALL against `foo' must be used in indirect CALL with RAX register only
@@ -1,5 +1,5 @@
#source: tlsdesc4.s
#name: TLS GDesc call (indirect CALL)
-#as: --64
+#as: --64 -mtls-check=no
#ld: -shared -melf_x86_64
#error: .*: relocation R_X86_64_TLSDESC_CALL against `foo' must be used in indirect CALL with RAX register only
@@ -1,4 +1,4 @@
#name: TLS IE->LE transition check
-#as: --64
+#as: --64 -mtls-check=no
#ld: -melf_x86_64
#error: .*: relocation R_X86_64_GOTTPOFF against `foo' must be used in ADD or MOV only
@@ -1,4 +1,4 @@
#name: TLS IE->LE transition check (%r12)
-#as: --64
+#as: --64 -mtls-check=no
#ld: -melf_x86_64
#error: .*: relocation R_X86_64_GOTTPOFF against `foo' must be used in ADD or MOV only
@@ -1,4 +1,4 @@
#name: TLS IE->LE transition check (APX)
-#as: --64
+#as: --64 -mtls-check=no
#ld: -melf_x86_64
#error: .*: relocation R_X86_64_CODE_6_GOTTPOFF against `foo' must be used in ADD only