[PATCH v3] x86: Add tls check in gas

H.J. Lu hjl.tools@gmail.com
Wed Sep 18 01:56:49 GMT 2024


On Wed, Sep 11, 2024 at 2:08 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 v3:
> 1. Added has_gotrel to indicate whether tls relocations need to be checked.
> 2. Removed RegDI, check register rdi with reg_num and reg_flags.
> 3. Added dest register size check in x86_check_tls_relocation, and reloc() will check memory registers.
> 4. Added rex/rex2 prefix check for X32 in BFD_RELOC_X86_64_GOTPC32_TLSDESC and add comments for it.
> 5. Refine tls error report.
> 6. Add more invalid test cases.
> -----------------------------
>
> 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/tls.d: New test.
>         * 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                      | 383 ++++++++++++++++++++--
>  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    |   2 +-
>  gas/testsuite/gas/i386/ilp32/reloc64.d    |   2 +-
>  gas/testsuite/gas/i386/ilp32/x32-tls.d    |   1 +
>  gas/testsuite/gas/i386/inval-tls.l        |  32 ++
>  gas/testsuite/gas/i386/inval-tls.s        |  45 +++
>  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 |  18 +
>  gas/testsuite/gas/i386/x86-64-inval-tls.s |  27 ++
>  gas/testsuite/gas/i386/x86-64-tls.d       |  31 ++
>  gas/testsuite/gas/i386/x86-64-tls.s       |  33 ++
>  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 +-
>  33 files changed, 680 insertions(+), 43 deletions(-)
>  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..3f199d5b4a6 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 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 6cd57d9c12b..e0ece142ed2 100644
> --- a/gas/config/tc-i386.c
> +++ b/gas/config/tc-i386.c
> @@ -274,6 +274,26 @@ 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_sib,
> +  x86_tls_error_no_base_reg,
> +  x86_tls_error_require_no_base_index_reg,
> +  x86_tls_error_base_reg_name,
> +  x86_tls_error_index_ebx,
> +  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_dest_reg_size,
> +  x86_tls_error_REX_prefix
> +};
> +
>  struct _i386_insn
>    {
>      /* TM holds the template for the insn were currently assembling.  */
> @@ -365,6 +385,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 +740,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,
> @@ -6353,6 +6379,305 @@ 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), %reg --> 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_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(%reg), %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_reg_size;
> +      if (i.index_reg)
> +       {
> +         if (i.base_reg)
> +           return x86_tls_error_base_reg_name;
> +         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_RegA;
> +       }
> +      break;
> +
> +    case BFD_RELOC_386_TLS_LDM:
> +      /*  Check LDM access model:
> +
> +         leal foo@tlsldm(%reg), %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_RegA;
> +      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_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, when dest is Egpr, gas will automatically add rex2 to it.
> +        When dest is Gpr, we need to check whether there is a rex/rex2 prefix.
> +       */
> +      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)
> +       return x86_tls_error_rip;
> +      if (i.op[1].regs->reg_type.bitfield.dword
> +              && !(i.op[1].regs->reg_flags & RegRex2)

Please align &&

> +              && (pp.rex2_encoding == false

No need for (

> +                  && pp.rex_encoding == false
> +                  && i.prefix[REX_PREFIX] != REX_OPCODE))

Limit it to x86_elf_abi == X86_64_ABI since output_insn will add a dummy
REX_OPCODE prefix for lea with R_X86_64_GOTPC32_TLSDESC
relocation when generating x32 object.  Otherwise, I got

/export/build/gnu/tools-build/binutils-gitlab/build-x86_64-linux/ld/../gas/as-new
 -mx86-used-note=no --x32  -o tmpdir/pr25416-1.o
/export/gnu/import/git/gitlab/x86-binutils/ld/testsuite/ld-x86-64/pr25416-1.s
Executing on host: sh -c
{/export/build/gnu/tools-build/binutils-gitlab/build-x86_64-linux/ld/../gas/as-new
 -mx86-used-note=no --x32  -o tmpdir/pr25416-1.o
/export/gnu/import/git/gitlab/x86-binutils/ld/testsuite/ld-x86-64/pr25416-1.s
2>&1}  /dev/null dump.tmp (timeout = 300)
spawn [open ...]^M
/export/gnu/import/git/gitlab/x86-binutils/ld/testsuite/ld-x86-64/pr25416-1.s:
Assembler messages:
/export/gnu/import/git/gitlab/x86-binutils/ld/testsuite/ld-x86-64/pr25416-1.s:5:
Error: @TLSDESC operator requires REX prefix in x32 mode
failed with: </export/gnu/import/git/gitlab/x86-binutils/ld/testsuite/ld-x86-64/pr25416-1.s:
Assembler messages:
/export/gnu/import/git/gitlab/x86-binutils/ld/testsuite/ld-x86-64/pr25416-1.s:5:
Error: @TLSDESC operator requires REX prefix in x32 mode>, no expected
output
FAIL: X32 GDesc 1

> +       return x86_tls_error_REX_prefix;
> +      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)
> +       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.base_reg)
> +       return x86_tls_error_no_base_reg;
> +      if (i.index_reg)
> +       return x86_tls_error_sib;
> +      if (!i.op[1].regs->reg_type.bitfield.dword)
> +       return x86_tls_error_dest_reg_size;
> +      break;
> +
> +    case BFD_RELOC_386_TLS_IE:
> +      /* Check IE access model:
> +
> +        movl foo@indntpoff, %reg --> Mod == 00 && r/m == 5
> +        addl foo@indntpoff, %reg --> 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.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_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.
> +       */
> +      if (i.tm.mnem_off != MN_add && i.tm.mnem_off != MN_mov)
> +       return x86_tls_error_insn;
> +      if (!i.base_reg)
> +       return x86_tls_error_no_base_reg;
> +      if (i.base_reg->reg_num != RegIP)
> +       return x86_tls_error_rip;
> +      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)

