-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[ELF] Reject certain unknown section types #85173
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ELF] Reject certain unknown section types #85173
Conversation
Created using spr 1.3.5-bogner
@llvm/pr-subscribers-lld Author: Fangrui Song (MaskRay) ChangesUnknown section sections may require special linking rule, and rejecting
but reports errors and stops linking for others (unless Close #84812 Full diff: https://github.com/llvm/llvm-project/pull/85173.diff 7 Files Affected:
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 9ae01eb90fa4a3..6c46249c528718 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -273,6 +273,7 @@ struct Config {
bool printGcSections;
bool printIcfSections;
bool printMemoryUsage;
+ bool rejectMismatch;
bool relax;
bool relaxGP;
bool relocatable;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 2439d141fb6643..e7160a47bd2142 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -1348,6 +1348,7 @@ static void readConfigs(opt::InputArgList &args) {
config->printArchiveStats = args.getLastArgValue(OPT_print_archive_stats);
config->printSymbolOrder =
args.getLastArgValue(OPT_print_symbol_order);
+ config->rejectMismatch = !args.hasArg(OPT_no_warn_mismatch);
config->relax = args.hasFlag(OPT_relax, OPT_no_relax, true);
config->relaxGP = args.hasFlag(OPT_relax_gp, OPT_no_relax_gp, false);
config->rpath = getRpath(args);
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index 00aebb47640e84..ad022c9685f716 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -741,6 +741,31 @@ template <class ELFT> void ObjFile<ELFT>::initializeJustSymbols() {
sections.resize(numELFShdrs);
}
+static bool isKnownSpecificSectionType(uint32_t t, uint32_t flags) {
+ if (SHT_LOUSER <= t && t <= SHT_HIUSER && !(flags & SHF_ALLOC))
+ return true;
+ if (SHT_LOOS <= t && t <= SHT_HIOS && !(flags & SHF_OS_NONCONFORMING))
+ return true;
+ switch (config->emachine) {
+ case EM_ARM:
+ return t == SHT_ARM_EXIDX || t == SHT_ARM_ATTRIBUTES;
+ case EM_AARCH64:
+ return t == SHT_AARCH64_MEMTAG_GLOBALS_STATIC;
+ case EM_MIPS:
+ return is_contained(
+ {SHT_MIPS_REGINFO, SHT_MIPS_OPTIONS, SHT_MIPS_DWARF, SHT_MIPS_ABIFLAGS},
+ t);
+ case EM_MSP430:
+ return t == SHT_MSP430_ATTRIBUTES;
+ case EM_RISCV:
+ return t == SHT_RISCV_ATTRIBUTES;
+ case EM_X86_64:
+ return t == SHT_X86_64_UNWIND;
+ default:
+ return false;
+ }
+}
+
template <class ELFT>
void ObjFile<ELFT>::initializeSections(bool ignoreComdats,
const llvm::object::ELFFile<ELFT> &obj) {
@@ -752,14 +777,15 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats,
if (this->sections[i] == &InputSection::discarded)
continue;
const Elf_Shdr &sec = objSections[i];
+ const uint32_t type = sec.sh_type;
// SHF_EXCLUDE'ed sections are discarded by the linker. However,
// if -r is given, we'll let the final link discard such sections.
// This is compatible with GNU.
if ((sec.sh_flags & SHF_EXCLUDE) && !config->relocatable) {
- if (sec.sh_type == SHT_LLVM_CALL_GRAPH_PROFILE)
+ if (type == SHT_LLVM_CALL_GRAPH_PROFILE)
cgProfileSectionIndex = i;
- if (sec.sh_type == SHT_LLVM_ADDRSIG) {
+ if (type == SHT_LLVM_ADDRSIG) {
// We ignore the address-significance table if we know that the object
// file was created by objcopy or ld -r. This is because these tools
// will reorder the symbols in the symbol table, invalidating the data
@@ -778,7 +804,7 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats,
continue;
}
- switch (sec.sh_type) {
+ switch (type) {
case SHT_GROUP: {
if (!config->relocatable)
sections[i] = &InputSection::discarded;
@@ -801,12 +827,25 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats,
case SHT_RELA:
case SHT_NULL:
break;
- case SHT_LLVM_SYMPART:
- ctx.hasSympart.store(true, std::memory_order_relaxed);
- [[fallthrough]];
+ case SHT_PROGBITS:
+ case SHT_NOTE:
+ case SHT_NOBITS:
+ case SHT_INIT_ARRAY:
+ case SHT_FINI_ARRAY:
+ case SHT_PREINIT_ARRAY:
+ this->sections[i] =
+ createInputSection(i, sec, check(obj.getSectionName(sec, shstrtab)));
+ break;
default:
this->sections[i] =
createInputSection(i, sec, check(obj.getSectionName(sec, shstrtab)));
+ if (type == SHT_LLVM_SYMPART)
+ ctx.hasSympart.store(true, std::memory_order_relaxed);
+ else if (config->rejectMismatch &&
+ !isKnownSpecificSectionType(type, sec.sh_flags))
+ errorOrWarn(toString(this->sections[i]) + ": unknown section type 0x" +
+ Twine::utohexstr(type));
+ break;
}
}
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index 3819b86238ea64..c5e95d0d25c1ae 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -312,6 +312,9 @@ def no_dynamic_linker: F<"no-dynamic-linker">,
def noinhibit_exec: F<"noinhibit-exec">,
HelpText<"Retain the executable output file whenever it is still usable">;
+def no_warn_mismatch: F<"no-warn-mismatch">,
+ HelpText<"Suppress errors for certain unknown seciton types">;
+
def no_nmagic: F<"no-nmagic">, MetaVarName<"<magic>">,
HelpText<"Page align sections (default)">;
@@ -753,7 +756,6 @@ def: FF<"no-add-needed">;
def: F<"no-copy-dt-needed-entries">;
def: F<"no-ctors-in-init-array">;
def: F<"no-keep-memory">;
-def: F<"no-warn-mismatch">;
def: Separate<["--", "-"], "rpath-link">;
def: J<"rpath-link=">;
def: F<"secure-plt">;
diff --git a/lld/test/ELF/incompatible-section-types2.s b/lld/test/ELF/incompatible-section-types2.s
index 3e281ce6c5da38..919515fe37e396 100644
--- a/lld/test/ELF/incompatible-section-types2.s
+++ b/lld/test/ELF/incompatible-section-types2.s
@@ -6,5 +6,5 @@
// CHECK-NEXT: >>> <internal>:(.shstrtab): SHT_STRTAB
// CHECK-NEXT: >>> output section .shstrtab: Unknown
-.section .shstrtab,"",@12345
+.section .shstrtab,"",@0x60000000
.short 20
diff --git a/lld/test/ELF/linkerscript/custom-section-type.s b/lld/test/ELF/linkerscript/custom-section-type.s
index 68454f4df1c860..8ca0a4db325bda 100644
--- a/lld/test/ELF/linkerscript/custom-section-type.s
+++ b/lld/test/ELF/linkerscript/custom-section-type.s
@@ -76,7 +76,7 @@ SECTIONS {
.section progbits,"a",@note
.byte 0
-.section expr,"a",@12345
+.section expr,"a",@0x60000000
.byte 0
#--- unknown1.lds
diff --git a/lld/test/ELF/unknown-section.test b/lld/test/ELF/unknown-section.test
new file mode 100644
index 00000000000000..7cca5e913c3c0f
--- /dev/null
+++ b/lld/test/ELF/unknown-section.test
@@ -0,0 +1,50 @@
+# RUN: rm -rf %t && mkdir %t && cd %t
+# RUN: yaml2obj %s -o a.o
+# RUN: not ld.lld a.o -o /dev/null 2>&1 | FileCheck %s --implicit-check-not=error:
+
+# CHECK: error: a.o:(relr): unknown section type 0x13
+# CHECK-NEXT: error: a.o:(regular): unknown section type 0x15
+# CHECK-NEXT: error: a.o:(loos_nonconforming): unknown section type 0x60000000
+# CHECK-NEXT: error: a.o:(hios_nonconforming): unknown section type 0x6fffffff
+# CHECK-NEXT: error: a.o:(loproc): unknown section type 0x70000000
+# CHECK-NEXT: error: a.o:(hiproc): unknown section type 0x7fffffff
+# CHECK-NEXT: error: a.o:(louser_alloc): unknown section type 0x80000000
+# CHECK-NEXT: error: a.o:(hiuser_alloc): unknown section type 0xffffffff
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: relr
+ Type: 19
+ - Name: regular
+ Type: 21
+ - Name: loos
+ Type: 0x60000000
+ - Name: hios
+ Type: 0x6fffffff
+ - Name: loos_nonconforming
+ Type: 0x60000000
+ Flags: [ SHF_OS_NONCONFORMING ]
+ - Name: hios_nonconforming
+ Type: 0x6fffffff
+ Flags: [ SHF_OS_NONCONFORMING ]
+
+ - Name: loproc
+ Type: 0x70000000
+ - Name: hiproc
+ Type: 0x7fffffff
+
+ - Name: louser
+ Type: 0x80000000
+ - Name: hiuser
+ Type: 0xffffffff
+ - Name: louser_alloc
+ Type: 0x80000000
+ Flags: [ SHF_ALLOC ]
+ - Name: hiuser_alloc
+ Type: 0xffffffff
+ Flags: [ SHF_ALLOC ]
|
@llvm/pr-subscribers-lld-elf Author: Fangrui Song (MaskRay) ChangesUnknown section sections may require special linking rule, and rejecting
but reports errors and stops linking for others (unless Close #84812 Full diff: https://github.com/llvm/llvm-project/pull/85173.diff 7 Files Affected:
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 9ae01eb90fa4a3..6c46249c528718 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -273,6 +273,7 @@ struct Config {
bool printGcSections;
bool printIcfSections;
bool printMemoryUsage;
+ bool rejectMismatch;
bool relax;
bool relaxGP;
bool relocatable;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 2439d141fb6643..e7160a47bd2142 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -1348,6 +1348,7 @@ static void readConfigs(opt::InputArgList &args) {
config->printArchiveStats = args.getLastArgValue(OPT_print_archive_stats);
config->printSymbolOrder =
args.getLastArgValue(OPT_print_symbol_order);
+ config->rejectMismatch = !args.hasArg(OPT_no_warn_mismatch);
config->relax = args.hasFlag(OPT_relax, OPT_no_relax, true);
config->relaxGP = args.hasFlag(OPT_relax_gp, OPT_no_relax_gp, false);
config->rpath = getRpath(args);
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index 00aebb47640e84..ad022c9685f716 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -741,6 +741,31 @@ template <class ELFT> void ObjFile<ELFT>::initializeJustSymbols() {
sections.resize(numELFShdrs);
}
+static bool isKnownSpecificSectionType(uint32_t t, uint32_t flags) {
+ if (SHT_LOUSER <= t && t <= SHT_HIUSER && !(flags & SHF_ALLOC))
+ return true;
+ if (SHT_LOOS <= t && t <= SHT_HIOS && !(flags & SHF_OS_NONCONFORMING))
+ return true;
+ switch (config->emachine) {
+ case EM_ARM:
+ return t == SHT_ARM_EXIDX || t == SHT_ARM_ATTRIBUTES;
+ case EM_AARCH64:
+ return t == SHT_AARCH64_MEMTAG_GLOBALS_STATIC;
+ case EM_MIPS:
+ return is_contained(
+ {SHT_MIPS_REGINFO, SHT_MIPS_OPTIONS, SHT_MIPS_DWARF, SHT_MIPS_ABIFLAGS},
+ t);
+ case EM_MSP430:
+ return t == SHT_MSP430_ATTRIBUTES;
+ case EM_RISCV:
+ return t == SHT_RISCV_ATTRIBUTES;
+ case EM_X86_64:
+ return t == SHT_X86_64_UNWIND;
+ default:
+ return false;
+ }
+}
+
template <class ELFT>
void ObjFile<ELFT>::initializeSections(bool ignoreComdats,
const llvm::object::ELFFile<ELFT> &obj) {
@@ -752,14 +777,15 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats,
if (this->sections[i] == &InputSection::discarded)
continue;
const Elf_Shdr &sec = objSections[i];
+ const uint32_t type = sec.sh_type;
// SHF_EXCLUDE'ed sections are discarded by the linker. However,
// if -r is given, we'll let the final link discard such sections.
// This is compatible with GNU.
if ((sec.sh_flags & SHF_EXCLUDE) && !config->relocatable) {
- if (sec.sh_type == SHT_LLVM_CALL_GRAPH_PROFILE)
+ if (type == SHT_LLVM_CALL_GRAPH_PROFILE)
cgProfileSectionIndex = i;
- if (sec.sh_type == SHT_LLVM_ADDRSIG) {
+ if (type == SHT_LLVM_ADDRSIG) {
// We ignore the address-significance table if we know that the object
// file was created by objcopy or ld -r. This is because these tools
// will reorder the symbols in the symbol table, invalidating the data
@@ -778,7 +804,7 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats,
continue;
}
- switch (sec.sh_type) {
+ switch (type) {
case SHT_GROUP: {
if (!config->relocatable)
sections[i] = &InputSection::discarded;
@@ -801,12 +827,25 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats,
case SHT_RELA:
case SHT_NULL:
break;
- case SHT_LLVM_SYMPART:
- ctx.hasSympart.store(true, std::memory_order_relaxed);
- [[fallthrough]];
+ case SHT_PROGBITS:
+ case SHT_NOTE:
+ case SHT_NOBITS:
+ case SHT_INIT_ARRAY:
+ case SHT_FINI_ARRAY:
+ case SHT_PREINIT_ARRAY:
+ this->sections[i] =
+ createInputSection(i, sec, check(obj.getSectionName(sec, shstrtab)));
+ break;
default:
this->sections[i] =
createInputSection(i, sec, check(obj.getSectionName(sec, shstrtab)));
+ if (type == SHT_LLVM_SYMPART)
+ ctx.hasSympart.store(true, std::memory_order_relaxed);
+ else if (config->rejectMismatch &&
+ !isKnownSpecificSectionType(type, sec.sh_flags))
+ errorOrWarn(toString(this->sections[i]) + ": unknown section type 0x" +
+ Twine::utohexstr(type));
+ break;
}
}
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index 3819b86238ea64..c5e95d0d25c1ae 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -312,6 +312,9 @@ def no_dynamic_linker: F<"no-dynamic-linker">,
def noinhibit_exec: F<"noinhibit-exec">,
HelpText<"Retain the executable output file whenever it is still usable">;
+def no_warn_mismatch: F<"no-warn-mismatch">,
+ HelpText<"Suppress errors for certain unknown seciton types">;
+
def no_nmagic: F<"no-nmagic">, MetaVarName<"<magic>">,
HelpText<"Page align sections (default)">;
@@ -753,7 +756,6 @@ def: FF<"no-add-needed">;
def: F<"no-copy-dt-needed-entries">;
def: F<"no-ctors-in-init-array">;
def: F<"no-keep-memory">;
-def: F<"no-warn-mismatch">;
def: Separate<["--", "-"], "rpath-link">;
def: J<"rpath-link=">;
def: F<"secure-plt">;
diff --git a/lld/test/ELF/incompatible-section-types2.s b/lld/test/ELF/incompatible-section-types2.s
index 3e281ce6c5da38..919515fe37e396 100644
--- a/lld/test/ELF/incompatible-section-types2.s
+++ b/lld/test/ELF/incompatible-section-types2.s
@@ -6,5 +6,5 @@
// CHECK-NEXT: >>> <internal>:(.shstrtab): SHT_STRTAB
// CHECK-NEXT: >>> output section .shstrtab: Unknown
-.section .shstrtab,"",@12345
+.section .shstrtab,"",@0x60000000
.short 20
diff --git a/lld/test/ELF/linkerscript/custom-section-type.s b/lld/test/ELF/linkerscript/custom-section-type.s
index 68454f4df1c860..8ca0a4db325bda 100644
--- a/lld/test/ELF/linkerscript/custom-section-type.s
+++ b/lld/test/ELF/linkerscript/custom-section-type.s
@@ -76,7 +76,7 @@ SECTIONS {
.section progbits,"a",@note
.byte 0
-.section expr,"a",@12345
+.section expr,"a",@0x60000000
.byte 0
#--- unknown1.lds
diff --git a/lld/test/ELF/unknown-section.test b/lld/test/ELF/unknown-section.test
new file mode 100644
index 00000000000000..7cca5e913c3c0f
--- /dev/null
+++ b/lld/test/ELF/unknown-section.test
@@ -0,0 +1,50 @@
+# RUN: rm -rf %t && mkdir %t && cd %t
+# RUN: yaml2obj %s -o a.o
+# RUN: not ld.lld a.o -o /dev/null 2>&1 | FileCheck %s --implicit-check-not=error:
+
+# CHECK: error: a.o:(relr): unknown section type 0x13
+# CHECK-NEXT: error: a.o:(regular): unknown section type 0x15
+# CHECK-NEXT: error: a.o:(loos_nonconforming): unknown section type 0x60000000
+# CHECK-NEXT: error: a.o:(hios_nonconforming): unknown section type 0x6fffffff
+# CHECK-NEXT: error: a.o:(loproc): unknown section type 0x70000000
+# CHECK-NEXT: error: a.o:(hiproc): unknown section type 0x7fffffff
+# CHECK-NEXT: error: a.o:(louser_alloc): unknown section type 0x80000000
+# CHECK-NEXT: error: a.o:(hiuser_alloc): unknown section type 0xffffffff
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: relr
+ Type: 19
+ - Name: regular
+ Type: 21
+ - Name: loos
+ Type: 0x60000000
+ - Name: hios
+ Type: 0x6fffffff
+ - Name: loos_nonconforming
+ Type: 0x60000000
+ Flags: [ SHF_OS_NONCONFORMING ]
+ - Name: hios_nonconforming
+ Type: 0x6fffffff
+ Flags: [ SHF_OS_NONCONFORMING ]
+
+ - Name: loproc
+ Type: 0x70000000
+ - Name: hiproc
+ Type: 0x7fffffff
+
+ - Name: louser
+ Type: 0x80000000
+ - Name: hiuser
+ Type: 0xffffffff
+ - Name: louser_alloc
+ Type: 0x80000000
+ Flags: [ SHF_ALLOC ]
+ - Name: hiuser_alloc
+ Type: 0xffffffff
+ Flags: [ SHF_ALLOC ]
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will be good to see if we can get some comments from people interested in their SHT_LOPROC SHT_HIPROC range.
lld/ELF/InputFiles.cpp
Outdated
case EM_ARM: | ||
return t == SHT_ARM_EXIDX || t == SHT_ARM_ATTRIBUTES; | ||
case EM_AARCH64: | ||
return t == SHT_AARCH64_MEMTAG_GLOBALS_STATIC; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GNU ld will accept SHT_AARCH64_ATTRIBUTES in AArch64 too. This is reserved for the spec and can be ignored if a linker does not understand the contents. It would be useful to add this so that when SHT_AARCH64_ATTRIBUTES is added lld doesn't choke on them.
This may be the case for other LOPROC/HIPROC values that lld doesn't currently understand, but I'm only familiar with Arm and AArch64.
Of the ones in AArch64 there is also SHT_AARCH64_AUTH_RELR
defined in https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#7section-types
I know there is a pull-request to add LLD support for that. May be worth adding as a constant until the symbolic value is known.
The other section types in https://github.com/ARM-software/abi-aa/blob/main/aaelf32/aaelf32.rst not implemented by LLD don't need to be added as these are linker generated sections for the benefit of debuggers/post-link tools.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. Sounds good to allow SHT_AARCH64_ATTRIBUTES as well even if it is unused now.
SHT_AARCH64_AUTH_RELR is for dynamic relocations only, so rejecting it here is fine. The test has a SHT_RELR example.
Shall we just allow all processor-specific relocation types?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's an interesting question. It is a pity there isn't a SHF_PROC_NONCONFORMING
flag that would make this easier to reason about.
I think allowing processor section types would be an easier way to introduce this patch as it wouldn't need all the processor specific looked over, which may be difficult to do. Perhaps start with it this way, then as we get more information we could perhaps limit to the section types that we know exist in the specifications.
I know at Arm we are reluctant to introduce new section types because of the problem of older, and other proprietary linkers, that may not want to suppport them. I expect many other processor namespace ABIs think similarly.
Created using spr 1.3.5-bogner
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM from me. I think we can optionally tighten up the processor specific section in a follow up patch.
Thanks for the additional context. My motivation was primarily to detect new section types in the generic range I agree that we can optionally tighten up the processor specific section in a follow up patch. I think certain architectures probably don't want the old-linker-detecting behavior ("time travel compatibility"). So we might not want to introduce the behavior. |
Unknown section sections may require special linking rules, and
rejecting such sections for older linkers may be desired. For example,
if we introduce a new section type to replace a control structure (e.g.
relocations), it would be nice for older linkers to reject the new
section type. GNU ld allows certain unknown section types:
but reports errors and stops linking for others (unless
--no-warn-mismatch is specified). Port its behavior. For convenience, we
additionally allow all [SHT_LOPROC,SHT_HIPROC] types so that we don't
have to hard code all known types for each processor.
Close #84812