[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
This commit is contained in:
Fangrui Song 2024-04-19 09:09:41 -07:00 committed by GitHub
parent 26a59bf6fc
commit f02a27df2f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 87 additions and 4 deletions

View File

@ -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");
}

View File

@ -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:

View File

@ -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">;

View File

@ -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

View File

@ -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 : {}
}

View File

@ -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