[lld] f02a27d - [ELF] Add --default-script/-dT

via llvm-commits llvm-commits at lists.llvm.org
Fri Apr 19 09:09:45 PDT 2024


Author: Fangrui Song
Date: 2024-04-19T09:09:41-07:00
New Revision: f02a27df2f133503b39bad38d0e2b3e95d3f8a23

URL: https://github.com/llvm/llvm-project/commit/f02a27df2f133503b39bad38d0e2b3e95d3f8a23
DIFF: https://github.com/llvm/llvm-project/commit/f02a27df2f133503b39bad38d0e2b3e95d3f8a23.diff

LOG: [ELF] Add --default-script/-dT

GNU ld added --default-script (alias: -dT) in 2007. The option specifies
a default script that is processed if --script/-T is not specified. -dT
can be used to override GNU ld's internal linker script, but only when
the application does not specify -T.
In addition, dynamorio's CMakeLists.txt may use -dT.

The implementation is simple and the feature can be useful to dabble
with different section layouts.

Pull Request: https://github.com/llvm/llvm-project/pull/89327

Added: 
    lld/test/ELF/linkerscript/default-script.s

Modified: 
    lld/ELF/Driver.cpp
    lld/ELF/DriverUtils.cpp
    lld/ELF/Options.td
    lld/docs/ld.lld.1
    lld/test/ELF/reproduce.s

Removed: 
    


