aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-12-28 21:23:25 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-12-28 21:23:25 +0000
commitae1a339de31cf4065777531959a11e55a2e5fa00 (patch)
treeae204c76257fe2799a8fdc5fcb12a2523805c7c8
parente30c72b844bec93f6c197ea6c7c8cd0188964208 (diff)
downloadsrc-ae1a339de31cf4065777531959a11e55a2e5fa00.tar.gz
src-ae1a339de31cf4065777531959a11e55a2e5fa00.zip
Notes
Notes: svn path=/vendor/lld/dist/; revision=327308 svn path=/vendor/lld/lld-trunk-r321545/; revision=327326; tag=vendor/lld/lld-trunk-r321545
-rw-r--r--COFF/Config.h1
-rw-r--r--COFF/Driver.cpp16
-rw-r--r--COFF/Driver.h7
-rw-r--r--COFF/DriverUtils.cpp16
-rw-r--r--COFF/Options.td2
-rw-r--r--COFF/SymbolTable.cpp15
-rw-r--r--ELF/Arch/X86.cpp18
-rw-r--r--ELF/Arch/X86_64.cpp22
-rw-r--r--ELF/Relocations.cpp43
-rw-r--r--ELF/ScriptLexer.cpp10
-rw-r--r--ELF/ScriptParser.cpp3
-rw-r--r--test/COFF/ignore4217.yaml72
-rw-r--r--test/ELF/Inputs/writable-sec-plt-reloc.s4
-rw-r--r--test/ELF/Inputs/znotext-copy-relocations.s5
-rw-r--r--test/ELF/Inputs/znotext-plt-relocations-protected.s5
-rw-r--r--test/ELF/arm-thumb-no-undefined-thunk.s2
-rw-r--r--test/ELF/arm-undefined-weak.s2
-rw-r--r--test/ELF/gnu-ifunc-i386.s4
-rw-r--r--test/ELF/gnu-ifunc.s4
-rw-r--r--test/ELF/writable-sec-plt-reloc.s14
-rw-r--r--test/ELF/x86-64-dyn-rel-error.s4
-rw-r--r--test/ELF/x86-64-dyn-rel-error2.s4
-rw-r--r--test/ELF/znotext-copy-relocation.s16
-rw-r--r--test/ELF/znotext-plt-relocations-protected.s11
-rw-r--r--test/ELF/znotext-weak-undef.s16
25 files changed, 253 insertions, 63 deletions
diff --git a/COFF/Config.h b/COFF/Config.h
index 4eb8bae3c622..93bef23a97f0 100644
--- a/COFF/Config.h
+++ b/COFF/Config.h
@@ -174,6 +174,7 @@ struct Configuration {
bool HighEntropyVA = false;
bool AppContainer = false;
bool MinGW = false;
+ bool WarnLocallyDefinedImported = true;
};
extern Configuration *Config;
diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp
index 0e7db7b6ae34..1aaec355c7a5 100644
--- a/COFF/Driver.cpp
+++ b/COFF/Driver.cpp
@@ -227,7 +227,7 @@ static bool isDecorated(StringRef Sym) {
void LinkerDriver::parseDirectives(StringRef S) {
ArgParser Parser;
// .drectve is always tokenized using Windows shell rules.
- opt::InputArgList Args = Parser.parse(S);
+ opt::InputArgList Args = Parser.parseDirectives(S);
for (auto *Arg : Args) {
switch (Arg->getOption().getUnaliasedOption().getID()) {
@@ -245,6 +245,13 @@ void LinkerDriver::parseDirectives(StringRef S) {
Config->Entry = addUndefined(mangle(Arg->getValue()));
break;
case OPT_export: {
+ // If a common header file contains dllexported function
+ // declarations, many object files may end up with having the
+ // same /EXPORT options. In order to save cost of parsing them,
+ // we dedup them first.
+ if (!DirectivesExports.insert(Arg->getValue()).second)
+ break;
+
Export E = parseExport(Arg->getValue());
if (Config->Machine == I386 && Config->MinGW) {
if (!isDecorated(E.Name))
@@ -795,6 +802,13 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
SearchPaths.push_back(Arg->getValue());
addLibSearchPaths();
+ // Handle /ignore
+ for (auto *Arg : Args.filtered(OPT_ignore)) {
+ if (StringRef(Arg->getValue()) == "4217")
+ Config->WarnLocallyDefinedImported = false;
+ // Other warning numbers are ignored.
+ }
+
// Handle /out
if (auto *Arg = Args.getLastArg(OPT_out))
Config->OutputFile = Arg->getValue();
diff --git a/COFF/Driver.h b/COFF/Driver.h
index 63d41cf69093..3f7fad1038f3 100644
--- a/COFF/Driver.h
+++ b/COFF/Driver.h
@@ -16,6 +16,7 @@
#include "lld/Common/Reproduce.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/COFF.h"
#include "llvm/Option/Arg.h"
@@ -54,6 +55,10 @@ public:
// Tokenizes a given string and then parses as command line options.
llvm::opt::InputArgList parse(StringRef S) { return parse(tokenize(S)); }
+ // Tokenizes a given string and then parses as command line options in
+ // .drectve section.
+ llvm::opt::InputArgList parseDirectives(StringRef S);
+
private:
// Parses command line options.
llvm::opt::InputArgList parse(llvm::ArrayRef<const char *> Args);
@@ -123,6 +128,8 @@ private:
std::list<std::function<void()>> TaskQueue;
std::vector<StringRef> FilePaths;
std::vector<MemoryBufferRef> Resources;
+
+ llvm::StringSet<> DirectivesExports;
};
// Functions below this line are defined in DriverUtils.cpp.
diff --git a/COFF/DriverUtils.cpp b/COFF/DriverUtils.cpp
index 07783b51c519..e0641e04a017 100644
--- a/COFF/DriverUtils.cpp
+++ b/COFF/DriverUtils.cpp
@@ -750,6 +750,22 @@ opt::InputArgList ArgParser::parse(ArrayRef<const char *> Argv) {
return Args;
}
+// Tokenizes and parses a given string as command line in .drective section.
+opt::InputArgList ArgParser::parseDirectives(StringRef S) {
+ // Make InputArgList from string vectors.
+ unsigned MissingIndex;
+ unsigned MissingCount;
+
+ opt::InputArgList Args =
+ Table.ParseArgs(tokenize(S), MissingIndex, MissingCount);
+
+ if (MissingCount)
+ fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument");
+ for (auto *Arg : Args.filtered(OPT_UNKNOWN))
+ warn("ignoring unknown argument: " + Arg->getSpelling());
+ return Args;
+}
+
// link.exe has an interesting feature. If LINK or _LINK_ environment
// variables exist, their contents are handled as command line strings.
// So you can pass extra arguments using them.
diff --git a/COFF/Options.td b/COFF/Options.td
index 0e7a79730fa2..7d4cdba14f75 100644
--- a/COFF/Options.td
+++ b/COFF/Options.td
@@ -29,6 +29,7 @@ def export : P<"export", "Export a function">;
// No help text because /failifmismatch is not intended to be used by the user.
def failifmismatch : P<"failifmismatch", "">;
def heap : P<"heap", "Size of the heap">;
+def ignore : P<"ignore", "Specify warning codes to ignore">;
def implib : P<"implib", "Import library name">;
def libpath : P<"libpath", "Additional library search path">;
def linkrepro : P<"linkrepro", "Dump linker invocation and input files for debugging">;
@@ -155,7 +156,6 @@ def fastfail : F<"fastfail">;
def delay : QF<"delay">;
def errorreport : QF<"errorreport">;
def idlout : QF<"idlout">;
-def ignore : QF<"ignore">;
def maxilksize : QF<"maxilksize">;
def natvis : QF<"natvis">;
def pdbaltpath : QF<"pdbaltpath">;
diff --git a/COFF/SymbolTable.cpp b/COFF/SymbolTable.cpp
index 95b48e6d059f..df76679535cb 100644
--- a/COFF/SymbolTable.cpp
+++ b/COFF/SymbolTable.cpp
@@ -117,9 +117,10 @@ void SymbolTable::reportRemainingUndefines() {
for (Symbol *B : Config->GCRoot) {
if (Undefs.count(B))
errorOrWarn("<root>: undefined symbol: " + B->getName());
- if (Symbol *Imp = LocalImports.lookup(B))
- warn("<root>: locally defined symbol imported: " + Imp->getName() +
- " (defined in " + toString(Imp->getFile()) + ")");
+ if (Config->WarnLocallyDefinedImported)
+ if (Symbol *Imp = LocalImports.lookup(B))
+ warn("<root>: locally defined symbol imported: " + Imp->getName() +
+ " (defined in " + toString(Imp->getFile()) + ")");
}
for (ObjFile *File : ObjFile::Instances) {
@@ -128,9 +129,11 @@ void SymbolTable::reportRemainingUndefines() {
continue;
if (Undefs.count(Sym))
errorOrWarn(toString(File) + ": undefined symbol: " + Sym->getName());
- if (Symbol *Imp = LocalImports.lookup(Sym))
- warn(toString(File) + ": locally defined symbol imported: " +
- Imp->getName() + " (defined in " + toString(Imp->getFile()) + ")");
+ if (Config->WarnLocallyDefinedImported)
+ if (Symbol *Imp = LocalImports.lookup(Sym))
+ warn(toString(File) + ": locally defined symbol imported: " +
+ Imp->getName() + " (defined in " + toString(Imp->getFile()) +
+ ")");
}
}
}
diff --git a/ELF/Arch/X86.cpp b/ELF/Arch/X86.cpp
index fc848917d4e9..10517bef14f3 100644
--- a/ELF/Arch/X86.cpp
+++ b/ELF/Arch/X86.cpp
@@ -192,9 +192,9 @@ void X86::writePltHeader(uint8_t *Buf) const {
}
const uint8_t PltData[] = {
- 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushl (GOTPLT+4)
- 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *(GOTPLT+8)
- 0x90, 0x90, 0x90, 0x90 // nop
+ 0xff, 0x35, 0, 0, 0, 0, // pushl (GOTPLT+4)
+ 0xff, 0x25, 0, 0, 0, 0, // jmp *(GOTPLT+8)
+ 0x90, 0x90, 0x90, 0x90, // nop
};
memcpy(Buf, PltData, sizeof(PltData));
uint32_t GotPlt = InX::GotPlt->getVA();
@@ -206,9 +206,9 @@ void X86::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
const uint8_t Inst[] = {
- 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, // jmp *foo_in_GOT|*foo@GOT(%ebx)
- 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $reloc_offset
- 0xe9, 0x00, 0x00, 0x00, 0x00 // jmp .PLT0@PC
+ 0xff, 0x00, 0, 0, 0, 0, // jmp *foo_in_GOT or jmp *foo@GOT(%ebx)
+ 0x68, 0, 0, 0, 0, // pushl $reloc_offset
+ 0xe9, 0, 0, 0, 0, // jmp .PLT0@PC
};
memcpy(Buf, Inst, sizeof(Inst));
@@ -318,7 +318,7 @@ void X86::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
// subl $x@ntpoff,%eax
const uint8_t Inst[] = {
0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax
- 0x81, 0xe8, 0x00, 0x00, 0x00, 0x00 // subl 0(%ebx), %eax
+ 0x81, 0xe8, 0, 0, 0, 0, // subl Val(%ebx), %eax
};
memcpy(Loc - 3, Inst, sizeof(Inst));
write32le(Loc + 5, Val);
@@ -333,7 +333,7 @@ void X86::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const {
// addl x@gotntpoff(%ebx), %eax
const uint8_t Inst[] = {
0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax
- 0x03, 0x83, 0x00, 0x00, 0x00, 0x00 // addl 0(%ebx), %eax
+ 0x03, 0x83, 0, 0, 0, 0, // addl Val(%ebx), %eax
};
memcpy(Loc - 3, Inst, sizeof(Inst));
write32le(Loc + 5, Val);
@@ -394,7 +394,7 @@ void X86::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
const uint8_t Inst[] = {
0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax
0x90, // nop
- 0x8d, 0x74, 0x26, 0x00 // leal 0(%esi,1),%esi
+ 0x8d, 0x74, 0x26, 0x00, // leal 0(%esi,1),%esi
};
memcpy(Loc - 2, Inst, sizeof(Inst));
}
diff --git a/ELF/Arch/X86_64.cpp b/ELF/Arch/X86_64.cpp
index 14e354b9f4fb..c977d9247d92 100644
--- a/ELF/Arch/X86_64.cpp
+++ b/ELF/Arch/X86_64.cpp
@@ -129,9 +129,9 @@ void X86_64<ELFT>::writeGotPlt(uint8_t *Buf, const Symbol &S) const {
template <class ELFT> void X86_64<ELFT>::writePltHeader(uint8_t *Buf) const {
const uint8_t PltData[] = {
- 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOTPLT+8(%rip)
- 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOTPLT+16(%rip)
- 0x0f, 0x1f, 0x40, 0x00 // nop
+ 0xff, 0x35, 0, 0, 0, 0, // pushq GOTPLT+8(%rip)
+ 0xff, 0x25, 0, 0, 0, 0, // jmp *GOTPLT+16(%rip)
+ 0x0f, 0x1f, 0x40, 0x00, // nop
};
memcpy(Buf, PltData, sizeof(PltData));
uint64_t GotPlt = InX::GotPlt->getVA();
@@ -145,9 +145,9 @@ void X86_64<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
const uint8_t Inst[] = {
- 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *got(%rip)
- 0x68, 0x00, 0x00, 0x00, 0x00, // pushq <relocation index>
- 0xe9, 0x00, 0x00, 0x00, 0x00 // jmpq plt[0]
+ 0xff, 0x25, 0, 0, 0, 0, // jmpq *got(%rip)
+ 0x68, 0, 0, 0, 0, // pushq <relocation index>
+ 0xe9, 0, 0, 0, 0, // jmpq plt[0]
};
memcpy(Buf, Inst, sizeof(Inst));
@@ -175,7 +175,7 @@ void X86_64<ELFT>::relaxTlsGdToLe(uint8_t *Loc, RelType Type,
// lea x@tpoff,%rax
const uint8_t Inst[] = {
0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax
- 0x48, 0x8d, 0x80, 0x00, 0x00, 0x00, 0x00 // lea x@tpoff,%rax
+ 0x48, 0x8d, 0x80, 0, 0, 0, 0, // lea x@tpoff,%rax
};
memcpy(Loc - 4, Inst, sizeof(Inst));
@@ -198,7 +198,7 @@ void X86_64<ELFT>::relaxTlsGdToIe(uint8_t *Loc, RelType Type,
// addq x@tpoff,%rax
const uint8_t Inst[] = {
0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax
- 0x48, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00 // addq x@tpoff,%rax
+ 0x48, 0x03, 0x05, 0, 0, 0, 0, // addq x@tpoff,%rax
};
memcpy(Loc - 4, Inst, sizeof(Inst));
@@ -274,9 +274,9 @@ void X86_64<ELFT>::relaxTlsLdToLe(uint8_t *Loc, RelType Type,
}
const uint8_t Inst[] = {
- 0x66, 0x66, // .word 0x6666
- 0x66, // .byte 0x66
- 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00 // mov %fs:0,%rax
+ 0x66, 0x66, // .word 0x6666
+ 0x66, // .byte 0x66
+ 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0,%rax
};
memcpy(Loc - 3, Inst, sizeof(Inst));
}
diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp
index 94ea3e1557c4..1aa0957b1d01 100644
--- a/ELF/Relocations.cpp
+++ b/ELF/Relocations.cpp
@@ -581,44 +581,38 @@ static RelExpr getPltExpr(Symbol &Sym, RelExpr Expr, bool &IsConstant) {
return toPlt(Expr);
}
+// This modifies the expression if we can use a copy relocation or point the
+// symbol to the PLT.
template <class ELFT>
static RelExpr adjustExpr(Symbol &Sym, RelExpr Expr, RelType Type,
InputSectionBase &S, uint64_t RelOff,
bool &IsConstant) {
- // We can create any dynamic relocation if a section is simply writable.
- if (S.Flags & SHF_WRITE)
- return Expr;
-
- // Or, if we are allowed to create dynamic relocations against
- // read-only sections (i.e. when "-z notext" is given),
- // we can create a dynamic relocation as we want, too.
- if (!Config->ZText) {
- // We use PLT for relocations that may overflow in runtime,
- // see comment for getPltExpr().
- if (Sym.isFunc() && !Target->isPicRel(Type))
- return getPltExpr(Sym, Expr, IsConstant);
- return Expr;
- }
-
// If a relocation can be applied at link-time, we don't need to
// create a dynamic relocation in the first place.
if (IsConstant)
return Expr;
- // If we got here we know that this relocation would require the dynamic
- // linker to write a value to read only memory.
-
- // If the relocation is to a weak undef, give up on it and produce a
- // non preemptible 0.
- if (Sym.isUndefWeak()) {
+ // If the relocation is to a weak undef, and we are producing
+ // executable, give up on it and produce a non preemptible 0.
+ if (!Config->Shared && Sym.isUndefWeak()) {
Sym.IsPreemptible = false;
IsConstant = true;
return Expr;
}
+ // We can create any dynamic relocation supported by the dynamic linker if a
+ // section is writable or we are passed -z notext.
+ bool CanWrite = (S.Flags & SHF_WRITE) || !Config->ZText;
+ if (CanWrite && Target->isPicRel(Type))
+ return Expr;
+
+ // If we got here we know that this relocation would require the dynamic
+ // linker to write a value to read only memory or use an unsupported
+ // relocation.
+
// We can hack around it if we are producing an executable and
// the refered symbol can be preemepted to refer to the executable.
- if (Config->Shared || (Config->Pic && !isRelExpr(Expr))) {
+ if (!CanWrite && (Config->Shared || (Config->Pic && !isRelExpr(Expr)))) {
error(
"can't create dynamic relocation " + toString(Type) + " against " +
(Sym.getName().empty() ? "local symbol" : "symbol: " + toString(Sym)) +
@@ -627,6 +621,11 @@ static RelExpr adjustExpr(Symbol &Sym, RelExpr Expr, RelType Type,
return Expr;
}
+ // Copy relocations are only possible if we are creating an executable and the
+ // symbol is shared.
+ if (!Sym.isShared() || Config->Shared)
+ return Expr;
+
if (Sym.getVisibility() != STV_DEFAULT) {
error("cannot preempt symbol: " + toString(Sym) +
getLocation(S, Sym, RelOff));
diff --git a/ELF/ScriptLexer.cpp b/ELF/ScriptLexer.cpp
index 9f33c16f36b0..ef5a1cff7590 100644
--- a/ELF/ScriptLexer.cpp
+++ b/ELF/ScriptLexer.cpp
@@ -115,11 +115,19 @@ void ScriptLexer::tokenize(MemoryBufferRef MB) {
continue;
}
+ // ">foo" is parsed to ">" and "foo", but ">>" is parsed to ">>".
+ if (S.startswith("<<") || S.startswith("<=") || S.startswith(">>") ||
+ S.startswith(">=")) {
+ Vec.push_back(S.substr(0, 2));
+ S = S.substr(2);
+ continue;
+ }
+
// Unquoted token. This is more relaxed than tokens in C-like language,
// so that you can write "file-name.cpp" as one bare token, for example.
size_t Pos = S.find_first_not_of(
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
- "0123456789_.$/\\~=+[]*?-!<>^:");
+ "0123456789_.$/\\~=+[]*?-!^:");
// A character that cannot start a word (which is usually a
// punctuation) forms a single character token.
diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp
index c1176ccfa8d5..4263944981f2 100644
--- a/ELF/ScriptParser.cpp
+++ b/ELF/ScriptParser.cpp
@@ -151,6 +151,7 @@ static ExprValue add(ExprValue A, ExprValue B) {
}
static ExprValue sub(ExprValue A, ExprValue B) {
+ // The distance between two symbols in sections is absolute.
if (!A.isAbsolute() && !B.isAbsolute())
return A.getValue() - B.getValue();
return {A.Sec, false, A.getSectionOffset() - B.getValue(), A.Loc};
@@ -707,8 +708,6 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) {
if (consume(">"))
Cmd->MemoryRegionName = next();
- else if (peek().startswith(">"))
- Cmd->MemoryRegionName = next().drop_front();
Cmd->Phdrs = readOutputSectionPhdrs();
diff --git a/test/COFF/ignore4217.yaml b/test/COFF/ignore4217.yaml
new file mode 100644
index 000000000000..5f9d3e3ddf84
--- /dev/null
+++ b/test/COFF/ignore4217.yaml
@@ -0,0 +1,72 @@
+# Tests that /ignore:4217 suppresses "locally defined symbol imported" warnings.
+# RUN: yaml2obj < %s > %t.obj
+
+# RUN: lld-link -entry:main -out:%t.exe %t.obj 2>&1 \
+# RUN: | FileCheck -check-prefix=WARNINGS %s
+# RUN: lld-link -ignore:4217 -entry:main -out:%t.exe %t.obj 2>&1 \
+# RUN: | FileCheck -allow-empty -check-prefix=SUPPRESSED %s
+
+# WARNINGS: locally defined symbol imported
+# SUPPRESSED-NOT: locally defined symbol imported
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: B82A000000C3662E0F1F8400000000004883EC28C744242400000000E800000000904883C428C3
+ Relocations:
+ - VirtualAddress: 29
+ SymbolName: __imp_foo
+ Type: IMAGE_REL_AMD64_REL32
+ - Name: .data
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: ''
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 39
+ NumberOfRelocations: 1
+ NumberOfLinenumbers: 0
+ CheckSum: 3087210877
+ Number: 1
+ - Name: .data
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 0
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 2
+ - Name: foo
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: main
+ Value: 16
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: __imp_foo
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/ELF/Inputs/writable-sec-plt-reloc.s b/test/ELF/Inputs/writable-sec-plt-reloc.s
new file mode 100644
index 000000000000..fc5d839a5166
--- /dev/null
+++ b/test/ELF/Inputs/writable-sec-plt-reloc.s
@@ -0,0 +1,4 @@
+ .global foo
+ .type foo, @function
+foo:
+ retq
diff --git a/test/ELF/Inputs/znotext-copy-relocations.s b/test/ELF/Inputs/znotext-copy-relocations.s
new file mode 100644
index 000000000000..a23abbe3d402
--- /dev/null
+++ b/test/ELF/Inputs/znotext-copy-relocations.s
@@ -0,0 +1,5 @@
+.global foo
+.type foo,@object
+.size foo, 8
+foo:
+.quad 42
diff --git a/test/ELF/Inputs/znotext-plt-relocations-protected.s b/test/ELF/Inputs/znotext-plt-relocations-protected.s
new file mode 100644
index 000000000000..c9eacf5b54c5
--- /dev/null
+++ b/test/ELF/Inputs/znotext-plt-relocations-protected.s
@@ -0,0 +1,5 @@
+.global foo
+.type foo,@function
+.protected foo
+foo:
+ nop
diff --git a/test/ELF/arm-thumb-no-undefined-thunk.s b/test/ELF/arm-thumb-no-undefined-thunk.s
index 775e6fa9c0e0..e8d8d8db684c 100644
--- a/test/ELF/arm-thumb-no-undefined-thunk.s
+++ b/test/ELF/arm-thumb-no-undefined-thunk.s
@@ -21,4 +21,4 @@ _start:
// 69636 = 0x11004 = next instruction
// CHECK: 11000: {{.*}} bl #0
// CHECK-NEXT: 11004: {{.*}} b.w #0 <_start+0x8>
-// CHECK-NEXT: 11008: {{.*}} b.w #0 <_start+0xC>
+// CHECK-NEXT: 11008: {{.*}} b.w #0 <_start+0xc>
diff --git a/test/ELF/arm-undefined-weak.s b/test/ELF/arm-undefined-weak.s
index 57a3f57dea1b..8af9f4916a95 100644
--- a/test/ELF/arm-undefined-weak.s
+++ b/test/ELF/arm-undefined-weak.s
@@ -32,7 +32,7 @@ _start:
// CHECK: 11000: {{.*}} b #-4 <_start+0x4>
// CHECK-NEXT: 11004: {{.*}} bl #-4 <_start+0x8>
// blx is transformed into bl so we don't change state
-// CHECK-NEXT: 11008: {{.*}} bl #-4 <_start+0xC>
+// CHECK-NEXT: 11008: {{.*}} bl #-4 <_start+0xc>
// CHECK-NEXT: 1100c: {{.*}} movt r0, #0
// CHECK-NEXT: 11010: {{.*}} movw r0, #0
// CHECK: 11014: {{.*}} .word 0x00000000
diff --git a/test/ELF/gnu-ifunc-i386.s b/test/ELF/gnu-ifunc-i386.s
index 559e98a3e625..4eda32f378d9 100644
--- a/test/ELF/gnu-ifunc-i386.s
+++ b/test/ELF/gnu-ifunc-i386.s
@@ -102,10 +102,10 @@
// DISASM-NEXT: .plt:
// DISASM-NEXT: 11020: ff 25 00 20 01 00 jmpl *73728
// DISASM-NEXT: 11026: 68 10 00 00 00 pushl $16
-// DISASM-NEXT: 1102b: e9 e0 ff ff ff jmp -32 <_start+0xE>
+// DISASM-NEXT: 1102b: e9 e0 ff ff ff jmp -32 <_start+0xe>
// DISASM-NEXT: 11030: ff 25 04 20 01 00 jmpl *73732
// DISASM-NEXT: 11036: 68 18 00 00 00 pushl $24
-// DISASM-NEXT: 1103b: e9 d0 ff ff ff jmp -48 <_start+0xE>
+// DISASM-NEXT: 1103b: e9 d0 ff ff ff jmp -48 <_start+0xe>
.text
.type foo STT_GNU_IFUNC
diff --git a/test/ELF/gnu-ifunc.s b/test/ELF/gnu-ifunc.s
index 17883a3209f5..4911da6bce00 100644
--- a/test/ELF/gnu-ifunc.s
+++ b/test/ELF/gnu-ifunc.s
@@ -102,10 +102,10 @@
// DISASM-NEXT: .plt:
// DISASM-NEXT: 201020: {{.*}} jmpq *4058(%rip)
// DISASM-NEXT: 201026: {{.*}} pushq $0
-// DISASM-NEXT: 20102b: {{.*}} jmp -32 <_start+0xE>
+// DISASM-NEXT: 20102b: {{.*}} jmp -32 <_start+0xe>
// DISASM-NEXT: 201030: {{.*}} jmpq *4050(%rip)
// DISASM-NEXT: 201036: {{.*}} pushq $1
-// DISASM-NEXT: 20103b: {{.*}} jmp -48 <_start+0xE>
+// DISASM-NEXT: 20103b: {{.*}} jmp -48 <_start+0xe>
.text
.type foo STT_GNU_IFUNC
diff --git a/test/ELF/writable-sec-plt-reloc.s b/test/ELF/writable-sec-plt-reloc.s
new file mode 100644
index 000000000000..97a21b5fac02
--- /dev/null
+++ b/test/ELF/writable-sec-plt-reloc.s
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+# RUN: llvm-mc %p/Inputs/writable-sec-plt-reloc.s -o %t2.o -filetype=obj -triple=x86_64-pc-linux
+# RUN: ld.lld %t2.o -o %t2.so -shared
+# RUN: ld.lld %t.o %t2.so -o %t
+# RUN: llvm-readelf --symbols -r %t | FileCheck %s
+
+# CHECK: R_X86_64_JUMP_SLOT {{.*}} foo + 0
+# CHECK: 0000000000201010 0 FUNC GLOBAL DEFAULT UND foo
+
+.section .bar,"awx"
+.global _start
+_start:
+ call foo
diff --git a/test/ELF/x86-64-dyn-rel-error.s b/test/ELF/x86-64-dyn-rel-error.s
index f479eca2e778..7a705eb54177 100644
--- a/test/ELF/x86-64-dyn-rel-error.s
+++ b/test/ELF/x86-64-dyn-rel-error.s
@@ -2,12 +2,12 @@
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %t2.o
// RUN: ld.lld %t2.o -shared -o %t2.so
-// RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s
+// RUN: not ld.lld -shared %t.o %t2.so -o %t 2>&1 | FileCheck %s
.global _start
_start:
.data
- .long bar
+ .long zed
// CHECK: relocation R_X86_64_32 cannot be used against shared object; recompile with -fPIC
diff --git a/test/ELF/x86-64-dyn-rel-error2.s b/test/ELF/x86-64-dyn-rel-error2.s
index e316aeae54f4..9b731e268875 100644
--- a/test/ELF/x86-64-dyn-rel-error2.s
+++ b/test/ELF/x86-64-dyn-rel-error2.s
@@ -2,7 +2,7 @@
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %t2.o
// RUN: ld.lld %t2.o -shared -o %t2.so
-// RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s
+// RUN: not ld.lld -shared %t.o %t2.so -o %t 2>&1 | FileCheck %s
// CHECK: relocation R_X86_64_PC32 cannot be used against shared object; recompile with -fPIC
// CHECK: >>> defined in {{.*}}.so
@@ -11,4 +11,4 @@
.global _start
_start:
.data
- .long bar - .
+ .long zed - .
diff --git a/test/ELF/znotext-copy-relocation.s b/test/ELF/znotext-copy-relocation.s
new file mode 100644
index 000000000000..a5fc4f99dba5
--- /dev/null
+++ b/test/ELF/znotext-copy-relocation.s
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/znotext-copy-relocations.s -o %t2.o
+# RUN: ld.lld %t2.o -o %t2.so -shared
+# RUN: ld.lld -z notext %t.o %t2.so -o %t
+# RUN: llvm-readobj -r %t | FileCheck %s
+
+# CHECK: Relocations [
+# CHECK-NEXT: Section ({{.*}}) .rela.dyn {
+# CHECK-NEXT: R_X86_64_COPY foo 0x0
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+.global _start
+_start:
+.long foo
diff --git a/test/ELF/znotext-plt-relocations-protected.s b/test/ELF/znotext-plt-relocations-protected.s
new file mode 100644
index 000000000000..03d20b12e352
--- /dev/null
+++ b/test/ELF/znotext-plt-relocations-protected.s
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/znotext-plt-relocations-protected.s -o %t2.o
+# RUN: ld.lld %t2.o -o %t2.so -shared
+# RUN: not ld.lld -z notext %t.o %t2.so -o %t 2>&1 | FileCheck %s
+
+# CHECK: error: cannot preempt symbol: foo
+
+.global _start
+_start:
+callq foo
diff --git a/test/ELF/znotext-weak-undef.s b/test/ELF/znotext-weak-undef.s
new file mode 100644
index 000000000000..d606d872bc4f
--- /dev/null
+++ b/test/ELF/znotext-weak-undef.s
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: not ld.lld -z notext -shared %t.o -o %t 2>&1 | FileCheck %s
+# CHECK: relocation R_X86_64_32 cannot be used against shared object; recompile with -fPIC
+
+# RUN: ld.lld -z notext %t.o -o %t
+# RUN: llvm-readobj -r %t | FileCheck %s --check-prefix=EXE
+# EXE: Relocations [
+# EXE-NEXT: ]
+
+.text
+.global foo
+.weak foo
+
+_start:
+mov $foo,%eax