Add OUTPUT_FORMAT linker script directive support.

This patch adds a support for OUTPUT_FORMAT linker script directive.
Since I'm not 100% confident with BFD names you can use in the directive
for all architectures, I added only a few in this patch. We can add
other names for other archtiectures later.

We still do not support triple-style OUTPUT_FORMAT directive, namely,
OUTPUT_FORMAT(bfdname, big, little). If you pass -EL (little endian)
or -EB (big endian) to the linker, GNU linkers pick up big or little
as a BFD name, correspondingly, so that you can use a single linker
script for bi-endian processor. I'm not sure if we really need to
support that, so I'll leave it alone for now.

Note that -m takes precedence over OUTPUT_FORAMT, but we always parse
a BFD name given to OUTPUT_FORMAT for error checking. You cannot write
an invalid name in the OUTPUT_FORMAT directive.

Differential Revision: https://reviews.llvm.org/D53495

llvm-svn: 344952
This commit is contained in:
Rui Ueyama 2018-10-22 20:50:01 +00:00
parent 01cc58bfb0
commit ea8cd00a1d
5 changed files with 56 additions and 12 deletions

View File

@ -94,6 +94,7 @@ private:
SortSectionPolicy readSortKind();
SymbolAssignment *readProvideHidden(bool Provide, bool Hidden);
SymbolAssignment *readAssignment(StringRef Tok);
std::pair<ELFKind, uint16_t> readBfdName();
void readSort();
Expr readAssert();
Expr readConstant();
@ -382,10 +383,34 @@ void ScriptParser::readOutputArch() {
skip();
}
std::pair<ELFKind, uint16_t> ScriptParser::readBfdName() {
StringRef S = next();
if (S == "elf32-i386")
return {ELF32LEKind, EM_386};
if (S == "elf32-iamcu")
return {ELF32LEKind, EM_IAMCU};
if (S == "elf32-x86-64")
return {ELF32LEKind, EM_X86_64};
if (S == "elf64-littleaarch64")
return {ELF64LEKind, EM_AARCH64};
if (S == "elf64-x86-64")
return {ELF64LEKind, EM_X86_64};
setError("unknown output format name: " + S);
return {ELFNoneKind, EM_NONE};
}
// Parse OUTPUT_FORMAT(bfdname) or OUTPUT_FORMAT(bfdname, big, little).
// Currently we ignore big and little parameters.
void ScriptParser::readOutputFormat() {
// Error checking only for now.
expect("(");
skip();
std::pair<ELFKind, uint16_t> P = readBfdName();
if (Config->EKind == ELFNoneKind) {
Config->EKind = P.first;
Config->EMachine = P.second;
}
if (consume(")"))
return;
expect(",");

View File

@ -38,6 +38,10 @@
# RUN: llvm-readobj -file-headers %t2x64 | FileCheck --check-prefix=X86-64 %s
# RUN: ld.lld %tx64 -o %t3x64
# RUN: llvm-readobj -file-headers %t3x64 | FileCheck --check-prefix=X86-64 %s
# RUN: echo 'OUTPUT_FORMAT(elf64-x86-64)' > %t4x64.script
# RUN: ld.lld %t4x64.script %tx64 -o %t4x64
# RUN: ld.lld %tx64 -o %t4x64 %t4x64.script
# RUN: llvm-readobj -file-headers %t4x64 | FileCheck --check-prefix=X86-64 %s
# X86-64: ElfHeader {
# X86-64-NEXT: Ident {
# X86-64-NEXT: Magic: (7F 45 4C 46)
@ -69,6 +73,9 @@
# RUN: llvm-readobj -file-headers %t2x32 | FileCheck --check-prefix=X32 %s
# RUN: ld.lld %tx32 -o %t3x32
# RUN: llvm-readobj -file-headers %t3x32 | FileCheck --check-prefix=X32 %s
# RUN: echo 'OUTPUT_FORMAT(elf32-x86-64)' > %t4x32.script
# RUN: ld.lld %t4x32.script %tx32 -o %t4x32
# RUN: llvm-readobj -file-headers %t4x32 | FileCheck --check-prefix=X32 %s
# X32: ElfHeader {
# X32-NEXT: Ident {
# X32-NEXT: Magic: (7F 45 4C 46)
@ -100,6 +107,9 @@
# RUN: llvm-readobj -file-headers %t2x86 | FileCheck --check-prefix=X86 %s
# RUN: ld.lld %tx86 -o %t3x86
# RUN: llvm-readobj -file-headers %t3x86 | FileCheck --check-prefix=X86 %s
# RUN: echo 'OUTPUT_FORMAT(elf32-i386)' > %t4x86.script
# RUN: ld.lld %t4x86.script %tx86 -o %t4x86
# RUN: llvm-readobj -file-headers %t4x86 | FileCheck --check-prefix=X86 %s
# X86: ElfHeader {
# X86-NEXT: Ident {
# X86-NEXT: Magic: (7F 45 4C 46)
@ -162,6 +172,9 @@
# RUN: llvm-readobj -file-headers %t2iamcu | FileCheck --check-prefix=IAMCU %s
# RUN: ld.lld %tiamcu -o %t3iamcu
# RUN: llvm-readobj -file-headers %t3iamcu | FileCheck --check-prefix=IAMCU %s
# RUN: echo 'OUTPUT_FORMAT(elf32-iamcu)' > %t4iamcu.script
# RUN: ld.lld %t4iamcu.script %tiamcu -o %t4iamcu
# RUN: llvm-readobj -file-headers %t4iamcu | FileCheck --check-prefix=IAMCU %s
# IAMCU: ElfHeader {
# IAMCU-NEXT: Ident {
# IAMCU-NEXT: Magic: (7F 45 4C 46)
@ -373,6 +386,9 @@
# RUN: llvm-readobj -file-headers %t4aarch64 | FileCheck --check-prefix=AARCH64 %s
# RUN: ld.lld %taarch64 -o %t5aarch64
# RUN: llvm-readobj -file-headers %t5aarch64 | FileCheck --check-prefix=AARCH64 %s
# RUN: echo 'OUTPUT_FORMAT(elf64-littleaarch64)' > %t4aarch64.script
# RUN: ld.lld %t4aarch64.script %taarch64 -o %t4aarch64
# RUN: llvm-readobj -file-headers %t4aarch64 | FileCheck --check-prefix=AARCH64 %s
# AARCH64: ElfHeader {
# AARCH64-NEXT: Ident {
# AARCH64-NEXT: Magic: (7F 45 4C 46)

View File

@ -55,3 +55,9 @@
# CHECK-NEXT: Other: 0
# CHECK-NEXT: Section: Absolute
# CHECK-NEXT: }
# RUN: echo 'OUTPUT_FORMAT(elf64-x86-64)' > %t.script
# RUN: ld.lld -b binary %t.binary -T %t.script -o %t.out
# RUN: llvm-readobj %t.out -sections -section-data -symbols | FileCheck -check-prefix=X86-64 %s
# X86-64: Format: ELF64-x86-64

View File

@ -50,5 +50,11 @@
# RUN: echo "OUTPUT_FORMAT(x y z)" > %t8
# RUN: not ld.lld %t8 no-such-file 2>&1 | FileCheck -check-prefix=ERR8 %s
# ERR8: , expected, but got y
# 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: cannot open no-such-file:
# RUN: echo "OUTPUT_FORMAT(elf64-x86-64 y z)" > %t9
# RUN: not ld.lld %t9 no-such-file 2>&1 | FileCheck -check-prefix=ERR9 %s
# ERR9: , expected, but got y
# ERR9: cannot open no-such-file:

View File

@ -1,9 +0,0 @@
# REQUIRES: x86
# RUN: echo "OUTPUT_FORMAT(x, y, z)" > %t.script
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t1
# RUN: ld.lld -shared -o %t2 %t1 %t.script
# RUN: llvm-readobj %t2 > /dev/null
# RUN: echo "OUTPUT_FORMAT(x, y)" > %t.script
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t1
# RUN: not ld.lld -shared -o %t2 %t1 %t.script