From 3385bc7a3511d1c920a7286010cb66696bce2c35 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Thu, 30 Jul 2026 13:43:56 +0800
Subject: [PATCH v2] x86: Check invalid GOT/PLT/TLS relocations
1. Since non-alloc sections aren't checked for TLS, GOT and PLT usages,
relocate_section should issue error for TLS, GOT and PLT relocations in
non-alloc and non-debugging sections.
2. Since TLS relocations must be against thread local symbols, scan_relocs
should issue an error for TLS relocation against non-thread local symbol.
PR ld/34444
PR ld/34448
* elf32-i386.c (elf_i386_tls_transition): Replace
_bfd_x86_elf_link_report_tls_invalid_section_error with
_bfd_x86_elf_link_report_error.
(elf_i386_scan_relocs): Issue an error for TLS relocation against
non-thread local symbol.
(elf_i386_relocate_section): Issue error for TLS, GOT and PLT
relocations in non-alloc and non-debugging sections.
* elf64-x86-64.c (elf_x86_64_tls_transition): Replace
_bfd_x86_elf_link_report_tls_invalid_section_error with
_bfd_x86_elf_link_report_error.
(elf_x86_64_scan_relocs): Issue an error for TLS relocation
against non-thread local symbol.
* elfxx-x86.c (_bfd_x86_elf_link_report_tls_invalid_section_error):
Renamed to ...
(_bfd_x86_elf_link_report_error): This. Add an argument for
link error type and handle it.
* elfxx-x86.h (elf_x86_error_type): New enum.
(_bfd_x86_elf_link_report_tls_invalid_section_error): Renamed
to ...
(_bfd_x86_elf_link_report_error): This. Add an argument of
enum elf_x86_error_type.
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
---
bfd/elf32-i386.c | 50 ++++++++++++++++++++++++++++++++++++++-----
bfd/elf64-x86-64.c | 53 +++++++++++++++++++++++++++++++++++++++++-----
bfd/elfxx-x86.c | 53 ++++++++++++++++++++++++++++++++++++++--------
bfd/elfxx-x86.h | 11 ++++++++--
4 files changed, 146 insertions(+), 21 deletions(-)
@@ -1175,8 +1175,8 @@ elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd,
|| (sec->flags & SEC_CODE) == 0))
{
reloc_howto_type *howto = elf_i386_rtype_to_howto (from_type);
- _bfd_x86_elf_link_report_tls_invalid_section_error
- (abfd, sec, symtab_hdr, h, sym, howto);
+ _bfd_x86_elf_link_report_error (abfd, sec, symtab_hdr, h, sym,
+ howto, elf_x86_error_tls);
return false;
}
@@ -1749,11 +1749,15 @@ elf_i386_scan_relocs (bfd *abfd,
if (tls_type >= GOT_TLS_GD
&& tls_type <= GOT_TLS_GDESC
- && (elf_section_type (sec) != SHT_PROGBITS
+ && ((h != NULL
+ ? h->type != STT_TLS
+ : ELF_ST_TYPE (isym->st_info) != STT_TLS)
+ || elf_section_type (sec) != SHT_PROGBITS
|| (sec->flags & SEC_CODE) == 0))
{
- _bfd_x86_elf_link_report_tls_invalid_section_error
- (abfd, sec, symtab_hdr, h, isym, howto);
+ _bfd_x86_elf_link_report_error (abfd, sec, symtab_hdr,
+ h, isym, howto,
+ elf_x86_error_tls);
goto error_return;
}
@@ -2585,6 +2589,18 @@ elf_i386_relocate_section (struct bfd_link_info *info,
{
case R_386_GOT32X:
case R_386_GOT32:
+ /* Since we don't allow non-alloced sections to create GOT/PLT
+ entries, issue an error if a non-alloced section references
+ GOT. */
+ if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+ {
+ non_alloc_error:
+ _bfd_x86_elf_link_report_error (input_bfd, input_section,
+ symtab_hdr, h, sym, howto,
+ elf_x86_error_non_alloc);
+ return false;
+ }
+
/* Relocation is to the entry for this symbol in the global
offset table. */
if (htab->elf.sgot == NULL)
@@ -2717,6 +2733,9 @@ elf_i386_relocate_section (struct bfd_link_info *info,
break;
case R_386_GOTOFF:
+ if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+ goto non_alloc_error;
+
/* Relocation is relative to the start of the global offset
table. */
@@ -2781,6 +2800,9 @@ elf_i386_relocate_section (struct bfd_link_info *info,
break;
case R_386_GOTPC:
+ if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+ goto non_alloc_error;
+
/* Use global offset table as symbol value. */
relocation = htab->elf.sgotplt->output_section->vma
+ htab->elf.sgotplt->output_offset;
@@ -2788,6 +2810,9 @@ elf_i386_relocate_section (struct bfd_link_info *info,
break;
case R_386_PLT32:
+ if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+ goto non_alloc_error;
+
/* Relocation is to the entry for this symbol in the
procedure linkage table. */
@@ -2915,6 +2940,9 @@ elf_i386_relocate_section (struct bfd_link_info *info,
break;
case R_386_TLS_IE:
+ if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+ goto non_alloc_error;
+
if (!bfd_link_executable (info))
{
Elf_Internal_Rela outrel;
@@ -2942,6 +2970,9 @@ elf_i386_relocate_section (struct bfd_link_info *info,
case R_386_TLS_DESC_CALL:
case R_386_TLS_IE_32:
case R_386_TLS_GOTIE:
+ if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+ goto non_alloc_error;
+
tls_type = GOT_UNKNOWN;
if (h == NULL && local_got_offsets)
tls_type = elf_x86_local_got_tls_type (input_bfd) [r_symndx];
@@ -3440,6 +3471,9 @@ elf_i386_relocate_section (struct bfd_link_info *info,
break;
case R_386_TLS_LDM:
+ if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+ goto non_alloc_error;
+
if (! elf_i386_tls_transition (info, input_bfd,
input_section, contents,
symtab_hdr, sym_hashes,
@@ -3512,6 +3546,9 @@ elf_i386_relocate_section (struct bfd_link_info *info,
break;
case R_386_TLS_LDO_32:
+ if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+ goto non_alloc_error;
+
if (!bfd_link_executable (info)
|| (input_section->flags & SEC_CODE) == 0)
relocation -= _bfd_x86_elf_dtpoff_base (info);
@@ -3522,6 +3559,9 @@ elf_i386_relocate_section (struct bfd_link_info *info,
case R_386_TLS_LE_32:
case R_386_TLS_LE:
+ if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+ goto non_alloc_error;
+
if (!bfd_link_executable (info))
{
Elf_Internal_Rela outrel;
@@ -1633,8 +1633,8 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
{
reloc_howto_type *howto = elf_x86_64_rtype_to_howto (abfd,
from_type);
- _bfd_x86_elf_link_report_tls_invalid_section_error
- (abfd, sec, symtab_hdr, h, sym, howto);
+ _bfd_x86_elf_link_report_error (abfd, sec, symtab_hdr, h,
+ sym, howto, elf_x86_error_tls);
return false;
}
@@ -2772,11 +2772,15 @@ need_got:
if (tls_type >= GOT_TLS_GD
&& tls_type <= GOT_TLS_GDESC
- && (elf_section_type (sec) != SHT_PROGBITS
+ && ((h != NULL
+ ? h->type != STT_TLS
+ : ELF_ST_TYPE (isym->st_info) != STT_TLS)
+ || elf_section_type (sec) != SHT_PROGBITS
|| (sec->flags & SEC_CODE) == 0))
{
- _bfd_x86_elf_link_report_tls_invalid_section_error
- (abfd, sec, symtab_hdr, h, isym, howto);
+ _bfd_x86_elf_link_report_error (abfd, sec, symtab_hdr,
+ h, isym, howto,
+ elf_x86_error_tls);
goto error_return;
}
@@ -3602,6 +3606,18 @@ elf_x86_64_relocate_section (struct bfd_link_info *info,
case R_X86_64_GOTPCREL64:
/* Use global offset table entry as symbol value. */
case R_X86_64_GOTPLT64:
+ /* Since we don't allow non-alloced sections to create GOT/PLT
+ entries, issue an error if a non-alloced section references
+ GOT. */
+ if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+ {
+ non_alloc_error:
+ _bfd_x86_elf_link_report_error (input_bfd, input_section,
+ symtab_hdr, h, sym, howto,
+ elf_x86_error_non_alloc);
+ return false;
+ }
+
/* This is obsolete and treated the same as GOT64. */
base_got = htab->elf.sgot;
@@ -3740,6 +3756,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *info,
break;
case R_X86_64_GOTOFF64:
+ if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+ goto non_alloc_error;
+
/* Relocation is relative to the start of the global offset
table. */
@@ -3806,6 +3825,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *info,
case R_X86_64_GOTPC32:
case R_X86_64_GOTPC64:
+ if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+ goto non_alloc_error;
+
/* Use global offset table as symbol value. */
relocation = htab->elf.sgotplt->output_section->vma
+ htab->elf.sgotplt->output_offset;
@@ -3813,6 +3835,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *info,
break;
case R_X86_64_PLTOFF64:
+ if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+ goto non_alloc_error;
+
/* Relocation is PLT entry relative to GOT. For local
symbols it's the symbol itself relative to GOT. */
if (h != NULL
@@ -3849,6 +3874,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *info,
break;
case R_X86_64_PLT32:
+ if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+ goto non_alloc_error;
+
/* Relocation is to the entry for this symbol in the
procedure linkage table. */
@@ -4157,6 +4185,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *info,
case R_X86_64_CODE_4_GOTTPOFF:
case R_X86_64_CODE_5_GOTTPOFF:
case R_X86_64_CODE_6_GOTTPOFF:
+ if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+ goto non_alloc_error;
+
tls_type = GOT_UNKNOWN;
if (h == NULL && local_got_offsets)
tls_type = elf_x86_local_got_tls_type (input_bfd) [r_symndx];
@@ -4883,6 +4914,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *info,
break;
case R_X86_64_TLSLD:
+ if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+ goto non_alloc_error;
+
if (! elf_x86_64_tls_transition (info, input_bfd,
input_section, contents,
symtab_hdr, sym_hashes,
@@ -5012,6 +5046,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *info,
break;
case R_X86_64_DTPOFF32:
+ if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+ goto non_alloc_error;
+
if (!bfd_link_executable (info)
|| (input_section->flags & SEC_CODE) == 0)
relocation -= _bfd_x86_elf_dtpoff_base (info);
@@ -5021,11 +5058,17 @@ elf_x86_64_relocate_section (struct bfd_link_info *info,
case R_X86_64_TPOFF32:
case R_X86_64_TPOFF64:
+ if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+ goto non_alloc_error;
+
BFD_ASSERT (bfd_link_executable (info));
relocation = elf_x86_64_tpoff (info, relocation);
break;
case R_X86_64_DTPOFF64:
+ if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+ goto non_alloc_error;
+
BFD_ASSERT ((input_section->flags & SEC_CODE) == 0);
relocation -= _bfd_x86_elf_dtpoff_base (info);
break;
@@ -3369,23 +3369,58 @@ _bfd_x86_elf_link_report_tls_transition_error
bfd_set_error (bfd_error_bad_value);
}
-/* Report TLS invalid section error. */
+/* Report link error. */
void
-_bfd_x86_elf_link_report_tls_invalid_section_error
+_bfd_x86_elf_link_report_error
(bfd *abfd, asection *sec, Elf_Internal_Shdr *symtab_hdr,
struct elf_link_hash_entry *h, Elf_Internal_Sym *sym,
- reloc_howto_type *howto)
+ reloc_howto_type *howto, enum elf_x86_error_type type)
{
const char *name;
+ bool non_thread_local;
if (h)
- name = h->root.root.string;
+ {
+ non_thread_local = h->type != STT_TLS;
+ name = h->root.root.string;
+ }
else
- name = bfd_elf_sym_name (abfd, symtab_hdr, sym, NULL);
- _bfd_error_handler
- /* xgettext:c-format */
- (_("%pB: relocation %s against thread local symbol `%s' in "
- "invalid section `%pA'"), abfd, howto->name, name, sec);
+ {
+ non_thread_local = ELF_ST_TYPE (sym->st_info) != STT_TLS;
+ name = bfd_elf_sym_name (abfd, symtab_hdr, sym, NULL);
+ if (name[0] == '\0')
+ name = "*unknown*";
+ }
+
+ switch (type)
+ {
+ case elf_x86_error_tls:
+ if (non_thread_local)
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: relocation %s against non-thread local symbol "
+ "`%s' in section `%pA'"),
+ abfd, howto->name, name, sec);
+ else
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: relocation %s against thread local symbol `%s' in "
+ "invalid section `%pA'"), abfd, howto->name, name, sec);
+ break;
+
+ case elf_x86_error_non_alloc:
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: relocation %s against symbol `%s' in non-alloc "
+ "section `%pA'"),
+ abfd, howto->name, name, sec);
+ break;
+
+ default:
+ abort ();
+ break;
+ }
+
bfd_set_error (bfd_error_bad_value);
}
@@ -794,6 +794,12 @@ enum elf_x86_tls_error_type
elf_x86_tls_error_yes
};
+enum elf_x86_error_type
+{
+ elf_x86_error_tls,
+ elf_x86_error_non_alloc
+};
+
/* Set if a relocation is converted from a GOTPCREL relocation. */
#define R_X86_64_converted_reloc_bit (1 << 7)
@@ -951,9 +957,10 @@ extern void _bfd_x86_elf_link_report_tls_transition_error
const Elf_Internal_Rela *, const char *, const char *,
enum elf_x86_tls_error_type) ATTRIBUTE_HIDDEN;
-extern void _bfd_x86_elf_link_report_tls_invalid_section_error
+extern void _bfd_x86_elf_link_report_error
(bfd *, asection *, Elf_Internal_Shdr *, struct elf_link_hash_entry *,
- Elf_Internal_Sym *, reloc_howto_type *) ATTRIBUTE_HIDDEN;
+ Elf_Internal_Sym *, reloc_howto_type *,
+ enum elf_x86_error_type) ATTRIBUTE_HIDDEN;
extern bool
_bfd_elf_x86_copy_special_section_fields
--
2.55.0