Line is too long.

> +{
> +  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_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_name:
> +      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_RegA:
> +      as_bad (_("@%s operator requires `%seax/rax' as base register"),
> +             gotrel[k].str, 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_dest_reg_size:
> +      as_bad (_("@%s operator requires 32-bit dest register"),
> +             gotrel[k].str);
> +      return;
> +
> +    case x86_tls_error_REX_prefix:
> +      as_bad (_("@%s operator requires REX prefix in x32 mode"),
> +             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.  */
> @@ -6691,6 +7016,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)
> @@ -6701,28 +7041,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.  */
> @@ -12492,6 +12810,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)
> @@ -16225,6 +16544,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[] =
>  {
> @@ -16271,6 +16591,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);
> @@ -16827,6 +17148,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;
> @@ -17069,6 +17398,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"));

Please use spaces not tab and align it with other help messages.
Output TLS instead of tls.

> +
>    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..a4cdeb80900 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_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-tls-check      check 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 check tls relocation.
> +ac_default_x86_tls_check=unset
> +# Provide a configure time option to override our default.
> +# Check whether --enable-tls_check was given.
> +if test "${enable_tls_check+set}" = set; then :
> +  enableval=$enable_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..5fe57e52746 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 check tls relocation.

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(tls_check,

x86_tls_check

> +             AS_HELP_STRING([--enable-tls-check],
> +             [check tls relocation by default]),

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 tls relocation by default.])

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..5da673a0287 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-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..b32da8725b5 100644
> --- a/gas/testsuite/gas/i386/ilp32/ilp32.exp
> +++ b/gas/testsuite/gas/i386/ilp32/ilp32.exp
> @@ -37,7 +37,7 @@ 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"
>
>      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-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/inval-tls.l b/gas/testsuite/gas/i386/inval-tls.l
> index 98f7a29f1ab..20a7324c13e 100644
> --- a/gas/testsuite/gas/i386/inval-tls.l
> +++ b/gas/testsuite/gas/i386/inval-tls.l
> @@ -1,2 +1,34 @@
>  .*: Assembler messages:
>  .*:3: Error: @GOTNTPOFF operator cannot be used with `kmovd'
> +.*:6: Error: @TLSGD operator cannot be used with `add'
> +.*:7: Error: @TLSGD operator requires `%ebx' as index register
> +.*:8: Error: @TLSGD operator requires scale factor of 1
> +.*:9: Error: @TLSGD operator requires no base register
> +.*:10: Error: @TLSGD operator requires `%eax' as dest register
> +.*:11: Error: @TLSGD operator requires `%eax' as dest register
> +.*:12: Error: @TLSGD operator requires `%eax/rax' as base register
> +.*:13: Error: @TLSGD operator requires 32-bit dest register
> +.*:16: Error: @TLSLDM operator cannot be used with `add'
> +.*:17: Error: @TLSLDM operator requires `%eax' as dest register
> +.*:18: Error: @TLSLDM operator requires `%eax/rax' as base register
> +.*:19: Error: @TLSLDM operator requires no SIB
> +.*:20: Error: @TLSLDM operator requires 32-bit dest register
> +.*:23: Error: @TLSDESC operator cannot be used with `add'
> +.*:24: Error: @TLSDESC operator requires `%ebx' as base register
> +.*:25: Error: @TLSDESC operator requires no SIB
> +.*:26: Error: @TLSDESC operator requires 32-bit dest register
> +.*:29: Error: @INDNTPOFF operator cannot be used with `sub'
> +.*:30: Error: @INDNTPOFF operator requires no base/index register
> +.*:31: Error: @INDNTPOFF operator requires no base/index register
> +.*:32: Error: @INDNTPOFF operator requires 32-bit dest register
> +.*:35: Error: @GOTNTPOFF operator cannot be used with `lea'
> +.*:36: Error: @GOTNTPOFF operator requires base register
> +.*:37: Error: @GOTNTPOFF operator cannot be used with `lea'
> +.*:40: Error: @GOTTPOFF operator cannot be used with `lea'
> +.*:41: Error: @GOTTPOFF operator requires base register
> +.*:42: Error: @GOTTPOFF operator requires 32-bit dest register
> +.*:45: Error: @TLSCALL operator cannot be used with `lea'
> +.*:46: Error: @TLSCALL operator requires `%eax/rax' as base register
> +.*:47: Error: @TLSCALL operator requires no SIB
> +.*:47: Error: 0-byte relocation cannot be applied to 4-byte field
> +.*:48: 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..9ea4a74e235 100644
> --- a/gas/testsuite/gas/i386/inval-tls.s
> +++ b/gas/testsuite/gas/i386/inval-tls.s
> @@ -1,3 +1,48 @@
>         .text
>  # All the following should be illegal
>         kmovd   foo@gotntpoff(%eax), %k0
> +
> +       /* Invalid testcase for BFD_RELOC_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 BFD_RELOC_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 BFD_RELOC_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 BFD_RELOC_386_TLS_IE.  */
> +       subl foo@indntpoff, %ecx
> +       addl foo@indntpoff(%ebx), %ecx
> +       movl foo@indntpoff(%ebx), %ecx
> +       add foo@indntpoff, %cx
> +
> +       /* Invalid testcase for BFD_RELOC_386_TLS_GOTIE.  */
> +       leal foo@gotntpoff(%ebx), %ecx
> +       subl foo@gotntpoff(,%ebx,1), %ecx
> +       lea foo@gotntpoff(%ebx), %cx
> +
> +       /* Invalid testcase for BFD_RELOC_386_TLS_IE_32.  */
> +       leal foo@gottpoff(%ebx), %ecx
> +       subl foo@gottpoff(,%ebx,1), %ecx
> +       add foo@gottpoff(%ebx), %cx
> +
> +       /* Invalid testcase for BFD_RELOC_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..7a0a83147e4
> --- /dev/null
> +++ b/gas/testsuite/gas/i386/tls.s
> @@ -0,0 +1,31 @@
> +# Check tls relocation 32-bit mode
> +
> +       .text
> +_start:
> +       /* BFD_RELOC_386_TLS_GD.  */
> +       leal foo@tlsgd(,%ebx,1), %eax
> +       leal foo@tlsgd(%ecx), %eax
> +
> +       /* BFD_RELOC_386_TLS_LDM.  */
> +       leal foo@tlsldm(%ebx), %eax
> +
> +       /* BFD_RELOC_386_TLS_GOTDESC.  */
> +       leal x@tlsdesc(%ebx), %eax
> +
> +       /* BFD_RELOC_386_TLS_IE.  */
> +       movl foo@indntpoff, %eax
> +       movl foo@indntpoff, %ebx
> +       addl foo@indntpoff, %edx
> +
> +       /* BFD_RELOC_386_TLS_GOTIE.  */
> +       subl foo@gotntpoff(%ebx), %ecx
> +       movl foo@gotntpoff(%ebx), %ecx
> +       addl foo@gotntpoff(%ebx), %ecx
> +
> +       /* BFD_RELOC_386_TLS_IE_32.  */
> +       subl foo@gottpoff(%ebx), %ecx
> +       movl foo@gottpoff(%ebx), %ecx
> +       addl foo@gottpoff(%ebx), %ecx
> +
> +       /* BFD_RELOC_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..26bf69ef157 100644
> --- a/gas/testsuite/gas/i386/x86-64-inval-tls.l
> +++ b/gas/testsuite/gas/i386/x86-64-inval-tls.l
> @@ -1,3 +1,21 @@
>  .*: 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
> +.*:13: Error: @TLSLD operator cannot be used with `add'
> +.*:14: Error: @TLSLD operator requires `%rdi' as dest register
> +.*:15: Error: @TLSLD operator requires `%rip' as base register
> +.*:16: Error: @TLSLD operator requires base register
> +.*:19: Error: @TLSDESC operator cannot be used with `add'
> +.*:20: Error: @TLSDESC operator requires `%rip' as base register
> +.*:21: Error: @TLSDESC operator requires REX prefix in x32 mode
> +.*:24: Error: @GOTTPOFF operator cannot be used with `sub'
> +.*:25: Error: @GOTTPOFF operator cannot be used with `xor'
> +.*:26: Error: @GOTTPOFF operator requires `%rip' as base register
> +.*:27: Error: @GOTTPOFF operator requires `%rip' as base register
> +.*:30: Error: @TLSCALL operator cannot be used with `lea'
> +.*:31: Error: @TLSCALL operator requires `%eax/rax' as base register
> +.*:31: Error: 0-byte relocation cannot be applied to 4-byte field
> diff --git a/gas/testsuite/gas/i386/x86-64-inval-tls.s b/gas/testsuite/gas/i386/x86-64-inval-tls.s
> index 71e19272ba9..66e3d9038af 100644
> --- a/gas/testsuite/gas/i386/x86-64-inval-tls.s
> +++ b/gas/testsuite/gas/i386/x86-64-inval-tls.s
> @@ -2,3 +2,30 @@
>  # All the following should be illegal
>         kmovq   foo@gottpoff(%rip), %k0
>         kmovq   foo@tlsld(%rip), %k0
> +
> +       /* Invalid testcase for BFD_RELOC_X86_64_TLSGD.  */
> +       addq foo@tlsgd(%rip), %rdi
> +       leaq foo@tlsgd(%rip), %rax
> +       leaq foo@tlsgd(%rax), %rdi
> +       leaq foo@tlsgd(,%rax,1), %rdi
> +
> +       /* Invalid testcase for BFD_RELOC_X86_64_TLSLD.  */
> +       addq foo@tlsld(%rip), %rdi
> +       leaq foo@tlsld(%rip), %rax
> +       leaq foo@tlsld(%rax), %rdi
> +       leaq foo@tlsld(,%rax,1), %rdi
> +
> +       /* Invalid testcase for BFD_RELOC_X86_64_GOTPC32_TLSDESC.  */
> +       addq x@tlsdesc(%rip), %rax
> +       leaq x@tlsdesc(%rbx), %rax
> +       leal x@tlsdesc(%rip), %eax
> +
> +       /* Invalid testcase for BFD_RELOC_X86_64_GOTTPOFF.  */
> +       subq foo@gottpoff(%rip), %r12
> +       xorq foo@gottpoff(%rip), %rax
> +       movq foo@gottpoff(%rbx), %rax
> +       addq foo@gottpoff(%rbx), %rax
> +
> +       /* Invalid testcase for BFD_RELOC_X86_64_TLSDESC_CALL.  */
> +       leaq foo@tlscall(%rax), %rbx
> +       call *foo@tlscall(%rip)
> 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..0bceeb63d94
> --- /dev/null
> +++ b/gas/testsuite/gas/i386/x86-64-tls.d
> @@ -0,0 +1,31 @@
> +#as:
> +#objdump: -drw
> +#name: Check tls relocation x86-64
> +
> +.*: +file format .*
> +
> +
> +Disassembly of section .text:
> +
> +0000000000000000 <_start>:
> +\s*[a-f0-9]+:\s*48 8d 3d 00 00 00 00   lea    0x0\(%rip\),%rdi        # 7 <_start\+0x7>        3: R_X86_64_TLSGD       foo-0x4
> +\s*[a-f0-9]+:\s*48 8d 3d 00 00 00 00   lea    0x0\(%rip\),%rdi        # e <_start\+0xe>        a: R_X86_64_TLSLD       foo-0x4
> +\s*[a-f0-9]+:\s*48 8d 05 00 00 00 00   lea    0x0\(%rip\),%rax        # 15 <_start\+0x15>      11: R_X86_64_GOTPC32_TLSDESC    x-0x4
> +\s*[a-f0-9]+:\s*40 8d 05 00 00 00 00   rex lea 0x0\(%rip\),%eax        # 1c <_start\+0x1c>     18: R_X86_64_GOTPC32_TLSDESC    x-0x4
> +\s*[a-f0-9]+:\s*40 8d 05 00 00 00 00   rex lea 0x0\(%rip\),%eax        # 23 <_start\+0x23>     1f: R_X86_64_GOTPC32_TLSDESC    x-0x4
> +\s*[a-f0-9]+:\s*d5 00 8d 05 00 00 00 00        \{rex2 0x0\} lea 0x0\(%rip\),%eax        # 2b <_start\+0x2b>    27: R_X86_64_CODE_4_GOTPC32_TLSDESC     x-0x4
> +\s*[a-f0-9]+:\s*d5 40 8d 05 00 00 00 00        lea    0x0\(%rip\),%r16d        # 33 <_start\+0x33>     2f: R_X86_64_CODE_4_GOTPC32_TLSDESC     x-0x4
> +\s*[a-f0-9]+:\s*4c 03 25 00 00 00 00   add    0x0\(%rip\),%r12        # 3a <_start\+0x3a>      36: R_X86_64_GOTTPOFF   foo-0x4
> +\s*[a-f0-9]+:\s*48 8b 05 00 00 00 00   mov    0x0\(%rip\),%rax        # 41 <_start\+0x41>      3d: R_X86_64_GOTTPOFF   foo-0x4
> +\s*[a-f0-9]+:\s*44 03 25 00 00 00 00   add    0x0\(%rip\),%r12d        # 48 <_start\+0x48>     44: R_X86_64_GOTTPOFF   foo-0x4
> +\s*[a-f0-9]+:\s*8b 05 00 00 00 00      mov    0x0\(%rip\),%eax        # 4e <_start\+0x4e>      4a: R_X86_64_GOTTPOFF   foo-0x4
> +\s*[a-f0-9]+:\s*d5 48 03 05 00 00 00 00        add    0x0\(%rip\),%r16        # 56 <_start\+0x56>      52: R_X86_64_CODE_4_GOTTPOFF    foo-0x4
> +\s*[a-f0-9]+:\s*d5 48 8b 25 00 00 00 00        mov    0x0\(%rip\),%r20        # 5e <_start\+0x5e>      5a: R_X86_64_CODE_4_GOTTPOFF    foo-0x4
> +\s*[a-f0-9]+:\s*62 64 bc 18 01 35 00 00 00 00  add    %r30,0x0\(%rip\),%r8        # 68 <_start\+0x68>  64: R_X86_64_CODE_6_GOTTPOFF    foo-0x4
> +\s*[a-f0-9]+:\s*62 f4 dc 10 03 05 00 00 00 00  add    0x0\(%rip\),%rax,%r20        # 72 <_start\+0x72> 6e: R_X86_64_CODE_6_GOTTPOFF    foo-0x4
> +\s*[a-f0-9]+:\s*62 e4 fc 0c 03 05 00 00 00 00  {nf} add 0x0\(%rip\),%r16        # 7c <_start\+0x7c>    78: R_X86_64_CODE_6_GOTTPOFF    foo-0x4
> +\s*[a-f0-9]+:\s*62 64 bc 1c 01 35 00 00 00 00  {nf} add %r30,0x0\(%rip\),%r8        # 86 <_start\+0x86>        82: R_X86_64_CODE_6_GOTTPOFF    foo-0x4
> +\s*[a-f0-9]+:\s*62 f4 dc 14 03 05 00 00 00 00  {nf} add 0x0\(%rip\),%rax,%r20        # 90 <_start\+0x90>       8c: R_X86_64_CODE_6_GOTTPOFF    foo-0x4
> +\s*[a-f0-9]+:\s*ff 10                  call   \*\(%rax\)       90: R_X86_64_TLSDESC_CALL       x
> +\s*[a-f0-9]+:\s*67 ff 10               call   \*\(%eax\)       92: 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..94bcb0af4e7
> --- /dev/null
> +++ b/gas/testsuite/gas/i386/x86-64-tls.s
> @@ -0,0 +1,33 @@
> +# Check tls relocation 64-bit mode
> +
> +       .text
> +_start:
> +       /* BFD_RELOC_X86_64_TLSGD.  */
> +       leaq foo@tlsgd(%rip), %rdi
> +
> +       /* BFD_RELOC_X86_64_TLSLD.  */
> +       leaq foo@tlsld(%rip), %rdi
> +
> +       /* BFD_RELOC_X86_64_GOTPC32_TLSDESC.  */
> +       leaq     x@tlsdesc(%rip), %rax
> +       rex leal x@tlsdesc(%rip), %eax
> +       {rex} leal x@tlsdesc(%rip), %eax
> +       {rex2} leal x@tlsdesc(%rip), %eax
> +       leal     x@tlsdesc(%rip), %r16d
> +
> +       /* BFD_RELOC_X86_64_GOTTPOFF.  */
> +       addq     foo@gottpoff(%rip), %r12
> +       movq     foo@gottpoff(%rip), %rax
> +       addl     foo@gottpoff(%rip), %r12d
> +       movl     foo@gottpoff(%rip), %eax
> +       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
> +
> +       /* BFD_RELOC_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
>

I am en closing changes here.

-- 
H.J.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-Update-x86-Add-tls-check-in-gas.patch
Type: text/x-patch
Size: 5135 bytes
Desc: not available
URL: <https://sourceware.org/pipermail/binutils/attachments/20240918/3d982b3b/attachment-0001.bin>


More information about the Binutils mailing list