[ELF] Inspect -EL & -EB for OUTPUT_FORMAT(default, big, little)
Choose big if -EB is specified, little if -EL is specified, or default if neither is specified.
The new behavior matches GNU ld.
Fixes: https://github.com/ClangBuiltLinux/linux/issues/1025
Differential Revision: https://reviews.llvm.org/D96214
GitOrigin-RevId: eea34aae2e74e9b6fbdd5b95f479bc7f397bf387
diff --git a/ELF/Config.h b/ELF/Config.h
index 7881dfe..f80c6fb 100644
--- a/ELF/Config.h
+++ b/ELF/Config.h
@@ -187,6 +187,8 @@
bool nostdlib;
bool oFormatBinary;
bool omagic;
+ bool optEB = false;
+ bool optEL = false;
bool optimizeBBJumps;
bool optRemarksWithHotness;
bool picThunk;
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp
index 09c2c17..fe722eb 100644
--- a/ELF/Driver.cpp
+++ b/ELF/Driver.cpp
@@ -1125,6 +1125,13 @@
config->zWxneeded = hasZOption(args, "wxneeded");
setUnresolvedSymbolPolicy(args);
+ if (opt::Arg *arg = args.getLastArg(OPT_eb, OPT_el)) {
+ if (arg->getOption().matches(OPT_eb))
+ config->optEB = true;
+ else
+ config->optEL = true;
+ }
+
for (opt::Arg *arg : args.filtered(OPT_z)) {
std::pair<StringRef, StringRef> option =
StringRef(arg->getValue()).split('=');
diff --git a/ELF/Options.td b/ELF/Options.td
index 65ef3e8..e1eccdb 100644
--- a/ELF/Options.td
+++ b/ELF/Options.td
@@ -159,6 +159,9 @@
"shared object. Implies -Bsymbolic but does not set DF_SYMBOLIC">,
MetaVarName<"<file>">;
+def eb: F<"EB">, HelpText<"Select the big-endian format in OUTPUT_FORMAT">;
+def el: F<"EL">, HelpText<"Select the little-endian format in OUTPUT_FORMAT">;
+
defm eh_frame_hdr: B<"eh-frame-hdr",
"Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header",
"Do not create .eh_frame_hdr section">;
@@ -687,8 +690,6 @@
def: F<"warn-execstack">;
def: F<"warn-once">;
def: F<"warn-shared-textrel">;
-def: F<"EB">;
-def: F<"EL">;
def: JoinedOrSeparate<["-"], "G">;
def: F<"Qy">;
diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp
index 3af6383..4b15a71 100644
--- a/ELF/ScriptParser.cpp
+++ b/ELF/ScriptParser.cpp
@@ -431,13 +431,26 @@
.Default({ELFNoneKind, EM_NONE});
}
-// Parse OUTPUT_FORMAT(bfdname) or OUTPUT_FORMAT(bfdname, big, little).
-// Currently we ignore big and little parameters.
+// Parse OUTPUT_FORMAT(bfdname) or OUTPUT_FORMAT(default, big, little). Choose
+// big if -EB is specified, little if -EL is specified, or default if neither is
+// specified.
void ScriptParser::readOutputFormat() {
expect("(");
+ StringRef s;
config->bfdname = unquote(next());
- StringRef s = config->bfdname;
+ if (!consume(")")) {
+ expect(",");
+ s = unquote(next());
+ if (config->optEB)
+ config->bfdname = s;
+ expect(",");
+ s = unquote(next());
+ if (config->optEL)
+ config->bfdname = s;
+ consume(")");
+ }
+ s = config->bfdname;
if (s.consume_back("-freebsd"))
config->osabi = ELFOSABI_FREEBSD;
@@ -448,14 +461,6 @@
config->mipsN32Abi = true;
if (config->emachine == EM_MSP430)
config->osabi = ELFOSABI_STANDALONE;
-
- if (consume(")"))
- return;
- expect(",");
- skip();
- expect(",");
- skip();
- expect(")");
}
void ScriptParser::readPhdrs() {
diff --git a/docs/ld.lld.1 b/docs/ld.lld.1
index 79a684d..cd9052e 100644
--- a/docs/ld.lld.1
+++ b/docs/ld.lld.1
@@ -161,6 +161,10 @@
(shared object) References to matched non-local STV_DEFAULT symbols shouldn't be bound to definitions within the shared object. Implies
.Cm -Bsymbolic
but does not set DF_SYMBOLIC
+.It Fl -EB
+Select the big-endian format in the OUTPUT_FORMAT command.
+.It Fl -EL
+Select the little-endian format in the OUTPUT_FORMAT command.
.It Fl -eh-frame-hdr
Request creation of
.Li .eh_frame_hdr
diff --git a/test/ELF/emulation-aarch64.s b/test/ELF/emulation-aarch64.s
index e5ba733..2d26a1e 100644
--- a/test/ELF/emulation-aarch64.s
+++ b/test/ELF/emulation-aarch64.s
@@ -23,6 +23,20 @@
# RUN: ld.lld %t.script %t.be.o -o %t3.be
# RUN: llvm-readobj --file-headers %t3.be | FileCheck --check-prefixes=AARCH64,BE %s
+## Test OUTPUT_FORMAT(default, big, little).
+# RUN: echo 'OUTPUT_FORMAT("elf64-littleaarch64", "elf64-bigaarch64", "elf64-littleaarch64")' > %t.script
+# RUN: ld.lld -EL -T %t.script %t.o -o %t4.le
+# RUN: llvm-readobj --file-headers %t4.le | FileCheck --check-prefixes=AARCH64,LE %s
+# RUN: not ld.lld -EB -T %t.script %t.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR_BE %s
+
+# RUN: not ld.lld -T %t.script %t.be.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR_LE %s
+# RUN: not ld.lld -EL -T %t.script %t.be.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR_LE %s
+# RUN: ld.lld -EB -T %t.script %t.be.o -o %t4.be
+# RUN: llvm-readobj --file-headers %t4.be | FileCheck --check-prefixes=AARCH64,BE %s
+
+# ERR_LE: error: {{.*}}.o is incompatible with elf64-littleaarch64
+# ERR_BE: error: {{.*}}.o is incompatible with elf64-bigaarch64
+
# AARCH64: ElfHeader {
# AARCH64-NEXT: Ident {
# AARCH64-NEXT: Magic: (7F 45 4C 46)
diff --git a/test/ELF/invalid-linkerscript.test b/test/ELF/invalid-linkerscript.test
index e635ae4..c8770bd 100644
--- a/test/ELF/invalid-linkerscript.test
+++ b/test/ELF/invalid-linkerscript.test
@@ -51,7 +51,7 @@
# RUN: echo "OUTPUT_FORMAT(x y z)" > %t8
# RUN: not ld.lld %t8 no-such-file 2>&1 | FileCheck -check-prefix=ERR8 %s
# RUN: not ld.lld -m elf_amd64 %t8 no-such-file 2>&1 | FileCheck -check-prefix=ERR8 %s
-# ERR8: unknown output format name: x
+# ERR8: , expected, but got y
# ERR8: cannot open no-such-file:
# RUN: echo "OUTPUT_FORMAT(elf64-x86-64 y z)" > %t9