################################################################################
diff  --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 5fffdc51f34ddf..a5b47f020f8726 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -1856,8 +1856,9 @@ void LinkerDriver::createFiles(opt::InputArgList &args) {
   std::vector<std::tuple<bool, bool, bool>> stack;
 
   // Iterate over argv to process input files and positional arguments.
+  std::optional<MemoryBufferRef> defaultScript;
   InputFile::isInGroup = false;
-  bool hasInput = false;
+  bool hasInput = false, hasScript = false;
   for (auto *arg : args) {
     switch (arg->getOption().getID()) {
     case OPT_library:
@@ -1879,9 +1880,16 @@ void LinkerDriver::createFiles(opt::InputArgList &args) {
       break;
     }
     case OPT_script:
+    case OPT_default_script:
       if (std::optional<std::string> path = searchScript(arg->getValue())) {
-        if (std::optional<MemoryBufferRef> mb = readFile(*path))
-          readLinkerScript(*mb);
+        if (std::optional<MemoryBufferRef> mb = readFile(*path)) {
+          if (arg->getOption().matches(OPT_default_script)) {
+            defaultScript = mb;
+          } else {
+            readLinkerScript(*mb);
+            hasScript = true;
+          }
+        }
         break;
       }
       error(Twine("cannot find linker script ") + arg->getValue());
@@ -1961,6 +1969,8 @@ void LinkerDriver::createFiles(opt::InputArgList &args) {
     }
   }
 
+  if (defaultScript && !hasScript)
+    readLinkerScript(*defaultScript);
   if (files.empty() && !hasInput && errorCount() == 0)
     error("no input files");
 }

diff  --git a/lld/ELF/DriverUtils.cpp b/lld/ELF/DriverUtils.cpp
index de8ffab0e21249..ac74604408152d 100644
--- a/lld/ELF/DriverUtils.cpp
+++ b/lld/ELF/DriverUtils.cpp
@@ -186,6 +186,7 @@ std::string elf::createResponseFile(const opt::InputArgList &args) {
       os << arg->getSpelling() << quote(rewritePath(arg->getValue())) << "\n";
       break;
     case OPT_call_graph_ordering_file:
+    case OPT_default_script:
     case OPT_dynamic_list:
     case OPT_export_dynamic_symbol_list:
     case OPT_just_symbols:

diff  --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index d470646ed0eeef..72eaf157a181cf 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -157,6 +157,8 @@ defm debug_names: BB<"debug-names",
     "Generate a merged .debug_names section",
     "Do not generate a merged .debug_names section (default)">;
 
+defm default_script: EEq<"default-script", "In the absence of --script, read this default linker script">;
+
 defm demangle: B<"demangle",
     "Demangle symbol names (default)",
     "Do not demangle symbol names">;
@@ -555,6 +557,7 @@ HelpText<"Format diagnostics for Visual Studio compatibility">;
 def package_metadata: JJ<"package-metadata=">, HelpText<"Emit package metadata note">;
 
 // Aliases
+def: Separate<["-"], "dT">, Alias<default_script>, HelpText<"Alias for --default-script">;
 def: Separate<["-"], "f">, Alias<auxiliary>, HelpText<"Alias for --auxiliary">;
 def: F<"call_shared">, Alias<Bdynamic>, HelpText<"Alias for --Bdynamic">;
 def: F<"dy">, Alias<Bdynamic>, HelpText<"Alias for --Bdynamic">;

diff  --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1
index ba8ce8f784759a..3861120915e8bc 100644
--- a/lld/docs/ld.lld.1
+++ b/lld/docs/ld.lld.1
@@ -176,6 +176,10 @@ is specified, print to the map file.
 Generate a merged
 .Li .debug_names
 section.
+.It Fl -default-script Ns = Ns Ar file , Fl dT Ar file
+In the absence of
+.Fl -script ,
+read this default linker script.
 .It Fl -defsym Ns = Ns Ar symbol Ns = Ns Ar expression
 Define a symbol alias.
 .Ar expression

diff  --git a/lld/test/ELF/linkerscript/default-script.s b/lld/test/ELF/linkerscript/default-script.s
new file mode 100644
index 00000000000000..bb716a5fe0cddf
--- /dev/null
+++ b/lld/test/ELF/linkerscript/default-script.s
@@ -0,0 +1,63 @@
+# REQUIRES: x86
+# RUN: rm -rf %t && split-file %s %t && cd %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a.o
+# RUN: ld.lld --default-script=def.t b.t -T a.t a.o -o out
+# RUN: llvm-readelf -Ss out | FileCheck %s
+
+# CHECK:      Name
+# CHECK:      .foo2
+# CHECK-NEXT: .foo0
+# CHECK-NEXT: .foo1
+# CHECK:      1: 000000000000000c     0 NOTYPE  GLOBAL DEFAULT     4 _start
+# CHECK-NEXT: 2: 000000000000002a     0 NOTYPE  GLOBAL DEFAULT   ABS b
+# CHECK-NEXT: 3: 000000000000002a     0 NOTYPE  GLOBAL DEFAULT   ABS a
+# CHECK-EMPTY:
+
+## In the absence of --script options, the default linker script is read.
+# RUN: ld.lld --default-script def.t b.t a.o -o out1
+# RUN: llvm-readelf -Ss out1 | FileCheck %s --check-prefix=CHECK1
+# RUN: ld.lld -dT def.t b.t a.o -o out1a && cmp out1 out1a
+## If multiple -dT options are specified, the last -dT wins.
+# RUN: ld.lld -dT a.t -dT def.t b.t a.o -o out1a && cmp out1 out1a
+
+# RUN: mkdir d && cp def.t d/default.t
+# RUN: ld.lld -L d -dT default.t b.t a.o -o out1a && cmp out1 out1a
+
+# CHECK1:      Name
+# CHECK1:      .foo2
+# CHECK1-NEXT: .foo1
+# CHECK1-NEXT: .foo0
+# CHECK1:      1: 000000000000000c     0 NOTYPE  GLOBAL DEFAULT     4 _start
+# CHECK1-NEXT: 2: 000000000000002a     0 NOTYPE  GLOBAL DEFAULT   ABS b
+# CHECK1-NEXT: 3: 000000000000002a     0 NOTYPE  GLOBAL DEFAULT   ABS def
+# CHECK1-EMPTY:
+
+# RUN: not ld.lld --default-script not-exist.t b.t -T a.t a.o 2>&1 | FileCheck %s --check-prefix=ERR
+# ERR: error: cannot find linker script not-exist.t
+
+#--- a.s
+.globl _start
+_start:
+
+.section .foo0,"a"; .long 0
+.section .foo1,"a"; .long 0
+.section .foo2,"a"; .long 0
+
+#--- a.t
+a = 42;
+SECTIONS {
+  .foo2 : {}
+  .foo0 : {}
+  .foo1 : {}
+}
+
+#--- b.t
+b = 42;
+
+#--- def.t
+def = 42;
+SECTIONS {
+  .foo2 : {}
+  .foo1 : {}
+  .foo0 : {}
+}

diff  --git a/lld/test/ELF/reproduce.s b/lld/test/ELF/reproduce.s
index 314c08b4f7cdd5..8818a9e35f4039 100644
--- a/lld/test/ELF/reproduce.s
+++ b/lld/test/ELF/reproduce.s
@@ -34,10 +34,11 @@
 # RUN: cp dyn dyn2
 # RUN: echo > file
 # RUN: echo > file2
+# RUN: echo > file3
 # RUN: echo "_start" > order
 # RUN: mkdir "sysroot with spaces"
 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o 'foo bar'
-# RUN: ld.lld --reproduce repro3.tar 'foo bar' -L"foo bar" -Lfile -Tfile2 \
+# RUN: ld.lld --reproduce repro3.tar 'foo bar' -L"foo bar" -Lfile -Tfile2 -dT file3 \
 # RUN:   --dynamic-list dyn --export-dynamic-symbol-list dyn2 -rpath file --script=file --symbol-ordering-file order \
 # RUN:   --sysroot "sysroot with spaces" --sysroot="sysroot with spaces" \
 # RUN:   --version-script ver --dynamic-linker "some unusual/path" -soname 'foo bar' \
@@ -48,6 +49,7 @@
 # RSP3-NEXT: -L "[[BASEDIR:.+]]/foo bar"
 # RSP3-NEXT: -L [[BASEDIR]]/file
 # RSP3-NEXT: --script [[BASEDIR]]/file2
+# RSP3-NEXT: --default-script [[BASEDIR]]/file3
 # RSP3-NEXT: --dynamic-list [[BASEDIR]]/dyn
 # RSP3-NEXT: --export-dynamic-symbol-list [[BASEDIR]]/dyn2
 # RSP3-NEXT: -rpath [[BASEDIR]]/file


        


More information about the llvm-commits mailing list