[lld] [lld][ELF] Enable link script to support absolute path matching (PR #156353)

via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 1 18:24:12 PDT 2025


https://github.com/mykouHW updated https://github.com/llvm/llvm-project/pull/156353

>From c9aa1c621aaa8d1774a142e0823b6dfcf9c379ec Mon Sep 17 00:00:00 2001
From: koumeiyuan <koumeiyuan at huawei.com>
Date: Mon, 25 Aug 2025 17:34:40 +0000
Subject: [PATCH] [lld][ELF] Enable link script to support absolute path
 matching

Fixing the vulnerability in LLVM lld regarding file matching in linker scripts:
There is a compatibility issue with filename matching. When input files use absolute paths, the matching results from mc lld do not meet expectations.
---
 lld/ELF/LinkerScript.cpp                   | 31 +++++++++---
 lld/ELF/LinkerScript.h                     |  2 +-
 lld/test/ELF/linkerscript/abs-path-match.s | 56 ++++++++++++++++++++++
 3 files changed, 81 insertions(+), 8 deletions(-)
 create mode 100644 lld/test/ELF/linkerscript/abs-path-match.s

diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index 921128dae2bdb..c325f18616fe3 100644
--- a/lld/ELF/LinkerScript.cpp
+++ b/lld/ELF/LinkerScript.cpp
@@ -411,7 +411,17 @@ void LinkerScript::assignSymbol(SymbolAssignment *cmd, bool inSec) {
   cmd->sym->type = v.type;
 }
 
-bool InputSectionDescription::matchesFile(const InputFile &file) const {
+// Convert an absolute address to a filename
+static inline StringRef getExtractFilename(StringRef filename) {
+  size_t pos = filename.rfind("/");
+  if (pos != std::string::npos) {
+    return filename.substr(pos + 1);
+  }
+  return filename;
+}
+
+bool InputSectionDescription::matchesFile(const InputFile &file,
+                                          bool ExtractFlag) const {
   if (filePat.isTrivialMatchAll())
     return true;
 
@@ -419,10 +429,17 @@ bool InputSectionDescription::matchesFile(const InputFile &file) const {
     if (matchType == MatchType::WholeArchive) {
       matchesFileCache.emplace(&file, filePat.match(file.archiveName));
     } else {
-      if (matchType == MatchType::ArchivesExcluded && !file.archiveName.empty())
+      if (matchType == MatchType::ArchivesExcluded && !file.archiveName.empty()){
         matchesFileCache.emplace(&file, false);
-      else
-        matchesFileCache.emplace(&file, filePat.match(file.getNameForScript()));
+      } else {
+        bool MatchFilename = filePat.match(file.getNameForScript());
+        StringRef ExtractFilename = getExtractFilename(file.getNameForScript());
+        // only use for computeInputSections
+        if (ExtractFlag) {
+          MatchFilename = MatchFilename || filePat.match(ExtractFilename);
+        }
+        matchesFileCache.emplace(&file, MatchFilename);
+      }
     }
   }
 
@@ -442,7 +459,7 @@ bool SectionPattern::excludesFile(const InputFile &file) const {
 
 bool LinkerScript::shouldKeep(InputSectionBase *s) {
   for (InputSectionDescription *id : keptSections)
-    if (id->matchesFile(*s->file))
+    if (id->matchesFile(*s->file, false))
       for (SectionPattern &p : id->sectionPatterns)
         if (p.sectionPat.match(s->name) &&
             (s->flags & id->withFlags) == id->withFlags &&
@@ -571,8 +588,8 @@ LinkerScript::computeInputSections(const InputSectionDescription *cmd,
         if (!pat.sectionPat.match(sec->name))
           continue;
 
-        if (!cmd->matchesFile(*sec->file) || pat.excludesFile(*sec->file) ||
-            !flagsMatch(sec))
+        if (!cmd->matchesFile(*sec->file, true) ||
+            pat.excludesFile(*sec->file) || !flagsMatch(sec))
           continue;
 
         if (sec->parent) {
diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h
index 80c4f564afabc..452cfbcd9b777 100644
--- a/lld/ELF/LinkerScript.h
+++ b/lld/ELF/LinkerScript.h
@@ -227,7 +227,7 @@ class InputSectionDescription : public SectionCommand {
     return c->kind == InputSectionKind;
   }
 
-  bool matchesFile(const InputFile &file) const;
+  bool matchesFile(const InputFile &file, bool ExtractFilename) const;
 
   // Input sections that matches at least one of SectionPatterns
   // will be associated with this InputSectionDescription.
diff --git a/lld/test/ELF/linkerscript/abs-path-match.s b/lld/test/ELF/linkerscript/abs-path-match.s
new file mode 100644
index 0000000000000..cc31dcd1e8031
--- /dev/null
+++ b/lld/test/ELF/linkerscript/abs-path-match.s
@@ -0,0 +1,56 @@
+# REQUIRES: x86
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: split-file %s %t && cd %t
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64 main.s -o main.o
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64 foo.s -o foo.o
+# RUN: llvm-objcopy --rename-section .text=.text_foo  foo.o foo.o
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64 bar.s -o bar.o
+# RUN: llvm-objcopy --rename-section .text=.text_bar  bar.o bar.o
+
+# RUN: ld.lld -r main.o %t/foo.o %t/bar.o -T script.ld -o main_abs.o
+
+# RUN: llvm-objdump -S main_abs.o > main_abs
+# RUN: llvm-objdump -S main_abs.o | FileCheck %s
+# CHECK: Disassembly of section .goo:
+
+
+#--- foo.s
+    .text
+    .globl	foo
+    .p2align	4
+    .type	foo, at function
+foo:
+    nop
+
+
+#--- bar.s
+    .text
+    .globl	bar
+    .p2align	4
+    .type	bar, at function
+bar:      
+    nop
+
+
+#--- main.s
+	.text
+	.globl	main
+	.p2align	4
+	.type	main, at function
+main:
+	callq	foo at PLT
+	callq	bar at PLT
+	retq
+
+
+#--- script.ld
+SECTIONS {
+  .text : { *(.text) }
+  .goo : {
+    bar.o(.text_bar);
+    foo.o(.text_foo);
+  }
+}
\ No newline at end of file



More information about the llvm-commits mailing list