Merge 861196015 for LLVM update to 333878
Change-Id: I87e5ea27d2c64708ab338200f6d39a7fd332c86e
diff --git a/COFF/Chunks.cpp b/COFF/Chunks.cpp
index 451e18a..ab6160c 100644
--- a/COFF/Chunks.cpp
+++ b/COFF/Chunks.cpp
@@ -31,8 +31,7 @@
SectionChunk::SectionChunk(ObjFile *F, const coff_section *H)
: Chunk(SectionKind), Repl(this), Header(H), File(F),
- Relocs(File->getCOFFObj()->getRelocations(Header)),
- NumRelocs(std::distance(Relocs.begin(), Relocs.end())) {
+ Relocs(File->getCOFFObj()->getRelocations(Header)) {
// Initialize SectionName.
File->getCOFFObj()->getSectionName(Header, SectionName);
@@ -163,7 +162,7 @@
uint64_t S, uint64_t P) const {
// Pointer to thumb code must have the LSB set.
uint64_t SX = S;
- if (OS && (OS->getPermissions() & IMAGE_SCN_MEM_EXECUTE))
+ if (OS && (OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE))
SX |= 1;
switch (Type) {
case IMAGE_REL_ARM_ADDR32: add32(Off, SX + Config->ImageBase); break;
@@ -182,11 +181,11 @@
// Interpret the existing immediate value as a byte offset to the
// target symbol, then update the instruction with the immediate as
// the page offset from the current instruction to the target.
-static void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P) {
+static void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P, int Shift) {
uint32_t Orig = read32le(Off);
uint64_t Imm = ((Orig >> 29) & 0x3) | ((Orig >> 3) & 0x1FFFFC);
S += Imm;
- Imm = (S >> 12) - (P >> 12);
+ Imm = (S >> Shift) - (P >> Shift);
uint32_t ImmLo = (Imm & 0x3) << 29;
uint32_t ImmHi = (Imm & 0x1FFFFC) << 3;
uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3);
@@ -248,13 +247,34 @@
applyArm64Ldr(Off, (S - OS->getRVA()) & 0xfff);
}
+static void applyArm64Branch26(uint8_t *Off, int64_t V) {
+ if (!isInt<28>(V))
+ fatal("relocation out of range");
+ or32(Off, (V & 0x0FFFFFFC) >> 2);
+}
+
+static void applyArm64Branch19(uint8_t *Off, int64_t V) {
+ if (!isInt<21>(V))
+ fatal("relocation out of range");
+ or32(Off, (V & 0x001FFFFC) << 3);
+}
+
+static void applyArm64Branch14(uint8_t *Off, int64_t V) {
+ if (!isInt<16>(V))
+ fatal("relocation out of range");
+ or32(Off, (V & 0x0000FFFC) << 3);
+}
+
void SectionChunk::applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS,
uint64_t S, uint64_t P) const {
switch (Type) {
- case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(Off, S, P); break;
+ case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(Off, S, P, 12); break;
+ case IMAGE_REL_ARM64_REL21: applyArm64Addr(Off, S, P, 0); break;
case IMAGE_REL_ARM64_PAGEOFFSET_12A: applyArm64Imm(Off, S & 0xfff, 0); break;
case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(Off, S & 0xfff); break;
- case IMAGE_REL_ARM64_BRANCH26: or32(Off, ((S - P) & 0x0FFFFFFC) >> 2); break;
+ case IMAGE_REL_ARM64_BRANCH26: applyArm64Branch26(Off, S - P); break;
+ case IMAGE_REL_ARM64_BRANCH19: applyArm64Branch19(Off, S - P); break;
+ case IMAGE_REL_ARM64_BRANCH14: applyArm64Branch14(Off, S - P); break;
case IMAGE_REL_ARM64_ADDR32: add32(Off, S + Config->ImageBase); break;
case IMAGE_REL_ARM64_ADDR32NB: add32(Off, S); break;
case IMAGE_REL_ARM64_ADDR64: add64(Off, S + Config->ImageBase); break;
@@ -262,6 +282,7 @@
case IMAGE_REL_ARM64_SECREL_LOW12A: applySecRelLow12A(this, Off, OS, S); break;
case IMAGE_REL_ARM64_SECREL_HIGH12A: applySecRelHigh12A(this, Off, OS, S); break;
case IMAGE_REL_ARM64_SECREL_LOW12L: applySecRelLdr(this, Off, OS, S); break;
+ case IMAGE_REL_ARM64_SECTION: applySecIdx(Off, OS); break;
default:
fatal("unsupported relocation type 0x" + Twine::utohexstr(Type));
}
@@ -272,7 +293,8 @@
return;
// Copy section contents from source object file to output file.
ArrayRef<uint8_t> A = getContents();
- memcpy(Buf + OutputSectionOff, A.data(), A.size());
+ if (!A.empty())
+ memcpy(Buf + OutputSectionOff, A.data(), A.size());
// Apply relocations.
size_t InputSize = getSize();
@@ -388,8 +410,8 @@
return !(Header->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA);
}
-uint32_t SectionChunk::getPermissions() const {
- return Header->Characteristics & PermMask;
+uint32_t SectionChunk::getOutputCharacteristics() const {
+ return Header->Characteristics & (PermMask | TypeMask);
}
bool SectionChunk::isCOMDAT() const {
@@ -416,6 +438,7 @@
}
void SectionChunk::replace(SectionChunk *Other) {
+ Alignment = std::max(Alignment, Other->Alignment);
Other->Repl = Repl;
Other->Live = false;
}
@@ -426,7 +449,7 @@
Alignment = std::min(uint64_t(32), PowerOf2Ceil(Sym.getValue()));
}
-uint32_t CommonChunk::getPermissions() const {
+uint32_t CommonChunk::getOutputCharacteristics() const {
return IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ |
IMAGE_SCN_MEM_WRITE;
}
@@ -471,7 +494,7 @@
void ImportThunkChunkARM64::writeTo(uint8_t *Buf) const {
int64_t Off = ImpSymbol->getRVA() & 0xfff;
memcpy(Buf + OutputSectionOff, ImportThunkARM64, sizeof(ImportThunkARM64));
- applyArm64Addr(Buf + OutputSectionOff, ImpSymbol->getRVA(), RVA);
+ applyArm64Addr(Buf + OutputSectionOff, ImpSymbol->getRVA(), RVA, 12);
applyArm64Ldr(Buf + OutputSectionOff + 4, Off);
}
@@ -601,7 +624,7 @@
}
}
-uint32_t MergeChunk::getPermissions() const {
+uint32_t MergeChunk::getOutputCharacteristics() const {
return IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA;
}
diff --git a/COFF/Chunks.h b/COFF/Chunks.h
index b95869a..9e89653 100644
--- a/COFF/Chunks.h
+++ b/COFF/Chunks.h
@@ -38,9 +38,11 @@
class OutputSection;
class Symbol;
-// Mask for section types (code, data, bss, disacardable, etc.)
-// and permissions (writable, readable or executable).
-const uint32_t PermMask = 0xFF0000F0;
+// Mask for permissions (discardable, writable, readable, executable, etc).
+const uint32_t PermMask = 0xFE000000;
+
+// Mask for section types (code, data, bss).
+const uint32_t TypeMask = 0x000000E0;
// A Chunk represents a chunk of data that will occupy space in the
// output (if the resolver chose that). It may or may not be backed by
@@ -75,7 +77,7 @@
virtual bool hasData() const { return true; }
// Returns readable/writable/executable bits.
- virtual uint32_t getPermissions() const { return 0; }
+ virtual uint32_t getOutputCharacteristics() const { return 0; }
// Returns the section name if this is a section chunk.
// It is illegal to call this function on non-section chunks.
@@ -142,7 +144,7 @@
ArrayRef<uint8_t> getContents() const;
void writeTo(uint8_t *Buf) const override;
bool hasData() const override;
- uint32_t getPermissions() const override;
+ uint32_t getOutputCharacteristics() const override;
StringRef getSectionName() const override { return SectionName; }
void getBaserels(std::vector<Baserel> *Res) override;
bool isCOMDAT() const;
@@ -213,11 +215,11 @@
// The COMDAT leader symbol if this is a COMDAT chunk.
DefinedRegular *Sym = nullptr;
+ ArrayRef<coff_relocation> Relocs;
+
private:
StringRef SectionName;
std::vector<SectionChunk *> AssocChildren;
- llvm::iterator_range<const coff_relocation *> Relocs;
- size_t NumRelocs;
// Used by the garbage collector.
bool Live;
@@ -242,7 +244,7 @@
static void addSection(SectionChunk *C);
void finalizeContents() override;
- uint32_t getPermissions() const override;
+ uint32_t getOutputCharacteristics() const override;
StringRef getSectionName() const override { return ".rdata"; }
size_t getSize() const override;
void writeTo(uint8_t *Buf) const override;
@@ -260,7 +262,7 @@
CommonChunk(const COFFSymbolRef Sym);
size_t getSize() const override { return Sym.getValue(); }
bool hasData() const override { return false; }
- uint32_t getPermissions() const override;
+ uint32_t getOutputCharacteristics() const override;
StringRef getSectionName() const override { return ".bss"; }
private:
diff --git a/COFF/Config.h b/COFF/Config.h
index 1a03a24..3ccccb6 100644
--- a/COFF/Config.h
+++ b/COFF/Config.h
@@ -92,6 +92,7 @@
std::string ImportName;
bool DoGC = true;
bool DoICF = true;
+ bool TailMerge;
bool Relocatable = true;
bool Force = false;
bool Debug = false;
@@ -100,6 +101,7 @@
bool ShowTiming = false;
unsigned DebugTypes = static_cast<unsigned>(DebugType::None);
std::vector<std::string> NatvisFiles;
+ llvm::SmallString<128> PDBAltPath;
llvm::SmallString<128> PDBPath;
std::vector<llvm::StringRef> Argv;
@@ -127,10 +129,10 @@
Symbol *SEHCount = nullptr;
// Used for /opt:lldlto=N
- unsigned LTOOptLevel = 2;
+ unsigned LTOO = 2;
// Used for /opt:lldltojobs=N
- unsigned LTOJobs = 0;
+ unsigned ThinLTOJobs = 0;
// Used for /opt:lldltopartitions=N
unsigned LTOPartitions = 1;
@@ -179,6 +181,7 @@
uint32_t MinorImageVersion = 0;
uint32_t MajorOSVersion = 6;
uint32_t MinorOSVersion = 0;
+ uint32_t Timestamp = 0;
bool DynamicBase = true;
bool AllowBind = true;
bool NxCompat = true;
@@ -191,7 +194,9 @@
bool WarnMissingOrderSymbol = true;
bool WarnLocallyDefinedImported = true;
bool Incremental = true;
+ bool IntegrityCheck = false;
bool KillAt = false;
+ bool Repro = false;
};
extern Configuration *Config;
diff --git a/COFF/DLL.h b/COFF/DLL.h
index ad31278..c5d6e7c 100644
--- a/COFF/DLL.h
+++ b/COFF/DLL.h
@@ -76,6 +76,11 @@
public:
EdataContents();
std::vector<Chunk *> Chunks;
+
+ uint64_t getRVA() { return Chunks[0]->getRVA(); }
+ uint64_t getSize() {
+ return Chunks.back()->getRVA() + Chunks.back()->getSize() - getRVA();
+ }
};
} // namespace coff
diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp
index 02b2208..64a7d72 100644
--- a/COFF/Driver.cpp
+++ b/COFF/Driver.cpp
@@ -97,7 +97,7 @@
// Create a std::future that opens and maps a file using the best strategy for
// the host platform.
static std::future<MBErrPair> createFutureForFile(std::string Path) {
-#if LLVM_ON_WIN32
+#if _WIN32
// On Windows, file I/O is relatively slow so it is best to do this
// asynchronously.
auto Strategy = std::launch::async;
@@ -105,7 +105,9 @@
auto Strategy = std::launch::deferred;
#endif
return std::async(Strategy, [=]() {
- auto MBOrErr = MemoryBuffer::getFile(Path);
+ auto MBOrErr = MemoryBuffer::getFile(Path,
+ /*FileSize*/ -1,
+ /*RequiresNullTerminator*/ false);
if (!MBOrErr)
return MBErrPair{nullptr, MBOrErr.getError()};
return MBErrPair{std::move(*MBOrErr), std::error_code()};
@@ -557,16 +559,17 @@
if (!Config->Incremental) {
HandleError(writeImportLibrary(LibName, Path, Exports, Config->Machine,
- false, Config->MinGW));
+ Config->MinGW));
return;
}
// If the import library already exists, replace it only if the contents
// have changed.
- ErrorOr<std::unique_ptr<MemoryBuffer>> OldBuf = MemoryBuffer::getFile(Path);
+ ErrorOr<std::unique_ptr<MemoryBuffer>> OldBuf = MemoryBuffer::getFile(
+ Path, /*FileSize*/ -1, /*RequiresNullTerminator*/ false);
if (!OldBuf) {
HandleError(writeImportLibrary(LibName, Path, Exports, Config->Machine,
- false, Config->MinGW));
+ Config->MinGW));
return;
}
@@ -577,12 +580,13 @@
EC.message());
if (Error E = writeImportLibrary(LibName, TmpName, Exports, Config->Machine,
- false, Config->MinGW)) {
+ Config->MinGW)) {
HandleError(std::move(E));
return;
}
- std::unique_ptr<MemoryBuffer> NewBuf = check(MemoryBuffer::getFile(TmpName));
+ std::unique_ptr<MemoryBuffer> NewBuf = check(MemoryBuffer::getFile(
+ TmpName, /*FileSize*/ -1, /*RequiresNullTerminator*/ false));
if ((*OldBuf)->getBuffer() != NewBuf->getBuffer()) {
OldBuf->reset();
HandleError(errorCodeToError(sys::fs::rename(TmpName, Path)));
@@ -621,9 +625,18 @@
for (COFFShortExport E1 : M.Exports) {
Export E2;
+ // In simple cases, only Name is set. Renamed exports are parsed
+ // and set as "ExtName = Name". If Name has the form "OtherDll.Func",
+ // it shouldn't be a normal exported function but a forward to another
+ // DLL instead. This is supported by both MS and GNU linkers.
+ if (E1.ExtName != E1.Name && StringRef(E1.Name).contains('.')) {
+ E2.Name = Saver.save(E1.ExtName);
+ E2.ForwardTo = Saver.save(E1.Name);
+ Config->Exports.push_back(E2);
+ continue;
+ }
E2.Name = Saver.save(E1.Name);
- if (E1.isWeak())
- E2.ExtName = Saver.save(E1.ExtName);
+ E2.ExtName = Saver.save(E1.ExtName);
E2.Ordinal = E1.Ordinal;
E2.Noname = E1.Noname;
E2.Data = E1.Data;
@@ -936,6 +949,8 @@
if (ShouldCreatePDB) {
if (auto *Arg = Args.getLastArg(OPT_pdb))
Config->PDBPath = Arg->getValue();
+ if (auto *Arg = Args.getLastArg(OPT_pdbaltpath))
+ Config->PDBAltPath = Arg->getValue();
if (Args.hasArg(OPT_natvis))
Config->NatvisFiles = Args.getAllArgValues(OPT_natvis);
}
@@ -1018,6 +1033,23 @@
parseSubsystem(Arg->getValue(), &Config->Subsystem, &Config->MajorOSVersion,
&Config->MinorOSVersion);
+ // Handle /timestamp
+ if (llvm::opt::Arg *Arg = Args.getLastArg(OPT_timestamp, OPT_repro)) {
+ if (Arg->getOption().getID() == OPT_repro) {
+ Config->Timestamp = 0;
+ Config->Repro = true;
+ } else {
+ Config->Repro = false;
+ StringRef Value(Arg->getValue());
+ if (Value.getAsInteger(0, Config->Timestamp))
+ fatal(Twine("invalid timestamp: ") + Value +
+ ". Expected 32-bit integer");
+ }
+ } else {
+ Config->Repro = false;
+ Config->Timestamp = time(nullptr);
+ }
+
// Handle /alternatename
for (auto *Arg : Args.filtered(OPT_alternatename))
parseAlternateName(Arg->getValue());
@@ -1034,6 +1066,7 @@
bool DoGC = !Args.hasArg(OPT_debug) || Args.hasArg(OPT_profile);
unsigned ICFLevel =
Args.hasArg(OPT_profile) ? 0 : 1; // 0: off, 1: limited, 2: on
+ unsigned TailMerge = 1;
for (auto *Arg : Args.filtered(OPT_opt)) {
std::string Str = StringRef(Arg->getValue()).lower();
SmallVector<StringRef, 1> Vec;
@@ -1047,14 +1080,18 @@
ICFLevel = 2;
} else if (S == "noicf") {
ICFLevel = 0;
+ } else if (S == "lldtailmerge") {
+ TailMerge = 2;
+ } else if (S == "nolldtailmerge") {
+ TailMerge = 0;
} else if (S.startswith("lldlto=")) {
StringRef OptLevel = S.substr(7);
- if (OptLevel.getAsInteger(10, Config->LTOOptLevel) ||
- Config->LTOOptLevel > 3)
+ if (OptLevel.getAsInteger(10, Config->LTOO) || Config->LTOO > 3)
error("/opt:lldlto: invalid optimization level: " + OptLevel);
} else if (S.startswith("lldltojobs=")) {
StringRef Jobs = S.substr(11);
- if (Jobs.getAsInteger(10, Config->LTOJobs) || Config->LTOJobs == 0)
+ if (Jobs.getAsInteger(10, Config->ThinLTOJobs) ||
+ Config->ThinLTOJobs == 0)
error("/opt:lldltojobs: invalid job count: " + Jobs);
} else if (S.startswith("lldltopartitions=")) {
StringRef N = S.substr(17);
@@ -1075,6 +1112,7 @@
ICFLevel = 0;
Config->DoGC = DoGC;
Config->DoICF = ICFLevel > 0;
+ Config->TailMerge = (TailMerge == 1 && Config->DoICF) || TailMerge == 2;
// Handle /lldsavetemps
if (Args.hasArg(OPT_lldsavetemps))
@@ -1102,6 +1140,14 @@
for (auto *Arg : Args.filtered(OPT_merge))
parseMerge(Arg->getValue());
+ // Add default section merging rules after user rules. User rules take
+ // precedence, but we will emit a warning if there is a conflict.
+ parseMerge(".idata=.rdata");
+ parseMerge(".didat=.rdata");
+ parseMerge(".edata=.rdata");
+ parseMerge(".xdata=.rdata");
+ parseMerge(".bss=.data");
+
// Handle /section
for (auto *Arg : Args.filtered(OPT_section))
parseSection(Arg->getValue());
@@ -1150,8 +1196,11 @@
Args.hasFlag(OPT_incremental, OPT_incremental_no,
!Config->DoGC && !Config->DoICF && !Args.hasArg(OPT_order) &&
!Args.hasArg(OPT_profile));
+ Config->IntegrityCheck =
+ Args.hasFlag(OPT_integritycheck, OPT_integritycheck_no, false);
Config->NxCompat = Args.hasFlag(OPT_nxcompat, OPT_nxcompat_no, true);
- Config->TerminalServerAware = Args.hasFlag(OPT_tsaware, OPT_tsaware_no, true);
+ Config->TerminalServerAware =
+ !Config->DLL && Args.hasFlag(OPT_tsaware, OPT_tsaware_no, true);
Config->DebugDwarf = Args.hasArg(OPT_debug_dwarf);
Config->DebugGHashes = Args.hasArg(OPT_debug_ghash);
@@ -1301,10 +1350,19 @@
getOutputPath((*Args.filtered(OPT_INPUT).begin())->getValue());
}
- // Put the PDB next to the image if no /pdb flag was passed.
- if (ShouldCreatePDB && Config->PDBPath.empty()) {
- Config->PDBPath = Config->OutputFile;
- sys::path::replace_extension(Config->PDBPath, ".pdb");
+ if (ShouldCreatePDB) {
+ // Put the PDB next to the image if no /pdb flag was passed.
+ if (Config->PDBPath.empty()) {
+ Config->PDBPath = Config->OutputFile;
+ sys::path::replace_extension(Config->PDBPath, ".pdb");
+ }
+
+ // The embedded PDB path should be the absolute path to the PDB if no
+ // /pdbaltpath flag was passed.
+ if (Config->PDBAltPath.empty()) {
+ Config->PDBAltPath = Config->PDBPath;
+ sys::fs::make_absolute(Config->PDBAltPath);
+ }
}
// Set default image base if /base is not given.
@@ -1414,7 +1472,7 @@
E.Name = Def->getName();
E.Sym = Def;
if (Def->getChunk() &&
- !(Def->getChunk()->getPermissions() & IMAGE_SCN_MEM_EXECUTE))
+ !(Def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE))
E.Data = true;
Config->Exports.push_back(E);
});
diff --git a/COFF/DriverUtils.cpp b/COFF/DriverUtils.cpp
index 0b705f4..9875119 100644
--- a/COFF/DriverUtils.cpp
+++ b/COFF/DriverUtils.cpp
@@ -185,6 +185,10 @@
std::tie(From, To) = S.split('=');
if (From.empty() || To.empty())
fatal("/merge: invalid argument: " + S);
+ if (From == ".rsrc" || To == ".rsrc")
+ fatal("/merge: cannot merge '.rsrc' with any section");
+ if (From == ".reloc" || To == ".reloc")
+ fatal("/merge: cannot merge '.reloc' with any section");
auto Pair = Config->Merge.insert(std::make_pair(From, To));
bool Inserted = Pair.second;
if (!Inserted) {
@@ -752,6 +756,28 @@
COFFOptTable::COFFOptTable() : OptTable(InfoTable, true) {}
+// Set color diagnostics according to --color-diagnostics={auto,always,never}
+// or --no-color-diagnostics flags.
+static void handleColorDiagnostics(opt::InputArgList &Args) {
+ auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
+ OPT_no_color_diagnostics);
+ if (!Arg)
+ return;
+ if (Arg->getOption().getID() == OPT_color_diagnostics) {
+ errorHandler().ColorDiagnostics = true;
+ } else if (Arg->getOption().getID() == OPT_no_color_diagnostics) {
+ errorHandler().ColorDiagnostics = false;
+ } else {
+ StringRef S = Arg->getValue();
+ if (S == "always")
+ errorHandler().ColorDiagnostics = true;
+ else if (S == "never")
+ errorHandler().ColorDiagnostics = false;
+ else if (S != "auto")
+ error("unknown option: --color-diagnostics=" + S);
+ }
+}
+
static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) {
if (auto *Arg = Args.getLastArg(OPT_rsp_quoting)) {
StringRef S = Arg->getValue();
@@ -795,6 +821,9 @@
if (MissingCount)
fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument");
+
+ handleColorDiagnostics(Args);
+
for (auto *Arg : Args.filtered(OPT_UNKNOWN))
warn("ignoring unknown argument: " + Arg->getSpelling());
return Args;
diff --git a/COFF/ICF.cpp b/COFF/ICF.cpp
index 77c05b7..6297209 100644
--- a/COFF/ICF.cpp
+++ b/COFF/ICF.cpp
@@ -45,6 +45,8 @@
private:
void segregate(size_t Begin, size_t End, bool Constant);
+ bool assocEquals(const SectionChunk *A, const SectionChunk *B);
+
bool equalsConstant(const SectionChunk *A, const SectionChunk *B);
bool equalsVariable(const SectionChunk *A, const SectionChunk *B);
@@ -65,8 +67,8 @@
// Returns a hash value for S.
uint32_t ICF::getHash(SectionChunk *C) {
- return hash_combine(C->getPermissions(), C->SectionName, C->NumRelocs,
- C->Alignment, uint32_t(C->Header->SizeOfRawData),
+ return hash_combine(C->getOutputCharacteristics(), C->SectionName,
+ C->Relocs.size(), uint32_t(C->Header->SizeOfRawData),
C->Checksum, C->getContents());
}
@@ -77,21 +79,27 @@
// 2017) says that /opt:icf folds both functions and read-only data.
// Despite that, the MSVC linker folds only functions. We found
// a few instances of programs that are not safe for data merging.
-// Therefore, we merge only functions just like the MSVC tool. However, we merge
-// identical .xdata sections, because the address of unwind information is
-// insignificant to the user program and the Visual C++ linker does this.
+// Therefore, we merge only functions just like the MSVC tool. However, we also
+// merge read-only sections in a couple of cases where the address of the
+// section is insignificant to the user program and the behaviour matches that
+// of the Visual C++ linker.
bool ICF::isEligible(SectionChunk *C) {
// Non-comdat chunks, dead chunks, and writable chunks are not elegible.
- bool Writable = C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_WRITE;
+ bool Writable = C->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_WRITE;
if (!C->isCOMDAT() || !C->isLive() || Writable)
return false;
// Code sections are eligible.
- if (C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE)
+ if (C->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE)
return true;
- // .xdata unwind info sections are eligble.
- return C->getSectionName().split('$').first == ".xdata";
+ // .pdata and .xdata unwind info sections are eligible.
+ StringRef OutSecName = C->getSectionName().split('$').first;
+ if (OutSecName == ".pdata" || OutSecName == ".xdata")
+ return true;
+
+ // So are vtables.
+ return C->Sym && C->Sym->getName().startswith("??_7");
}
// Split an equivalence class into smaller classes.
@@ -120,10 +128,23 @@
}
}
+// Returns true if two sections' associative children are equal.
+bool ICF::assocEquals(const SectionChunk *A, const SectionChunk *B) {
+ auto ChildClasses = [&](const SectionChunk *SC) {
+ std::vector<uint32_t> Classes;
+ for (const SectionChunk *C : SC->children())
+ if (!C->SectionName.startswith(".debug") &&
+ C->SectionName != ".gfids$y" && C->SectionName != ".gljmp$y")
+ Classes.push_back(C->Class[Cnt % 2]);
+ return Classes;
+ };
+ return ChildClasses(A) == ChildClasses(B);
+}
+
// Compare "non-moving" part of two sections, namely everything
// except relocation targets.
bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) {
- if (A->NumRelocs != B->NumRelocs)
+ if (A->Relocs.size() != B->Relocs.size())
return false;
// Compare relocations.
@@ -146,10 +167,11 @@
return false;
// Compare section attributes and contents.
- return A->getPermissions() == B->getPermissions() &&
- A->SectionName == B->SectionName && A->Alignment == B->Alignment &&
+ return A->getOutputCharacteristics() == B->getOutputCharacteristics() &&
+ A->SectionName == B->SectionName &&
A->Header->SizeOfRawData == B->Header->SizeOfRawData &&
- A->Checksum == B->Checksum && A->getContents() == B->getContents();
+ A->Checksum == B->Checksum && A->getContents() == B->getContents() &&
+ assocEquals(A, B);
}
// Compare "moving" part of two sections, namely relocation targets.
@@ -165,7 +187,9 @@
return D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2];
return false;
};
- return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq);
+ return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(),
+ Eq) &&
+ assocEquals(A, B);
}
// Find the first Chunk after Begin that has a different class from Begin.
diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp
index 78bfe34..9e2345b 100644
--- a/COFF/InputFiles.cpp
+++ b/COFF/InputFiles.cpp
@@ -170,8 +170,8 @@
// CodeView needs a linker support. We need to interpret and debug
// info, and then write it to a separate .pdb file.
- // Ignore debug info unless /debug is given.
- if (!Config->Debug && Name.startswith(".debug"))
+ // Ignore DWARF debug info unless /debug is given.
+ if (!Config->Debug && Name.startswith(".debug_"))
return nullptr;
if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE)
@@ -190,8 +190,8 @@
GuardLJmpChunks.push_back(C);
else if (Name == ".sxdata")
SXDataChunks.push_back(C);
- else if (Config->DoICF && Sec->NumberOfRelocations == 0 && Name == ".rdata" &&
- LeaderName.startswith("??_C@"))
+ else if (Config->TailMerge && Sec->NumberOfRelocations == 0 &&
+ Name == ".rdata" && LeaderName.startswith("??_C@"))
// COFF sections that look like string literal sections (i.e. no
// relocations, in .rdata, leader symbol name matches the MSVC name mangling
// for string literals) are subject to string tail merging.
@@ -326,14 +326,13 @@
if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG)
return nullptr;
- // Reserved sections numbers don't have contents.
if (llvm::COFF::isReservedSectionNumber(SectionNumber))
- fatal("broken object file: " + toString(this));
+ fatal(toString(this) + ": " + Name +
+ " should not refer to special section " + Twine(SectionNumber));
- // This symbol references a section which is not present in the section
- // header.
if ((uint32_t)SectionNumber >= SparseChunks.size())
- fatal("broken object file: " + toString(this));
+ fatal(toString(this) + ": " + Name +
+ " should not refer to non-existent section " + Twine(SectionNumber));
// Handle comdat leader symbols.
if (const coff_aux_section_definition *Def = ComdatDefs[SectionNumber]) {
@@ -465,7 +464,7 @@
} else {
Sym = Symtab->addRegular(this, SymName);
}
- SymbolBodies.push_back(Sym);
+ Symbols.push_back(Sym);
}
Directives = Obj->getCOFFLinkerOpts();
}
diff --git a/COFF/InputFiles.h b/COFF/InputFiles.h
index 3ee5780..9f4db45 100644
--- a/COFF/InputFiles.h
+++ b/COFF/InputFiles.h
@@ -201,8 +201,7 @@
// for details about the format.
class ImportFile : public InputFile {
public:
- explicit ImportFile(MemoryBufferRef M)
- : InputFile(ImportKind, M), Live(!Config->DoGC) {}
+ explicit ImportFile(MemoryBufferRef M) : InputFile(ImportKind, M) {}
static bool classof(const InputFile *F) { return F->kind() == ImportKind; }
@@ -221,12 +220,15 @@
Chunk *Location = nullptr;
// We want to eliminate dllimported symbols if no one actually refers them.
- // This "Live" bit is used to keep track of which import library members
+ // These "Live" bits are used to keep track of which import library members
// are actually in use.
//
// If the Live bit is turned off by MarkLive, Writer will ignore dllimported
- // symbols provided by this import library member.
- bool Live;
+ // symbols provided by this import library member. We also track whether the
+ // imported symbol is used separately from whether the thunk is used in order
+ // to avoid creating unnecessary thunks.
+ bool Live = !Config->DoGC;
+ bool ThunkLive = !Config->DoGC;
};
// Used for LTO.
@@ -234,7 +236,7 @@
public:
explicit BitcodeFile(MemoryBufferRef M) : InputFile(BitcodeKind, M) {}
static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
- ArrayRef<Symbol *> getSymbols() { return SymbolBodies; }
+ ArrayRef<Symbol *> getSymbols() { return Symbols; }
MachineTypes getMachineType() override;
static std::vector<BitcodeFile *> Instances;
std::unique_ptr<llvm::lto::InputFile> Obj;
@@ -242,7 +244,7 @@
private:
void parse() override;
- std::vector<Symbol *> SymbolBodies;
+ std::vector<Symbol *> Symbols;
};
} // namespace coff
diff --git a/COFF/LTO.cpp b/COFF/LTO.cpp
index 56ca8c0..93f7ba3 100644
--- a/COFF/LTO.cpp
+++ b/COFF/LTO.cpp
@@ -12,6 +12,7 @@
#include "InputFiles.h"
#include "Symbols.h"
#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Strings.h"
#include "lld/Common/TargetOptionsCommandFlags.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
@@ -40,53 +41,32 @@
using namespace lld;
using namespace lld::coff;
-static void diagnosticHandler(const DiagnosticInfo &DI) {
- SmallString<128> ErrStorage;
- raw_svector_ostream OS(ErrStorage);
- DiagnosticPrinterRawOStream DP(OS);
- DI.print(DP);
- warn(ErrStorage);
-}
-
-static void checkError(Error E) {
- handleAllErrors(std::move(E),
- [&](ErrorInfoBase &EIB) { error(EIB.message()); });
-}
-
-static void saveBuffer(StringRef Buffer, const Twine &Path) {
- std::error_code EC;
- raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None);
- if (EC)
- error("cannot create " + Path + ": " + EC.message());
- OS << Buffer;
-}
-
static std::unique_ptr<lto::LTO> createLTO() {
- lto::Config Conf;
- Conf.Options = InitTargetOptionsFromCodeGenFlags();
+ lto::Config C;
+ C.Options = InitTargetOptionsFromCodeGenFlags();
// Always emit a section per function/datum with LTO. LLVM LTO should get most
// of the benefit of linker GC, but there are still opportunities for ICF.
- Conf.Options.FunctionSections = true;
- Conf.Options.DataSections = true;
+ C.Options.FunctionSections = true;
+ C.Options.DataSections = true;
// Use static reloc model on 32-bit x86 because it usually results in more
// compact code, and because there are also known code generation bugs when
// using the PIC model (see PR34306).
if (Config->Machine == COFF::IMAGE_FILE_MACHINE_I386)
- Conf.RelocModel = Reloc::Static;
+ C.RelocModel = Reloc::Static;
else
- Conf.RelocModel = Reloc::PIC_;
- Conf.DisableVerify = true;
- Conf.DiagHandler = diagnosticHandler;
- Conf.OptLevel = Config->LTOOptLevel;
+ C.RelocModel = Reloc::PIC_;
+ C.DisableVerify = true;
+ C.DiagHandler = diagnosticHandler;
+ C.OptLevel = Config->LTOO;
if (Config->SaveTemps)
- checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".",
- /*UseInputModulePath*/ true));
+ checkError(C.addSaveTemps(std::string(Config->OutputFile) + ".",
+ /*UseInputModulePath*/ true));
lto::ThinBackend Backend;
- if (Config->LTOJobs != 0)
- Backend = lto::createInProcessThinBackend(Config->LTOJobs);
- return llvm::make_unique<lto::LTO>(std::move(Conf), Backend,
+ if (Config->ThinLTOJobs != 0)
+ Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs);
+ return llvm::make_unique<lto::LTO>(std::move(C), Backend,
Config->LTOPartitions);
}
@@ -125,7 +105,7 @@
// and return the resulting objects.
std::vector<StringRef> BitcodeCompiler::compile() {
unsigned MaxTasks = LTOObj->getMaxTasks();
- Buff.resize(MaxTasks);
+ Buf.resize(MaxTasks);
Files.resize(MaxTasks);
// The /lldltocache option specifies the path to a directory in which to cache
@@ -141,7 +121,7 @@
checkError(LTOObj->run(
[&](size_t Task) {
return llvm::make_unique<lto::NativeObjectStream>(
- llvm::make_unique<raw_svector_ostream>(Buff[Task]));
+ llvm::make_unique<raw_svector_ostream>(Buf[Task]));
},
Cache));
@@ -150,15 +130,15 @@
std::vector<StringRef> Ret;
for (unsigned I = 0; I != MaxTasks; ++I) {
- if (Buff[I].empty())
+ if (Buf[I].empty())
continue;
if (Config->SaveTemps) {
if (I == 0)
- saveBuffer(Buff[I], Config->OutputFile + ".lto.obj");
+ saveBuffer(Buf[I], Config->OutputFile + ".lto.obj");
else
- saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.obj");
+ saveBuffer(Buf[I], Config->OutputFile + Twine(I) + ".lto.obj");
}
- Ret.emplace_back(Buff[I].data(), Buff[I].size());
+ Ret.emplace_back(Buf[I].data(), Buf[I].size());
}
for (std::unique_ptr<MemoryBuffer> &File : Files)
diff --git a/COFF/LTO.h b/COFF/LTO.h
index a444aa7..f009246 100644
--- a/COFF/LTO.h
+++ b/COFF/LTO.h
@@ -48,7 +48,7 @@
private:
std::unique_ptr<llvm::lto::LTO> LTOObj;
- std::vector<SmallString<0>> Buff;
+ std::vector<SmallString<0>> Buf;
std::vector<std::unique_ptr<MemoryBuffer>> Files;
};
}
diff --git a/COFF/MarkLive.cpp b/COFF/MarkLive.cpp
index d5d6ecf..57ae450 100644
--- a/COFF/MarkLive.cpp
+++ b/COFF/MarkLive.cpp
@@ -48,7 +48,7 @@
else if (auto *Sym = dyn_cast<DefinedImportData>(B))
Sym->File->Live = true;
else if (auto *Sym = dyn_cast<DefinedImportThunk>(B))
- Sym->WrappedSym->File->Live = true;
+ Sym->WrappedSym->File->Live = Sym->WrappedSym->File->ThunkLive = true;
};
// Add GC root chunks.
diff --git a/COFF/MinGW.cpp b/COFF/MinGW.cpp
index b7a4716..2ca0058 100644
--- a/COFF/MinGW.cpp
+++ b/COFF/MinGW.cpp
@@ -138,7 +138,7 @@
<< "@" << E.Ordinal;
if (auto *Def = dyn_cast_or_null<Defined>(E.Sym)) {
if (Def && Def->getChunk() &&
- !(Def->getChunk()->getPermissions() & IMAGE_SCN_MEM_EXECUTE))
+ !(Def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE))
OS << " DATA";
}
OS << "\n";
diff --git a/COFF/Options.td b/COFF/Options.td
index 243671d..9051b0b 100644
--- a/COFF/Options.td
+++ b/COFF/Options.td
@@ -20,6 +20,10 @@
def aligncomm : P<"aligncomm", "Set common symbol alignment">;
def alternatename : P<"alternatename", "Define weak alias">;
def base : P<"base", "Base address of the program">;
+def color_diagnostics: Flag<["--"], "color-diagnostics">,
+ HelpText<"Use colors in diagnostics">;
+def color_diagnostics_eq: Joined<["--"], "color-diagnostics=">,
+ HelpText<"Use colors in diagnostics; one of 'always', 'never', 'auto'">;
def defaultlib : P<"defaultlib", "Add the library to the list of input files">;
def delayload : P<"delayload", "Delay loaded DLL name">;
def entry : P<"entry", "Name of entry point symbol">;
@@ -46,11 +50,15 @@
def order : P<"order", "Put functions in order">;
def out : P<"out", "Path to file to write output">;
def natvis : P<"natvis", "Path to natvis file to embed in the PDB">;
+def no_color_diagnostics: F<"no-color-diagnostics">,
+ HelpText<"Do not use colors in diagnostics">;
def pdb : P<"pdb", "PDB file path">;
+def pdbaltpath : P<"pdbaltpath", "PDB file path to embed in the image">;
def section : P<"section", "Specify section attributes">;
def stack : P<"stack", "Size of the stack">;
def stub : P<"stub", "Specify DOS stub file">;
def subsystem : P<"subsystem", "Specify subsystem">;
+def timestamp : P<"timestamp", "Specify the PE header timestamp">;
def version : P<"version", "Specify a version number in the PE header">;
def wholearchive_file : P<"wholearchive", "Include all object files from this archive">;
@@ -75,12 +83,14 @@
HelpText<"Use module-definition file">;
def debug : F<"debug">, HelpText<"Embed a symbol table in the image">;
+def debug_full : F<"debug:full">, Alias<debug>;
def debugtype : P<"debugtype", "Debug Info Options">;
def dll : F<"dll">, HelpText<"Create a DLL">;
def driver : P<"driver", "Generate a Windows NT Kernel Mode Driver">;
def nodefaultlib_all : F<"nodefaultlib">;
def noentry : F<"noentry">;
def profile : F<"profile">;
+def repro : F<"Brepro">, HelpText<"Use a hash of the executable as the PE header timestamp">;
def swaprun_cd : F<"swaprun:cd">;
def swaprun_net : F<"swaprun:net">;
def verbose : F<"verbose">;
@@ -107,7 +117,10 @@
"Disable 64-bit ASLR">;
defm incremental : B<"incremental",
"Keep original import library if contents are unchanged",
- "Replace import library file even if contents are unchanged">;
+ "Overwrite import library even if contents are unchanged">;
+defm integritycheck : B<"integritycheck",
+ "Set FORCE_INTEGRITY bit in PE header",
+ "No effect (default)">;
defm largeaddressaware : B<"largeaddressaware",
"Enable large addresses (default on 64-bit)",
"Disable large addresses (default on 32-bit)">;
@@ -163,7 +176,6 @@
def errorreport : QF<"errorreport">;
def idlout : QF<"idlout">;
def maxilksize : QF<"maxilksize">;
-def pdbaltpath : QF<"pdbaltpath">;
def tlbid : QF<"tlbid">;
def tlbout : QF<"tlbout">;
def verbose_all : QF<"verbose">;
diff --git a/COFF/PDB.cpp b/COFF/PDB.cpp
index 91131c6..6dc2cdd 100644
--- a/COFF/PDB.cpp
+++ b/COFF/PDB.cpp
@@ -125,9 +125,6 @@
void addSections(ArrayRef<OutputSection *> OutputSections,
ArrayRef<uint8_t> SectionTable);
- void addSectionContrib(pdb::DbiModuleDescriptorBuilder &LinkerModule,
- OutputSection *OS, Chunk *C);
-
/// Write the PDB to disk.
void commit();
@@ -208,8 +205,8 @@
DebugH = DebugH.drop_front(sizeof(object::debug_h_header));
return Header->Magic == COFF::DEBUG_HASHES_SECTION_MAGIC &&
Header->Version == 0 &&
- Header->HashAlgorithm == uint16_t(GlobalTypeHashAlg::SHA1) &&
- (DebugH.size() % 20 == 0);
+ Header->HashAlgorithm == uint16_t(GlobalTypeHashAlg::SHA1_8) &&
+ (DebugH.size() % 8 == 0);
}
static Optional<ArrayRef<uint8_t>> getDebugH(ObjFile *File) {
@@ -780,6 +777,32 @@
".debug$S");
}
+static pdb::SectionContrib createSectionContrib(const Chunk *C, uint32_t Modi) {
+ OutputSection *OS = C->getOutputSection();
+ pdb::SectionContrib SC;
+ memset(&SC, 0, sizeof(SC));
+ SC.ISect = OS->SectionIndex;
+ SC.Off = C->getRVA() - OS->getRVA();
+ SC.Size = C->getSize();
+ if (auto *SecChunk = dyn_cast<SectionChunk>(C)) {
+ SC.Characteristics = SecChunk->Header->Characteristics;
+ SC.Imod = SecChunk->File->ModuleDBI->getModuleIndex();
+ ArrayRef<uint8_t> Contents = SecChunk->getContents();
+ JamCRC CRC(0);
+ ArrayRef<char> CharContents = makeArrayRef(
+ reinterpret_cast<const char *>(Contents.data()), Contents.size());
+ CRC.update(CharContents);
+ SC.DataCrc = CRC.getCRC();
+ } else {
+ SC.Characteristics = OS->Header.Characteristics;
+ // FIXME: When we start creating DBI for import libraries, use those here.
+ SC.Imod = Modi;
+ }
+ SC.RelocCrc = 0; // FIXME
+
+ return SC;
+}
+
void PDBLinker::addObjFile(ObjFile *File) {
// Add a module descriptor for every object file. We need to put an absolute
// path to the object into the PDB. If this is a plain object, we make its
@@ -794,6 +817,17 @@
File->ModuleDBI = &ExitOnErr(Builder.getDbiBuilder().addModuleInfo(Name));
File->ModuleDBI->setObjFileName(Path);
+ auto Chunks = File->getChunks();
+ uint32_t Modi = File->ModuleDBI->getModuleIndex();
+ for (Chunk *C : Chunks) {
+ auto *SecChunk = dyn_cast<SectionChunk>(C);
+ if (!SecChunk || !SecChunk->isLive())
+ continue;
+ pdb::SectionContrib SC = createSectionContrib(SecChunk, Modi);
+ File->ModuleDBI->setFirstSectionContrib(SC);
+ break;
+ }
+
// Before we can process symbol substreams from .debug$S, we need to process
// type information, file checksums, and the string table. Add type info to
// the PDB first, so that we can get the map from object file type and item
@@ -832,9 +866,6 @@
for (const DebugSubsectionRecord &SS : Subsections) {
switch (SS.kind()) {
case DebugSubsectionKind::StringTable: {
- auto Data = SS.getRecordData();
- ArrayRef<uint8_t> Buffer;
- cantFail(Data.readLongestContiguousChunk(0, Buffer));
assert(!CVStrTab.valid() &&
"Encountered multiple string table subsections!");
ExitOnErr(CVStrTab.initialize(SS.getRecordData()));
@@ -981,6 +1012,23 @@
}
}
+static codeview::CPUType toCodeViewMachine(COFF::MachineTypes Machine) {
+ switch (Machine) {
+ case COFF::IMAGE_FILE_MACHINE_AMD64:
+ return codeview::CPUType::X64;
+ case COFF::IMAGE_FILE_MACHINE_ARM:
+ return codeview::CPUType::ARM7;
+ case COFF::IMAGE_FILE_MACHINE_ARM64:
+ return codeview::CPUType::ARM64;
+ case COFF::IMAGE_FILE_MACHINE_ARMNT:
+ return codeview::CPUType::ARMNT;
+ case COFF::IMAGE_FILE_MACHINE_I386:
+ return codeview::CPUType::Intel80386;
+ default:
+ llvm_unreachable("Unsupported CPU Type");
+ }
+}
+
static void addCommonLinkerModuleSymbols(StringRef Path,
pdb::DbiModuleDescriptorBuilder &Mod,
BumpPtrAllocator &Allocator) {
@@ -991,7 +1039,7 @@
ONS.Name = "* Linker *";
ONS.Signature = 0;
- CS.Machine = Config->is64() ? CPUType::X64 : CPUType::Intel80386;
+ CS.Machine = toCodeViewMachine(Config->Machine);
// Interestingly, if we set the string to 0.0.0.0, then when trying to view
// local variables WinDbg emits an error that private symbols are not present.
// By setting this to a valid MSVC linker version string, local variables are
@@ -1042,7 +1090,7 @@
BumpPtrAllocator &Allocator) {
SectionSym Sym(SymbolRecordKind::SectionSym);
Sym.Alignment = 12; // 2^12 = 4KB
- Sym.Characteristics = OS.getCharacteristics();
+ Sym.Characteristics = OS.Header.Characteristics;
Sym.Length = OS.getVirtualSize();
Sym.Name = OS.Name;
Sym.Rva = OS.getRVA();
@@ -1088,31 +1136,12 @@
pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder();
DbiBuilder.setAge(BuildId.PDB70.Age);
DbiBuilder.setVersionHeader(pdb::PdbDbiV70);
-}
-
-void PDBLinker::addSectionContrib(pdb::DbiModuleDescriptorBuilder &LinkerModule,
- OutputSection *OS, Chunk *C) {
- pdb::SectionContrib SC;
- memset(&SC, 0, sizeof(SC));
- SC.ISect = OS->SectionIndex;
- SC.Off = C->getRVA() - OS->getRVA();
- SC.Size = C->getSize();
- if (auto *SecChunk = dyn_cast<SectionChunk>(C)) {
- SC.Characteristics = SecChunk->Header->Characteristics;
- SC.Imod = SecChunk->File->ModuleDBI->getModuleIndex();
- ArrayRef<uint8_t> Contents = SecChunk->getContents();
- JamCRC CRC(0);
- ArrayRef<char> CharContents = makeArrayRef(
- reinterpret_cast<const char *>(Contents.data()), Contents.size());
- CRC.update(CharContents);
- SC.DataCrc = CRC.getCRC();
- } else {
- SC.Characteristics = OS->getCharacteristics();
- // FIXME: When we start creating DBI for import libraries, use those here.
- SC.Imod = LinkerModule.getModuleIndex();
- }
- SC.RelocCrc = 0; // FIXME
- Builder.getDbiBuilder().addSectionContrib(SC);
+ DbiBuilder.setMachineType(Config->Machine);
+ // Technically we are not link.exe 14.11, but there are known cases where
+ // debugging tools on Windows expect Microsoft-specific version numbers or
+ // they fail to work at all. Since we know we produce PDBs that are
+ // compatible with LINK 14.11, we set that version number here.
+ DbiBuilder.setBuildNumber(14, 11);
}
void PDBLinker::addSections(ArrayRef<OutputSection *> OutputSections,
@@ -1130,8 +1159,11 @@
// Add section contributions. They must be ordered by ascending RVA.
for (OutputSection *OS : OutputSections) {
addLinkerModuleSectionSymbol(LinkerModule, *OS, Alloc);
- for (Chunk *C : OS->getChunks())
- addSectionContrib(LinkerModule, OS, C);
+ for (Chunk *C : OS->getChunks()) {
+ pdb::SectionContrib SC =
+ createSectionContrib(C, LinkerModule.getModuleIndex());
+ Builder.getDbiBuilder().addSectionContrib(SC);
+ }
}
// Add Section Map stream.
@@ -1150,3 +1182,145 @@
// Write to a file.
ExitOnErr(Builder.commit(Config->PDBPath));
}
+
+static Expected<StringRef>
+getFileName(const DebugStringTableSubsectionRef &Strings,
+ const DebugChecksumsSubsectionRef &Checksums, uint32_t FileID) {
+ auto Iter = Checksums.getArray().at(FileID);
+ if (Iter == Checksums.getArray().end())
+ return make_error<CodeViewError>(cv_error_code::no_records);
+ uint32_t Offset = Iter->FileNameOffset;
+ return Strings.getString(Offset);
+}
+
+static uint32_t getSecrelReloc() {
+ switch (Config->Machine) {
+ case AMD64:
+ return COFF::IMAGE_REL_AMD64_SECREL;
+ case I386:
+ return COFF::IMAGE_REL_I386_SECREL;
+ case ARMNT:
+ return COFF::IMAGE_REL_ARM_SECREL;
+ case ARM64:
+ return COFF::IMAGE_REL_ARM64_SECREL;
+ default:
+ llvm_unreachable("unknown machine type");
+ }
+}
+
+// Try to find a line table for the given offset Addr into the given chunk C.
+// If a line table was found, the line table, the string and checksum tables
+// that are used to interpret the line table, and the offset of Addr in the line
+// table are stored in the output arguments. Returns whether a line table was
+// found.
+static bool findLineTable(const SectionChunk *C, uint32_t Addr,
+ DebugStringTableSubsectionRef &CVStrTab,
+ DebugChecksumsSubsectionRef &Checksums,
+ DebugLinesSubsectionRef &Lines,
+ uint32_t &OffsetInLinetable) {
+ ExitOnError ExitOnErr;
+ uint32_t SecrelReloc = getSecrelReloc();
+
+ for (SectionChunk *DbgC : C->File->getDebugChunks()) {
+ if (DbgC->getSectionName() != ".debug$S")
+ continue;
+
+ // Build a mapping of SECREL relocations in DbgC that refer to C.
+ DenseMap<uint32_t, uint32_t> Secrels;
+ for (const coff_relocation &R : DbgC->Relocs) {
+ if (R.Type != SecrelReloc)
+ continue;
+
+ if (auto *S = dyn_cast_or_null<DefinedRegular>(
+ C->File->getSymbols()[R.SymbolTableIndex]))
+ if (S->getChunk() == C)
+ Secrels[R.VirtualAddress] = S->getValue();
+ }
+
+ ArrayRef<uint8_t> Contents =
+ consumeDebugMagic(DbgC->getContents(), ".debug$S");
+ DebugSubsectionArray Subsections;
+ BinaryStreamReader Reader(Contents, support::little);
+ ExitOnErr(Reader.readArray(Subsections, Contents.size()));
+
+ for (const DebugSubsectionRecord &SS : Subsections) {
+ switch (SS.kind()) {
+ case DebugSubsectionKind::StringTable: {
+ assert(!CVStrTab.valid() &&
+ "Encountered multiple string table subsections!");
+ ExitOnErr(CVStrTab.initialize(SS.getRecordData()));
+ break;
+ }
+ case DebugSubsectionKind::FileChecksums:
+ assert(!Checksums.valid() &&
+ "Encountered multiple checksum subsections!");
+ ExitOnErr(Checksums.initialize(SS.getRecordData()));
+ break;
+ case DebugSubsectionKind::Lines: {
+ ArrayRef<uint8_t> Bytes;
+ auto Ref = SS.getRecordData();
+ ExitOnErr(Ref.readLongestContiguousChunk(0, Bytes));
+ size_t OffsetInDbgC = Bytes.data() - DbgC->getContents().data();
+
+ // Check whether this line table refers to C.
+ auto I = Secrels.find(OffsetInDbgC);
+ if (I == Secrels.end())
+ break;
+
+ // Check whether this line table covers Addr in C.
+ DebugLinesSubsectionRef LinesTmp;
+ ExitOnErr(LinesTmp.initialize(BinaryStreamReader(Ref)));
+ uint32_t OffsetInC = I->second + LinesTmp.header()->RelocOffset;
+ if (Addr < OffsetInC || Addr >= OffsetInC + LinesTmp.header()->CodeSize)
+ break;
+
+ assert(!Lines.header() &&
+ "Encountered multiple line tables for function!");
+ ExitOnErr(Lines.initialize(BinaryStreamReader(Ref)));
+ OffsetInLinetable = Addr - OffsetInC;
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (CVStrTab.valid() && Checksums.valid() && Lines.header())
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Use CodeView line tables to resolve a file and line number for the given
+// offset into the given chunk and return them, or {"", 0} if a line table was
+// not found.
+std::pair<StringRef, uint32_t> coff::getFileLine(const SectionChunk *C,
+ uint32_t Addr) {
+ ExitOnError ExitOnErr;
+
+ DebugStringTableSubsectionRef CVStrTab;
+ DebugChecksumsSubsectionRef Checksums;
+ DebugLinesSubsectionRef Lines;
+ uint32_t OffsetInLinetable;
+
+ if (!findLineTable(C, Addr, CVStrTab, Checksums, Lines, OffsetInLinetable))
+ return {"", 0};
+
+ uint32_t NameIndex;
+ uint32_t LineNumber;
+ for (LineColumnEntry &Entry : Lines) {
+ for (const LineNumberEntry &LN : Entry.LineNumbers) {
+ if (LN.Offset > OffsetInLinetable) {
+ StringRef Filename =
+ ExitOnErr(getFileName(CVStrTab, Checksums, NameIndex));
+ return {Filename, LineNumber};
+ }
+ LineInfo LI(LN.Flags);
+ NameIndex = Entry.NameIndex;
+ LineNumber = LI.getStartLine();
+ }
+ }
+ StringRef Filename = ExitOnErr(getFileName(CVStrTab, Checksums, NameIndex));
+ return {Filename, LineNumber};
+}
diff --git a/COFF/PDB.h b/COFF/PDB.h
index defd7d2..a98d129 100644
--- a/COFF/PDB.h
+++ b/COFF/PDB.h
@@ -22,12 +22,16 @@
namespace lld {
namespace coff {
class OutputSection;
+class SectionChunk;
class SymbolTable;
void createPDB(SymbolTable *Symtab,
llvm::ArrayRef<OutputSection *> OutputSections,
llvm::ArrayRef<uint8_t> SectionTable,
const llvm::codeview::DebugInfo &BuildId);
+
+std::pair<llvm::StringRef, uint32_t> getFileLine(const SectionChunk *C,
+ uint32_t Addr);
}
}
diff --git a/COFF/SymbolTable.cpp b/COFF/SymbolTable.cpp
index 32420df..6b07c35 100644
--- a/COFF/SymbolTable.cpp
+++ b/COFF/SymbolTable.cpp
@@ -11,6 +11,7 @@
#include "Config.h"
#include "Driver.h"
#include "LTO.h"
+#include "PDB.h"
#include "Symbols.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
@@ -37,8 +38,9 @@
if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
Config->Machine = MT;
} else if (MT != IMAGE_FILE_MACHINE_UNKNOWN && Config->Machine != MT) {
- fatal(toString(File) + ": machine type " + machineToStr(MT) +
+ error(toString(File) + ": machine type " + machineToStr(MT) +
" conflicts with " + machineToStr(Config->Machine));
+ return;
}
if (auto *F = dyn_cast<ObjFile>(File)) {
@@ -64,6 +66,66 @@
error(S);
}
+// Returns the name of the symbol in SC whose value is <= Addr that is closest
+// to Addr. This is generally the name of the global variable or function whose
+// definition contains Addr.
+static StringRef getSymbolName(SectionChunk *SC, uint32_t Addr) {
+ DefinedRegular *Candidate = nullptr;
+
+ for (Symbol *S : SC->File->getSymbols()) {
+ auto *D = dyn_cast_or_null<DefinedRegular>(S);
+ if (!D || D->getChunk() != SC || D->getValue() > Addr ||
+ (Candidate && D->getValue() < Candidate->getValue()))
+ continue;
+
+ Candidate = D;
+ }
+
+ if (!Candidate)
+ return "";
+ return Candidate->getName();
+}
+
+static std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex) {
+ struct Location {
+ StringRef SymName;
+ std::pair<StringRef, uint32_t> FileLine;
+ };
+ std::vector<Location> Locations;
+
+ for (Chunk *C : File->getChunks()) {
+ auto *SC = dyn_cast<SectionChunk>(C);
+ if (!SC)
+ continue;
+ for (const coff_relocation &R : SC->Relocs) {
+ if (R.SymbolTableIndex != SymIndex)
+ continue;
+ std::pair<StringRef, uint32_t> FileLine =
+ getFileLine(SC, R.VirtualAddress);
+ StringRef SymName = getSymbolName(SC, R.VirtualAddress);
+ if (!FileLine.first.empty() || !SymName.empty())
+ Locations.push_back({SymName, FileLine});
+ }
+ }
+
+ if (Locations.empty())
+ return "\n>>> referenced by " + toString(File) + "\n";
+
+ std::string Out;
+ llvm::raw_string_ostream OS(Out);
+ for (Location Loc : Locations) {
+ OS << "\n>>> referenced by ";
+ if (!Loc.FileLine.first.empty())
+ OS << Loc.FileLine.first << ":" << Loc.FileLine.second
+ << "\n>>> ";
+ OS << toString(File);
+ if (!Loc.SymName.empty())
+ OS << ":(" << Loc.SymName << ')';
+ }
+ OS << '\n';
+ return OS.str();
+}
+
void SymbolTable::reportRemainingUndefines() {
SmallPtrSet<Symbol *, 8> Undefs;
DenseMap<Symbol *, Symbol *> LocalImports;
@@ -127,11 +189,14 @@
}
for (ObjFile *File : ObjFile::Instances) {
+ size_t SymIndex = -1ull;
for (Symbol *Sym : File->getSymbols()) {
+ ++SymIndex;
if (!Sym)
continue;
if (Undefs.count(Sym))
- errorOrWarn(toString(File) + ": undefined symbol: " + Sym->getName());
+ errorOrWarn("undefined symbol: " + Sym->getName() +
+ getSymbolLocations(File, SymIndex));
if (Config->WarnLocallyDefinedImported)
if (Symbol *Imp = LocalImports.lookup(Sym))
warn(toString(File) + ": locally defined symbol imported: " +
diff --git a/COFF/Symbols.cpp b/COFF/Symbols.cpp
index fedb337..7c8b7d5 100644
--- a/COFF/Symbols.cpp
+++ b/COFF/Symbols.cpp
@@ -58,7 +58,7 @@
if (auto *Imp = dyn_cast<DefinedImportData>(this))
return Imp->File->Live;
if (auto *Imp = dyn_cast<DefinedImportThunk>(this))
- return Imp->WrappedSym->File->Live;
+ return Imp->WrappedSym->File->ThunkLive;
// Assume any other kind of symbol is live.
return true;
}
diff --git a/COFF/Writer.cpp b/COFF/Writer.cpp
index 6f173de..dff87c5 100644
--- a/COFF/Writer.cpp
+++ b/COFF/Writer.cpp
@@ -121,14 +121,8 @@
class CVDebugRecordChunk : public Chunk {
public:
- CVDebugRecordChunk() {
- PDBAbsPath = Config->PDBPath;
- if (!PDBAbsPath.empty())
- llvm::sys::fs::make_absolute(PDBAbsPath);
- }
-
size_t getSize() const override {
- return sizeof(codeview::DebugInfo) + PDBAbsPath.size() + 1;
+ return sizeof(codeview::DebugInfo) + Config->PDBAltPath.size() + 1;
}
void writeTo(uint8_t *B) const override {
@@ -138,12 +132,11 @@
// variable sized field (PDB Path)
char *P = reinterpret_cast<char *>(B + OutputSectionOff + sizeof(*BuildId));
- if (!PDBAbsPath.empty())
- memcpy(P, PDBAbsPath.data(), PDBAbsPath.size());
- P[PDBAbsPath.size()] = '\0';
+ if (!Config->PDBAltPath.empty())
+ memcpy(P, Config->PDBAltPath.data(), Config->PDBAltPath.size());
+ P[Config->PDBAltPath.size()] = '\0';
}
- SmallString<128> PDBAbsPath;
mutable codeview::DebugInfo *BuildId = nullptr;
};
@@ -158,19 +151,19 @@
void createMiscChunks();
void createImportTables();
void createExportTable();
+ void mergeSections();
void assignAddresses();
void removeEmptySections();
void createSymbolAndStringTable();
void openFile(StringRef OutputPath);
template <typename PEHeaderTy> void writeHeader();
- void createSEHTable(OutputSection *RData);
- void createGuardCFTables(OutputSection *RData);
- void createGLJmpTable(OutputSection *RData);
+ void createSEHTable();
+ void createGuardCFTables();
void markSymbolsForRVATable(ObjFile *File,
ArrayRef<SectionChunk *> SymIdxChunks,
SymbolRVASet &TableSymbols);
- void maybeAddRVATable(OutputSection *RData, SymbolRVASet TableSymbols,
- StringRef TableSym, StringRef CountSym);
+ void maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym,
+ StringRef CountSym);
void setSectionPermissions();
void writeSections();
void writeBuildId();
@@ -180,9 +173,8 @@
size_t addEntryToStringTable(StringRef Str);
OutputSection *findSection(StringRef Name);
- OutputSection *createSection(StringRef Name);
- void addBaserels(OutputSection *Dest);
- void addBaserelBlocks(OutputSection *Dest, std::vector<Baserel> &V);
+ void addBaserels();
+ void addBaserelBlocks(std::vector<Baserel> &V);
uint32_t getSizeOfInitializedData();
std::map<StringRef, std::vector<DefinedImportData *>> binImports();
@@ -194,8 +186,7 @@
IdataContents Idata;
DelayLoadContents DelayIdata;
EdataContents Edata;
- RVATableChunk *GuardFidsTable = nullptr;
- RVATableChunk *SEHTable = nullptr;
+ bool SetNoSEHCharacteristic = false;
DebugDirectoryChunk *DebugDirectory = nullptr;
std::vector<Chunk *> DebugRecords;
@@ -207,6 +198,28 @@
uint32_t PointerToSymbolTable = 0;
uint64_t SizeOfImage;
uint64_t SizeOfHeaders;
+
+ OutputSection *TextSec;
+ OutputSection *RdataSec;
+ OutputSection *DataSec;
+ OutputSection *PdataSec;
+ OutputSection *IdataSec;
+ OutputSection *EdataSec;
+ OutputSection *DidatSec;
+ OutputSection *RsrcSec;
+ OutputSection *RelocSec;
+
+ // The first and last .pdata sections in the output file.
+ //
+ // We need to keep track of the location of .pdata in whichever section it
+ // gets merged into so that we can sort its contents and emit a correct data
+ // directory entry for the exception table. This is also the case for some
+ // other sections (such as .edata) but because the contents of those sections
+ // are entirely linker-generated we can keep track of their locations using
+ // the chunks that the linker creates. All .pdata chunks come from input
+ // files, so we need to keep track of them separately.
+ Chunk *FirstPdata = nullptr;
+ Chunk *LastPdata;
};
} // anonymous namespace
@@ -223,12 +236,16 @@
C->setOutputSection(this);
}
-void OutputSection::addPermissions(uint32_t C) {
- Header.Characteristics |= C & PermMask;
+void OutputSection::setPermissions(uint32_t C) {
+ Header.Characteristics &= ~PermMask;
+ Header.Characteristics |= C;
}
-void OutputSection::setPermissions(uint32_t C) {
- Header.Characteristics = C & PermMask;
+void OutputSection::merge(OutputSection *Other) {
+ for (Chunk *C : Other->Chunks)
+ C->setOutputSection(this);
+ Chunks.insert(Chunks.end(), Other->Chunks.begin(), Other->Chunks.end());
+ Other->Chunks.clear();
}
// Write the section header to a given buffer.
@@ -318,8 +335,7 @@
createMiscChunks();
createImportTables();
createExportTable();
- if (Config->Relocatable)
- createSection(".reloc");
+ mergeSections();
assignAddresses();
removeEmptySections();
setSectionPermissions();
@@ -356,17 +372,12 @@
fatal("failed to write the output file: " + toString(std::move(E)));
}
-static StringRef getOutputSection(StringRef Name) {
+static StringRef getOutputSectionName(StringRef Name) {
StringRef S = Name.split('$').first;
// Treat a later period as a separator for MinGW, for sections like
// ".ctors.01234".
- S = S.substr(0, S.find('.', 1));
-
- auto It = Config->Merge.find(S);
- if (It == Config->Merge.end())
- return S;
- return It->second;
+ return S.substr(0, S.find('.', 1));
}
// For /order.
@@ -386,8 +397,39 @@
// Create output section objects and add them to OutputSections.
void Writer::createSections() {
- // First, bin chunks by name.
- std::map<StringRef, std::vector<Chunk *>> Map;
+ // First, create the builtin sections.
+ const uint32_t DATA = IMAGE_SCN_CNT_INITIALIZED_DATA;
+ const uint32_t BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA;
+ const uint32_t CODE = IMAGE_SCN_CNT_CODE;
+ const uint32_t DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE;
+ const uint32_t R = IMAGE_SCN_MEM_READ;
+ const uint32_t W = IMAGE_SCN_MEM_WRITE;
+ const uint32_t X = IMAGE_SCN_MEM_EXECUTE;
+
+ SmallDenseMap<std::pair<StringRef, uint32_t>, OutputSection *> Sections;
+ auto CreateSection = [&](StringRef Name, uint32_t OutChars) {
+ OutputSection *&Sec = Sections[{Name, OutChars}];
+ if (!Sec) {
+ Sec = make<OutputSection>(Name, OutChars);
+ OutputSections.push_back(Sec);
+ }
+ return Sec;
+ };
+
+ // Try to match the section order used by link.exe.
+ TextSec = CreateSection(".text", CODE | R | X);
+ CreateSection(".bss", BSS | R | W);
+ RdataSec = CreateSection(".rdata", DATA | R);
+ DataSec = CreateSection(".data", DATA | R | W);
+ PdataSec = CreateSection(".pdata", DATA | R);
+ IdataSec = CreateSection(".idata", DATA | R);
+ EdataSec = CreateSection(".edata", DATA | R);
+ DidatSec = CreateSection(".didat", DATA | R);
+ RsrcSec = CreateSection(".rsrc", DATA | R);
+ RelocSec = CreateSection(".reloc", DATA | DISCARDABLE | R);
+
+ // Then bin chunks by name and output characteristics.
+ std::map<std::pair<StringRef, uint32_t>, std::vector<Chunk *>> Map;
for (Chunk *C : Symtab->getChunks()) {
auto *SC = dyn_cast<SectionChunk>(C);
if (SC && !SC->isLive()) {
@@ -395,7 +437,7 @@
SC->printDiscardedMessage();
continue;
}
- Map[C->getSectionName()].push_back(C);
+ Map[{C->getSectionName(), C->getOutputCharacteristics()}].push_back(C);
}
// Process an /order option.
@@ -407,32 +449,54 @@
// '$' and all following characters in input section names are
// discarded when determining output section. So, .text$foo
// contributes to .text, for example. See PE/COFF spec 3.2.
- SmallDenseMap<StringRef, OutputSection *> Sections;
for (auto Pair : Map) {
- StringRef Name = getOutputSection(Pair.first);
- OutputSection *&Sec = Sections[Name];
- if (!Sec) {
- Sec = make<OutputSection>(Name);
- OutputSections.push_back(Sec);
- }
+ StringRef Name = getOutputSectionName(Pair.first.first);
+ uint32_t OutChars = Pair.first.second;
+
+ // In link.exe, there is a special case for the I386 target where .CRT
+ // sections are treated as if they have output characteristics DATA | R if
+ // their characteristics are DATA | R | W. This implements the same special
+ // case for all architectures.
+ if (Name == ".CRT")
+ OutChars = DATA | R;
+
+ OutputSection *Sec = CreateSection(Name, OutChars);
std::vector<Chunk *> &Chunks = Pair.second;
- for (Chunk *C : Chunks) {
+ for (Chunk *C : Chunks)
Sec->addChunk(C);
- Sec->addPermissions(C->getPermissions());
- }
}
+
+ // Finally, move some output sections to the end.
+ auto SectionOrder = [&](OutputSection *S) {
+ // .reloc should come last of all since it refers to RVAs of data in the
+ // previous sections.
+ if (S == RelocSec)
+ return 3;
+ // Move DISCARDABLE (or non-memory-mapped) sections to the end of file because
+ // the loader cannot handle holes.
+ if (S->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
+ return 2;
+ // .rsrc should come at the end of the non-discardable sections because its
+ // size may change by the Win32 UpdateResources() function, causing
+ // subsequent sections to move (see https://crbug.com/827082).
+ if (S == RsrcSec)
+ return 1;
+ return 0;
+ };
+ std::stable_sort(OutputSections.begin(), OutputSections.end(),
+ [&](OutputSection *S, OutputSection *T) {
+ return SectionOrder(S) < SectionOrder(T);
+ });
}
void Writer::createMiscChunks() {
- OutputSection *RData = createSection(".rdata");
-
for (auto &P : MergeChunk::Instances)
- RData->addChunk(P.second);
+ RdataSec->addChunk(P.second);
// Create thunks for locally-dllimported symbols.
if (!Symtab->LocalImportChunks.empty()) {
for (Chunk *C : Symtab->LocalImportChunks)
- RData->addChunk(C);
+ RdataSec->addChunk(C);
}
// Create Debug Information Chunks
@@ -447,18 +511,18 @@
BuildId = CVChunk;
DebugRecords.push_back(CVChunk);
- RData->addChunk(DebugDirectory);
+ RdataSec->addChunk(DebugDirectory);
for (Chunk *C : DebugRecords)
- RData->addChunk(C);
+ RdataSec->addChunk(C);
}
// Create SEH table. x86-only.
if (Config->Machine == I386)
- createSEHTable(RData);
+ createSEHTable();
// Create /guard:cf tables if requested.
if (Config->GuardCF != GuardCFLevel::Off)
- createGuardCFTables(RData);
+ createGuardCFTables();
}
// Create .idata section for the DLL-imported symbol table.
@@ -479,15 +543,10 @@
std::string DLL = StringRef(File->DLLName).lower();
if (Config->DLLOrder.count(DLL) == 0)
Config->DLLOrder[DLL] = Config->DLLOrder.size();
- }
-
- OutputSection *Text = createSection(".text");
- for (ImportFile *File : ImportFile::Instances) {
- if (!File->Live)
- continue;
if (DefinedImportThunk *Thunk = File->ThunkSym)
- Text->addChunk(Thunk->getChunk());
+ if (File->ThunkLive)
+ TextSec->addChunk(Thunk->getChunk());
if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) {
if (!File->ThunkSym)
@@ -499,33 +558,27 @@
}
}
- if (!Idata.empty()) {
- OutputSection *Sec = createSection(".idata");
+ if (!Idata.empty())
for (Chunk *C : Idata.getChunks())
- Sec->addChunk(C);
- }
+ IdataSec->addChunk(C);
if (!DelayIdata.empty()) {
Defined *Helper = cast<Defined>(Config->DelayLoadHelper);
DelayIdata.create(Helper);
- OutputSection *Sec = createSection(".didat");
for (Chunk *C : DelayIdata.getChunks())
- Sec->addChunk(C);
- Sec = createSection(".data");
+ DidatSec->addChunk(C);
for (Chunk *C : DelayIdata.getDataChunks())
- Sec->addChunk(C);
- Sec = createSection(".text");
+ DataSec->addChunk(C);
for (Chunk *C : DelayIdata.getCodeChunks())
- Sec->addChunk(C);
+ TextSec->addChunk(C);
}
}
void Writer::createExportTable() {
if (Config->Exports.empty())
return;
- OutputSection *Sec = createSection(".edata");
for (Chunk *C : Edata.Chunks)
- Sec->addChunk(C);
+ EdataSec->addChunk(C);
}
// The Windows loader doesn't seem to like empty sections,
@@ -549,19 +602,28 @@
}
Optional<coff_symbol16> Writer::createSymbol(Defined *Def) {
- // Relative symbols are unrepresentable in a COFF symbol table.
- if (isa<DefinedSynthetic>(Def))
+ coff_symbol16 Sym;
+ switch (Def->kind()) {
+ case Symbol::DefinedAbsoluteKind:
+ Sym.Value = Def->getRVA();
+ Sym.SectionNumber = IMAGE_SYM_ABSOLUTE;
+ break;
+ case Symbol::DefinedSyntheticKind:
+ // Relative symbols are unrepresentable in a COFF symbol table.
return None;
-
- // Don't write dead symbols or symbols in codeview sections to the symbol
- // table.
- if (!Def->isLive())
- return None;
- if (auto *D = dyn_cast<DefinedRegular>(Def))
- if (D->getChunk()->isCodeView())
+ default: {
+ // Don't write symbols that won't be written to the output to the symbol
+ // table.
+ OutputSection *OS = Def->getChunk()->getOutputSection();
+ if (!OS)
return None;
- coff_symbol16 Sym;
+ Sym.Value = Def->getRVA() - OS->getRVA();
+ Sym.SectionNumber = OS->SectionIndex;
+ break;
+ }
+ }
+
StringRef Name = Def->getName();
if (Name.size() > COFF::NameSize) {
Sym.Name.Offset.Zeroes = 0;
@@ -580,25 +642,6 @@
Sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
}
Sym.NumberOfAuxSymbols = 0;
-
- switch (Def->kind()) {
- case Symbol::DefinedAbsoluteKind:
- Sym.Value = Def->getRVA();
- Sym.SectionNumber = IMAGE_SYM_ABSOLUTE;
- break;
- default: {
- uint64_t RVA = Def->getRVA();
- OutputSection *Sec = nullptr;
- for (OutputSection *S : OutputSections) {
- if (S->getRVA() > RVA)
- break;
- Sec = S;
- }
- Sym.Value = RVA - Sec->getRVA();
- Sym.SectionNumber = Sec->SectionIndex;
- break;
- }
- }
return Sym;
}
@@ -614,7 +657,7 @@
for (OutputSection *Sec : OutputSections) {
if (Sec->Name.size() <= COFF::NameSize)
continue;
- if ((Sec->getPermissions() & IMAGE_SCN_MEM_DISCARDABLE) == 0)
+ if ((Sec->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0)
continue;
Sec->setStringTableOff(addEntryToStringTable(Sec->Name));
}
@@ -644,6 +687,37 @@
FileSize = alignTo(FileOff, SectorSize);
}
+void Writer::mergeSections() {
+ if (!PdataSec->getChunks().empty()) {
+ FirstPdata = PdataSec->getChunks().front();
+ LastPdata = PdataSec->getChunks().back();
+ }
+
+ for (auto &P : Config->Merge) {
+ StringRef ToName = P.second;
+ if (P.first == ToName)
+ continue;
+ StringSet<> Names;
+ while (1) {
+ if (!Names.insert(ToName).second)
+ fatal("/merge: cycle found for section '" + P.first + "'");
+ auto I = Config->Merge.find(ToName);
+ if (I == Config->Merge.end())
+ break;
+ ToName = I->second;
+ }
+ OutputSection *From = findSection(P.first);
+ OutputSection *To = findSection(ToName);
+ if (!From)
+ continue;
+ if (!To) {
+ From->Name = ToName;
+ continue;
+ }
+ To->merge(From);
+ }
+}
+
// Visits all sections to assign incremental, non-overlapping RVAs and
// file offsets.
void Writer::assignAddresses() {
@@ -655,15 +729,10 @@
SizeOfHeaders = alignTo(SizeOfHeaders, SectorSize);
uint64_t RVA = PageSize; // The first page is kept unmapped.
FileSize = SizeOfHeaders;
- // Move DISCARDABLE (or non-memory-mapped) sections to the end of file because
- // the loader cannot handle holes.
- std::stable_partition(
- OutputSections.begin(), OutputSections.end(), [](OutputSection *S) {
- return (S->getPermissions() & IMAGE_SCN_MEM_DISCARDABLE) == 0;
- });
+
for (OutputSection *Sec : OutputSections) {
- if (Sec->Name == ".reloc")
- addBaserels(Sec);
+ if (Sec == RelocSec)
+ addBaserels();
uint64_t RawSize = 0, VirtualSize = 0;
Sec->Header.VirtualAddress = RVA;
for (Chunk *C : Sec->getChunks()) {
@@ -780,24 +849,25 @@
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION;
if (Config->GuardCF != GuardCFLevel::Off)
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_GUARD_CF;
- if (Config->Machine == I386 && !SEHTable &&
- !Symtab->findUnderscore("_load_config_used"))
+ if (Config->IntegrityCheck)
+ PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY;
+ if (SetNoSEHCharacteristic)
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_SEH;
if (Config->TerminalServerAware)
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE;
PE->NumberOfRvaAndSize = NumberfOfDataDirectory;
- if (OutputSection *Text = findSection(".text")) {
- PE->BaseOfCode = Text->getRVA();
- PE->SizeOfCode = Text->getRawSize();
+ if (TextSec->getVirtualSize()) {
+ PE->BaseOfCode = TextSec->getRVA();
+ PE->SizeOfCode = TextSec->getRawSize();
}
PE->SizeOfInitializedData = getSizeOfInitializedData();
// Write data directory
auto *Dir = reinterpret_cast<data_directory *>(Buf);
Buf += sizeof(*Dir) * NumberfOfDataDirectory;
- if (OutputSection *Sec = findSection(".edata")) {
- Dir[EXPORT_TABLE].RelativeVirtualAddress = Sec->getRVA();
- Dir[EXPORT_TABLE].Size = Sec->getVirtualSize();
+ if (!Config->Exports.empty()) {
+ Dir[EXPORT_TABLE].RelativeVirtualAddress = Edata.getRVA();
+ Dir[EXPORT_TABLE].Size = Edata.getSize();
}
if (!Idata.empty()) {
Dir[IMPORT_TABLE].RelativeVirtualAddress = Idata.getDirRVA();
@@ -805,17 +875,18 @@
Dir[IAT].RelativeVirtualAddress = Idata.getIATRVA();
Dir[IAT].Size = Idata.getIATSize();
}
- if (OutputSection *Sec = findSection(".rsrc")) {
- Dir[RESOURCE_TABLE].RelativeVirtualAddress = Sec->getRVA();
- Dir[RESOURCE_TABLE].Size = Sec->getVirtualSize();
+ if (RsrcSec->getVirtualSize()) {
+ Dir[RESOURCE_TABLE].RelativeVirtualAddress = RsrcSec->getRVA();
+ Dir[RESOURCE_TABLE].Size = RsrcSec->getVirtualSize();
}
- if (OutputSection *Sec = findSection(".pdata")) {
- Dir[EXCEPTION_TABLE].RelativeVirtualAddress = Sec->getRVA();
- Dir[EXCEPTION_TABLE].Size = Sec->getVirtualSize();
+ if (FirstPdata) {
+ Dir[EXCEPTION_TABLE].RelativeVirtualAddress = FirstPdata->getRVA();
+ Dir[EXCEPTION_TABLE].Size =
+ LastPdata->getRVA() + LastPdata->getSize() - FirstPdata->getRVA();
}
- if (OutputSection *Sec = findSection(".reloc")) {
- Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = Sec->getRVA();
- Dir[BASE_RELOCATION_TABLE].Size = Sec->getVirtualSize();
+ if (RelocSec->getVirtualSize()) {
+ Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = RelocSec->getRVA();
+ Dir[BASE_RELOCATION_TABLE].Size = RelocSec->getVirtualSize();
}
if (Symbol *Sym = Symtab->findUnderscore("_tls_used")) {
if (Defined *B = dyn_cast<Defined>(Sym)) {
@@ -884,7 +955,11 @@
"failed to open " + Path);
}
-void Writer::createSEHTable(OutputSection *RData) {
+void Writer::createSEHTable() {
+ // Set the no SEH characteristic on x86 binaries unless we find exception
+ // handlers.
+ SetNoSEHCharacteristic = true;
+
SymbolRVASet Handlers;
for (ObjFile *File : ObjFile::Instances) {
// FIXME: We should error here instead of earlier unless /safeseh:no was
@@ -895,7 +970,13 @@
markSymbolsForRVATable(File, File->getSXDataChunks(), Handlers);
}
- maybeAddRVATable(RData, std::move(Handlers), "__safe_se_handler_table",
+ // Remove the "no SEH" characteristic if all object files were built with
+ // safeseh, we found some exception handlers, and there is a load config in
+ // the object.
+ SetNoSEHCharacteristic =
+ Handlers.empty() || !Symtab->findUnderscore("_load_config_used");
+
+ maybeAddRVATable(std::move(Handlers), "__safe_se_handler_table",
"__safe_se_handler_count");
}
@@ -930,7 +1011,7 @@
if (auto *D = dyn_cast_or_null<Defined>(Ref)) {
Chunk *RefChunk = D->getChunk();
OutputSection *OS = RefChunk ? RefChunk->getOutputSection() : nullptr;
- if (OS && OS->getPermissions() & IMAGE_SCN_MEM_EXECUTE)
+ if (OS && OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE)
addSymbolToRVASet(UsedSymbols, D);
}
}
@@ -940,7 +1021,7 @@
// Create the guard function id table. This is a table of RVAs of all
// address-taken functions. It is sorted and uniqued, just like the safe SEH
// table.
-void Writer::createGuardCFTables(OutputSection *RData) {
+void Writer::createGuardCFTables() {
SymbolRVASet AddressTakenSyms;
SymbolRVASet LongJmpTargets;
for (ObjFile *File : ObjFile::Instances) {
@@ -961,12 +1042,12 @@
if (Config->Entry)
addSymbolToRVASet(AddressTakenSyms, cast<Defined>(Config->Entry));
- maybeAddRVATable(RData, std::move(AddressTakenSyms), "__guard_fids_table",
+ maybeAddRVATable(std::move(AddressTakenSyms), "__guard_fids_table",
"__guard_fids_count");
// Add the longjmp target table unless the user told us not to.
if (Config->GuardCF == GuardCFLevel::Full)
- maybeAddRVATable(RData, std::move(LongJmpTargets), "__guard_longjmp_table",
+ maybeAddRVATable(std::move(LongJmpTargets), "__guard_longjmp_table",
"__guard_longjmp_count");
// Set __guard_flags, which will be used in the load config to indicate that
@@ -1023,14 +1104,13 @@
// Replace the absolute table symbol with a synthetic symbol pointing to
// TableChunk so that we can emit base relocations for it and resolve section
// relative relocations.
-void Writer::maybeAddRVATable(OutputSection *RData,
- SymbolRVASet TableSymbols,
- StringRef TableSym, StringRef CountSym) {
+void Writer::maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym,
+ StringRef CountSym) {
if (TableSymbols.empty())
return;
RVATableChunk *TableChunk = make<RVATableChunk>(std::move(TableSymbols));
- RData->addChunk(TableChunk);
+ RdataSec->addChunk(TableChunk);
Symbol *T = Symtab->findUnderscore(TableSym);
Symbol *C = Symtab->findUnderscore(CountSym);
@@ -1044,8 +1124,9 @@
for (auto &P : Config->Section) {
StringRef Name = P.first;
uint32_t Perm = P.second;
- if (auto *Sec = findSection(Name))
- Sec->setPermissions(Perm);
+ for (OutputSection *Sec : OutputSections)
+ if (Sec->Name == Name)
+ Sec->setPermissions(Perm);
}
}
@@ -1061,7 +1142,7 @@
// Fill gaps between functions in .text with INT3 instructions
// instead of leaving as NUL bytes (which can be interpreted as
// ADD instructions).
- if (Sec->getPermissions() & IMAGE_SCN_CNT_CODE)
+ if (Sec->Header.Characteristics & IMAGE_SCN_CNT_CODE)
memset(SecBuf, 0xCC, Sec->getRawSize());
for_each(parallel::par, Sec->getChunks().begin(), Sec->getChunks().end(),
[&](Chunk *C) { C->writeTo(SecBuf); });
@@ -1103,26 +1184,31 @@
reinterpret_cast<const char *>(Buffer->getBufferStart()),
Buffer->getBufferSize());
- uint32_t Hash = static_cast<uint32_t>(xxHash64(OutputFileData));
+ uint32_t Timestamp = Config->Timestamp;
+ if (Config->Repro)
+ Timestamp = static_cast<uint32_t>(xxHash64(OutputFileData));
if (DebugDirectory)
- DebugDirectory->setTimeDateStamp(Hash);
+ DebugDirectory->setTimeDateStamp(Timestamp);
uint8_t *Buf = Buffer->getBufferStart();
Buf += DOSStubSize + sizeof(PEMagic);
object::coff_file_header *CoffHeader =
reinterpret_cast<coff_file_header *>(Buf);
- CoffHeader->TimeDateStamp = Hash;
+ CoffHeader->TimeDateStamp = Timestamp;
}
// Sort .pdata section contents according to PE/COFF spec 5.5.
void Writer::sortExceptionTable() {
- OutputSection *Sec = findSection(".pdata");
- if (!Sec)
+ if (!FirstPdata)
return;
// We assume .pdata contains function table entries only.
- uint8_t *Begin = Buffer->getBufferStart() + Sec->getFileOff();
- uint8_t *End = Begin + Sec->getVirtualSize();
+ auto BufAddr = [&](Chunk *C) {
+ return Buffer->getBufferStart() + C->getOutputSection()->getFileOff() +
+ C->getRVA() - C->getOutputSection()->getRVA();
+ };
+ uint8_t *Begin = BufAddr(FirstPdata);
+ uint8_t *End = BufAddr(LastPdata) + LastPdata->getSize();
if (Config->Machine == AMD64) {
struct Entry { ulittle32_t Begin, End, Unwind; };
sort(parallel::par, (Entry *)Begin, (Entry *)End,
@@ -1148,55 +1234,31 @@
uint32_t Writer::getSizeOfInitializedData() {
uint32_t Res = 0;
for (OutputSection *S : OutputSections)
- if (S->getPermissions() & IMAGE_SCN_CNT_INITIALIZED_DATA)
+ if (S->Header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
Res += S->getRawSize();
return Res;
}
-// Returns an existing section or create a new one if not found.
-OutputSection *Writer::createSection(StringRef Name) {
- if (auto *Sec = findSection(Name))
- return Sec;
- const auto DATA = IMAGE_SCN_CNT_INITIALIZED_DATA;
- const auto BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA;
- const auto CODE = IMAGE_SCN_CNT_CODE;
- const auto DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE;
- const auto R = IMAGE_SCN_MEM_READ;
- const auto W = IMAGE_SCN_MEM_WRITE;
- const auto X = IMAGE_SCN_MEM_EXECUTE;
- uint32_t Perms = StringSwitch<uint32_t>(Name)
- .Case(".bss", BSS | R | W)
- .Case(".data", DATA | R | W)
- .Cases(".didat", ".edata", ".idata", ".rdata", DATA | R)
- .Case(".reloc", DATA | DISCARDABLE | R)
- .Case(".text", CODE | R | X)
- .Default(0);
- if (!Perms)
- llvm_unreachable("unknown section name");
- auto Sec = make<OutputSection>(Name);
- Sec->addPermissions(Perms);
- OutputSections.push_back(Sec);
- return Sec;
-}
-
-// Dest is .reloc section. Add contents to that section.
-void Writer::addBaserels(OutputSection *Dest) {
+// Add base relocations to .reloc section.
+void Writer::addBaserels() {
+ if (!Config->Relocatable)
+ return;
std::vector<Baserel> V;
for (OutputSection *Sec : OutputSections) {
- if (Sec == Dest)
+ if (Sec == RelocSec)
continue;
// Collect all locations for base relocations.
for (Chunk *C : Sec->getChunks())
C->getBaserels(&V);
// Add the addresses to .reloc section.
if (!V.empty())
- addBaserelBlocks(Dest, V);
+ addBaserelBlocks(V);
V.clear();
}
}
// Add addresses to .reloc section. Note that addresses are grouped by page.
-void Writer::addBaserelBlocks(OutputSection *Dest, std::vector<Baserel> &V) {
+void Writer::addBaserelBlocks(std::vector<Baserel> &V) {
const uint32_t Mask = ~uint32_t(PageSize - 1);
uint32_t Page = V[0].RVA & Mask;
size_t I = 0, J = 1;
@@ -1204,11 +1266,11 @@
uint32_t P = V[J].RVA & Mask;
if (P == Page)
continue;
- Dest->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
+ RelocSec->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
I = J;
Page = P;
}
if (I == J)
return;
- Dest->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
+ RelocSec->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
}
diff --git a/COFF/Writer.h b/COFF/Writer.h
index 1dc1e61..d37276c 100644
--- a/COFF/Writer.h
+++ b/COFF/Writer.h
@@ -30,13 +30,14 @@
// non-overlapping file offsets and RVAs.
class OutputSection {
public:
- OutputSection(llvm::StringRef N) : Name(N), Header({}) {}
+ OutputSection(llvm::StringRef N, uint32_t Chars) : Name(N) {
+ Header.Characteristics = Chars;
+ }
void addChunk(Chunk *C);
+ void merge(OutputSection *Other);
ArrayRef<Chunk *> getChunks() { return Chunks; }
void addPermissions(uint32_t C);
void setPermissions(uint32_t C);
- uint32_t getPermissions() { return Header.Characteristics & PermMask; }
- uint32_t getCharacteristics() { return Header.Characteristics; }
uint64_t getRVA() { return Header.VirtualAddress; }
uint64_t getFileOff() { return Header.PointerToRawData; }
void writeHeaderTo(uint8_t *Buf);
@@ -59,7 +60,7 @@
uint32_t SectionIndex = 0;
llvm::StringRef Name;
- llvm::object::coff_section Header;
+ llvm::object::coff_section Header = {};
private:
uint32_t StringTableOff = 0;
diff --git a/Common/Args.cpp b/Common/Args.cpp
index 680cf5b..ff77bfc 100644
--- a/Common/Args.cpp
+++ b/Common/Args.cpp
@@ -18,13 +18,17 @@
using namespace lld;
int lld::args::getInteger(opt::InputArgList &Args, unsigned Key, int Default) {
- int V = Default;
- if (auto *Arg = Args.getLastArg(Key)) {
- StringRef S = Arg->getValue();
- if (!to_integer(S, V, 10))
- error(Arg->getSpelling() + ": number expected, but got '" + S + "'");
- }
- return V;
+ auto *A = Args.getLastArg(Key);
+ if (!A)
+ return Default;
+
+ int V;
+ if (to_integer(A->getValue(), V, 10))
+ return V;
+
+ StringRef Spelling = Args.getArgString(A->getIndex());
+ error(Spelling + ": number expected, but got '" + A->getValue() + "'");
+ return 0;
}
std::vector<StringRef> lld::args::getStrings(opt::InputArgList &Args, int Id) {
diff --git a/Common/ErrorHandler.cpp b/Common/ErrorHandler.cpp
index 18affce..6dacc2c 100644
--- a/Common/ErrorHandler.cpp
+++ b/Common/ErrorHandler.cpp
@@ -12,7 +12,8 @@
#include "lld/Common/Threads.h"
#include "llvm/ADT/Twine.h"
-#include "llvm/Support/Error.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/raw_ostream.h"
#include <mutex>
@@ -59,6 +60,19 @@
_exit(Val);
}
+void lld::diagnosticHandler(const DiagnosticInfo &DI) {
+ SmallString<128> S;
+ raw_svector_ostream OS(S);
+ DiagnosticPrinterRawOStream DP(OS);
+ DI.print(DP);
+ warn(S);
+}
+
+void lld::checkError(Error E) {
+ handleAllErrors(std::move(E),
+ [&](ErrorInfoBase &EIB) { error(EIB.message()); });
+}
+
void ErrorHandler::print(StringRef S, raw_ostream::Colors C) {
*ErrorOS << LogName << ": ";
if (ColorDiagnostics) {
diff --git a/Common/Strings.cpp b/Common/Strings.cpp
index 1fac65b..36f4f77 100644
--- a/Common/Strings.cpp
+++ b/Common/Strings.cpp
@@ -98,3 +98,12 @@
std::all_of(S.begin() + 1, S.end(),
[](char C) { return C == '_' || isAlnum(C); });
}
+
+// Write the contents of the a buffer to a file
+void lld::saveBuffer(StringRef Buffer, const Twine &Path) {
+ std::error_code EC;
+ raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None);
+ if (EC)
+ error("cannot create " + Path + ": " + EC.message());
+ OS << Buffer;
+}
diff --git a/Common/TargetOptionsCommandFlags.cpp b/Common/TargetOptionsCommandFlags.cpp
index 2d6819b..b46df36 100644
--- a/Common/TargetOptionsCommandFlags.cpp
+++ b/Common/TargetOptionsCommandFlags.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
//
// This file exists as a place for global variables defined in LLVM's
-// CodeGen/CommandFlags.def. By putting the resulting object file in
+// CodeGen/CommandFlags.inc. By putting the resulting object file in
// an archive and linking with it, the definitions will automatically be
// included when needed and skipped when already present.
//
@@ -16,12 +16,12 @@
#include "lld/Common/TargetOptionsCommandFlags.h"
-#include "llvm/CodeGen/CommandFlags.def"
+#include "llvm/CodeGen/CommandFlags.inc"
#include "llvm/Target/TargetOptions.h"
// Define an externally visible version of
// InitTargetOptionsFromCodeGenFlags, so that its functionality can be
-// used without having to include llvm/CodeGen/CommandFlags.def, which
+// used without having to include llvm/CodeGen/CommandFlags.inc, which
// would lead to multiple definitions of the command line flags.
llvm::TargetOptions lld::InitTargetOptionsFromCodeGenFlags() {
return ::InitTargetOptionsFromCodeGenFlags();
diff --git a/ELF/Arch/AArch64.cpp b/ELF/Arch/AArch64.cpp
index 2307ed1..c7b3c08 100644
--- a/ELF/Arch/AArch64.cpp
+++ b/ELF/Arch/AArch64.cpp
@@ -34,7 +34,7 @@
AArch64();
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
- bool isPicRel(RelType Type) const override;
+ RelType getDynRel(RelType Type) const override;
void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
void writePltHeader(uint8_t *Buf) const override;
void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
@@ -89,6 +89,11 @@
return R_TLSDESC_CALL;
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+ case R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
+ case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
+ case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
+ case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
+ case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC:
return R_TLS;
case R_AARCH64_CALL26:
case R_AARCH64_CONDBR19:
@@ -144,8 +149,10 @@
}
}
-bool AArch64::isPicRel(RelType Type) const {
- return Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64;
+RelType AArch64::getDynRel(RelType Type) const {
+ if (Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64)
+ return Type;
+ return R_AARCH64_NONE;
}
void AArch64::writeGotPlt(uint8_t *Buf, const Symbol &) const {
@@ -287,28 +294,30 @@
checkInt(Loc, Val, 21, Type);
or32le(Loc, (Val & 0x1FFFFC) << 3);
break;
- case R_AARCH64_LD64_GOT_LO12_NC:
- case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
- case R_AARCH64_TLSDESC_LD64_LO12:
- checkAlignment(Loc, Val, 8, Type);
- or32le(Loc, (Val & 0xFF8) << 7);
- break;
case R_AARCH64_LDST8_ABS_LO12_NC:
+ case R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
or32AArch64Imm(Loc, getBits(Val, 0, 11));
break;
case R_AARCH64_LDST16_ABS_LO12_NC:
+ case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
checkAlignment(Loc, Val, 2, Type);
or32AArch64Imm(Loc, getBits(Val, 1, 11));
break;
case R_AARCH64_LDST32_ABS_LO12_NC:
+ case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
checkAlignment(Loc, Val, 4, Type);
or32AArch64Imm(Loc, getBits(Val, 2, 11));
break;
case R_AARCH64_LDST64_ABS_LO12_NC:
+ case R_AARCH64_LD64_GOT_LO12_NC:
+ case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+ case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
+ case R_AARCH64_TLSDESC_LD64_LO12:
checkAlignment(Loc, Val, 8, Type);
or32AArch64Imm(Loc, getBits(Val, 3, 11));
break;
case R_AARCH64_LDST128_ABS_LO12_NC:
+ case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC:
checkAlignment(Loc, Val, 16, Type);
or32AArch64Imm(Loc, getBits(Val, 4, 11));
break;
diff --git a/ELF/Arch/ARM.cpp b/ELF/Arch/ARM.cpp
index 9927430..d99be9b 100644
--- a/ELF/Arch/ARM.cpp
+++ b/ELF/Arch/ARM.cpp
@@ -29,7 +29,6 @@
uint32_t calcEFlags() const override;
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
- bool isPicRel(RelType Type) const override;
RelType getDynRel(RelType Type) const override;
int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override;
void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
@@ -162,18 +161,10 @@
}
}
-bool ARM::isPicRel(RelType Type) const {
- return (Type == R_ARM_TARGET1 && !Config->Target1Rel) ||
- (Type == R_ARM_ABS32);
-}
-
RelType ARM::getDynRel(RelType Type) const {
- if (Type == R_ARM_TARGET1 && !Config->Target1Rel)
+ if ((Type == R_ARM_ABS32) || (Type == R_ARM_TARGET1 && !Config->Target1Rel))
return R_ARM_ABS32;
- if (Type == R_ARM_ABS32)
- return Type;
- // Keep it going with a dummy value so that we can find more reloc errors.
- return R_ARM_ABS32;
+ return R_ARM_NONE;
}
void ARM::writeGotPlt(uint8_t *Buf, const Symbol &) const {
diff --git a/ELF/Arch/Mips.cpp b/ELF/Arch/Mips.cpp
index a8e54a8..f2a1aea 100644
--- a/ELF/Arch/Mips.cpp
+++ b/ELF/Arch/Mips.cpp
@@ -32,7 +32,6 @@
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override;
- bool isPicRel(RelType Type) const override;
RelType getDynRel(RelType Type) const override;
void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
void writePltHeader(uint8_t *Buf) const override;
@@ -184,12 +183,10 @@
}
}
-template <class ELFT> bool MIPS<ELFT>::isPicRel(RelType Type) const {
- return Type == R_MIPS_32 || Type == R_MIPS_64;
-}
-
template <class ELFT> RelType MIPS<ELFT>::getDynRel(RelType Type) const {
- return RelativeRel;
+ if (Type == R_MIPS_32 || Type == R_MIPS_64)
+ return RelativeRel;
+ return R_MIPS_NONE;
}
template <class ELFT>
@@ -661,14 +658,21 @@
// Return true if the symbol is a PIC function.
template <class ELFT> bool elf::isMipsPIC(const Defined *Sym) {
- typedef typename ELFT::Ehdr Elf_Ehdr;
- if (!Sym->Section || !Sym->isFunc())
+ if (!Sym->isFunc())
return false;
- auto *Sec = cast<InputSectionBase>(Sym->Section);
- const Elf_Ehdr *Hdr = Sec->template getFile<ELFT>()->getObj().getHeader();
- return (Sym->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC ||
- (Hdr->e_flags & EF_MIPS_PIC);
+ if (Sym->StOther & STO_MIPS_PIC)
+ return true;
+
+ if (!Sym->Section)
+ return false;
+
+ ObjFile<ELFT> *File =
+ cast<InputSectionBase>(Sym->Section)->template getFile<ELFT>();
+ if (!File)
+ return false;
+
+ return File->getObj().getHeader()->e_flags & EF_MIPS_PIC;
}
template <class ELFT> TargetInfo *elf::getMipsTargetInfo() {
diff --git a/ELF/Arch/PPC64.cpp b/ELF/Arch/PPC64.cpp
index d3c2dbd..1d5d939 100644
--- a/ELF/Arch/PPC64.cpp
+++ b/ELF/Arch/PPC64.cpp
@@ -43,10 +43,13 @@
uint32_t calcEFlags() const override;
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
+ void writePltHeader(uint8_t *Buf) const override;
void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
void writeGotHeader(uint8_t *Buf) const override;
+ bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
+ uint64_t BranchAddr, const Symbol &S) const override;
};
} // namespace
@@ -63,16 +66,24 @@
static uint16_t applyPPCHighesta(uint64_t V) { return (V + 0x8000) >> 48; }
PPC64::PPC64() {
- PltRel = GotRel = R_PPC64_GLOB_DAT;
+ GotRel = R_PPC64_GLOB_DAT;
+ PltRel = R_PPC64_JMP_SLOT;
RelativeRel = R_PPC64_RELATIVE;
+ IRelativeRel = R_PPC64_IRELATIVE;
GotEntrySize = 8;
+ PltEntrySize = 4;
GotPltEntrySize = 8;
- PltEntrySize = 32;
- PltHeaderSize = 0;
GotBaseSymInGotPlt = false;
GotBaseSymOff = 0x8000;
- if (Config->EKind == ELF64LEKind)
- GotHeaderEntriesNum = 1;
+ GotHeaderEntriesNum = 1;
+ GotPltHeaderEntriesNum = 2;
+ PltHeaderSize = 60;
+ NeedsThunks = true;
+
+ TlsModuleIndexRel = R_PPC64_DTPMOD64;
+ TlsOffsetRel = R_PPC64_DTPREL64;
+
+ TlsGotRel = R_PPC64_TPREL64;
// We need 64K pages (at least under glibc/Linux, the loader won't
// set different permissions on a finer granularity than that).
@@ -87,42 +98,59 @@
// And because the lowest non-zero 256M boundary is 0x10000000, PPC64 linkers
// use 0x10000000 as the starting address.
DefaultImageBase = 0x10000000;
+
+ TrapInstr =
+ (Config->IsLE == sys::IsLittleEndianHost) ? 0x7fe00008 : 0x0800e07f;
}
static uint32_t getEFlags(InputFile *File) {
- // Get the e_flag from the input file and if it is unspecified, then set it to
- // the e_flag appropriate for the ABI.
-
- // We are currently handling both ELF64LE and ELF64BE but eventually will
- // remove BE support once v2 ABI support is complete.
+ // Get the e_flag from the input file and issue an error if incompatible
+ // e_flag encountered.
+ uint32_t EFlags;
switch (Config->EKind) {
case ELF64BEKind:
- if (uint32_t EFlags =
- cast<ObjFile<ELF64BE>>(File)->getObj().getHeader()->e_flags)
- return EFlags;
- return 1;
+ EFlags = cast<ObjFile<ELF64BE>>(File)->getObj().getHeader()->e_flags;
+ break;
case ELF64LEKind:
- if (uint32_t EFlags =
- cast<ObjFile<ELF64LE>>(File)->getObj().getHeader()->e_flags)
- return EFlags;
- return 2;
+ EFlags = cast<ObjFile<ELF64LE>>(File)->getObj().getHeader()->e_flags;
+ break;
default:
llvm_unreachable("unknown Config->EKind");
}
+ if (EFlags > 2) {
+ error("incompatible e_flags: " + toString(File));
+ return 0;
+ }
+ return EFlags;
}
uint32_t PPC64::calcEFlags() const {
assert(!ObjectFiles.empty());
- uint32_t Ret = getEFlags(ObjectFiles[0]);
- // Verify that all input files have the same e_flags.
- for (InputFile *F : makeArrayRef(ObjectFiles).slice(1)) {
- if (Ret == getEFlags(F))
+ uint32_t NonZeroFlag;
+ for (InputFile *F : makeArrayRef(ObjectFiles)) {
+ NonZeroFlag = getEFlags(F);
+ if (NonZeroFlag)
+ break;
+ }
+
+ // Verify that all input files have either the same e_flags, or zero.
+ for (InputFile *F : makeArrayRef(ObjectFiles)) {
+ uint32_t Flag = getEFlags(F);
+ if (Flag == 0 || Flag == NonZeroFlag)
continue;
- error("incompatible e_flags: " + toString(F));
+ error(toString(F) + ": ABI version " + Twine(Flag) +
+ " is not compatible with ABI version " + Twine(NonZeroFlag) +
+ " output");
return 0;
}
- return Ret;
+
+ if (NonZeroFlag == 1) {
+ error("PPC64 V1 ABI not supported");
+ return 0;
+ }
+
+ return 2;
}
RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S,
@@ -138,55 +166,97 @@
case R_PPC64_TOC:
return R_PPC_TOC;
case R_PPC64_REL24:
- return R_PPC_PLT_OPD;
+ return R_PPC_CALL_PLT;
case R_PPC64_REL16_LO:
case R_PPC64_REL16_HA:
+ case R_PPC64_REL32:
+ case R_PPC64_REL64:
return R_PC;
+ case R_PPC64_GOT_TLSGD16:
+ case R_PPC64_GOT_TLSGD16_HA:
+ case R_PPC64_GOT_TLSGD16_HI:
+ case R_PPC64_GOT_TLSGD16_LO:
+ return R_TLSGD_GOT;
+ case R_PPC64_GOT_TLSLD16:
+ case R_PPC64_GOT_TLSLD16_HA:
+ case R_PPC64_GOT_TLSLD16_HI:
+ case R_PPC64_GOT_TLSLD16_LO:
+ return R_TLSLD_GOT;
+ case R_PPC64_GOT_TPREL16_HA:
+ case R_PPC64_GOT_TPREL16_LO_DS:
+ case R_PPC64_GOT_TPREL16_DS:
+ case R_PPC64_GOT_TPREL16_HI:
+ return R_GOT_OFF;
+ case R_PPC64_TLSGD:
+ case R_PPC64_TLSLD:
+ case R_PPC64_TLS:
+ return R_HINT;
default:
return R_ABS;
}
}
void PPC64::writeGotHeader(uint8_t *Buf) const {
- if (Config->EKind == ELF64LEKind)
- write64(Buf, getPPC64TocBase());
+ write64(Buf, getPPC64TocBase());
+}
+
+void PPC64::writePltHeader(uint8_t *Buf) const {
+ // The generic resolver stub goes first.
+ write32(Buf + 0, 0x7c0802a6); // mflr r0
+ write32(Buf + 4, 0x429f0005); // bcl 20,4*cr7+so,8 <_glink+0x8>
+ write32(Buf + 8, 0x7d6802a6); // mflr r11
+ write32(Buf + 12, 0x7c0803a6); // mtlr r0
+ write32(Buf + 16, 0x7d8b6050); // subf r12, r11, r12
+ write32(Buf + 20, 0x380cffcc); // subi r0,r12,52
+ write32(Buf + 24, 0x7800f082); // srdi r0,r0,62,2
+ write32(Buf + 28, 0xe98b002c); // ld r12,44(r11)
+ write32(Buf + 32, 0x7d6c5a14); // add r11,r12,r11
+ write32(Buf + 36, 0xe98b0000); // ld r12,0(r11)
+ write32(Buf + 40, 0xe96b0008); // ld r11,8(r11)
+ write32(Buf + 44, 0x7d8903a6); // mtctr r12
+ write32(Buf + 48, 0x4e800420); // bctr
+
+ // The 'bcl' instruction will set the link register to the address of the
+ // following instruction ('mflr r11'). Here we store the offset from that
+ // instruction to the first entry in the GotPlt section.
+ int64_t GotPltOffset = InX::GotPlt->getVA() - (InX::Plt->getVA() + 8);
+ write64(Buf + 52, GotPltOffset);
}
void PPC64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
- uint64_t Off = GotPltEntryAddr - getPPC64TocBase();
-
- // FIXME: What we should do, in theory, is get the offset of the function
- // descriptor in the .opd section, and use that as the offset from %r2 (the
- // TOC-base pointer). Instead, we have the GOT-entry offset, and that will
- // be a pointer to the function descriptor in the .opd section. Using
- // this scheme is simpler, but requires an extra indirection per PLT dispatch.
-
- write32(Buf, 0xf8410028); // std %r2, 40(%r1)
- write32(Buf + 4, 0x3d620000 | applyPPCHa(Off)); // addis %r11, %r2, X@ha
- write32(Buf + 8, 0xe98b0000 | applyPPCLo(Off)); // ld %r12, X@l(%r11)
- write32(Buf + 12, 0xe96c0000); // ld %r11,0(%r12)
- write32(Buf + 16, 0x7d6903a6); // mtctr %r11
- write32(Buf + 20, 0xe84c0008); // ld %r2,8(%r12)
- write32(Buf + 24, 0xe96c0010); // ld %r11,16(%r12)
- write32(Buf + 28, 0x4e800420); // bctr
+ int32_t Offset = PltHeaderSize + Index * PltEntrySize;
+ // bl __glink_PLTresolve
+ write32(Buf, 0x48000000 | ((-Offset) & 0x03FFFFFc));
}
static std::pair<RelType, uint64_t> toAddr16Rel(RelType Type, uint64_t Val) {
uint64_t V = Val - PPC64TocOffset;
switch (Type) {
+ case R_PPC64_GOT_TLSGD16:
+ case R_PPC64_GOT_TLSLD16:
case R_PPC64_TOC16:
return {R_PPC64_ADDR16, V};
case R_PPC64_TOC16_DS:
+ case R_PPC64_GOT_TPREL16_DS:
return {R_PPC64_ADDR16_DS, V};
+ case R_PPC64_GOT_TLSGD16_HA:
+ case R_PPC64_GOT_TLSLD16_HA:
+ case R_PPC64_GOT_TPREL16_HA:
case R_PPC64_TOC16_HA:
return {R_PPC64_ADDR16_HA, V};
+ case R_PPC64_GOT_TLSGD16_HI:
+ case R_PPC64_GOT_TLSLD16_HI:
+ case R_PPC64_GOT_TPREL16_HI:
case R_PPC64_TOC16_HI:
return {R_PPC64_ADDR16_HI, V};
+ case R_PPC64_GOT_TLSGD16_LO:
+ case R_PPC64_GOT_TLSLD16_LO:
case R_PPC64_TOC16_LO:
return {R_PPC64_ADDR16_LO, V};
case R_PPC64_TOC16_LO_DS:
+ case R_PPC64_GOT_TPREL16_LO_DS:
return {R_PPC64_ADDR16_LO_DS, V};
default:
return {Type, Val};
@@ -262,6 +332,13 @@
}
}
+bool PPC64::needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
+ uint64_t BranchAddr, const Symbol &S) const {
+ // If a function is in the plt it needs to be called through
+ // a call stub.
+ return Type == R_PPC64_REL24 && S.isInPlt();
+}
+
TargetInfo *elf::getPPC64TargetInfo() {
static PPC64 Target;
return &Target;
diff --git a/ELF/Arch/X86.cpp b/ELF/Arch/X86.cpp
index 87c84ad..19a0b60 100644
--- a/ELF/Arch/X86.cpp
+++ b/ELF/Arch/X86.cpp
@@ -73,9 +73,9 @@
case R_386_TLS_LDO_32:
return R_ABS;
case R_386_TLS_GD:
- return R_TLSGD;
+ return R_TLSGD_GOT_FROM_END;
case R_386_TLS_LDM:
- return R_TLSLD;
+ return R_TLSLD_GOT_FROM_END;
case R_386_PLT32:
return R_PLT_PC;
case R_386_PC8:
@@ -255,7 +255,7 @@
// R_386_{PC,}{8,16} are not part of the i386 psABI, but they are
// being used for some 16-bit programs such as boot loaders, so
// we want to support them.
- checkUInt(Loc, Val, 8, Type);
+ checkIntUInt(Loc, Val, 8, Type);
*Loc = Val;
break;
case R_386_PC8:
@@ -263,7 +263,7 @@
*Loc = Val;
break;
case R_386_16:
- checkUInt(Loc, Val, 16, Type);
+ checkIntUInt(Loc, Val, 16, Type);
write16le(Loc, Val);
break;
case R_386_PC16:
diff --git a/ELF/Arch/X86_64.cpp b/ELF/Arch/X86_64.cpp
index a370508..8fd28d3 100644
--- a/ELF/Arch/X86_64.cpp
+++ b/ELF/Arch/X86_64.cpp
@@ -28,7 +28,7 @@
X86_64();
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
- bool isPicRel(RelType Type) const override;
+ RelType getDynRel(RelType Type) const override;
void writeGotPltHeader(uint8_t *Buf) const override;
void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
void writePltHeader(uint8_t *Buf) const override;
@@ -123,7 +123,7 @@
template <class ELFT>
void X86_64<ELFT>::writeGotPlt(uint8_t *Buf, const Symbol &S) const {
// See comments in X86::writeGotPlt.
- write32le(Buf, S.getPltVA() + 6);
+ write64le(Buf, S.getPltVA() + 6);
}
template <class ELFT> void X86_64<ELFT>::writePltHeader(uint8_t *Buf) const {
@@ -155,9 +155,11 @@
write32le(Buf + 12, -getPltEntryOffset(Index) - 16);
}
-template <class ELFT> bool X86_64<ELFT>::isPicRel(RelType Type) const {
- return Type != R_X86_64_PC32 && Type != R_X86_64_32 &&
- Type != R_X86_64_TPOFF32;
+template <class ELFT> RelType X86_64<ELFT>::getDynRel(RelType Type) const {
+ if (Type == R_X86_64_64 || Type == R_X86_64_PC64 || Type == R_X86_64_SIZE32 ||
+ Type == R_X86_64_SIZE64)
+ return Type;
+ return R_X86_64_NONE;
}
template <class ELFT>
@@ -459,6 +461,15 @@
write32le(Loc - 1, Val + 1);
}
+// These nonstandard PLT entries are to migtigate Spectre v2 security
+// vulnerability. In order to mitigate Spectre v2, we want to avoid indirect
+// branch instructions such as `jmp *GOTPLT(%rip)`. So, in the following PLT
+// entries, we use a CALL followed by MOV and RET to do the same thing as an
+// indirect jump. That instruction sequence is so-called "retpoline".
+//
+// We have two types of retpoline PLTs as a size optimization. If `-z now`
+// is specified, all dynamic symbols are resolved at load-time. Thus, when
+// that option is given, we can omit code for symbol lazy resolution.
namespace {
template <class ELFT> class Retpoline : public X86_64<ELFT> {
public:
@@ -486,7 +497,7 @@
template <class ELFT>
void Retpoline<ELFT>::writeGotPlt(uint8_t *Buf, const Symbol &S) const {
- write32le(Buf, S.getPltVA() + 17);
+ write64le(Buf, S.getPltVA() + 17);
}
template <class ELFT> void Retpoline<ELFT>::writePltHeader(uint8_t *Buf) const {
@@ -571,7 +582,7 @@
write32le(Buf + 8, -TargetInfo::getPltEntryOffset(Index) - 12);
}
-template <class ELFT> TargetInfo *getTargetInfo() {
+template <class ELFT> static TargetInfo *getTargetInfo() {
if (Config->ZRetpolineplt) {
if (Config->ZNow) {
static RetpolineZNow<ELFT> T;
diff --git a/ELF/CMakeLists.txt b/ELF/CMakeLists.txt
index b9ff414..af2bed3 100644
--- a/ELF/CMakeLists.txt
+++ b/ELF/CMakeLists.txt
@@ -19,6 +19,7 @@
Arch/SPARCV9.cpp
Arch/X86.cpp
Arch/X86_64.cpp
+ CallGraphSort.cpp
Driver.cpp
DriverUtils.cpp
EhFrame.cpp
@@ -45,6 +46,7 @@
LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
BinaryFormat
+ BitWriter
Core
DebugInfoDWARF
LTO
diff --git a/ELF/CallGraphSort.cpp b/ELF/CallGraphSort.cpp
new file mode 100644
index 0000000..33ac159
--- /dev/null
+++ b/ELF/CallGraphSort.cpp
@@ -0,0 +1,249 @@
+//===- CallGraphSort.cpp --------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// Implementation of Call-Chain Clustering from: Optimizing Function Placement
+/// for Large-Scale Data-Center Applications
+/// https://research.fb.com/wp-content/uploads/2017/01/cgo2017-hfsort-final1.pdf
+///
+/// The goal of this algorithm is to improve runtime performance of the final
+/// executable by arranging code sections such that page table and i-cache
+/// misses are minimized.
+///
+/// Definitions:
+/// * Cluster
+/// * An ordered list of input sections which are layed out as a unit. At the
+/// beginning of the algorithm each input section has its own cluster and
+/// the weight of the cluster is the sum of the weight of all incomming
+/// edges.
+/// * Call-Chain Clustering (C³) Heuristic
+/// * Defines when and how clusters are combined. Pick the highest weighted
+/// input section then add it to its most likely predecessor if it wouldn't
+/// penalize it too much.
+/// * Density
+/// * The weight of the cluster divided by the size of the cluster. This is a
+/// proxy for the ammount of execution time spent per byte of the cluster.
+///
+/// It does so given a call graph profile by the following:
+/// * Build a weighted call graph from the call graph profile
+/// * Sort input sections by weight
+/// * For each input section starting with the highest weight
+/// * Find its most likely predecessor cluster
+/// * Check if the combined cluster would be too large, or would have too low
+/// a density.
+/// * If not, then combine the clusters.
+/// * Sort non-empty clusters by density
+///
+//===----------------------------------------------------------------------===//
+
+#include "CallGraphSort.h"
+#include "OutputSections.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+
+using namespace llvm;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+struct Edge {
+ int From;
+ uint64_t Weight;
+};
+
+struct Cluster {
+ Cluster(int Sec, size_t S) {
+ Sections.push_back(Sec);
+ Size = S;
+ }
+
+ double getDensity() const {
+ if (Size == 0)
+ return 0;
+ return double(Weight) / double(Size);
+ }
+
+ std::vector<int> Sections;
+ size_t Size = 0;
+ uint64_t Weight = 0;
+ uint64_t InitialWeight = 0;
+ std::vector<Edge> Preds;
+};
+
+class CallGraphSort {
+public:
+ CallGraphSort();
+
+ DenseMap<const InputSectionBase *, int> run();
+
+private:
+ std::vector<Cluster> Clusters;
+ std::vector<const InputSectionBase *> Sections;
+
+ void groupClusters();
+};
+
+// Maximum ammount the combined cluster density can be worse than the original
+// cluster to consider merging.
+constexpr int MAX_DENSITY_DEGRADATION = 8;
+
+// Maximum cluster size in bytes.
+constexpr uint64_t MAX_CLUSTER_SIZE = 1024 * 1024;
+} // end anonymous namespace
+
+// Take the edge list in Config->CallGraphProfile, resolve symbol names to
+// Symbols, and generate a graph between InputSections with the provided
+// weights.
+CallGraphSort::CallGraphSort() {
+ llvm::MapVector<std::pair<const InputSectionBase *, const InputSectionBase *>,
+ uint64_t> &Profile = Config->CallGraphProfile;
+ DenseMap<const InputSectionBase *, int> SecToCluster;
+
+ auto GetOrCreateNode = [&](const InputSectionBase *IS) -> int {
+ auto Res = SecToCluster.insert(std::make_pair(IS, Clusters.size()));
+ if (Res.second) {
+ Sections.push_back(IS);
+ Clusters.emplace_back(Clusters.size(), IS->getSize());
+ }
+ return Res.first->second;
+ };
+
+ // Create the graph.
+ for (const auto &C : Profile) {
+ const auto *FromSB = cast<InputSectionBase>(C.first.first->Repl);
+ const auto *ToSB = cast<InputSectionBase>(C.first.second->Repl);
+ uint64_t Weight = C.second;
+
+ // Ignore edges between input sections belonging to different output
+ // sections. This is done because otherwise we would end up with clusters
+ // containing input sections that can't actually be placed adjacently in the
+ // output. This messes with the cluster size and density calculations. We
+ // would also end up moving input sections in other output sections without
+ // moving them closer to what calls them.
+ if (FromSB->getOutputSection() != ToSB->getOutputSection())
+ continue;
+
+ int From = GetOrCreateNode(FromSB);
+ int To = GetOrCreateNode(ToSB);
+
+ Clusters[To].Weight += Weight;
+
+ if (From == To)
+ continue;
+
+ // Add an edge
+ Clusters[To].Preds.push_back({From, Weight});
+ }
+ for (Cluster &C : Clusters)
+ C.InitialWeight = C.Weight;
+}
+
+// It's bad to merge clusters which would degrade the density too much.
+static bool isNewDensityBad(Cluster &A, Cluster &B) {
+ double NewDensity = double(A.Weight + B.Weight) / double(A.Size + B.Size);
+ if (NewDensity < A.getDensity() / MAX_DENSITY_DEGRADATION)
+ return true;
+ return false;
+}
+
+static void mergeClusters(Cluster &Into, Cluster &From) {
+ Into.Sections.insert(Into.Sections.end(), From.Sections.begin(),
+ From.Sections.end());
+ Into.Size += From.Size;
+ Into.Weight += From.Weight;
+ From.Sections.clear();
+ From.Size = 0;
+ From.Weight = 0;
+}
+
+// Group InputSections into clusters using the Call-Chain Clustering heuristic
+// then sort the clusters by density.
+void CallGraphSort::groupClusters() {
+ std::vector<int> SortedSecs(Clusters.size());
+ std::vector<Cluster *> SecToCluster(Clusters.size());
+
+ for (int SI = 0, SE = Clusters.size(); SI != SE; ++SI) {
+ SortedSecs[SI] = SI;
+ SecToCluster[SI] = &Clusters[SI];
+ }
+
+ std::stable_sort(SortedSecs.begin(), SortedSecs.end(), [&](int A, int B) {
+ return Clusters[B].getDensity() < Clusters[A].getDensity();
+ });
+
+ for (int SI : SortedSecs) {
+ // Clusters[SI] is the same as SecToClusters[SI] here because it has not
+ // been merged into another cluster yet.
+ Cluster &C = Clusters[SI];
+
+ int BestPred = -1;
+ uint64_t BestWeight = 0;
+
+ for (Edge &E : C.Preds) {
+ if (BestPred == -1 || E.Weight > BestWeight) {
+ BestPred = E.From;
+ BestWeight = E.Weight;
+ }
+ }
+
+ // don't consider merging if the edge is unlikely.
+ if (BestWeight * 10 <= C.InitialWeight)
+ continue;
+
+ Cluster *PredC = SecToCluster[BestPred];
+ if (PredC == &C)
+ continue;
+
+ if (C.Size + PredC->Size > MAX_CLUSTER_SIZE)
+ continue;
+
+ if (isNewDensityBad(*PredC, C))
+ continue;
+
+ // NOTE: Consider using a disjoint-set to track section -> cluster mapping
+ // if this is ever slow.
+ for (int SI : C.Sections)
+ SecToCluster[SI] = PredC;
+
+ mergeClusters(*PredC, C);
+ }
+
+ // Remove empty or dead nodes. Invalidates all cluster indices.
+ llvm::erase_if(Clusters, [](const Cluster &C) {
+ return C.Size == 0 || C.Sections.empty();
+ });
+
+ // Sort by density.
+ std::stable_sort(Clusters.begin(), Clusters.end(),
+ [](const Cluster &A, const Cluster &B) {
+ return A.getDensity() > B.getDensity();
+ });
+}
+
+DenseMap<const InputSectionBase *, int> CallGraphSort::run() {
+ groupClusters();
+
+ // Generate order.
+ llvm::DenseMap<const InputSectionBase *, int> OrderMap;
+ ssize_t CurOrder = 1;
+
+ for (const Cluster &C : Clusters)
+ for (int SecIndex : C.Sections)
+ OrderMap[Sections[SecIndex]] = CurOrder++;
+
+ return OrderMap;
+}
+
+// Sort sections by the profile data provided by -callgraph-profile-file
+//
+// This first builds a call graph based on the profile data then merges sections
+// according to the C³ huristic. All clusters are then sorted by a density
+// metric to further improve locality.
+DenseMap<const InputSectionBase *, int> elf::computeCallGraphProfileOrder() {
+ return CallGraphSort().run();
+}
diff --git a/ELF/CallGraphSort.h b/ELF/CallGraphSort.h
new file mode 100644
index 0000000..3f96dc8
--- /dev/null
+++ b/ELF/CallGraphSort.h
@@ -0,0 +1,23 @@
+//===- CallGraphSort.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_CALL_GRAPH_SORT_H
+#define LLD_ELF_CALL_GRAPH_SORT_H
+
+#include "llvm/ADT/DenseMap.h"
+
+namespace lld {
+namespace elf {
+class InputSectionBase;
+
+llvm::DenseMap<const InputSectionBase *, int> computeCallGraphProfileOrder();
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/Config.h b/ELF/Config.h
index 2007992..60276f9 100644
--- a/ELF/Config.h
+++ b/ELF/Config.h
@@ -24,6 +24,7 @@
namespace elf {
class InputFile;
+class InputSectionBase;
enum ELFKind {
ELFNoneKind,
@@ -85,6 +86,8 @@
llvm::StringRef Init;
llvm::StringRef LTOAAPipeline;
llvm::StringRef LTONewPmPasses;
+ llvm::StringRef LTOObjPath;
+ llvm::StringRef LTOSampleProfile;
llvm::StringRef MapFile;
llvm::StringRef OutputFile;
llvm::StringRef OptRemarksFilename;
@@ -92,6 +95,9 @@
llvm::StringRef SoName;
llvm::StringRef Sysroot;
llvm::StringRef ThinLTOCacheDir;
+ llvm::StringRef ThinLTOIndexOnlyArg;
+ std::pair<llvm::StringRef, llvm::StringRef> ThinLTOObjectSuffixReplace;
+ std::pair<llvm::StringRef, llvm::StringRef> ThinLTOPrefixReplace;
std::string Rpath;
std::vector<VersionDefinition> VersionDefinitions;
std::vector<llvm::StringRef> AuxiliaryList;
@@ -103,6 +109,9 @@
std::vector<SymbolVersion> VersionScriptGlobals;
std::vector<SymbolVersion> VersionScriptLocals;
std::vector<uint8_t> BuildIdVector;
+ llvm::MapVector<std::pair<const InputSectionBase *, const InputSectionBase *>,
+ uint64_t>
+ CallGraphProfile;
bool AllowMultipleDefinition;
bool AndroidPackDynRelocs = false;
bool ARMHasBlx = false;
@@ -131,6 +140,8 @@
bool ICF;
bool IgnoreDataAddressEquality;
bool IgnoreFunctionAddressEquality;
+ bool LTODebugPassManager;
+ bool LTONewPassManager;
bool MergeArmExidx;
bool MipsN32Abi = false;
bool NoinhibitExec;
@@ -149,15 +160,19 @@
bool SysvHash = false;
bool Target1Rel;
bool Trace;
+ bool ThinLTOEmitImportsFiles;
+ bool ThinLTOIndexOnly;
bool UndefinedVersion;
+ bool WarnBackrefs;
bool WarnCommon;
bool WarnMissingEntry;
bool WarnSymbolOrdering;
bool WriteAddends;
bool ZCombreloc;
+ bool ZCopyreloc;
bool ZExecstack;
bool ZHazardplt;
- bool ZNocopyreloc;
+ bool ZKeepTextSectionPrefix;
bool ZNodelete;
bool ZNodlopen;
bool ZNow;
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp
index 4565fde..2e3a425 100644
--- a/ELF/Driver.cpp
+++ b/ELF/Driver.cpp
@@ -118,7 +118,8 @@
std::pair<ELFKind, uint16_t> Ret =
StringSwitch<std::pair<ELFKind, uint16_t>>(S)
- .Cases("aarch64elf", "aarch64linux", {ELF64LEKind, EM_AARCH64})
+ .Cases("aarch64elf", "aarch64linux", "aarch64_elf64_le_vec",
+ {ELF64LEKind, EM_AARCH64})
.Cases("armelf", "armelf_linux_eabi", {ELF32LEKind, EM_ARM})
.Case("elf32_x86_64", {ELF32LEKind, EM_X86_64})
.Cases("elf32btsmip", "elf32btsmipn32", {ELF32BEKind, EM_MIPS})
@@ -313,6 +314,17 @@
return false;
}
+static bool getZFlag(opt::InputArgList &Args, StringRef K1, StringRef K2,
+ bool Default) {
+ for (auto *Arg : Args.filtered_reverse(OPT_z)) {
+ if (K1 == Arg->getValue())
+ return true;
+ if (K2 == Arg->getValue())
+ return false;
+ }
+ return Default;
+}
+
void LinkerDriver::main(ArrayRef<const char *> ArgsArr) {
ELFOptTable Parser;
opt::InputArgList Args = Parser.parse(ArgsArr.slice(1));
@@ -572,6 +584,45 @@
return {BuildIdKind::None, {}};
}
+static void readCallGraph(MemoryBufferRef MB) {
+ // Build a map from symbol name to section
+ DenseMap<StringRef, const Symbol *> SymbolNameToSymbol;
+ for (InputFile *File : ObjectFiles)
+ for (Symbol *Sym : File->getSymbols())
+ SymbolNameToSymbol[Sym->getName()] = Sym;
+
+ for (StringRef L : args::getLines(MB)) {
+ SmallVector<StringRef, 3> Fields;
+ L.split(Fields, ' ');
+ if (Fields.size() != 3)
+ fatal("parse error");
+ uint64_t Count;
+ if (!to_integer(Fields[2], Count))
+ fatal("parse error");
+ const Symbol *FromSym = SymbolNameToSymbol.lookup(Fields[0]);
+ const Symbol *ToSym = SymbolNameToSymbol.lookup(Fields[1]);
+ if (Config->WarnSymbolOrdering) {
+ if (!FromSym)
+ warn("call graph file: no such symbol: " + Fields[0]);
+ if (!ToSym)
+ warn("call graph file: no such symbol: " + Fields[1]);
+ }
+ if (!FromSym || !ToSym || Count == 0)
+ continue;
+ warnUnorderableSymbol(FromSym);
+ warnUnorderableSymbol(ToSym);
+ const Defined *FromSymD = dyn_cast<Defined>(FromSym);
+ const Defined *ToSymD = dyn_cast<Defined>(ToSym);
+ if (!FromSymD || !ToSymD)
+ continue;
+ const auto *FromSB = dyn_cast_or_null<InputSectionBase>(FromSymD->Section);
+ const auto *ToSB = dyn_cast_or_null<InputSectionBase>(ToSymD->Section);
+ if (!FromSB || !ToSB)
+ continue;
+ Config->CallGraphProfile[std::make_pair(FromSB, ToSB)] += Count;
+ }
+}
+
static bool getCompressDebugSections(opt::InputArgList &Args) {
StringRef S = Args.getLastArgValue(OPT_compress_debug_sections, "none");
if (S == "none")
@@ -583,12 +634,17 @@
return true;
}
-static int parseInt(StringRef S, opt::Arg *Arg) {
- int V = 0;
- if (!to_integer(S, V, 10))
- error(Arg->getSpelling() + "=" + Arg->getValue() +
- ": number expected, but got '" + S + "'");
- return V;
+static std::pair<StringRef, StringRef> getOldNewOptions(opt::InputArgList &Args,
+ unsigned Id) {
+ auto *Arg = Args.getLastArg(Id);
+ if (!Arg)
+ return {"", ""};
+
+ StringRef S = Arg->getValue();
+ std::pair<StringRef, StringRef> Ret = S.split(';');
+ if (Ret.second.empty())
+ error(Arg->getSpelling() + " expects 'old;new' format, but got " + S);
+ return Ret;
}
// Parse the symbol ordering file and warn for any duplicate entries.
@@ -617,6 +673,7 @@
errorHandler().Verbose = Args.hasArg(OPT_verbose);
errorHandler().FatalWarnings =
Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false);
+ ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true);
Config->AllowMultipleDefinition =
Args.hasFlag(OPT_allow_multiple_definition,
@@ -657,9 +714,13 @@
Args.hasArg(OPT_ignore_function_address_equality);
Config->Init = Args.getLastArgValue(OPT_init, "_init");
Config->LTOAAPipeline = Args.getLastArgValue(OPT_lto_aa_pipeline);
+ Config->LTODebugPassManager = Args.hasArg(OPT_lto_debug_pass_manager);
+ Config->LTONewPassManager = Args.hasArg(OPT_lto_new_pass_manager);
Config->LTONewPmPasses = Args.getLastArgValue(OPT_lto_newpm_passes);
Config->LTOO = args::getInteger(Args, OPT_lto_O, 2);
+ Config->LTOObjPath = Args.getLastArgValue(OPT_plugin_opt_obj_path_eq);
Config->LTOPartitions = args::getInteger(Args, OPT_lto_partitions, 1);
+ Config->LTOSampleProfile = Args.getLastArgValue(OPT_lto_sample_profile);
Config->MapFile = Args.getLastArgValue(OPT_Map);
Config->MergeArmExidx =
Args.hasFlag(OPT_merge_exidx_entries, OPT_no_merge_exidx_entries, true);
@@ -694,50 +755,51 @@
Config->ThinLTOCachePolicy = CHECK(
parseCachePruningPolicy(Args.getLastArgValue(OPT_thinlto_cache_policy)),
"--thinlto-cache-policy: invalid cache policy");
+ Config->ThinLTOEmitImportsFiles =
+ Args.hasArg(OPT_plugin_opt_thinlto_emit_imports_files);
+ Config->ThinLTOIndexOnly = Args.hasArg(OPT_plugin_opt_thinlto_index_only) ||
+ Args.hasArg(OPT_plugin_opt_thinlto_index_only_eq);
+ Config->ThinLTOIndexOnlyArg =
+ Args.getLastArgValue(OPT_plugin_opt_thinlto_index_only_eq);
Config->ThinLTOJobs = args::getInteger(Args, OPT_thinlto_jobs, -1u);
- ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true);
+ Config->ThinLTOObjectSuffixReplace =
+ getOldNewOptions(Args, OPT_plugin_opt_thinlto_object_suffix_replace_eq);
+ Config->ThinLTOPrefixReplace =
+ getOldNewOptions(Args, OPT_plugin_opt_thinlto_prefix_replace_eq);
Config->Trace = Args.hasArg(OPT_trace);
Config->Undefined = args::getStrings(Args, OPT_undefined);
Config->UndefinedVersion =
Args.hasFlag(OPT_undefined_version, OPT_no_undefined_version, true);
Config->UnresolvedSymbols = getUnresolvedSymbolPolicy(Args);
+ Config->WarnBackrefs =
+ Args.hasFlag(OPT_warn_backrefs, OPT_no_warn_backrefs, false);
Config->WarnCommon = Args.hasFlag(OPT_warn_common, OPT_no_warn_common, false);
Config->WarnSymbolOrdering =
Args.hasFlag(OPT_warn_symbol_ordering, OPT_no_warn_symbol_ordering, true);
- Config->ZCombreloc = !hasZOption(Args, "nocombreloc");
- Config->ZExecstack = hasZOption(Args, "execstack");
+ Config->ZCombreloc = getZFlag(Args, "combreloc", "nocombreloc", true);
+ Config->ZCopyreloc = getZFlag(Args, "copyreloc", "nocopyreloc", true);
+ Config->ZExecstack = getZFlag(Args, "execstack", "noexecstack", false);
Config->ZHazardplt = hasZOption(Args, "hazardplt");
- Config->ZNocopyreloc = hasZOption(Args, "nocopyreloc");
+ Config->ZKeepTextSectionPrefix = getZFlag(
+ Args, "keep-text-section-prefix", "nokeep-text-section-prefix", false);
Config->ZNodelete = hasZOption(Args, "nodelete");
Config->ZNodlopen = hasZOption(Args, "nodlopen");
- Config->ZNow = hasZOption(Args, "now");
+ Config->ZNow = getZFlag(Args, "now", "lazy", false);
Config->ZOrigin = hasZOption(Args, "origin");
- Config->ZRelro = !hasZOption(Args, "norelro");
+ Config->ZRelro = getZFlag(Args, "relro", "norelro", true);
Config->ZRetpolineplt = hasZOption(Args, "retpolineplt");
Config->ZRodynamic = hasZOption(Args, "rodynamic");
Config->ZStackSize = args::getZOptionValue(Args, OPT_z, "stack-size", 0);
- Config->ZText = !hasZOption(Args, "notext");
+ Config->ZText = getZFlag(Args, "text", "notext", true);
Config->ZWxneeded = hasZOption(Args, "wxneeded");
- // Parse LTO plugin-related options for compatibility with gold.
- for (auto *Arg : Args.filtered(OPT_plugin_opt)) {
- StringRef S = Arg->getValue();
- if (S == "disable-verify")
- Config->DisableVerify = true;
- else if (S == "save-temps")
- Config->SaveTemps = true;
- else if (S.startswith("O"))
- Config->LTOO = parseInt(S.substr(1), Arg);
- else if (S.startswith("lto-partitions="))
- Config->LTOPartitions = parseInt(S.substr(15), Arg);
- else if (S.startswith("jobs="))
- Config->ThinLTOJobs = parseInt(S.substr(5), Arg);
- else if (S.startswith("mcpu="))
- parseClangOption(Saver.save("-" + S), Arg->getSpelling());
- else if (!S.startswith("/") && !S.startswith("-fresolution=") &&
- !S.startswith("-pass-through=") && !S.startswith("thinlto"))
- parseClangOption(S, Arg->getSpelling());
- }
+ // Parse LTO options.
+ if (auto *Arg = Args.getLastArg(OPT_plugin_opt_mcpu_eq))
+ parseClangOption(Saver.save("-mcpu=" + StringRef(Arg->getValue())),
+ Arg->getSpelling());
+
+ for (auto *Arg : Args.filtered(OPT_plugin_opt))
+ parseClangOption(Arg->getValue(), Arg->getSpelling());
// Parse -mllvm options.
for (auto *Arg : Args.filtered(OPT_mllvm))
@@ -878,6 +940,10 @@
}
void LinkerDriver::createFiles(opt::InputArgList &Args) {
+ // For --{push,pop}-state.
+ std::vector<std::tuple<bool, bool, bool>> Stack;
+
+ // Iterate over argv to process input files and positional arguments.
for (auto *Arg : Args) {
switch (Arg->getOption().getUnaliasedOption().getID()) {
case OPT_library:
@@ -928,11 +994,42 @@
Files.back()->JustSymbols = true;
}
break;
+ case OPT_start_group:
+ if (InputFile::IsInGroup)
+ error("nested --start-group");
+ InputFile::IsInGroup = true;
+ break;
+ case OPT_end_group:
+ if (!InputFile::IsInGroup)
+ error("stray --end-group");
+ InputFile::IsInGroup = false;
+ ++InputFile::NextGroupId;
+ break;
case OPT_start_lib:
+ if (InLib)
+ error("nested --start-lib");
+ if (InputFile::IsInGroup)
+ error("may not nest --start-lib in --start-group");
InLib = true;
+ InputFile::IsInGroup = true;
break;
case OPT_end_lib:
+ if (!InLib)
+ error("stray --end-lib");
InLib = false;
+ InputFile::IsInGroup = false;
+ ++InputFile::NextGroupId;
+ break;
+ case OPT_push_state:
+ Stack.emplace_back(Config->AsNeeded, Config->Static, InWholeArchive);
+ break;
+ case OPT_pop_state:
+ if (Stack.empty()) {
+ error("unbalanced --push-state/--pop-state");
+ break;
+ }
+ std::tie(Config->AsNeeded, Config->Static, InWholeArchive) = Stack.back();
+ Stack.pop_back();
break;
}
}
@@ -1024,6 +1121,57 @@
Sym->VersionId = VER_NDX_LOCAL;
}
+// Force Sym to be entered in the output. Used for -u or equivalent.
+template <class ELFT> static void handleUndefined(StringRef Name) {
+ Symbol *Sym = Symtab->find(Name);
+ if (!Sym)
+ return;
+
+ // Since symbol S may not be used inside the program, LTO may
+ // eliminate it. Mark the symbol as "used" to prevent it.
+ Sym->IsUsedInRegularObj = true;
+
+ if (Sym->isLazy())
+ Symtab->fetchLazy<ELFT>(Sym);
+}
+
+template <class ELFT> static bool shouldDemote(Symbol &Sym) {
+ // If all references to a DSO happen to be weak, the DSO is not added to
+ // DT_NEEDED. If that happens, we need to eliminate shared symbols created
+ // from the DSO. Otherwise, they become dangling references that point to a
+ // non-existent DSO.
+ if (auto *S = dyn_cast<SharedSymbol>(&Sym))
+ return !S->getFile<ELFT>().IsNeeded;
+
+ // We are done processing archives, so lazy symbols that were used but not
+ // found can be converted to undefined. We could also just delete the other
+ // lazy symbols, but that seems to be more work than it is worth.
+ return Sym.isLazy() && Sym.IsUsedInRegularObj;
+}
+
+template <class ELFT> static void demoteSymbols() {
+ for (Symbol *Sym : Symtab->getSymbols()) {
+ if (shouldDemote<ELFT>(*Sym)) {
+ bool Used = Sym->Used;
+ replaceSymbol<Undefined>(Sym, nullptr, Sym->getName(), Sym->Binding,
+ Sym->StOther, Sym->Type);
+ Sym->Used = Used;
+ }
+ }
+}
+
+// Record sections that define symbols mentioned in --keep-unique <symbol>
+// these sections are inelligible for ICF.
+static void findKeepUniqueSections(opt::InputArgList &Args) {
+ for (auto *Arg : Args.filtered(OPT_keep_unique)) {
+ StringRef Name = Arg->getValue();
+ if (auto *Sym = dyn_cast_or_null<Defined>(Symtab->find(Name)))
+ Sym->Section->KeepUnique = true;
+ else
+ warn("could not find symbol " + Name + " to keep unique");
+ }
+}
+
// Do actual linking. Note that when this function is called,
// all linker scripts have already been parsed.
template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
@@ -1088,12 +1236,12 @@
// Handle the `--undefined <sym>` options.
for (StringRef S : Config->Undefined)
- Symtab->fetchIfLazy<ELFT>(S);
+ handleUndefined<ELFT>(S);
// If an entry symbol is in a static archive, pull out that file now
// to complete the symbol table. After this, no new names except a
// few linker-synthesized ones will be added to the symbol table.
- Symtab->fetchIfLazy<ELFT>(Config->Entry);
+ handleUndefined<ELFT>(Config->Entry);
// Return if there were name resolution errors.
if (errorCount())
@@ -1133,10 +1281,18 @@
for (auto *Arg : Args.filtered(OPT_wrap))
Symtab->addSymbolWrap<ELFT>(Arg->getValue());
+ // Do link-time optimization if given files are LLVM bitcode files.
+ // This compiles bitcode files into real object files.
Symtab->addCombinedLTOObject<ELFT>();
if (errorCount())
return;
+ // If -thinlto-index-only is given, we should create only "index
+ // files" and not object files. Index file creation is already done
+ // in addCombinedLTOObject, so we are done if that's the case.
+ if (Config->ThinLTOIndexOnly)
+ return;
+
// Apply symbol renames for -wrap.
Symtab->applySymbolWrap();
@@ -1183,11 +1339,20 @@
// Do size optimizations: garbage collection, merging of SHF_MERGE sections
// and identical code folding.
- markLive<ELFT>();
decompressSections();
+ splitSections<ELFT>();
+ markLive<ELFT>();
+ demoteSymbols<ELFT>();
mergeSections();
- if (Config->ICF)
+ if (Config->ICF) {
+ findKeepUniqueSections(Args);
doIcf<ELFT>();
+ }
+
+ // Read the callgraph now that we know what was gced or icfed
+ if (auto *Arg = Args.getLastArg(OPT_call_graph_ordering_file))
+ if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
+ readCallGraph(*Buffer);
// Write the result to the file.
writeResult<ELFT>();
diff --git a/ELF/DriverUtils.cpp b/ELF/DriverUtils.cpp
index c768f92..35e3ba1 100644
--- a/ELF/DriverUtils.cpp
+++ b/ELF/DriverUtils.cpp
@@ -59,18 +59,18 @@
OPT_no_color_diagnostics);
if (!Arg)
return;
- else if (Arg->getOption().getID() == OPT_color_diagnostics)
+ if (Arg->getOption().getID() == OPT_color_diagnostics) {
errorHandler().ColorDiagnostics = true;
- else if (Arg->getOption().getID() == OPT_no_color_diagnostics)
+ } else if (Arg->getOption().getID() == OPT_no_color_diagnostics) {
errorHandler().ColorDiagnostics = false;
- else {
+ } else {
StringRef S = Arg->getValue();
if (S == "always")
errorHandler().ColorDiagnostics = true;
else if (S == "never")
errorHandler().ColorDiagnostics = false;
else if (S != "auto")
- error("unknown option: -color-diagnostics=" + S);
+ error("unknown option: --color-diagnostics=" + S);
}
}
@@ -88,6 +88,29 @@
return cl::TokenizeGNUCommandLine;
}
+// Gold LTO plugin takes a `--plugin-opt foo=bar` option as an alias for
+// `--plugin-opt=foo=bar`. We want to handle `--plugin-opt=foo=` as an
+// option name and `bar` as a value. Unfortunately, OptParser cannot
+// handle an option with a space in it.
+//
+// In this function, we concatenate command line arguments so that
+// `--plugin-opt <foo>` is converted to `--plugin-opt=<foo>`. This is a
+// bit hacky, but looks like it is still better than handling --plugin-opt
+// options by hand.
+static void concatLTOPluginOptions(SmallVectorImpl<const char *> &Args) {
+ SmallVector<const char *, 256> V;
+ for (size_t I = 0, E = Args.size(); I != E; ++I) {
+ StringRef S = Args[I];
+ if ((S == "-plugin-opt" || S == "--plugin-opt") && I + 1 != E) {
+ V.push_back(Saver.save(S + "=" + Args[I + 1]).data());
+ ++I;
+ } else {
+ V.push_back(Args[I]);
+ }
+ }
+ Args = std::move(V);
+}
+
// Parses a given list of options.
opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) {
// Make InputArgList from string vectors.
@@ -103,6 +126,7 @@
// Expand response files (arguments in the form of @<filename>)
// and then parse the argument again.
cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec);
+ concatLTOPluginOptions(Vec);
Args = this->ParseArgs(Vec, MissingIndex, MissingCount);
handleColorDiagnostics(Args);
diff --git a/ELF/EhFrame.cpp b/ELF/EhFrame.cpp
index 159108e..20b32c0 100644
--- a/ELF/EhFrame.cpp
+++ b/ELF/EhFrame.cpp
@@ -20,17 +20,16 @@
#include "Config.h"
#include "InputSection.h"
#include "Relocations.h"
+#include "Target.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Strings.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/Object/ELF.h"
-#include "llvm/Support/Endian.h"
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::dwarf;
using namespace llvm::object;
-using namespace llvm::support::endian;
using namespace lld;
using namespace lld::elf;
@@ -72,7 +71,7 @@
// First 4 bytes of CIE/FDE is the size of the record.
// If it is 0xFFFFFFFF, the next 8 bytes contain the size instead,
// but we do not support that format yet.
- uint64_t V = read32(D.data(), Config->Endianness);
+ uint64_t V = read32(D.data());
if (V == UINT32_MAX)
failOn(D.data(), "CIE/FDE too large");
uint64_t Size = V + 4;
diff --git a/ELF/Filesystem.cpp b/ELF/Filesystem.cpp
index 8d0b5d8..5cf240e 100644
--- a/ELF/Filesystem.cpp
+++ b/ELF/Filesystem.cpp
@@ -44,7 +44,7 @@
// The calling thread returns almost immediately.
void elf::unlinkAsync(StringRef Path) {
// Removing a file is async on windows.
-#if defined(LLVM_ON_WIN32)
+#if defined(_WIN32)
sys::fs::remove(Path);
#else
if (!ThreadsEnabled || !sys::fs::exists(Path) ||
diff --git a/ELF/ICF.cpp b/ELF/ICF.cpp
index ffd6029..f708d96 100644
--- a/ELF/ICF.cpp
+++ b/ELF/ICF.cpp
@@ -78,6 +78,7 @@
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
+#include "Writer.h"
#include "lld/Common/Threads.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/BinaryFormat/ELF.h"
@@ -162,7 +163,13 @@
// Returns true if section S is subject of ICF.
static bool isEligible(InputSection *S) {
- if (!S->Live || !(S->Flags & SHF_ALLOC) || (S->Flags & SHF_WRITE))
+ if (!S->Live || S->KeepUnique || !(S->Flags & SHF_ALLOC))
+ return false;
+
+ // Don't merge writable sections. .data.rel.ro sections are marked as writable
+ // but are semantically read-only.
+ if ((S->Flags & SHF_WRITE) && S->Name != ".data.rel.ro" &&
+ !S->Name.startswith(".data.rel.ro."))
return false;
// Don't merge read only data sections unless
@@ -181,6 +188,12 @@
if (S->Name == ".init" || S->Name == ".fini")
return false;
+ // A user program may enumerate sections named with a C identifier using
+ // __start_* and __stop_* symbols. We cannot ICF any such sections because
+ // that could change program semantics.
+ if (isValidCIdentifier(S->Name))
+ return false;
+
return true;
}
@@ -296,6 +309,13 @@
A->getSize() != B->getSize() || A->Data != B->Data)
return false;
+ // If two sections have different output sections, we cannot merge them.
+ // FIXME: This doesn't do the right thing in the case where there is a linker
+ // script. We probably need to move output section assignment before ICF to
+ // get the correct behaviour here.
+ if (getOutputSectionName(A) != getOutputSectionName(B))
+ return false;
+
if (A->AreRelocsRela)
return constantEq(A, A->template relas<ELFT>(), B,
B->template relas<ELFT>());
@@ -362,17 +382,12 @@
// vector. Therefore, Sections vector can be considered as contiguous
// groups of sections, grouped by the class.
//
-// This function calls Fn on every group that starts within [Begin, End).
-// Note that a group must start in that range but doesn't necessarily
-// have to end before End.
+// This function calls Fn on every group within [Begin, End).
template <class ELFT>
void ICF<ELFT>::forEachClassRange(size_t Begin, size_t End,
std::function<void(size_t, size_t)> Fn) {
- if (Begin > 0)
- Begin = findBoundary(Begin - 1, End);
-
while (Begin < End) {
- size_t Mid = findBoundary(Begin, Sections.size());
+ size_t Mid = findBoundary(Begin, End);
Fn(Begin, Mid);
Begin = Mid;
}
@@ -392,12 +407,23 @@
Current = Cnt % 2;
Next = (Cnt + 1) % 2;
- // Split sections into 256 shards and call Fn in parallel.
- size_t NumShards = 256;
+ // Shard into non-overlapping intervals, and call Fn in parallel.
+ // The sharding must be completed before any calls to Fn are made
+ // so that Fn can modify the Chunks in its shard without causing data
+ // races.
+ const size_t NumShards = 256;
size_t Step = Sections.size() / NumShards;
- parallelForEachN(0, NumShards, [&](size_t I) {
- size_t End = (I == NumShards - 1) ? Sections.size() : (I + 1) * Step;
- forEachClassRange(I * Step, End, Fn);
+ size_t Boundaries[NumShards + 1];
+ Boundaries[0] = 0;
+ Boundaries[NumShards] = Sections.size();
+
+ parallelForEachN(1, NumShards, [&](size_t I) {
+ Boundaries[I] = findBoundary((I - 1) * Step, Sections.size());
+ });
+
+ parallelForEachN(1, NumShards + 1, [&](size_t I) {
+ if (Boundaries[I - 1] < Boundaries[I])
+ forEachClassRange(Boundaries[I - 1], Boundaries[I], Fn);
});
++Cnt;
}
diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp
index bb20c83..8e4fbe3 100644
--- a/ELF/InputFiles.cpp
+++ b/ELF/InputFiles.cpp
@@ -38,14 +38,23 @@
using namespace lld;
using namespace lld::elf;
+bool InputFile::IsInGroup;
+uint32_t InputFile::NextGroupId;
std::vector<BinaryFile *> elf::BinaryFiles;
std::vector<BitcodeFile *> elf::BitcodeFiles;
+std::vector<LazyObjFile *> elf::LazyObjFiles;
std::vector<InputFile *> elf::ObjectFiles;
std::vector<InputFile *> elf::SharedFiles;
TarWriter *elf::Tar;
-InputFile::InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
+InputFile::InputFile(Kind K, MemoryBufferRef M)
+ : MB(M), GroupId(NextGroupId), FileKind(K) {
+ // All files within the same --{start,end}-group get the same group ID.
+ // Otherwise, a new file will get a new group ID.
+ if (!IsInGroup)
+ ++NextGroupId;
+}
Optional<MemoryBufferRef> elf::readFile(StringRef Path) {
// The --chroot option changes our virtual root directory.
@@ -55,7 +64,7 @@
log(Path);
- auto MBOrErr = MemoryBuffer::getFile(Path);
+ auto MBOrErr = MemoryBuffer::getFile(Path, -1, false);
if (auto EC = MBOrErr.getError()) {
error("cannot open " + Path + ": " + EC.message());
return None;
@@ -122,7 +131,17 @@
Config->Wordsize);
for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf->compile_units()) {
- const DWARFDebugLine::LineTable *LT = Dwarf->getLineTableForUnit(CU.get());
+ auto Report = [](Error Err) {
+ handleAllErrors(std::move(Err),
+ [](ErrorInfoBase &Info) { warn(Info.message()); });
+ };
+ Expected<const DWARFDebugLine::LineTable *> ExpectedLT =
+ Dwarf->getLineTableForUnit(CU.get(), Report);
+ const DWARFDebugLine::LineTable *LT = nullptr;
+ if (ExpectedLT)
+ LT = *ExpectedLT;
+ else
+ Report(ExpectedLT.takeError());
if (!LT)
continue;
LineTables.push_back(LT);
@@ -390,7 +409,7 @@
DenseSet<CachedHashStringRef> &ComdatGroups) {
const ELFFile<ELFT> &Obj = this->getObj();
- ArrayRef<Elf_Shdr> ObjSections = CHECK(this->getObj().sections(), this);
+ ArrayRef<Elf_Shdr> ObjSections = CHECK(Obj.sections(), this);
uint64_t Size = ObjSections.size();
this->Sections.resize(Size);
this->SectionStringTable =
@@ -742,27 +761,28 @@
}
// Returns a buffer pointing to a member file containing a given symbol.
-std::pair<MemoryBufferRef, uint64_t>
-ArchiveFile::getMember(const Archive::Symbol *Sym) {
+InputFile *ArchiveFile::fetch(const Archive::Symbol &Sym) {
Archive::Child C =
- CHECK(Sym->getMember(), toString(this) +
- ": could not get the member for symbol " +
- Sym->getName());
+ CHECK(Sym.getMember(), toString(this) +
+ ": could not get the member for symbol " +
+ Sym.getName());
if (!Seen.insert(C.getChildOffset()).second)
- return {MemoryBufferRef(), 0};
+ return nullptr;
- MemoryBufferRef Ret =
+ MemoryBufferRef MB =
CHECK(C.getMemoryBufferRef(),
toString(this) +
": could not get the buffer for the member defining symbol " +
- Sym->getName());
+ Sym.getName());
- if (C.getParent()->isThin() && Tar)
- Tar->append(relativeToRoot(CHECK(C.getFullName(), this)), Ret.getBuffer());
- if (C.getParent()->isThin())
- return {Ret, 0};
- return {Ret, C.getChildOffset()};
+ if (Tar && C.getParent()->isThin())
+ Tar->append(relativeToRoot(CHECK(C.getFullName(), this)), MB.getBuffer());
+
+ InputFile *File = createObjectFile(
+ MB, getName(), C.getParent()->isThin() ? 0 : C.getChildOffset());
+ File->GroupId = GroupId;
+ return File;
}
template <class ELFT>
@@ -907,6 +927,11 @@
std::vector<uint32_t> Versyms = parseVersyms(); // parse .gnu.version
ArrayRef<Elf_Shdr> Sections = CHECK(this->getObj().sections(), this);
+ // System libraries can have a lot of symbols with versions. Using a
+ // fixed buffer for computing the versions name (foo@ver) can save a
+ // lot of allocations.
+ SmallString<0> VersionedNameBuffer;
+
// Add symbols to the symbol table.
ArrayRef<Elf_Sym> Syms = this->getGlobalELFSyms();
for (size_t I = 0; I < Syms.size(); ++I) {
@@ -957,8 +982,9 @@
StringRef VerName =
this->StringTable.data() + Verdefs[Idx]->getAux()->vda_name;
- Name = Saver.save(Name + "@" + VerName);
- Symtab->addShared(Name, *this, Sym, Alignment, Idx);
+ VersionedNameBuffer.clear();
+ Name = (Name + "@" + VerName).toStringRef(VersionedNameBuffer);
+ Symtab->addShared(Saver.save(Name), *this, Sym, Alignment, Idx);
}
}
@@ -991,8 +1017,9 @@
case Triple::x86_64:
return EM_X86_64;
default:
- fatal(Path + ": could not infer e_machine from bitcode target triple " +
+ error(Path + ": could not infer e_machine from bitcode target triple " +
T.str());
+ return EM_NONE;
}
}
@@ -1001,17 +1028,21 @@
: InputFile(BitcodeKind, MB) {
this->ArchiveName = ArchiveName;
- // Here we pass a new MemoryBufferRef which is identified by ArchiveName
- // (the fully resolved path of the archive) + member name + offset of the
- // member in the archive.
- // ThinLTO uses the MemoryBufferRef identifier to access its internal
- // data structures and if two archives define two members with the same name,
- // this causes a collision which result in only one of the objects being
- // taken into consideration at LTO time (which very likely causes undefined
- // symbols later in the link stage).
- MemoryBufferRef MBRef(MB.getBuffer(),
- Saver.save(ArchiveName + MB.getBufferIdentifier() +
- utostr(OffsetInArchive)));
+ std::string Path = MB.getBufferIdentifier().str();
+ if (Config->ThinLTOIndexOnly)
+ Path = replaceThinLTOSuffix(MB.getBufferIdentifier());
+
+ // ThinLTO assumes that all MemoryBufferRefs given to it have a unique
+ // name. If two archives define two members with the same name, this
+ // causes a collision which result in only one of the objects being taken
+ // into consideration at LTO time (which very likely causes undefined
+ // symbols later in the link stage). So we append file offset to make
+ // filename unique.
+ MemoryBufferRef MBRef(
+ MB.getBuffer(),
+ Saver.save(ArchiveName + Path +
+ (ArchiveName.empty() ? "" : utostr(OffsetInArchive))));
+
Obj = CHECK(lto::InputFile::create(MBRef), this);
Triple T(Obj->getTargetTriple());
@@ -1035,7 +1066,7 @@
static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats,
const lto::InputFile::Symbol &ObjSym,
BitcodeFile &F) {
- StringRef NameRef = Saver.save(ObjSym.getName());
+ StringRef Name = Saver.save(ObjSym.getName());
uint32_t Binding = ObjSym.isWeak() ? STB_WEAK : STB_GLOBAL;
uint8_t Type = ObjSym.isTLS() ? STT_TLS : STT_NOTYPE;
@@ -1044,20 +1075,20 @@
int C = ObjSym.getComdatIndex();
if (C != -1 && !KeptComdats[C])
- return Symtab->addUndefined<ELFT>(NameRef, Binding, Visibility, Type,
+ return Symtab->addUndefined<ELFT>(Name, Binding, Visibility, Type,
CanOmitFromDynSym, &F);
if (ObjSym.isUndefined())
- return Symtab->addUndefined<ELFT>(NameRef, Binding, Visibility, Type,
+ return Symtab->addUndefined<ELFT>(Name, Binding, Visibility, Type,
CanOmitFromDynSym, &F);
if (ObjSym.isCommon())
- return Symtab->addCommon(NameRef, ObjSym.getCommonSize(),
+ return Symtab->addCommon(Name, ObjSym.getCommonSize(),
ObjSym.getCommonAlignment(), Binding, Visibility,
STT_OBJECT, F);
- return Symtab->addBitcode(NameRef, Binding, Visibility, Type,
- CanOmitFromDynSym, F);
+ return Symtab->addBitcode(Name, Binding, Visibility, Type, CanOmitFromDynSym,
+ F);
}
template <class ELFT>
@@ -1113,11 +1144,6 @@
Data.size(), 0, STB_GLOBAL, nullptr, nullptr);
}
-static bool isBitcode(MemoryBufferRef MB) {
- using namespace sys::fs;
- return identify_magic(MB.getBuffer()) == file_magic::bitcode;
-}
-
InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName,
uint64_t OffsetInArchive) {
if (isBitcode(MB))
@@ -1153,9 +1179,9 @@
}
MemoryBufferRef LazyObjFile::getBuffer() {
- if (Seen)
+ if (AddedToLink)
return MemoryBufferRef();
- Seen = true;
+ AddedToLink = true;
return MB;
}
@@ -1163,7 +1189,10 @@
MemoryBufferRef MBRef = getBuffer();
if (MBRef.getBuffer().empty())
return nullptr;
- return createObjectFile(MBRef, ArchiveName, OffsetInArchive);
+
+ InputFile *File = createObjectFile(MBRef, ArchiveName, OffsetInArchive);
+ File->GroupId = GroupId;
+ return File;
}
template <class ELFT> void LazyObjFile::parse() {
@@ -1216,6 +1245,18 @@
}
}
+std::string elf::replaceThinLTOSuffix(StringRef Path) {
+ StringRef Suffix = Config->ThinLTOObjectSuffixReplace.first;
+ StringRef Repl = Config->ThinLTOObjectSuffixReplace.second;
+
+ if (!Path.endswith(Suffix)) {
+ error("-thinlto-object-suffix-replace=" + Suffix + ";" + Repl +
+ " was given, but " + Path + " does not end with the suffix");
+ return "";
+ }
+ return (Path.drop_back(Suffix.size()) + Repl).str();
+}
+
template void ArchiveFile::parse<ELF32LE>();
template void ArchiveFile::parse<ELF32BE>();
template void ArchiveFile::parse<ELF64LE>();
diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h
index 8ec5953..072a5df 100644
--- a/ELF/InputFiles.h
+++ b/ELF/InputFiles.h
@@ -46,7 +46,6 @@
using llvm::object::Archive;
-class Lazy;
class Symbol;
// If -reproduce option is given, all input files are written
@@ -113,6 +112,14 @@
// True if this is an argument for --just-symbols. Usually false.
bool JustSymbols = false;
+ // GroupId is used for --warn-backrefs which is an optional error
+ // checking feature. All files within the same --{start,end}-group or
+ // --{start,end}-lib get the same group ID. Otherwise, each file gets a new
+ // group ID. For more info, see checkDependency() in SymbolTable.cpp.
+ uint32_t GroupId;
+ static bool IsInGroup;
+ static uint32_t NextGroupId;
+
protected:
InputFile(Kind K, MemoryBufferRef M);
std::vector<InputSectionBase *> Sections;
@@ -252,11 +259,11 @@
template <class ELFT> void parse();
MemoryBufferRef getBuffer();
InputFile *fetch();
+ bool AddedToLink = false;
private:
template <class ELFT> void addElfSymbols();
- bool Seen = false;
uint64_t OffsetInArchive;
};
@@ -267,11 +274,11 @@
static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; }
template <class ELFT> void parse();
- // Returns a memory buffer for a given symbol and the offset in the archive
- // for the member. An empty memory buffer and an offset of zero
- // is returned if we have already returned the same memory buffer.
- // (So that we don't instantiate same members more than once.)
- std::pair<MemoryBufferRef, uint64_t> getMember(const Archive::Symbol *Sym);
+ // Pulls out an object file that contains a definition for Sym and
+ // returns it. If the same file was instantiated before, this
+ // function returns a nullptr (so we don't instantiate the same file
+ // more than once.)
+ InputFile *fetch(const Archive::Symbol &Sym);
private:
std::unique_ptr<Archive> File;
@@ -344,8 +351,15 @@
uint64_t OffsetInArchive = 0);
InputFile *createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName);
+inline bool isBitcode(MemoryBufferRef MB) {
+ return identify_magic(MB.getBuffer()) == llvm::file_magic::bitcode;
+}
+
+std::string replaceThinLTOSuffix(StringRef Path);
+
extern std::vector<BinaryFile *> BinaryFiles;
extern std::vector<BitcodeFile *> BitcodeFiles;
+extern std::vector<LazyObjFile *> LazyObjFiles;
extern std::vector<InputFile *> ObjectFiles;
extern std::vector<InputFile *> SharedFiles;
diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp
index 49426e8..09bc39e 100644
--- a/ELF/InputSection.cpp
+++ b/ELF/InputSection.cpp
@@ -142,12 +142,8 @@
return Offset == uint64_t(-1) ? OS->Size : Offset;
}
case Regular:
- return cast<InputSection>(this->Repl)->OutSecOff + Offset;
- case Synthetic: {
- auto *IS = cast<InputSection>(this->Repl);
- // For synthetic sections we treat offset -1 as the end of the section.
- return IS->OutSecOff + (Offset == uint64_t(-1) ? IS->getSize() : Offset);
- }
+ case Synthetic:
+ return cast<InputSection>(this)->getOffset(Offset);
case EHFrame:
// The file crtbeginT.o has relocations pointing to the start of an empty
// .eh_frame that is known to be the first in the link. It does that to
@@ -156,8 +152,8 @@
case Merge:
const MergeInputSection *MS = cast<MergeInputSection>(this);
if (InputSection *IS = MS->getParent())
- return cast<InputSection>(IS->Repl)->OutSecOff + MS->getOffset(Offset);
- return MS->getOffset(Offset);
+ return IS->getOffset(MS->getParentOffset(Offset));
+ return MS->getParentOffset(Offset);
}
llvm_unreachable("invalid section kind");
}
@@ -177,7 +173,7 @@
Sec = EH->getParent();
else
return cast<OutputSection>(this);
- return Sec ? cast<InputSection>(Sec->Repl)->getParent() : nullptr;
+ return Sec ? Sec->getParent() : nullptr;
}
// Decompress section contents if required. Note that this function
@@ -329,7 +325,7 @@
*To++ = Sections[Idx]->getOutputSection()->SectionIndex;
}
-InputSectionBase *InputSection::getRelocatedSection() {
+InputSectionBase *InputSection::getRelocatedSection() const {
if (!File || (Type != SHT_RELA && Type != SHT_REL))
return nullptr;
ArrayRef<InputSectionBase *> Sections = File->getSections();
@@ -380,17 +376,32 @@
continue;
}
- if (RelTy::IsRela) {
- P->r_addend =
- Sym.getVA(getAddend<ELFT>(Rel)) - Section->getOutputSection()->Addr;
- } else if (Config->Relocatable) {
- const uint8_t *BufLoc = Sec->Data.begin() + Rel.r_offset;
- Sec->Relocations.push_back({R_ABS, Type, Rel.r_offset,
- Target->getImplicitAddend(BufLoc, Type),
- &Sym});
- }
- }
+ int64_t Addend = getAddend<ELFT>(Rel);
+ const uint8_t *BufLoc = Sec->Data.begin() + Rel.r_offset;
+ if (!RelTy::IsRela)
+ Addend = Target->getImplicitAddend(BufLoc, Type);
+ if (Config->EMachine == EM_MIPS && Config->Relocatable &&
+ Target->getRelExpr(Type, Sym, BufLoc) == R_MIPS_GOTREL) {
+ // Some MIPS relocations depend on "gp" value. By default,
+ // this value has 0x7ff0 offset from a .got section. But
+ // relocatable files produced by a complier or a linker
+ // might redefine this default value and we must use it
+ // for a calculation of the relocation result. When we
+ // generate EXE or DSO it's trivial. Generating a relocatable
+ // output is more difficult case because the linker does
+ // not calculate relocations in this mode and loses
+ // individual "gp" values used by each input object file.
+ // As a workaround we add the "gp" value to the relocation
+ // addend and save it back to the file.
+ Addend += Sec->getFile<ELFT>()->MipsGp0;
+ }
+
+ if (RelTy::IsRela)
+ P->r_addend = Sym.getVA(Addend) - Section->getOutputSection()->Addr;
+ else if (Config->Relocatable)
+ Sec->Relocations.push_back({R_ABS, Type, Rel.r_offset, Addend, &Sym});
+ }
}
}
@@ -570,25 +581,27 @@
case R_PLT:
return Sym.getPltVA() + A;
case R_PLT_PC:
- case R_PPC_PLT_OPD:
+ case R_PPC_CALL_PLT:
return Sym.getPltVA() + A - P;
- case R_PPC_OPD: {
+ case R_PPC_CALL: {
uint64_t SymVA = Sym.getVA(A);
// If we have an undefined weak symbol, we might get here with a symbol
// address of zero. That could overflow, but the code must be unreachable,
// so don't bother doing anything at all.
if (!SymVA)
return 0;
- if (Out::Opd) {
- // If this is a local call, and we currently have the address of a
- // function-descriptor, get the underlying code address instead.
- uint64_t OpdStart = Out::Opd->Addr;
- uint64_t OpdEnd = OpdStart + Out::Opd->Size;
- bool InOpd = OpdStart <= SymVA && SymVA < OpdEnd;
- if (InOpd)
- SymVA = read64be(&Out::OpdBuf[SymVA - OpdStart]);
- }
- return SymVA - P;
+
+ // PPC64 V2 ABI describes two entry points to a function. The global entry
+ // point sets up the TOC base pointer. When calling a local function, the
+ // call should branch to the local entry point rather than the global entry
+ // point. Section 3.4.1 describes using the 3 most significant bits of the
+ // st_other field to find out how many instructions there are between the
+ // local and global entry point.
+ uint8_t StOther = (Sym.StOther >> 5) & 7;
+ if (StOther == 0 || StOther == 1)
+ return SymVA - P;
+
+ return SymVA - P + (1LL << StOther);
}
case R_PPC_TOC:
return getPPC64TocBase() + A;
@@ -618,12 +631,16 @@
case R_TLSDESC_PAGE:
return getAArch64Page(InX::Got->getGlobalDynAddr(Sym) + A) -
getAArch64Page(P);
- case R_TLSGD:
+ case R_TLSGD_GOT:
+ return InX::Got->getGlobalDynOffset(Sym) + A;
+ case R_TLSGD_GOT_FROM_END:
return InX::Got->getGlobalDynOffset(Sym) + A - InX::Got->getSize();
case R_TLSGD_PC:
return InX::Got->getGlobalDynAddr(Sym) + A - P;
- case R_TLSLD:
+ case R_TLSLD_GOT_FROM_END:
return InX::Got->getTlsIndexOff() + A - InX::Got->getSize();
+ case R_TLSLD_GOT:
+ return InX::Got->getTlsIndexOff() + A;
case R_TLSLD_PC:
return InX::Got->getTlsIndexVA() + A - P;
}
@@ -710,10 +727,13 @@
const unsigned Bits = Config->Wordsize * 8;
for (const Relocation &Rel : Relocations) {
- uint8_t *BufLoc = Buf + getOffset(Rel.Offset);
+ uint64_t Offset = Rel.Offset;
+ if (auto *Sec = dyn_cast<InputSection>(this))
+ Offset += Sec->OutSecOff;
+ uint8_t *BufLoc = Buf + Offset;
RelType Type = Rel.Type;
- uint64_t AddrLoc = getVA(Rel.Offset);
+ uint64_t AddrLoc = getOutputSection()->Addr + Offset;
RelExpr Expr = Rel.Expr;
uint64_t TargetVA = SignExtend64(
getRelocTargetVA(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr), Bits);
@@ -739,11 +759,17 @@
case R_RELAX_TLS_GD_TO_IE_END:
Target->relaxTlsGdToIe(BufLoc, Type, TargetVA);
break;
- case R_PPC_PLT_OPD:
+ case R_PPC_CALL:
// Patch a nop (0x60000000) to a ld.
- if (BufLoc + 8 <= BufEnd && read32be(BufLoc + 4) == 0x60000000)
- write32be(BufLoc + 4, 0xe8410028); // ld %r2, 40(%r1)
- LLVM_FALLTHROUGH;
+ if (Rel.Sym->NeedsTocRestore) {
+ if (BufLoc + 8 > BufEnd || read32(BufLoc + 4) != 0x60000000) {
+ error(getErrorLocation(BufLoc) + "call lacks nop, can't restore toc");
+ break;
+ }
+ write32(BufLoc + 4, 0xe8410018); // ld %r2, 24(%r1)
+ }
+ Target->relocateOne(BufLoc, Type, TargetVA);
+ break;
default:
Target->relocateOne(BufLoc, Type, TargetVA);
break;
@@ -822,10 +848,6 @@
// .eh_frame is a sequence of CIE or FDE records.
// This function splits an input section into records and returns them.
template <class ELFT> void EhInputSection::split() {
- // Early exit if already split.
- if (!Pieces.empty())
- return;
-
if (AreRelocsRela)
split<ELFT>(relas<ELFT>());
else
@@ -920,9 +942,9 @@
else
splitNonStrings(Data, Entsize);
- if (Config->GcSections && (Flags & SHF_ALLOC))
- for (uint32_t Off : LiveOffsets)
- getSectionPiece(Off)->Live = true;
+ OffsetMap.reserve(Pieces.size());
+ for (size_t I = 0, E = Pieces.size(); I != E; ++I)
+ OffsetMap[Pieces[I].InputOff] = I;
}
template <class It, class T, class Compare>
@@ -939,25 +961,33 @@
}
// Do binary search to get a section piece at a given input offset.
-SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) {
- if (Data.size() <= Offset)
- fatal(toString(this) + ": entry is past the end of the section");
+static SectionPiece *findSectionPiece(MergeInputSection *Sec, uint64_t Offset) {
+ if (Sec->Data.size() <= Offset)
+ fatal(toString(Sec) + ": entry is past the end of the section");
// Find the element this offset points to.
auto I = fastUpperBound(
- Pieces.begin(), Pieces.end(), Offset,
+ Sec->Pieces.begin(), Sec->Pieces.end(), Offset,
[](const uint64_t &A, const SectionPiece &B) { return A < B.InputOff; });
--I;
return &*I;
}
+SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) {
+ // Find a piece starting at a given offset.
+ auto It = OffsetMap.find(Offset);
+ if (It != OffsetMap.end())
+ return &Pieces[It->second];
+
+ // If Offset is not at beginning of a section piece, it is not in the map.
+ // In that case we need to search from the original section piece vector.
+ return findSectionPiece(this, Offset);
+}
+
// Returns the offset in an output section for a given input offset.
// Because contents of a mergeable section is not contiguous in output,
// it is not just an addition to a base output offset.
-uint64_t MergeInputSection::getOffset(uint64_t Offset) const {
- if (!Live)
- return 0;
-
+uint64_t MergeInputSection::getParentOffset(uint64_t Offset) const {
// Find a string starting at a given offset.
auto It = OffsetMap.find(Offset);
if (It != OffsetMap.end())
@@ -965,20 +995,12 @@
// If Offset is not at beginning of a section piece, it is not in the map.
// In that case we need to search from the original section piece vector.
- const SectionPiece &Piece = *getSectionPiece(Offset);
- if (!Piece.Live)
- return 0;
-
+ const SectionPiece &Piece =
+ *findSectionPiece(const_cast<MergeInputSection *>(this), Offset);
uint64_t Addend = Offset - Piece.InputOff;
return Piece.OutputOff + Addend;
}
-void MergeInputSection::initOffsetMap() {
- OffsetMap.reserve(Pieces.size());
- for (size_t I = 0; I < Pieces.size(); ++I)
- OffsetMap[Pieces[I].InputOff] = I;
-}
-
template InputSection::InputSection(ObjFile<ELF32LE> &, const ELF32LE::Shdr &,
StringRef);
template InputSection::InputSection(ObjFile<ELF32BE> &, const ELF32BE::Shdr &,
diff --git a/ELF/InputSection.h b/ELF/InputSection.h
index 56b5412..7a83bf9 100644
--- a/ELF/InputSection.h
+++ b/ELF/InputSection.h
@@ -61,6 +61,9 @@
unsigned Bss : 1;
+ // Set for sections that should not be folded by ICF.
+ unsigned KeepUnique : 1;
+
// These corresponds to the fields in Elf_Shdr.
uint32_t Alignment;
uint64_t Flags;
@@ -78,15 +81,15 @@
// section.
uint64_t getOffset(uint64_t Offset) const;
- uint64_t getVA(uint64_t Offset) const;
+ uint64_t getVA(uint64_t Offset = 0) const;
protected:
SectionBase(Kind SectionKind, StringRef Name, uint64_t Flags,
uint64_t Entsize, uint64_t Alignment, uint32_t Type,
uint32_t Info, uint32_t Link)
: Name(Name), Repl(this), SectionKind(SectionKind), Live(false),
- Bss(false), Alignment(Alignment), Flags(Flags), Entsize(Entsize),
- Type(Type), Link(Link), Info(Info) {}
+ Bss(false), KeepUnique(false), Alignment(Alignment), Flags(Flags),
+ Entsize(Entsize), Type(Type), Link(Link), Info(Info) {}
};
// This corresponds to a section of an input file.
@@ -200,7 +203,7 @@
// be found by looking at the next one).
struct SectionPiece {
SectionPiece(size_t Off, uint32_t Hash, bool Live)
- : InputOff(Off), Hash(Hash), OutputOff(-1),
+ : InputOff(Off), Hash(Hash), OutputOff(0),
Live(Live || !Config->GcSections) {}
uint32_t InputOff;
@@ -223,19 +226,14 @@
static bool classof(const SectionBase *S) { return S->kind() == Merge; }
void splitIntoPieces();
- // Mark the piece at a given offset live. Used by GC.
- void markLiveAt(uint64_t Offset) {
- if (this->Flags & llvm::ELF::SHF_ALLOC)
- LiveOffsets.insert(Offset);
- }
-
- // Translate an offset in the input section to an offset
- // in the output section.
- uint64_t getOffset(uint64_t Offset) const;
+ // Translate an offset in the input section to an offset in the parent
+ // MergeSyntheticSection.
+ uint64_t getParentOffset(uint64_t Offset) const;
// Splittable sections are handled as a sequence of data
// rather than a single large blob of data.
std::vector<SectionPiece> Pieces;
+ llvm::DenseMap<uint32_t, uint32_t> OffsetMap;
// Returns I'th piece's data. This function is very hot when
// string merging is enabled, so we want to inline.
@@ -254,15 +252,10 @@
}
SyntheticSection *getParent() const;
- void initOffsetMap();
private:
void splitStrings(ArrayRef<uint8_t> A, size_t Size);
void splitNonStrings(ArrayRef<uint8_t> A, size_t Size);
-
- llvm::DenseMap<uint32_t, uint32_t> OffsetMap;
-
- llvm::DenseSet<uint32_t> LiveOffsets;
};
struct EhSectionPiece {
@@ -312,6 +305,8 @@
// beginning of the output section.
template <class ELFT> void writeTo(uint8_t *Buf);
+ uint64_t getOffset(uint64_t Offset) const { return OutSecOff + Offset; }
+
OutputSection *getParent() const;
// This variable has two usages. Initially, it represents an index in the
@@ -322,7 +317,7 @@
static bool classof(const SectionBase *S);
- InputSectionBase *getRelocatedSection();
+ InputSectionBase *getRelocatedSection() const;
template <class ELFT, class RelTy>
void relocateNonAlloc(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
diff --git a/ELF/LTO.cpp b/ELF/LTO.cpp
index f3d6896..ee55e7c 100644
--- a/ELF/LTO.cpp
+++ b/ELF/LTO.cpp
@@ -20,6 +20,8 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Bitcode/BitcodeReader.h"
+#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/LTO/Caching.h"
#include "llvm/LTO/Config.h"
@@ -29,7 +31,6 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstddef>
#include <memory>
@@ -44,71 +45,91 @@
using namespace lld;
using namespace lld::elf;
-// This is for use when debugging LTO.
-static void saveBuffer(StringRef Buffer, const Twine &Path) {
+// Creates an empty file to store a list of object files for final
+// linking of distributed ThinLTO.
+static std::unique_ptr<raw_fd_ostream> openFile(StringRef File) {
std::error_code EC;
- raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None);
- if (EC)
- error("cannot create " + Path + ": " + EC.message());
- OS << Buffer;
+ auto Ret =
+ llvm::make_unique<raw_fd_ostream>(File, EC, sys::fs::OpenFlags::F_None);
+ if (EC) {
+ error("cannot open " + File + ": " + EC.message());
+ return nullptr;
+ }
+ return Ret;
}
-static void diagnosticHandler(const DiagnosticInfo &DI) {
- SmallString<128> ErrStorage;
- raw_svector_ostream OS(ErrStorage);
- DiagnosticPrinterRawOStream DP(OS);
- DI.print(DP);
- warn(ErrStorage);
+static std::string getThinLTOOutputFile(StringRef ModulePath) {
+ return lto::getThinLTOOutputFile(ModulePath,
+ Config->ThinLTOPrefixReplace.first,
+ Config->ThinLTOPrefixReplace.second);
}
-static void checkError(Error E) {
- handleAllErrors(std::move(E),
- [&](ErrorInfoBase &EIB) { error(EIB.message()); });
-}
-
-static std::unique_ptr<lto::LTO> createLTO() {
- lto::Config Conf;
+static lto::Config createConfig() {
+ lto::Config C;
// LLD supports the new relocations.
- Conf.Options = InitTargetOptionsFromCodeGenFlags();
- Conf.Options.RelaxELFRelocations = true;
+ C.Options = InitTargetOptionsFromCodeGenFlags();
+ C.Options.RelaxELFRelocations = true;
// Always emit a section per function/datum with LTO.
- Conf.Options.FunctionSections = true;
- Conf.Options.DataSections = true;
+ C.Options.FunctionSections = true;
+ C.Options.DataSections = true;
if (Config->Relocatable)
- Conf.RelocModel = None;
+ C.RelocModel = None;
else if (Config->Pic)
- Conf.RelocModel = Reloc::PIC_;
+ C.RelocModel = Reloc::PIC_;
else
- Conf.RelocModel = Reloc::Static;
- Conf.CodeModel = GetCodeModelFromCMModel();
- Conf.DisableVerify = Config->DisableVerify;
- Conf.DiagHandler = diagnosticHandler;
- Conf.OptLevel = Config->LTOO;
- Conf.CPU = GetCPUStr();
+ C.RelocModel = Reloc::Static;
+
+ C.CodeModel = GetCodeModelFromCMModel();
+ C.DisableVerify = Config->DisableVerify;
+ C.DiagHandler = diagnosticHandler;
+ C.OptLevel = Config->LTOO;
+ C.CPU = GetCPUStr();
// Set up a custom pipeline if we've been asked to.
- Conf.OptPipeline = Config->LTONewPmPasses;
- Conf.AAPipeline = Config->LTOAAPipeline;
+ C.OptPipeline = Config->LTONewPmPasses;
+ C.AAPipeline = Config->LTOAAPipeline;
// Set up optimization remarks if we've been asked to.
- Conf.RemarksFilename = Config->OptRemarksFilename;
- Conf.RemarksWithHotness = Config->OptRemarksWithHotness;
+ C.RemarksFilename = Config->OptRemarksFilename;
+ C.RemarksWithHotness = Config->OptRemarksWithHotness;
+
+ C.SampleProfile = Config->LTOSampleProfile;
+ C.UseNewPM = Config->LTONewPassManager;
+ C.DebugPassManager = Config->LTODebugPassManager;
if (Config->SaveTemps)
- checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".",
- /*UseInputModulePath*/ true));
-
- lto::ThinBackend Backend;
- if (Config->ThinLTOJobs != -1u)
- Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs);
- return llvm::make_unique<lto::LTO>(std::move(Conf), Backend,
- Config->LTOPartitions);
+ checkError(C.addSaveTemps(Config->OutputFile.str() + ".",
+ /*UseInputModulePath*/ true));
+ return C;
}
-BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {
+BitcodeCompiler::BitcodeCompiler() {
+ // Initialize LTOObj.
+ lto::ThinBackend Backend;
+
+ if (Config->ThinLTOIndexOnly) {
+ StringRef Path = Config->ThinLTOIndexOnlyArg;
+ if (!Path.empty())
+ IndexFile = openFile(Path);
+
+ auto OnIndexWrite = [&](const std::string &Identifier) {
+ ObjectToIndexFileState[Identifier] = true;
+ };
+
+ Backend = lto::createWriteIndexesThinBackend(
+ Config->ThinLTOPrefixReplace.first, Config->ThinLTOPrefixReplace.second,
+ Config->ThinLTOEmitImportsFiles, IndexFile.get(), OnIndexWrite);
+ } else if (Config->ThinLTOJobs != -1U) {
+ Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs);
+ }
+
+ LTOObj = llvm::make_unique<lto::LTO>(createConfig(), Backend,
+ Config->LTOPartitions);
+
+ // Initialize UsedStartStop.
for (Symbol *Sym : Symtab->getSymbols()) {
StringRef Name = Sym->getName();
for (StringRef Prefix : {"__start_", "__stop_"})
@@ -126,17 +147,20 @@
void BitcodeCompiler::add(BitcodeFile &F) {
lto::InputFile &Obj = *F.Obj;
- unsigned SymNum = 0;
- std::vector<Symbol *> Syms = F.getSymbols();
+ bool IsExec = !Config->Shared && !Config->Relocatable;
+
+ if (Config->ThinLTOIndexOnly)
+ ObjectToIndexFileState.insert({Obj.getName(), false});
+
+ ArrayRef<Symbol *> Syms = F.getSymbols();
+ ArrayRef<lto::InputFile::Symbol> ObjSyms = Obj.symbols();
std::vector<lto::SymbolResolution> Resols(Syms.size());
- bool IsExecutable = !Config->Shared && !Config->Relocatable;
-
// Provide a resolution to the LTO API for each symbol.
- for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) {
- Symbol *Sym = Syms[SymNum];
- lto::SymbolResolution &R = Resols[SymNum];
- ++SymNum;
+ for (size_t I = 0, E = Syms.size(); I != E; ++I) {
+ Symbol *Sym = Syms[I];
+ const lto::InputFile::Symbol &ObjSym = ObjSyms[I];
+ lto::SymbolResolution &R = Resols[I];
// Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
// reports two symbols for module ASM defined. Without this check, lld
@@ -156,7 +180,7 @@
UsedStartStop.count(ObjSym.getSectionName());
const auto *DR = dyn_cast<Defined>(Sym);
R.FinalDefinitionInLinkageUnit =
- (IsExecutable || Sym->Visibility != STV_DEFAULT) && DR &&
+ (IsExec || Sym->Visibility != STV_DEFAULT) && DR &&
// Skip absolute symbols from ELF objects, otherwise PC-rel relocations
// will be generated by for them, triggering linker errors.
// Symbol section is always null for bitcode symbols, hence the check
@@ -175,12 +199,28 @@
checkError(LTOObj->add(std::move(F.Obj), Resols));
}
+static void createEmptyIndex(StringRef ModulePath) {
+ std::string Path = replaceThinLTOSuffix(getThinLTOOutputFile(ModulePath));
+ if (Path.empty())
+ return;
+
+ std::unique_ptr<raw_fd_ostream> OS = openFile(Path + ".thinlto.bc");
+ if (!OS)
+ return;
+
+ ModuleSummaryIndex M(false);
+ M.setSkipModuleByDistributedBackend();
+ WriteIndexToFile(M, *OS);
+
+ if (Config->ThinLTOEmitImportsFiles)
+ openFile(Path + ".imports");
+}
+
// Merge all the bitcode files we have seen, codegen the result
// and return the resulting ObjectFile(s).
std::vector<InputFile *> BitcodeCompiler::compile() {
- std::vector<InputFile *> Ret;
unsigned MaxTasks = LTOObj->getMaxTasks();
- Buff.resize(MaxTasks);
+ Buf.resize(MaxTasks);
Files.resize(MaxTasks);
// The --thinlto-cache-dir option specifies the path to a directory in which
@@ -197,29 +237,60 @@
checkError(LTOObj->run(
[&](size_t Task) {
return llvm::make_unique<lto::NativeObjectStream>(
- llvm::make_unique<raw_svector_ostream>(Buff[Task]));
+ llvm::make_unique<raw_svector_ostream>(Buf[Task]));
},
Cache));
+ // Emit empty index files for non-indexed files
+ if (Config->ThinLTOIndexOnly) {
+ for (auto &Identifier : ObjectToIndexFileState)
+ if (!Identifier.getValue()) {
+ std::string Path = getThinLTOOutputFile(Identifier.getKey());
+ openFile(Path + ".thinlto.bc");
+
+ if (Config->ThinLTOEmitImportsFiles)
+ openFile(Path + ".imports");
+ }
+ }
+
+ // If LazyObjFile has not been added to link, emit empty index files.
+ // This is needed because this is what GNU gold plugin does and we have a
+ // distributed build system that depends on that behavior.
+ if (Config->ThinLTOIndexOnly) {
+ for (LazyObjFile *F : LazyObjFiles)
+ if (!F->AddedToLink && isBitcode(F->MB))
+ createEmptyIndex(F->getName());
+
+ if (!Config->LTOObjPath.empty())
+ saveBuffer(Buf[0], Config->LTOObjPath);
+
+ // ThinLTO with index only option is required to generate only the index
+ // files. After that, we exit from linker and ThinLTO backend runs in a
+ // distributed environment.
+ if (IndexFile)
+ IndexFile->close();
+ return {};
+ }
+
if (!Config->ThinLTOCacheDir.empty())
pruneCache(Config->ThinLTOCacheDir, Config->ThinLTOCachePolicy);
+ std::vector<InputFile *> Ret;
for (unsigned I = 0; I != MaxTasks; ++I) {
- if (Buff[I].empty())
+ if (Buf[I].empty())
continue;
if (Config->SaveTemps) {
if (I == 0)
- saveBuffer(Buff[I], Config->OutputFile + ".lto.o");
+ saveBuffer(Buf[I], Config->OutputFile + ".lto.o");
else
- saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.o");
+ saveBuffer(Buf[I], Config->OutputFile + Twine(I) + ".lto.o");
}
- InputFile *Obj = createObjectFile(MemoryBufferRef(Buff[I], "lto.tmp"));
+ InputFile *Obj = createObjectFile(MemoryBufferRef(Buf[I], "lto.tmp"));
Ret.push_back(Obj);
}
for (std::unique_ptr<MemoryBuffer> &File : Files)
if (File)
Ret.push_back(createObjectFile(*File));
-
return Ret;
}
diff --git a/ELF/LTO.h b/ELF/LTO.h
index 223af50..8803078 100644
--- a/ELF/LTO.h
+++ b/ELF/LTO.h
@@ -24,6 +24,7 @@
#include "lld/Common/LLVM.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
#include <memory>
#include <vector>
@@ -38,6 +39,7 @@
class BitcodeFile;
class InputFile;
+class LazyObjFile;
class BitcodeCompiler {
public:
@@ -49,9 +51,11 @@
private:
std::unique_ptr<llvm::lto::LTO> LTOObj;
- std::vector<SmallString<0>> Buff;
+ std::vector<SmallString<0>> Buf;
std::vector<std::unique_ptr<MemoryBuffer>> Files;
llvm::DenseSet<StringRef> UsedStartStop;
+ std::unique_ptr<llvm::raw_fd_ostream> IndexFile;
+ llvm::StringMap<bool> ObjectToIndexFileState;
};
} // namespace elf
} // namespace lld
diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp
index d3a3d29..9cc836b 100644
--- a/ELF/LinkerScript.cpp
+++ b/ELF/LinkerScript.cpp
@@ -777,9 +777,8 @@
if (PhdrEntry *L = Ctx->OutSec->PtLoad)
L->LMAOffset = Ctx->LMAOffset;
- // The Size previously denoted how many InputSections had been added to this
- // section, and was used for sorting SHF_LINK_ORDER sections. Reset it to
- // compute the actual size value.
+ // We can call this method multiple times during the creation of
+ // thunks and want to start over calculation each time.
Sec->Size = 0;
// We visited SectionsCommands from processSectionCommands to
@@ -788,9 +787,9 @@
for (BaseCommand *Base : Sec->SectionCommands) {
// This handles the assignments to symbol or to the dot.
if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
- Cmd->Offset = Dot - Ctx->OutSec->Addr;
+ Cmd->Addr = Dot;
assignSymbol(Cmd, true);
- Cmd->Size = Dot - Ctx->OutSec->Addr - Cmd->Offset;
+ Cmd->Size = Dot - Cmd->Addr;
continue;
}
@@ -802,12 +801,6 @@
continue;
}
- // Handle ASSERT().
- if (auto *Cmd = dyn_cast<AssertCommand>(Base)) {
- Cmd->Expression();
- continue;
- }
-
// Handle a single input section description command.
// It calculates and assigns the offsets for each section and also
// updates the output section size.
@@ -875,6 +868,11 @@
if (!Sec)
continue;
+ // Handle align (e.g. ".foo : ALIGN(16) { ... }").
+ if (Sec->AlignExpr)
+ Sec->Alignment =
+ std::max<uint32_t>(Sec->Alignment, Sec->AlignExpr().getValue());
+
// A live output section means that some input section was added to it. It
// might have been removed (if it was empty synthetic section), but we at
// least know the flags.
@@ -913,10 +911,6 @@
error("memory region '" + Sec->LMARegionName + "' not declared");
}
Sec->MemRegion = findMemoryRegion(Sec);
- // Handle align (e.g. ".foo : ALIGN(16) { ... }").
- if (Sec->AlignExpr)
- Sec->Alignment =
- std::max<uint32_t>(Sec->Alignment, Sec->AlignExpr().getValue());
}
}
@@ -1049,15 +1043,11 @@
for (BaseCommand *Base : SectionCommands) {
if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
+ Cmd->Addr = Dot;
assignSymbol(Cmd, false);
+ Cmd->Size = Dot - Cmd->Addr;
continue;
}
-
- if (auto *Cmd = dyn_cast<AssertCommand>(Base)) {
- Cmd->Expression();
- continue;
- }
-
assignOffsets(cast<OutputSection>(Base));
}
Ctx = nullptr;
@@ -1121,9 +1111,9 @@
if (Symbol *Sym = Symtab->find(Name)) {
if (auto *DS = dyn_cast<Defined>(Sym))
return {DS->Section, false, DS->Value, Loc};
- if (auto *SS = dyn_cast<SharedSymbol>(Sym))
- if (!ErrorOnMissingSection || SS->CopyRelSec)
- return {SS->CopyRelSec, false, 0, Loc};
+ if (isa<SharedSymbol>(Sym))
+ if (!ErrorOnMissingSection)
+ return {nullptr, false, 0, Loc};
}
error(Loc + ": symbol not found: " + Name);
diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h
index f808849..3b790dd 100644
--- a/ELF/LinkerScript.h
+++ b/ELF/LinkerScript.h
@@ -75,7 +75,6 @@
AssignmentKind, // . = expr or <sym> = expr
OutputSectionKind,
InputSectionKind,
- AssertKind, // ASSERT(expr)
ByteKind // BYTE(expr), SHORT(expr), LONG(expr) or QUAD(expr)
};
@@ -86,10 +85,8 @@
// This represents ". = <expr>" or "<symbol> = <expr>".
struct SymbolAssignment : BaseCommand {
- SymbolAssignment(StringRef Name, Expr E, std::string Loc,
- std::string CommandString)
- : BaseCommand(AssignmentKind), Name(Name), Expression(E), Location(Loc),
- CommandString(CommandString) {}
+ SymbolAssignment(StringRef Name, Expr E, std::string Loc)
+ : BaseCommand(AssignmentKind), Name(Name), Expression(E), Location(Loc) {}
static bool classof(const BaseCommand *C) {
return C->Kind == AssignmentKind;
@@ -112,11 +109,11 @@
// A string representation of this command. We use this for -Map.
std::string CommandString;
- // This is just an offset of this assignment command in the output section.
- unsigned Offset;
+ // Address of this assignment command.
+ unsigned Addr;
- // Size of this assignment command. This is usually 0, but if you move '.'
- // or use a BYTE()-family command, this may be greater than 0."
+ // Size of this assignment command. This is usually 0, but if
+ // you move '.' this may be greater than 0.
unsigned Size;
};
@@ -179,15 +176,6 @@
std::vector<std::pair<ThunkSection *, uint32_t>> ThunkSections;
};
-// Represents an ASSERT().
-struct AssertCommand : BaseCommand {
- AssertCommand(Expr E) : BaseCommand(AssertKind), Expression(E) {}
-
- static bool classof(const BaseCommand *C) { return C->Kind == AssertKind; }
-
- Expr Expression;
-};
-
// Represents BYTE(), SHORT(), LONG(), or QUAD().
struct ByteCommand : BaseCommand {
ByteCommand(Expr E, unsigned Size, std::string CommandString)
@@ -200,7 +188,11 @@
std::string CommandString;
Expr Expression;
+
+ // This is just an offset of this assignment command in the output section.
unsigned Offset;
+
+ // Size of this data command.
unsigned Size;
};
diff --git a/ELF/MapFile.cpp b/ELF/MapFile.cpp
index f5dcec8..c5984c9 100644
--- a/ELF/MapFile.cpp
+++ b/ELF/MapFile.cpp
@@ -38,58 +38,46 @@
using namespace lld;
using namespace lld::elf;
-typedef DenseMap<const SectionBase *, SmallVector<Symbol *, 4>> SymbolMapTy;
+typedef DenseMap<const SectionBase *, SmallVector<Defined *, 4>> SymbolMapTy;
static const std::string Indent8 = " "; // 8 spaces
static const std::string Indent16 = " "; // 16 spaces
// Print out the first three columns of a line.
-static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size,
- uint64_t Align) {
- int W = Config->Is64 ? 16 : 8;
- OS << format("%0*llx %0*llx %5lld ", W, Addr, W, Size, Align);
+static void writeHeader(raw_ostream &OS, uint64_t VMA, uint64_t LMA,
+ uint64_t Size, uint64_t Align) {
+ if (Config->Is64)
+ OS << format("%16llx %16llx %8llx %5lld ", VMA, LMA, Size, Align);
+ else
+ OS << format("%8llx %8llx %8llx %5lld ", VMA, LMA, Size, Align);
}
// Returns a list of all symbols that we want to print out.
-static std::vector<Symbol *> getSymbols() {
- std::vector<Symbol *> V;
- for (InputFile *File : ObjectFiles) {
- for (Symbol *B : File->getSymbols()) {
- if (auto *SS = dyn_cast<SharedSymbol>(B))
- if (SS->CopyRelSec || SS->NeedsPltAddr)
- V.push_back(SS);
+static std::vector<Defined *> getSymbols() {
+ std::vector<Defined *> V;
+ for (InputFile *File : ObjectFiles)
+ for (Symbol *B : File->getSymbols())
if (auto *DR = dyn_cast<Defined>(B))
- if (DR->File == File && !DR->isSection() && DR->Section &&
- DR->Section->Live)
+ if (!DR->isSection() && DR->Section && DR->Section->Live &&
+ (DR->File == File || DR->NeedsPltAddr || DR->Section->Bss))
V.push_back(DR);
- }
- }
return V;
}
// Returns a map from sections to their symbols.
-static SymbolMapTy getSectionSyms(ArrayRef<Symbol *> Syms) {
+static SymbolMapTy getSectionSyms(ArrayRef<Defined *> Syms) {
SymbolMapTy Ret;
- for (Symbol *S : Syms) {
- if (auto *DR = dyn_cast<Defined>(S)) {
- Ret[DR->Section].push_back(S);
- continue;
- }
-
- SharedSymbol *SS = cast<SharedSymbol>(S);
- if (SS->CopyRelSec)
- Ret[SS->CopyRelSec].push_back(S);
- else
- Ret[InX::Plt].push_back(S);
- }
+ for (Defined *DR : Syms)
+ Ret[DR->Section].push_back(DR);
// Sort symbols by address. We want to print out symbols in the
// order in the output file rather than the order they appeared
// in the input files.
for (auto &It : Ret) {
- SmallVectorImpl<Symbol *> &V = It.second;
- std::sort(V.begin(), V.end(),
- [](Symbol *A, Symbol *B) { return A->getVA() < B->getVA(); });
+ SmallVectorImpl<Defined *> &V = It.second;
+ std::stable_sort(V.begin(), V.end(), [](Defined *A, Defined *B) {
+ return A->getVA() < B->getVA();
+ });
}
return Ret;
}
@@ -98,11 +86,14 @@
// Demangling symbols (which is what toString() does) is slow, so
// we do that in batch using parallel-for.
static DenseMap<Symbol *, std::string>
-getSymbolStrings(ArrayRef<Symbol *> Syms) {
+getSymbolStrings(ArrayRef<Defined *> Syms) {
std::vector<std::string> Str(Syms.size());
parallelForEachN(0, Syms.size(), [&](size_t I) {
raw_string_ostream OS(Str[I]);
- writeHeader(OS, Syms[I]->getVA(), Syms[I]->getSize(), 0);
+ OutputSection *OSec = Syms[I]->getOutputSection();
+ uint64_t VMA = Syms[I]->getVA();
+ uint64_t LMA = OSec ? OSec->getLMA() + VMA - OSec->getVA(0) : 0;
+ writeHeader(OS, VMA, LMA, Syms[I]->getSize(), 1);
OS << Indent16 << toString(*Syms[I]);
});
@@ -143,7 +134,8 @@
// Print out section pieces.
for (EhSectionPiece &P : Pieces) {
- writeHeader(OS, OSec->Addr + P.OutputOff, P.Size, 0);
+ writeHeader(OS, OSec->Addr + P.OutputOff, OSec->getLMA() + P.OutputOff,
+ P.Size, 1);
OS << Indent8 << toString(P.Sec->File) << ":(" << P.Sec->Name << "+0x"
<< Twine::utohexstr(P.InputOff) + ")\n";
}
@@ -162,18 +154,30 @@
}
// Collect symbol info that we want to print out.
- std::vector<Symbol *> Syms = getSymbols();
+ std::vector<Defined *> Syms = getSymbols();
SymbolMapTy SectionSyms = getSectionSyms(Syms);
DenseMap<Symbol *, std::string> SymStr = getSymbolStrings(Syms);
// Print out the header line.
int W = Config->Is64 ? 16 : 8;
- OS << left_justify("Address", W) << ' ' << left_justify("Size", W)
- << " Align Out In Symbol\n";
+ OS << right_justify("VMA", W) << ' ' << right_justify("LMA", W)
+ << " Size Align Out In Symbol\n";
- // Print out file contents.
- for (OutputSection *OSec : OutputSections) {
- writeHeader(OS, OSec->Addr, OSec->Size, OSec->Alignment);
+ for (BaseCommand *Base : Script->SectionCommands) {
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
+ if (Cmd->Provide && !Cmd->Sym)
+ continue;
+ //FIXME: calculate and print LMA.
+ writeHeader(OS, Cmd->Addr, 0, Cmd->Size, 1);
+ OS << Cmd->CommandString << '\n';
+ continue;
+ }
+
+ auto *OSec = dyn_cast<OutputSection>(Base);
+ if (!OSec)
+ continue;
+
+ writeHeader(OS, OSec->Addr, OSec->getLMA(), OSec->Size, OSec->Alignment);
OS << OSec->Name << '\n';
// Dump symbols for each input section.
@@ -185,7 +189,8 @@
continue;
}
- writeHeader(OS, IS->getVA(0), IS->getSize(), IS->Alignment);
+ writeHeader(OS, IS->getVA(0), OSec->getLMA() + IS->getOffset(0),
+ IS->getSize(), IS->Alignment);
OS << Indent8 << toString(IS) << '\n';
for (Symbol *Sym : SectionSyms[IS])
OS << SymStr[Sym] << '\n';
@@ -194,13 +199,17 @@
}
if (auto *Cmd = dyn_cast<ByteCommand>(Base)) {
- writeHeader(OS, OSec->Addr + Cmd->Offset, Cmd->Size, 1);
+ writeHeader(OS, OSec->Addr + Cmd->Offset, OSec->getLMA() + Cmd->Offset,
+ Cmd->Size, 1);
OS << Indent8 << Cmd->CommandString << '\n';
continue;
}
if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
- writeHeader(OS, OSec->Addr + Cmd->Offset, Cmd->Size, 1);
+ if (Cmd->Provide && !Cmd->Sym)
+ continue;
+ writeHeader(OS, Cmd->Addr, OSec->getLMA() + Cmd->Addr - OSec->getVA(0),
+ Cmd->Size, 1);
OS << Indent8 << Cmd->CommandString << '\n';
continue;
}
diff --git a/ELF/MarkLive.cpp b/ELF/MarkLive.cpp
index 6b80e8e..bacbf0e 100644
--- a/ELF/MarkLive.cpp
+++ b/ELF/MarkLive.cpp
@@ -159,10 +159,6 @@
if (!EH.NumRelocations)
return;
- // Unfortunately we need to split .eh_frame early since some relocations in
- // .eh_frame keep other section alive and some don't.
- EH.split<ELFT>();
-
if (EH.AreRelocsRela)
scanEhFrameSection<ELFT>(EH, EH.template relas<ELFT>(), Fn);
else
@@ -207,7 +203,7 @@
// (splittable) sections, each piece of data has independent liveness bit.
// So we explicitly tell it which offset is in use.
if (auto *MS = dyn_cast<MergeInputSection>(Sec))
- MS->markLiveAt(Offset);
+ MS->getSectionPiece(Offset)->Live = true;
if (Sec->Live)
return;
@@ -279,13 +275,18 @@
// The -gc-sections option works only for SHF_ALLOC sections
// (sections that are memory-mapped at runtime). So we can
- // unconditionally make non-SHF_ALLOC sections alive.
+ // unconditionally make non-SHF_ALLOC sections alive except
+ // SHF_LINK_ORDER and SHT_REL/SHT_RELA sections.
//
- // Non SHF_ALLOC sections are not removed even if they are
+ // Usually, SHF_ALLOC sections are not removed even if they are
// unreachable through relocations because reachability is not
// a good signal whether they are garbage or not (e.g. there is
// usually no section referring to a .comment section, but we
- // want to keep it.)
+ // want to keep it.).
+ //
+ // Note on SHF_LINK_ORDER: Such sections contain metadata and they
+ // have a reverse dependency on the InputSection they are linked with.
+ // We are able to garbage collect them.
//
// Note on SHF_REL{,A}: Such sections reach here only when -r
// or -emit-reloc were given. And they are subject of garbage
@@ -293,8 +294,9 @@
// remove its relocation section.
for (InputSectionBase *Sec : InputSections) {
bool IsAlloc = (Sec->Flags & SHF_ALLOC);
+ bool IsLinkOrder = (Sec->Flags & SHF_LINK_ORDER);
bool IsRel = (Sec->Type == SHT_REL || Sec->Type == SHT_RELA);
- if (!IsAlloc && !IsRel)
+ if (!IsAlloc && !IsLinkOrder && !IsRel)
Sec->Live = true;
}
diff --git a/ELF/Options.td b/ELF/Options.td
index 82a2a1c..256dc5a 100644
--- a/ELF/Options.td
+++ b/ELF/Options.td
@@ -5,9 +5,10 @@
class F<string name>: Flag<["--", "-"], name>;
class J<string name>: Joined<["--", "-"], name>;
-multiclass Eq<string name> {
+multiclass Eq<string name, string help> {
def NAME: Separate<["--", "-"], name>;
- def NAME # _eq: Joined<["--", "-"], name # "=">, Alias<!cast<Separate>(NAME)>;
+ def NAME # _eq: Joined<["--", "-"], name # "=">, Alias<!cast<Separate>(NAME)>,
+ HelpText<help>;
}
multiclass B<string name, string help1, string help2> {
@@ -15,48 +16,46 @@
def no_ # NAME: Flag<["--", "-"], "no-" # name>, HelpText<help2>;
}
-defm auxiliary: Eq<"auxiliary">,
- HelpText<"Set DT_AUXILIARY field to the specified name">;
+defm auxiliary: Eq<"auxiliary", "Set DT_AUXILIARY field to the specified name">;
def Bsymbolic: F<"Bsymbolic">, HelpText<"Bind defined symbols locally">;
def Bsymbolic_functions: F<"Bsymbolic-functions">,
HelpText<"Bind defined function symbols locally">;
-def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries">;
+def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries (default)">;
def Bstatic: F<"Bstatic">, HelpText<"Do not link against shared libraries">;
-def build_id: F<"build-id">, HelpText<"Generate build ID note">;
+def build_id: F<"build-id">, HelpText<"Alias for --build-id=fast">;
-def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">;
+def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">,
+ MetaVarName<"[fast,md5,sha,uuid,0x<hexstring>]">;
-defm check_sections : B<"check-sections",
- "Check section addresses for overlaps",
+defm check_sections: B<"check-sections",
+ "Check section addresses for overlaps (default)",
"Do not check section addresses for overlaps">;
-defm compress_debug_sections : Eq<"compress-debug-sections">,
- HelpText<"Compress DWARF debug sections">;
+defm compress_debug_sections:
+ Eq<"compress-debug-sections", "Compress DWARF debug sections">,
+ MetaVarName<"[none,zlib]">;
-defm defsym: Eq<"defsym">, HelpText<"Define a symbol alias">;
+defm defsym: Eq<"defsym", "Define a symbol alias">, MetaVarName<"<symbol>=<value>">;
-defm library_path: Eq<"library-path">,
- HelpText<"Add a directory to the library search path">, MetaVarName<"<dir>">;
+defm library_path:
+ Eq<"library-path", "Add a directory to the library search path">, MetaVarName<"<dir>">;
def O: JoinedOrSeparate<["-"], "O">, HelpText<"Optimize output file size">;
-defm Tbss: Eq<"Tbss">,
- HelpText<"Same as --section-start with .bss as the sectionname">;
+defm Tbss: Eq<"Tbss", "Same as --section-start with .bss as the sectionname">;
-defm Tdata: Eq<"Tdata">,
- HelpText<"Same as --section-start with .data as the sectionname">;
+defm Tdata: Eq<"Tdata", "Same as --section-start with .data as the sectionname">;
-defm Ttext: Eq<"Ttext">,
- HelpText<"Same as --section-start with .text as the sectionname">;
+defm Ttext: Eq<"Ttext", "Same as --section-start with .text as the sectionname">;
defm allow_multiple_definition: B<"allow-multiple-definition",
"Allow multiple definitions",
- "Do not allow multiple definitions">;
+ "Do not allow multiple definitions (default)">;
defm apply_dynamic_relocs: B<"apply-dynamic-relocs",
"Apply dynamic relocations to place",
@@ -64,16 +63,20 @@
defm as_needed: B<"as-needed",
"Only set DT_NEEDED for shared libraries if used",
- "Always set DT_NEEDED for shared libraries">;
+ "Always set DT_NEEDED for shared libraries (default)">;
+
+defm call_graph_ordering_file:
+ Eq<"call-graph-ordering-file", "Layout sections to optimize the given callgraph">;
// -chroot doesn't have a help text because it is an internal option.
-defm chroot: Eq<"chroot">;
+def chroot: Separate<["--", "-"], "chroot">;
def color_diagnostics: F<"color-diagnostics">,
- HelpText<"Use colors in diagnostics">;
+ HelpText<"Alias for --color-diagnostics=always">;
def color_diagnostics_eq: J<"color-diagnostics=">,
- HelpText<"Use colors in diagnostics">;
+ HelpText<"Use colors in diagnostics">,
+ MetaVarName<"[auto,always,never]">;
defm cref: B<"cref",
"Output cross reference table",
@@ -84,7 +87,7 @@
"Do not assign space to common symbols">;
defm demangle: B<"demangle",
- "Demangle symbol names",
+ "Demangle symbol names (default)",
"Do not demangle symbol names">;
def disable_new_dtags: F<"disable-new-dtags">,
@@ -98,11 +101,9 @@
def discard_none: F<"discard-none">,
HelpText<"Keep all symbols in the symbol table">;
-defm dynamic_linker: Eq<"dynamic-linker">,
- HelpText<"Which dynamic linker to use">;
+defm dynamic_linker: Eq<"dynamic-linker", "Which dynamic linker to use">;
-defm dynamic_list: Eq<"dynamic-list">,
- HelpText<"Read a list of dynamic symbols">;
+defm dynamic_list: Eq<"dynamic-list", "Read a list of dynamic symbols">;
defm eh_frame_hdr: B<"eh-frame-hdr",
"Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header",
@@ -111,67 +112,65 @@
def emit_relocs: F<"emit-relocs">, HelpText<"Generate relocations in output">;
def enable_new_dtags: F<"enable-new-dtags">,
- HelpText<"Enable new dynamic tags">;
+ HelpText<"Enable new dynamic tags (default)">;
+
+def end_group: F<"end-group">,
+ HelpText<"Ignored for compatibility with GNU unless you pass --warn-backrefs">;
def end_lib: F<"end-lib">,
HelpText<"End a grouping of objects that should be treated as if they were together in an archive">;
-defm entry: Eq<"entry">, HelpText<"Name of entry point symbol">,
+defm entry: Eq<"entry", "Name of entry point symbol">,
MetaVarName<"<entry>">;
-defm error_limit: Eq<"error-limit">,
- HelpText<"Maximum number of errors to emit before stopping (0 = no limit)">;
+defm error_limit:
+ Eq<"error-limit", "Maximum number of errors to emit before stopping (0 = no limit)">;
def error_unresolved_symbols: F<"error-unresolved-symbols">,
HelpText<"Report unresolved symbols as errors">;
-defm exclude_libs: Eq<"exclude-libs">,
- HelpText<"Exclude static libraries from automatic export">;
+defm exclude_libs: Eq<"exclude-libs", "Exclude static libraries from automatic export">;
defm export_dynamic: B<"export-dynamic",
"Put symbols in the dynamic symbol table",
- "Do not put symbols in the dynamic symbol table">;
+ "Do not put symbols in the dynamic symbol table (default)">;
-defm export_dynamic_symbol: Eq<"export-dynamic-symbol">,
- HelpText<"Put a symbol in the dynamic symbol table">;
+defm export_dynamic_symbol:
+ Eq<"export-dynamic-symbol", "Put a symbol in the dynamic symbol table">;
defm fatal_warnings: B<"fatal-warnings",
"Treat warnings as errors",
- "Do not treat warnings as errors">;
+ "Do not treat warnings as errors (default)">;
-defm filter: Eq<"filter">,
- HelpText<"Set DT_FILTER field to the specified name">;
+defm filter: Eq<"filter", "Set DT_FILTER field to the specified name">;
-defm fini: Eq<"fini">,
- HelpText<"Specify a finalizer function">, MetaVarName<"<symbol>">;
+defm fini: Eq<"fini", "Specify a finalizer function">, MetaVarName<"<symbol>">;
def fix_cortex_a53_843419: F<"fix-cortex-a53-843419">,
HelpText<"Apply fixes for AArch64 Cortex-A53 erratum 843419">;
-defm format: Eq<"format">,
- HelpText<"Change the input format of the inputs following this option">,
- MetaVarName<"<input-format>">;
+defm format: Eq<"format", "Change the input format of the inputs following this option">,
+ MetaVarName<"[default,elf,binary]">;
defm gc_sections: B<"gc-sections",
"Enable garbage collection of unused sections",
- "Disable garbage collection of unused sections">;
+ "Disable garbage collection of unused sections (default)">;
defm gdb_index: B<"gdb-index",
"Generate .gdb_index section",
- "Do not generate .gdb_index section">;
+ "Do not generate .gdb_index section (default)">;
defm gnu_unique: B<"gnu-unique",
- "Enable STB_GNU_UNIQUE symbol binding",
+ "Enable STB_GNU_UNIQUE symbol binding (default)",
"Disable STB_GNU_UNIQUE symbol binding">;
-defm hash_style: Eq<"hash-style">,
- HelpText<"Specify hash style (sysv, gnu or both)">;
+defm hash_style: Eq<"hash-style", "Specify hash style (sysv, gnu or both)">;
def help: F<"help">, HelpText<"Print option help">;
def icf_all: F<"icf=all">, HelpText<"Enable identical code folding">;
-def icf_none: F<"icf=none">, HelpText<"Disable identical code folding">;
+def icf_none: F<"icf=none">, HelpText<"Disable identical code folding (default)">;
def ignore_function_address_equality: F<"ignore-function-address-equality">,
HelpText<"lld can break the address equality of functions">;
@@ -179,25 +178,24 @@
def ignore_data_address_equality: F<"ignore-data-address-equality">,
HelpText<"lld can break the address equality of data">;
-defm image_base : Eq<"image-base">, HelpText<"Set the base address">;
+defm image_base: Eq<"image-base", "Set the base address">;
-defm init: Eq<"init">, HelpText<"Specify an initializer function">,
+defm init: Eq<"init", "Specify an initializer function">,
MetaVarName<"<symbol>">;
-defm just_symbols: Eq<"just-symbols">, HelpText<"Just link symbols">;
+defm just_symbols: Eq<"just-symbols", "Just link symbols">;
-defm library: Eq<"library">, HelpText<"Root name of library to use">,
+defm keep_unique: Eq<"keep-unique", "Do not fold this symbol during ICF">;
+
+defm library: Eq<"library", "Root name of library to use">,
MetaVarName<"<libName>">;
-def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">,
- HelpText<"Optimization level for LTO">;
-
def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">;
-defm Map: Eq<"Map">, HelpText<"Print a link map to the specified file">;
+defm Map: Eq<"Map", "Print a link map to the specified file">;
defm merge_exidx_entries: B<"merge-exidx-entries",
- "Enable merging .ARM.exidx entries",
+ "Enable merging .ARM.exidx entries (default)",
"Disable merging .ARM.exidx entries">;
def nostdlib: F<"nostdlib">,
@@ -230,49 +228,58 @@
def omagic: Flag<["--"], "omagic">, MetaVarName<"<magic>">,
HelpText<"Set the text and data sections to be readable and writable">;
-defm orphan_handling: Eq<"orphan-handling">,
- HelpText<"Control how orphan sections are handled when linker script used">;
+defm orphan_handling:
+ Eq<"orphan-handling", "Control how orphan sections are handled when linker script used">;
-defm pack_dyn_relocs: Eq<"pack-dyn-relocs">, MetaVarName<"<format>">,
- HelpText<"Pack dynamic relocations in the given format (none or android)">;
+defm pack_dyn_relocs:
+ Eq<"pack-dyn-relocs", "Pack dynamic relocations in the given format">,
+ MetaVarName<"[none,android]">;
defm pie: B<"pie",
"Create a position independent executable",
- "Do not create a position independent executable">;
+ "Do not create a position independent executable (default)">;
defm print_gc_sections: B<"print-gc-sections",
"List removed unused sections",
- "Do not list removed unused sections">;
+ "Do not list removed unused sections (default)">;
defm print_icf_sections: B<"print-icf-sections",
"List identical folded sections",
- "Do not list identical folded sections">;
+ "Do not list identical folded sections (default)">;
+
+def pop_state: F<"pop-state">,
+ HelpText<"Undo the effect of -push-state">;
+
+def push_state: F<"push-state">,
+ HelpText<"Save the current state of -as-needed, -static and -whole-archive">;
def print_map: F<"print-map">,
HelpText<"Print a link map to the standard output">;
-defm reproduce: Eq<"reproduce">,
- HelpText<"Dump linker invocation and input files for debugging">;
+defm reproduce: Eq<"reproduce", "Dump linker invocation and input files for debugging">;
-defm rpath: Eq<"rpath">, HelpText<"Add a DT_RUNPATH to the output">;
+defm rpath: Eq<"rpath", "Add a DT_RUNPATH to the output">;
def relocatable: F<"relocatable">, HelpText<"Create relocatable object file">;
-defm retain_symbols_file: Eq<"retain-symbols-file">,
- HelpText<"Retain only the symbols listed in the file">,
+defm retain_symbols_file:
+ Eq<"retain-symbols-file", "Retain only the symbols listed in the file">,
MetaVarName<"<file>">;
-defm script: Eq<"script">, HelpText<"Read linker script">;
+defm script: Eq<"script", "Read linker script">;
-defm section_start: Eq<"section-start">, MetaVarName<"<address>">,
- HelpText<"Set address of section">;
+defm section_start: Eq<"section-start", "Set address of section">,
+ MetaVarName<"<address>">;
def shared: F<"shared">, HelpText<"Build a shared object">;
-defm soname: Eq<"soname">, HelpText<"Set DT_SONAME">;
+defm soname: Eq<"soname", "Set DT_SONAME">;
-defm sort_section: Eq<"sort-section">,
- HelpText<"Specifies sections sorting rule when linkerscript is used">;
+defm sort_section:
+ Eq<"sort-section", "Specifies sections sorting rule when linkerscript is used">;
+
+def start_group: F<"start-group">,
+ HelpText<"Ignored for compatibility with GNU unless you pass --warn-backrefs">;
def start_lib: F<"start-lib">,
HelpText<"Start a grouping of objects that should be treated as if they were together in an archive">;
@@ -281,39 +288,39 @@
def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">;
-defm symbol_ordering_file: Eq<"symbol-ordering-file">,
- HelpText<"Layout sections in the order specified by symbol file">;
+defm symbol_ordering_file:
+ Eq<"symbol-ordering-file", "Layout sections to place symbols in the order specified by symbol ordering file">;
-defm sysroot: Eq<"sysroot">, HelpText<"Set the system root">;
+defm sysroot: Eq<"sysroot", "Set the system root">;
def target1_rel: F<"target1-rel">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_REL32">;
-def target1_abs: F<"target1-abs">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_ABS32">;
+def target1_abs: F<"target1-abs">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_ABS32 (default)">;
-defm target2: Eq<"target2">,
- HelpText<"Interpret R_ARM_TARGET2 as <type>, where <type> is one of rel, abs, or got-rel">,
+defm target2:
+ Eq<"target2", "Interpret R_ARM_TARGET2 as <type>, where <type> is one of rel, abs, or got-rel">,
MetaVarName<"<type>">;
defm threads: B<"threads",
- "Run the linker multi-threaded",
+ "Run the linker multi-threaded (default)",
"Do not run the linker multi-threaded">;
def trace: F<"trace">, HelpText<"Print the names of the input files">;
-defm trace_symbol : Eq<"trace-symbol">, HelpText<"Trace references to symbols">;
+defm trace_symbol: Eq<"trace-symbol", "Trace references to symbols">;
-defm undefined: Eq<"undefined">,
- HelpText<"Force undefined symbol during linking">;
+defm undefined: Eq<"undefined", "Force undefined symbol during linking">,
+ MetaVarName<"<symbol>">;
-defm unresolved_symbols: Eq<"unresolved-symbols">,
- HelpText<"Determine how to handle unresolved symbols">;
+defm unresolved_symbols:
+ Eq<"unresolved-symbols", "Determine how to handle unresolved symbols">;
defm undefined_version: B<"undefined-version",
- "Allow unused version in version script",
+ "Allow unused version in version script (default)",
"Report version scripts that refer undefined symbols">;
-defm rsp_quoting: Eq<"rsp-quoting">,
- HelpText<"Quoting style for response files. Values supported: windows|posix">;
+defm rsp_quoting: Eq<"rsp-quoting", "Quoting style for response files">,
+ MetaVarName<"[posix,windows]">;
def v: Flag<["-"], "v">, HelpText<"Display the version number">;
@@ -321,14 +328,18 @@
def version: F<"version">, HelpText<"Display the version number and exit">;
-defm version_script: Eq<"version-script">, HelpText<"Read a version script">;
+defm version_script: Eq<"version-script", "Read a version script">;
+
+defm warn_backrefs: B<"warn-backrefs",
+ "Warn about backward symbol references to fetch archive members",
+ "Do not warn about backward symbol references to fetch archive members (default)">;
defm warn_common: B<"warn-common",
"Warn about duplicate common symbols",
- "Do not warn about duplicate common symbols">;
+ "Do not warn about duplicate common symbols (default)">;
-defm warn_symbol_ordering : B<"warn-symbol-ordering",
- "Warn about problems with the symbol ordering file",
+defm warn_symbol_ordering: B<"warn-symbol-ordering",
+ "Warn about problems with the symbol ordering file (default)",
"Do not warn about problems with the symbol ordering file">;
def warn_unresolved_symbols: F<"warn-unresolved-symbols">,
@@ -336,83 +347,102 @@
defm whole_archive: B<"whole-archive",
"Force load of all members in a static library",
- "Do not force load of all members in a static library">;
+ "Do not force load of all members in a static library (default)">;
-defm wrap: Eq<"wrap">, HelpText<"Use wrapper functions for symbol">,
- MetaVarName<"<symbol>">;
+defm wrap: Eq<"wrap", "Use wrapper functions for symbol">,
+ MetaVarName<"<symbol>=<symbol>">;
def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">,
HelpText<"Linker option extensions">;
// Aliases
-def alias_auxiliary: Separate<["-"], "f">, Alias<auxiliary>;
-def alias_Bdynamic_call_shared: F<"call_shared">, Alias<Bdynamic>;
-def alias_Bdynamic_dy: F<"dy">, Alias<Bdynamic>;
-def alias_Bstatic_dn: F<"dn">, Alias<Bstatic>;
-def alias_Bstatic_non_shared: F<"non_shared">, Alias<Bstatic>;
-def alias_Bstatic_static: F<"static">, Alias<Bstatic>;
-def alias_define_common_d: Flag<["-"], "d">, Alias<define_common>;
-def alias_define_common_dc: F<"dc">, Alias<define_common>;
-def alias_define_common_dp: F<"dp">, Alias<define_common>;
-def alias_discard_all_x: Flag<["-"], "x">, Alias<discard_all>;
-def alias_discard_locals_X: Flag<["-"], "X">, Alias<discard_locals>;
-def alias_emit_relocs: Flag<["-"], "q">, Alias<emit_relocs>;
-def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>;
-def alias_export_dynamic_E: Flag<["-"], "E">, Alias<export_dynamic>;
-def alias_filter: Separate<["-"], "F">, Alias<filter>;
-def alias_format_b: Separate<["-"], "b">, Alias<format>;
-def alias_library: JoinedOrSeparate<["-"], "l">, Alias<library>;
-def alias_library_path: JoinedOrSeparate<["-"], "L">, Alias<library_path>;
-def alias_no_pie_pic_executable: F<"no-pic-executable">, Alias<no_pie>;
-def alias_omagic: Flag<["-"], "N">, Alias<omagic>;
-def alias_o_output: Joined<["--"], "output=">, Alias<o>;
-def alias_o_output2 : Separate<["--"], "output">, Alias<o>;
-def alias_pie_pic_executable: F<"pic-executable">, Alias<pie>;
-def alias_print_map_M: Flag<["-"], "M">, Alias<print_map>;
-def alias_relocatable_r: Flag<["-"], "r">, Alias<relocatable>;
-def alias_rpath_R: JoinedOrSeparate<["-"], "R">, Alias<rpath>;
-def alias_script_T: JoinedOrSeparate<["-"], "T">, Alias<script>;
-def alias_shared_Bshareable: F<"Bshareable">, Alias<shared>;
-def alias_soname_h: JoinedOrSeparate<["-"], "h">, Alias<soname>;
-def alias_strip_all: Flag<["-"], "s">, Alias<strip_all>;
-def alias_strip_debug_S: Flag<["-"], "S">, Alias<strip_debug>;
-def alias_trace: Flag<["-"], "t">, Alias<trace>;
-def alias_trace_symbol_y : JoinedOrSeparate<["-"], "y">, Alias<trace_symbol>;
-def alias_Ttext_segment: Separate<["-", "--"], "Ttext-segment">, Alias<Ttext>;
-def alias_Ttext_segment_eq: Joined<["-", "--"], "Ttext-segment=">, Alias<Ttext>;
-def alias_undefined_u: JoinedOrSeparate<["-"], "u">, Alias<undefined>;
-def alias_version_V: Flag<["-"], "V">, Alias<version>;
-
-// Our symbol resolution algorithm handles symbols in archive files differently
-// than traditional linkers, so we don't need --start-group and --end-group.
-// These options are recongized for compatibility but ignored.
-def end_group: F<"end-group">;
-def end_group_paren: Flag<["-"], ")">;
-def start_group: F<"start-group">;
-def start_group_paren: Flag<["-"], "(">;
+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">;
+def: F<"dn">, Alias<Bstatic>, HelpText<"Alias for --Bstatic">;
+def: F<"non_shared">, Alias<Bstatic>, HelpText<"Alias for --Bstatic">;
+def: F<"static">, Alias<Bstatic>, HelpText<"Alias for --Bstatic">;
+def: Flag<["-"], "d">, Alias<define_common>, HelpText<"Alias for --define-common">;
+def: F<"dc">, Alias<define_common>, HelpText<"Alias for --define-common">;
+def: F<"dp">, Alias<define_common>, HelpText<"Alias for --define-common">;
+def: Flag<["-"], "x">, Alias<discard_all>, HelpText<"Alias for --discard-all">;
+def: Flag<["-"], "X">, Alias<discard_locals>, HelpText<"Alias for --discard-locals">;
+def: Flag<["-"], "q">, Alias<emit_relocs>, HelpText<"Alias for --emit-relocs">;
+def: Flag<["-"], ")">, Alias<end_group>, HelpText<"Alias for --end-group">;
+def: JoinedOrSeparate<["-"], "e">, Alias<entry>, HelpText<"Alias for --entry">;
+def: Flag<["-"], "E">, Alias<export_dynamic>, HelpText<"Alias for --export-dynamic">;
+def: Separate<["-"], "F">, Alias<filter>, HelpText<"Alias for --filter">;
+def: Separate<["-"], "b">, Alias<format>, HelpText<"Alias for --format">;
+def: JoinedOrSeparate<["-"], "l">, Alias<library>, HelpText<"Alias for --library">;
+def: JoinedOrSeparate<["-"], "L">, Alias<library_path>, HelpText<"Alias for --library-path">;
+def: F<"no-pic-executable">, Alias<no_pie>, HelpText<"Alias for --no-pie">;
+def: Flag<["-"], "N">, Alias<omagic>, HelpText<"Alias for --omagic">;
+def: Joined<["--"], "output=">, Alias<o>, HelpText<"Alias for -o">;
+def: Separate<["--"], "output">, Alias<o>, HelpText<"Alias for -o">;
+def: F<"pic-executable">, Alias<pie>, HelpText<"Alias for --pie">;
+def: Flag<["-"], "M">, Alias<print_map>, HelpText<"Alias for --print-map">;
+def: Flag<["-"], "r">, Alias<relocatable>, HelpText<"Alias for --relocatable">;
+def: JoinedOrSeparate<["-"], "R">, Alias<rpath>, HelpText<"Alias for --rpath">;
+def: JoinedOrSeparate<["-"], "T">, Alias<script>, HelpText<"Alias for --script">;
+def: F<"Bshareable">, Alias<shared>, HelpText<"Alias for --shared">;
+def: JoinedOrSeparate<["-"], "h">, Alias<soname>, HelpText<"Alias for --soname">;
+def: Flag<["-"], "(">, Alias<start_group>, HelpText<"Alias for --start-group">;
+def: Flag<["-"], "s">, Alias<strip_all>, HelpText<"Alias for --strip-all">;
+def: Flag<["-"], "S">, Alias<strip_debug>, HelpText<"Alias for --strip-debug">;
+def: Flag<["-"], "t">, Alias<trace>, HelpText<"Alias for --trace">;
+def: JoinedOrSeparate<["-"], "y">, Alias<trace_symbol>, HelpText<"Alias for --trace-symbol">;
+def: Separate<["-", "--"], "Ttext-segment">, Alias<Ttext>, HelpText<"Alias for --Ttext">;
+def: Joined<["-", "--"], "Ttext-segment=">, Alias<Ttext>, HelpText<"Alias for --Ttext">;
+def: JoinedOrSeparate<["-"], "u">, Alias<undefined>, HelpText<"Alias for --undefined">;
+def: Flag<["-"], "V">, Alias<version>, HelpText<"Alias for --version">;
// LTO-related options.
def lto_aa_pipeline: J<"lto-aa-pipeline=">,
HelpText<"AA pipeline to run during LTO. Used in conjunction with -lto-newpm-passes">;
+def lto_debug_pass_manager: F<"lto-debug-pass-manager">,
+ HelpText<"Debug new pass manager">;
+def lto_new_pass_manager: F<"lto-new-pass-manager">,
+ HelpText<"Use new pass manager">;
def lto_newpm_passes: J<"lto-newpm-passes=">,
HelpText<"Passes to run during LTO">;
+def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">,
+ HelpText<"Optimization level for LTO">;
def lto_partitions: J<"lto-partitions=">,
HelpText<"Number of LTO codegen partitions">;
+def lto_sample_profile: J<"lto-sample-profile=">,
+ HelpText<"Sample profile file path">;
def disable_verify: F<"disable-verify">;
-defm mllvm: Eq<"mllvm">;
+defm mllvm: Eq<"mllvm", "Additional arguments to forward to LLVM's option processing">;
def opt_remarks_filename: Separate<["--"], "opt-remarks-filename">,
HelpText<"YAML output file for optimization remarks">;
def opt_remarks_with_hotness: Flag<["--"], "opt-remarks-with-hotness">,
HelpText<"Include hotness information in the optimization remarks file">;
-defm plugin_opt: Eq<"plugin-opt">,
- HelpText<"specifies LTO options for compatibility with GNU linkers">;
+defm plugin_opt: Eq<"plugin-opt", "specifies LTO options for compatibility with GNU linkers">;
def save_temps: F<"save-temps">;
def thinlto_cache_dir: J<"thinlto-cache-dir=">,
HelpText<"Path to ThinLTO cached object file directory">;
-defm thinlto_cache_policy: Eq<"thinlto-cache-policy">,
- HelpText<"Pruning policy for the ThinLTO cache">;
+defm thinlto_cache_policy: Eq<"thinlto-cache-policy", "Pruning policy for the ThinLTO cache">;
def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">;
+def: J<"plugin-opt=O">, Alias<lto_O>, HelpText<"Alias for -lto-O">;
+def: F<"plugin-opt=debug-pass-manager">,
+ Alias<lto_debug_pass_manager>, HelpText<"Alias for -lto-debug-pass-manager">;
+def: F<"plugin-opt=disable-verify">, Alias<disable_verify>, HelpText<"Alias for -disable-verify">;
+def: J<"plugin-opt=jobs=">, Alias<thinlto_jobs>, HelpText<"Alias for -thinlto-jobs">;
+def: J<"plugin-opt=lto-partitions=">, Alias<lto_partitions>, HelpText<"Alias for -lto-partitions">;
+def plugin_opt_mcpu_eq: J<"plugin-opt=mcpu=">;
+def: F<"plugin-opt=new-pass-manager">,
+ Alias<lto_new_pass_manager>, HelpText<"Alias for -lto-new-pass-manager">;
+def plugin_opt_obj_path_eq: J<"plugin-opt=obj-path=">;
+def: J<"plugin-opt=sample-profile=">,
+ Alias<lto_sample_profile>, HelpText<"Alias for -lto-sample-profile">;
+def: F<"plugin-opt=save-temps">, Alias<save_temps>, HelpText<"Alias for -save-temps">;
+def plugin_opt_thinlto_emit_imports_files: F<"plugin-opt=thinlto-emit-imports-files">;
+def plugin_opt_thinlto_index_only: F<"plugin-opt=thinlto-index-only">;
+def plugin_opt_thinlto_index_only_eq: J<"plugin-opt=thinlto-index-only=">;
+def plugin_opt_thinlto_object_suffix_replace_eq: J<"plugin-opt=thinlto-object-suffix-replace=">;
+def plugin_opt_thinlto_prefix_replace_eq: J<"plugin-opt=thinlto-prefix-replace=">;
+
// Ignore LTO plugin-related options.
// clang -flto passes -plugin and -plugin-opt to the linker. This is required
// for ld.gold and ld.bfd to get LTO working. But it's not for lld which doesn't
@@ -420,27 +450,33 @@
// just ignore the option on lld side as it's easier. In fact, the linker could
// be called 'ld' and understanding which linker is used would require parsing of
// --version output.
-defm plugin: Eq<"plugin">;
+defm plugin: Eq<"plugin", "Ignored for compatibility with GNU linkers">;
+
+def plugin_opt_fresolution_eq: J<"plugin-opt=-fresolution=">;
+def plugin_opt_pass_through_eq: J<"plugin-opt=-pass-through=">;
+def plugin_opt_thinlto: J<"plugin-opt=thinlto">;
+def plugin_opt_slash: J<"plugin-opt=/">;
// Options listed below are silently ignored for now for compatibility.
-def allow_shlib_undefined: F<"allow-shlib-undefined">;
-def detect_odr_violations: F<"detect-odr-violations">;
-def g: Flag<["-"], "g">;
-def long_plt: F<"long-plt">;
-def no_add_needed: F<"no-add-needed">;
-def no_allow_shlib_undefined: F<"no-allow-shlib-undefined">;
-def no_copy_dt_needed_entries: F<"no-copy-dt-needed-entries">;
-def no_ctors_in_init_array: F<"no-ctors-in-init-array">;
-def no_keep_memory: F<"no-keep-memory">;
-def no_mmap_output_file: F<"no-mmap-output-file">;
-def no_warn_mismatch: F<"no-warn-mismatch">;
-defm rpath_link: Eq<"rpath-link">;
-def sort_common: F<"sort-common">;
-def stats: F<"stats">;
-def warn_execstack: F<"warn-execstack">;
-def warn_once: F<"warn-once">;
-def warn_shared_textrel: F<"warn-shared-textrel">;
-def EB : F<"EB">;
-def EL : F<"EL">;
-def G: JoinedOrSeparate<["-"], "G">;
-def Qy : F<"Qy">;
+def: F<"allow-shlib-undefined">;
+def: F<"detect-odr-violations">;
+def: Flag<["-"], "g">;
+def: F<"long-plt">;
+def: F<"no-add-needed">;
+def: F<"no-allow-shlib-undefined">;
+def: F<"no-copy-dt-needed-entries">;
+def: F<"no-ctors-in-init-array">;
+def: F<"no-keep-memory">;
+def: F<"no-mmap-output-file">;
+def: F<"no-warn-mismatch">;
+def: Separate<["--", "-"], "rpath-link">;
+def: J<"rpath-link=">;
+def: F<"sort-common">;
+def: F<"stats">;
+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/OutputSections.cpp b/ELF/OutputSections.cpp
index 8e9e757..31e1d19 100644
--- a/ELF/OutputSections.cpp
+++ b/ELF/OutputSections.cpp
@@ -31,8 +31,6 @@
using namespace lld::elf;
uint8_t Out::First;
-OutputSection *Out::Opd;
-uint8_t *Out::OpdBuf;
PhdrEntry *Out::TlsPhdr;
OutputSection *Out::DebugInfo;
OutputSection *Out::ElfHeader;
@@ -123,7 +121,6 @@
Flags = AndFlags | OrFlags;
Alignment = std::max(Alignment, IS->Alignment);
- IS->OutSecOff = Size++;
// If this section contains a table of fixed-size entries, sh_entsize
// holds the element size. If it contains elements of different size we
diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h
index 514b9da..9720aab 100644
--- a/ELF/OutputSections.h
+++ b/ELF/OutputSections.h
@@ -128,8 +128,6 @@
// until Writer is initialized.
struct Out {
static uint8_t First;
- static OutputSection *Opd;
- static uint8_t *OpdBuf;
static PhdrEntry *TlsPhdr;
static OutputSection *DebugInfo;
static OutputSection *ElfHeader;
diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp
index bc4f4b2..5c4a797 100644
--- a/ELF/Relocations.cpp
+++ b/ELF/Relocations.cpp
@@ -198,7 +198,7 @@
return 1;
}
- if (isRelExprOneOf<R_TLSLD_PC, R_TLSLD>(Expr)) {
+ if (isRelExprOneOf<R_TLSLD_GOT, R_TLSLD_GOT_FROM_END, R_TLSLD_PC>(Expr)) {
// Local-Dynamic relocs can be relaxed to Local-Exec.
if (!Config->Shared) {
C.Relocations.push_back(
@@ -213,13 +213,14 @@
}
// Local-Dynamic relocs can be relaxed to Local-Exec.
- if (isRelExprOneOf<R_ABS, R_TLSLD, R_TLSLD_PC>(Expr) && !Config->Shared) {
+ if (isRelExprOneOf<R_ABS, R_TLSLD_GOT_FROM_END, R_TLSLD_PC>(Expr) &&
+ !Config->Shared) {
C.Relocations.push_back({R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym});
return 1;
}
- if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL, R_TLSGD,
- R_TLSGD_PC>(Expr)) {
+ if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL, R_TLSGD_GOT,
+ R_TLSGD_GOT_FROM_END, R_TLSGD_PC>(Expr)) {
if (Config->Shared) {
if (InX::Got->addDynTlsEntry(Sym)) {
uint64_t Off = InX::Got->getGlobalDynOffset(Sym);
@@ -312,7 +313,7 @@
// Returns true if Expr refers a PLT entry.
static bool needsPlt(RelExpr Expr) {
- return isRelExprOneOf<R_PLT_PC, R_PPC_PLT_OPD, R_PLT, R_PLT_PAGE_PC>(Expr);
+ return isRelExprOneOf<R_PLT_PC, R_PPC_CALL_PLT, R_PLT, R_PLT_PAGE_PC>(Expr);
}
// Returns true if Expr refers a GOT entry. Note that this function
@@ -328,7 +329,8 @@
// file (PC, or GOT for example).
static bool isRelExpr(RelExpr Expr) {
return isRelExprOneOf<R_PC, R_GOTREL, R_GOTREL_FROM_END, R_MIPS_GOTREL,
- R_PAGE_PC, R_RELAX_GOT_PC>(Expr);
+ R_PPC_CALL, R_PPC_CALL_PLT, R_PAGE_PC,
+ R_RELAX_GOT_PC>(Expr);
}
// Returns true if a given relocation can be computed at link-time.
@@ -346,9 +348,9 @@
if (isRelExprOneOf<R_GOT_FROM_END, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE,
R_MIPS_GOTREL, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32,
R_MIPS_GOT_GP_PC, R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC,
- R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_PC,
- R_TLSGD, R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE,
- R_HINT>(E))
+ R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_GOT,
+ R_TLSGD_GOT_FROM_END, R_TLSGD_PC, R_PPC_CALL_PLT,
+ R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT>(E))
return true;
// These never do, except if the entire file is position dependent or if
@@ -395,8 +397,8 @@
static RelExpr toPlt(RelExpr Expr) {
switch (Expr) {
- case R_PPC_OPD:
- return R_PPC_PLT_OPD;
+ case R_PPC_CALL:
+ return R_PPC_CALL_PLT;
case R_PC:
return R_PLT_PC;
case R_PAGE_PC:
@@ -414,8 +416,8 @@
switch (Expr) {
case R_PLT_PC:
return R_PC;
- case R_PPC_PLT_OPD:
- return R_PPC_OPD;
+ case R_PPC_CALL_PLT:
+ return R_PPC_CALL;
case R_PLT:
return R_ABS;
default:
@@ -461,6 +463,26 @@
return Ret;
}
+// When a symbol is copy relocated or we create a canonical plt entry, it is
+// effectively a defined symbol. In the case of copy relocation the symbol is
+// in .bss and in the case of a canonical plt entry it is in .plt. This function
+// replaces the existing symbol with a Defined pointing to the appropriate
+// location.
+static void replaceWithDefined(Symbol &Sym, SectionBase *Sec, uint64_t Value,
+ uint64_t Size) {
+ Symbol Old = Sym;
+ replaceSymbol<Defined>(&Sym, Sym.File, Sym.getName(), Sym.Binding,
+ Sym.StOther, Sym.Type, Value, Size, Sec);
+ Sym.PltIndex = Old.PltIndex;
+ Sym.GotIndex = Old.GotIndex;
+ Sym.VerdefIndex = Old.VerdefIndex;
+ Sym.IsInGlobalMipsGot = Old.IsInGlobalMipsGot;
+ Sym.IsPreemptible = true;
+ Sym.ExportDynamic = true;
+ Sym.IsUsedInRegularObj = true;
+ Sym.Used = true;
+}
+
// Reserve space in .bss or .bss.rel.ro for copy relocation.
//
// The copy relocation is pretty much a hack. If you use a copy relocation
@@ -522,11 +544,8 @@
// Look through the DSO's dynamic symbol table for aliases and create a
// dynamic symbol for each one. This causes the copy relocation to correctly
// interpose any aliases.
- for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS)) {
- Sym->CopyRelSec = Sec;
- Sym->IsUsedInRegularObj = true;
- Sym->Used = true;
- }
+ for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS))
+ replaceWithDefined(*Sym, Sec, 0, Sym->Size);
InX::RelaDyn->addReloc(Target->CopyRel, Sec, 0, &SS);
}
@@ -762,12 +781,12 @@
// complicates things for the dynamic linker and means we would have to reserve
// space for the extra PT_LOAD even if we end up not using it.
template <class ELFT, class RelTy>
-static RelExpr processRelocAux(InputSectionBase &Sec, RelExpr Expr,
- RelType Type, uint64_t Offset, Symbol &Sym,
- const RelTy &Rel, int64_t Addend) {
+static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type,
+ uint64_t Offset, Symbol &Sym, const RelTy &Rel,
+ int64_t Addend) {
if (isStaticLinkTimeConstant(Expr, Type, Sym, Sec, Offset)) {
Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
- return Expr;
+ return;
}
bool CanWrite = (Sec.Flags & SHF_WRITE) || !Config->ZText;
if (CanWrite) {
@@ -777,10 +796,9 @@
if (!IsPreemptibleValue) {
InX::RelaDyn->addReloc(Target->RelativeRel, &Sec, Offset, &Sym, Addend,
Expr, Type);
- return Expr;
- } else if (Target->isPicRel(Type)) {
- InX::RelaDyn->addReloc(Target->getDynRel(Type), &Sec, Offset, &Sym,
- Addend, R_ADDEND, Type);
+ return;
+ } else if (RelType Rel = Target->getDynRel(Type)) {
+ InX::RelaDyn->addReloc(Rel, &Sec, Offset, &Sym, Addend, R_ADDEND, Type);
// MIPS ABI turns using of GOT and dynamic relocations inside out.
// While regular ABI uses dynamic relocations to fill up GOT entries
@@ -799,7 +817,7 @@
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19
if (Config->EMachine == EM_MIPS)
InX::MipsGot->addEntry(Sym, Addend, Expr);
- return Expr;
+ return;
}
}
@@ -807,7 +825,7 @@
// executable, give up on it and produce a non preemptible 0.
if (!Config->Shared && Sym.isUndefWeak()) {
Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
- return Expr;
+ return;
}
if (!CanWrite && (Config->Pic && !isRelExpr(Expr))) {
@@ -817,7 +835,7 @@
" in readonly segment; recompile object files with -fPIC "
"or pass '-Wl,-z,notext' to allow text relocations in the output" +
getLocation(Sec, Sym, Offset));
- return Expr;
+ return;
}
// Copy relocations are only possible if we are creating an executable.
@@ -825,34 +843,31 @@
errorOrWarn("relocation " + toString(Type) +
" cannot be used against symbol " + toString(Sym) +
"; recompile with -fPIC" + getLocation(Sec, Sym, Offset));
- return Expr;
+ return;
}
// If the symbol is undefined we already reported any relevant errors.
- if (!Sym.isShared()) {
- assert(Sym.isUndefined());
- return Expr;
- }
+ if (Sym.isUndefined())
+ return;
if (!canDefineSymbolInExecutable(Sym)) {
error("cannot preempt symbol: " + toString(Sym) +
getLocation(Sec, Sym, Offset));
- return Expr;
+ return;
}
if (Sym.isObject()) {
// Produce a copy relocation.
- auto &SS = cast<SharedSymbol>(Sym);
- if (!SS.CopyRelSec) {
- if (Config->ZNocopyreloc)
+ if (auto *SS = dyn_cast<SharedSymbol>(&Sym)) {
+ if (!Config->ZCopyreloc)
error("unresolvable relocation " + toString(Type) +
- " against symbol '" + toString(SS) +
+ " against symbol '" + toString(*SS) +
"'; recompile with -fPIC or remove '-z nocopyreloc'" +
getLocation(Sec, Sym, Offset));
- addCopyRelSymbol<ELFT>(SS);
+ addCopyRelSymbol<ELFT>(*SS);
}
Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
- return Expr;
+ return;
}
if (Sym.isFunc()) {
@@ -887,15 +902,18 @@
errorOrWarn("symbol '" + toString(Sym) +
"' cannot be preempted; recompile with -fPIE" +
getLocation(Sec, Sym, Offset));
+ if (!Sym.isInPlt())
+ addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel,
+ Sym);
+ if (!Sym.isDefined())
+ replaceWithDefined(Sym, InX::Plt, Sym.getPltOffset(), 0);
Sym.NeedsPltAddr = true;
- Expr = toPlt(Expr);
Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
- return Expr;
+ return;
}
errorOrWarn("symbol '" + toString(Sym) + "' has no type" +
getLocation(Sec, Sym, Offset));
- return Expr;
}
template <class ELFT, class RelTy>
@@ -964,7 +982,6 @@
return;
}
- Expr = processRelocAux<ELFT>(Sec, Expr, Type, Offset, Sym, Rel, Addend);
// If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol.
if (needsPlt(Expr) && !Sym.isInPlt()) {
if (Sym.isGnuIFunc() && !Sym.IsPreemptible)
@@ -993,6 +1010,8 @@
addGotEntry<ELFT>(Sym);
}
}
+
+ processRelocAux<ELFT>(Sec, Expr, Type, Offset, Sym, Rel, Addend);
}
template <class ELFT, class RelTy>
diff --git a/ELF/Relocations.h b/ELF/Relocations.h
index 69afe31..3a930d9 100644
--- a/ELF/Relocations.h
+++ b/ELF/Relocations.h
@@ -59,8 +59,8 @@
R_PLT,
R_PLT_PAGE_PC,
R_PLT_PC,
- R_PPC_OPD,
- R_PPC_PLT_OPD,
+ R_PPC_CALL,
+ R_PPC_CALL_PLT,
R_PPC_TOC,
R_RELAX_GOT_PC,
R_RELAX_GOT_PC_NOPIC,
@@ -77,9 +77,11 @@
R_TLSDESC,
R_TLSDESC_CALL,
R_TLSDESC_PAGE,
- R_TLSGD,
+ R_TLSGD_GOT,
+ R_TLSGD_GOT_FROM_END,
R_TLSGD_PC,
- R_TLSLD,
+ R_TLSLD_GOT_FROM_END,
+ R_TLSLD_GOT,
R_TLSLD_PC,
};
diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp
index ff650d8..707e104 100644
--- a/ELF/ScriptParser.cpp
+++ b/ELF/ScriptParser.cpp
@@ -63,6 +63,7 @@
void readExtern();
void readGroup();
void readInclude();
+ void readInput();
void readMemory();
void readOutput();
void readOutputArch();
@@ -74,7 +75,7 @@
void readVersion();
void readVersionScriptCommand();
- SymbolAssignment *readAssignment(StringRef Name);
+ SymbolAssignment *readSymbolAssignment(StringRef Name);
ByteCommand *readByteCommand(StringRef Tok);
uint32_t readFill();
uint32_t parseFill(StringRef Tok);
@@ -88,10 +89,9 @@
unsigned readPhdrType();
SortSectionPolicy readSortKind();
SymbolAssignment *readProvideHidden(bool Provide, bool Hidden);
- SymbolAssignment *readProvideOrAssignment(StringRef Tok);
+ SymbolAssignment *readAssignment(StringRef Tok);
void readSort();
- AssertCommand *readAssert();
- Expr readAssertExpr();
+ Expr readAssert();
Expr readConstant();
Expr getPageSize();
@@ -227,16 +227,16 @@
if (Tok == ";")
continue;
- if (Tok == "ASSERT") {
- Script->SectionCommands.push_back(readAssert());
- } else if (Tok == "ENTRY") {
+ if (Tok == "ENTRY") {
readEntry();
} else if (Tok == "EXTERN") {
readExtern();
- } else if (Tok == "GROUP" || Tok == "INPUT") {
+ } else if (Tok == "GROUP") {
readGroup();
} else if (Tok == "INCLUDE") {
readInclude();
+ } else if (Tok == "INPUT") {
+ readInput();
} else if (Tok == "MEMORY") {
readMemory();
} else if (Tok == "OUTPUT") {
@@ -255,7 +255,7 @@
readSections();
} else if (Tok == "VERSION") {
readVersion();
- } else if (SymbolAssignment *Cmd = readProvideOrAssignment(Tok)) {
+ } else if (SymbolAssignment *Cmd = readAssignment(Tok)) {
Script->SectionCommands.push_back(Cmd);
} else {
setError("unknown directive: " + Tok);
@@ -267,8 +267,7 @@
Expr E = readExpr();
if (!atEOF())
setError("EOF expected, but got " + next());
- SymbolAssignment *Cmd = make<SymbolAssignment>(Name, E, getCurrentLocation(),
- "" /*CommandString*/);
+ SymbolAssignment *Cmd = make<SymbolAssignment>(Name, E, getCurrentLocation());
Script->SectionCommands.push_back(Cmd);
}
@@ -327,13 +326,12 @@
}
void ScriptParser::readGroup() {
- expect("(");
- while (!errorCount() && !consume(")")) {
- if (consume("AS_NEEDED"))
- readAsNeeded();
- else
- addFile(unquote(next()));
- }
+ bool Orig = InputFile::IsInGroup;
+ InputFile::IsInGroup = true;
+ readInput();
+ InputFile::IsInGroup = Orig;
+ if (!Orig)
+ ++InputFile::NextGroupId;
}
void ScriptParser::readInclude() {
@@ -352,6 +350,16 @@
setError("cannot find linker script " + Tok);
}
+void ScriptParser::readInput() {
+ expect("(");
+ while (!errorCount() && !consume(")")) {
+ if (consume("AS_NEEDED"))
+ readAsNeeded();
+ else
+ addFile(unquote(next()));
+ }
+}
+
void ScriptParser::readOutput() {
// -o <file> takes predecence over OUTPUT(<file>).
expect("(");
@@ -440,14 +448,10 @@
std::vector<BaseCommand *> V;
while (!errorCount() && !consume("}")) {
StringRef Tok = next();
- BaseCommand *Cmd = readProvideOrAssignment(Tok);
- if (!Cmd) {
- if (Tok == "ASSERT")
- Cmd = readAssert();
- else
- Cmd = readOutputSectionDescription(Tok);
- }
- V.push_back(Cmd);
+ if (BaseCommand *Cmd = readAssignment(Tok))
+ V.push_back(Cmd);
+ else
+ V.push_back(readOutputSectionDescription(Tok));
}
if (!atEOF() && consume("INSERT")) {
@@ -597,11 +601,7 @@
expect(")");
}
-AssertCommand *ScriptParser::readAssert() {
- return make<AssertCommand>(readAssertExpr());
-}
-
-Expr ScriptParser::readAssertExpr() {
+Expr ScriptParser::readAssert() {
expect("(");
Expr E = readExpr();
expect(",");
@@ -702,13 +702,10 @@
StringRef Tok = next();
if (Tok == ";") {
// Empty commands are allowed. Do nothing here.
- } else if (SymbolAssignment *Assign = readProvideOrAssignment(Tok)) {
+ } else if (SymbolAssignment *Assign = readAssignment(Tok)) {
Cmd->SectionCommands.push_back(Assign);
} else if (ByteCommand *Data = readByteCommand(Tok)) {
Cmd->SectionCommands.push_back(Data);
- } else if (Tok == "ASSERT") {
- Cmd->SectionCommands.push_back(readAssert());
- expect(";");
} else if (Tok == "CONSTRUCTORS") {
// CONSTRUCTORS is a keyword to make the linker recognize C++ ctors/dtors
// by name. This is for very old file formats such as ECOFF/XCOFF.
@@ -769,31 +766,39 @@
SymbolAssignment *ScriptParser::readProvideHidden(bool Provide, bool Hidden) {
expect("(");
- SymbolAssignment *Cmd = readAssignment(next());
+ SymbolAssignment *Cmd = readSymbolAssignment(next());
Cmd->Provide = Provide;
Cmd->Hidden = Hidden;
expect(")");
- expect(";");
return Cmd;
}
-SymbolAssignment *ScriptParser::readProvideOrAssignment(StringRef Tok) {
+SymbolAssignment *ScriptParser::readAssignment(StringRef Tok) {
+ // Assert expression returns Dot, so this is equal to ".=."
+ if (Tok == "ASSERT")
+ return make<SymbolAssignment>(".", readAssert(), getCurrentLocation());
+
+ size_t OldPos = Pos;
SymbolAssignment *Cmd = nullptr;
- if (peek() == "=" || peek() == "+=") {
- Cmd = readAssignment(Tok);
- expect(";");
- } else if (Tok == "PROVIDE") {
+ if (peek() == "=" || peek() == "+=")
+ Cmd = readSymbolAssignment(Tok);
+ else if (Tok == "PROVIDE")
Cmd = readProvideHidden(true, false);
- } else if (Tok == "HIDDEN") {
+ else if (Tok == "HIDDEN")
Cmd = readProvideHidden(false, true);
- } else if (Tok == "PROVIDE_HIDDEN") {
+ else if (Tok == "PROVIDE_HIDDEN")
Cmd = readProvideHidden(true, true);
+
+ if (Cmd) {
+ Cmd->CommandString =
+ Tok.str() + " " +
+ llvm::join(Tokens.begin() + OldPos, Tokens.begin() + Pos, " ");
+ expect(";");
}
return Cmd;
}
-SymbolAssignment *ScriptParser::readAssignment(StringRef Name) {
- size_t OldPos = Pos;
+SymbolAssignment *ScriptParser::readSymbolAssignment(StringRef Name) {
StringRef Op = next();
assert(Op == "=" || Op == "+=");
Expr E = readExpr();
@@ -801,11 +806,7 @@
std::string Loc = getCurrentLocation();
E = [=] { return add(Script->getSymbolValue(Name, Loc), E()); };
}
-
- std::string CommandString =
- Name.str() + " " +
- llvm::join(Tokens.begin() + OldPos, Tokens.begin() + Pos, " ");
- return make<SymbolAssignment>(Name, E, getCurrentLocation(), CommandString);
+ return make<SymbolAssignment>(Name, E, getCurrentLocation());
}
// This is an operator-precedence parser to parse a linker
@@ -1046,7 +1047,7 @@
};
}
if (Tok == "ASSERT")
- return readAssertExpr();
+ return readAssert();
if (Tok == "CONSTANT")
return readConstant();
if (Tok == "DATA_SEGMENT_ALIGN") {
diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp
index 40c7d7f..00c7f74 100644
--- a/ELF/SymbolTable.cpp
+++ b/ELF/SymbolTable.cpp
@@ -82,6 +82,7 @@
// Lazy object file
if (auto *F = dyn_cast<LazyObjFile>(File)) {
+ LazyObjFiles.push_back(F);
F->parse<ELFT>();
return;
}
@@ -296,26 +297,88 @@
uint8_t Visibility = getVisibility(StOther);
std::tie(S, WasInserted) =
insert(Name, Type, Visibility, CanOmitFromDynSym, File);
+
// An undefined symbol with non default visibility must be satisfied
// in the same DSO.
if (WasInserted || (isa<SharedSymbol>(S) && Visibility != STV_DEFAULT)) {
replaceSymbol<Undefined>(S, File, Name, Binding, StOther, Type);
return S;
}
+
if (S->isShared() || S->isLazy() || (S->isUndefined() && Binding != STB_WEAK))
S->Binding = Binding;
- if (Binding != STB_WEAK) {
+
+ if (!Config->GcSections && Binding != STB_WEAK)
if (auto *SS = dyn_cast<SharedSymbol>(S))
- if (!Config->GcSections)
- SS->getFile<ELFT>().IsNeeded = true;
- }
- if (auto *L = dyn_cast<Lazy>(S)) {
+ SS->getFile<ELFT>().IsNeeded = true;
+
+ if (S->isLazy()) {
// An undefined weak will not fetch archive members. See comment on Lazy in
// Symbols.h for the details.
- if (Binding == STB_WEAK)
- L->Type = Type;
- else if (InputFile *F = L->fetch())
- addFile<ELFT>(F);
+ if (Binding == STB_WEAK) {
+ S->Type = Type;
+ return S;
+ }
+
+ // Do extra check for --warn-backrefs.
+ //
+ // --warn-backrefs is an option to prevent an undefined reference from
+ // fetching an archive member written earlier in the command line. It can be
+ // used to keep compatibility with GNU linkers to some degree.
+ // I'll explain the feature and why you may find it useful in this comment.
+ //
+ // lld's symbol resolution semantics is more relaxed than traditional Unix
+ // linkers. For example,
+ //
+ // ld.lld foo.a bar.o
+ //
+ // succeeds even if bar.o contains an undefined symbol that has to be
+ // resolved by some object file in foo.a. Traditional Unix linkers don't
+ // allow this kind of backward reference, as they visit each file only once
+ // from left to right in the command line while resolving all undefined
+ // symbols at the moment of visiting.
+ //
+ // In the above case, since there's no undefined symbol when a linker visits
+ // foo.a, no files are pulled out from foo.a, and because the linker forgets
+ // about foo.a after visiting, it can't resolve undefined symbols in bar.o
+ // that could have been resolved otherwise.
+ //
+ // That lld accepts more relaxed form means that (besides it'd make more
+ // sense) you can accidentally write a command line or a build file that
+ // works only with lld, even if you have a plan to distribute it to wider
+ // users who may be using GNU linkers. With --warn-backrefs, you can detect
+ // a library order that doesn't work with other Unix linkers.
+ //
+ // The option is also useful to detect cyclic dependencies between static
+ // archives. Again, lld accepts
+ //
+ // ld.lld foo.a bar.a
+ //
+ // even if foo.a and bar.a depend on each other. With --warn-backrefs, it is
+ // handled as an error.
+ //
+ // Here is how the option works. We assign a group ID to each file. A file
+ // with a smaller group ID can pull out object files from an archive file
+ // with an equal or greater group ID. Otherwise, it is a reverse dependency
+ // and an error.
+ //
+ // A file outside --{start,end}-group gets a fresh ID when instantiated. All
+ // files within the same --{start,end}-group get the same group ID. E.g.
+ //
+ // ld.lld A B --start-group C D --end-group E
+ //
+ // A forms group 0. B form group 1. C and D (including their member object
+ // files) form group 2. E forms group 3. I think that you can see how this
+ // group assignment rule simulates the traditional linker's semantics.
+ bool Backref =
+ Config->WarnBackrefs && File && S->File->GroupId < File->GroupId;
+ fetchLazy<ELFT>(S);
+
+ // We don't report backward references to weak symbols as they can be
+ // overridden later.
+ if (Backref && S->Binding != STB_WEAK)
+ warn("backward reference detected: " + Name + " in " + toString(File) +
+ " refers to " + toString(S->File));
}
return S;
}
@@ -383,7 +446,11 @@
bool WasInserted;
std::tie(S, WasInserted) = insert(N, Type, getVisibility(StOther),
/*CanOmitFromDynSym*/ false, &File);
+
int Cmp = compareDefined(S, WasInserted, Binding, N);
+ if (Cmp < 0)
+ return S;
+
if (Cmp > 0) {
auto *Bss = make<BssSection>("COMMON", Size, Alignment);
Bss->File = &File;
@@ -391,24 +458,25 @@
InputSections.push_back(Bss);
replaceSymbol<Defined>(S, &File, N, Binding, StOther, Type, 0, Size, Bss);
- } else if (Cmp == 0) {
- auto *D = cast<Defined>(S);
- auto *Bss = dyn_cast_or_null<BssSection>(D->Section);
- if (!Bss) {
- // Non-common symbols take precedence over common symbols.
- if (Config->WarnCommon)
- warn("common " + S->getName() + " is overridden");
- return S;
- }
+ return S;
+ }
+ auto *D = cast<Defined>(S);
+ auto *Bss = dyn_cast_or_null<BssSection>(D->Section);
+ if (!Bss) {
+ // Non-common symbols take precedence over common symbols.
if (Config->WarnCommon)
- warn("multiple common of " + D->getName());
+ warn("common " + S->getName() + " is overridden");
+ return S;
+ }
- Bss->Alignment = std::max(Bss->Alignment, Alignment);
- if (Size > Bss->Size) {
- D->File = Bss->File = &File;
- D->Size = Bss->Size = Size;
- }
+ if (Config->WarnCommon)
+ warn("multiple common of " + D->getName());
+
+ Bss->Alignment = std::max(Bss->Alignment, Alignment);
+ if (Size > Bss->Size) {
+ D->File = Bss->File = &File;
+ D->Size = Bss->Size = Size;
}
return S;
}
@@ -528,14 +596,18 @@
return SymVector[It->second];
}
-template <class ELFT>
-void SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &F,
- const object::Archive::Symbol Sym) {
+// This is used to handle lazy symbols. May replace existent
+// symbol with lazy version or request to Fetch it.
+template <class ELFT, typename LazyT, typename... ArgT>
+static void replaceOrFetchLazy(StringRef Name, InputFile &File,
+ llvm::function_ref<InputFile *()> Fetch,
+ ArgT &&... Arg) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
+ std::tie(S, WasInserted) = Symtab->insert(Name);
if (WasInserted) {
- replaceSymbol<LazyArchive>(S, F, Sym, Symbol::UnknownType);
+ replaceSymbol<LazyT>(S, File, Symbol::UnknownType,
+ std::forward<ArgT>(Arg)...);
return;
}
if (!S->isUndefined())
@@ -544,47 +616,38 @@
// An undefined weak will not fetch archive members. See comment on Lazy in
// Symbols.h for the details.
if (S->isWeak()) {
- replaceSymbol<LazyArchive>(S, F, Sym, S->Type);
+ replaceSymbol<LazyT>(S, File, S->Type, std::forward<ArgT>(Arg)...);
S->Binding = STB_WEAK;
return;
}
- std::pair<MemoryBufferRef, uint64_t> MBInfo = F.getMember(&Sym);
- if (!MBInfo.first.getBuffer().empty())
- addFile<ELFT>(createObjectFile(MBInfo.first, F.getName(), MBInfo.second));
+
+ if (InputFile *F = Fetch())
+ Symtab->addFile<ELFT>(F);
+}
+
+template <class ELFT>
+void SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &F,
+ const object::Archive::Symbol Sym) {
+ replaceOrFetchLazy<ELFT, LazyArchive>(Name, F, [&]() { return F.fetch(Sym); },
+ Sym);
}
template <class ELFT>
void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &Obj) {
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
- if (WasInserted) {
- replaceSymbol<LazyObject>(S, Obj, Name, Symbol::UnknownType);
- return;
- }
- if (!S->isUndefined())
- return;
-
- // See comment for addLazyArchive above.
- if (S->isWeak()) {
- replaceSymbol<LazyObject>(S, Obj, Name, S->Type);
- S->Binding = STB_WEAK;
- return;
- }
- if (InputFile *F = Obj.fetch())
- addFile<ELFT>(F);
+ replaceOrFetchLazy<ELFT, LazyObject>(Name, Obj, [&]() { return Obj.fetch(); },
+ Name);
}
-// If we already saw this symbol, force loading its file.
-template <class ELFT> void SymbolTable::fetchIfLazy(StringRef Name) {
- if (Symbol *B = find(Name)) {
- // Mark the symbol not to be eliminated by LTO
- // even if it is a bitcode symbol.
- B->IsUsedInRegularObj = true;
- if (auto *L = dyn_cast<Lazy>(B))
- if (InputFile *File = L->fetch())
- addFile<ELFT>(File);
+template <class ELFT> void SymbolTable::fetchLazy(Symbol *Sym) {
+ if (auto *S = dyn_cast<LazyArchive>(Sym)) {
+ if (InputFile *File = S->fetch())
+ addFile<ELFT>(File);
+ return;
}
+
+ auto *S = cast<LazyObject>(Sym);
+ if (InputFile *File = cast<LazyObjFile>(S->File)->fetch())
+ addFile<ELFT>(File);
}
// Initialize DemangledSyms with a map from demangled symbols to symbol
@@ -795,6 +858,11 @@
template void SymbolTable::addLazyObject<ELF64LE>(StringRef, LazyObjFile &);
template void SymbolTable::addLazyObject<ELF64BE>(StringRef, LazyObjFile &);
+template void SymbolTable::fetchLazy<ELF32LE>(Symbol *);
+template void SymbolTable::fetchLazy<ELF32BE>(Symbol *);
+template void SymbolTable::fetchLazy<ELF64LE>(Symbol *);
+template void SymbolTable::fetchLazy<ELF64BE>(Symbol *);
+
template void SymbolTable::addShared<ELF32LE>(StringRef, SharedFile<ELF32LE> &,
const typename ELF32LE::Sym &,
uint32_t Alignment, uint32_t);
@@ -807,8 +875,3 @@
template void SymbolTable::addShared<ELF64BE>(StringRef, SharedFile<ELF64BE> &,
const typename ELF64BE::Sym &,
uint32_t Alignment, uint32_t);
-
-template void SymbolTable::fetchIfLazy<ELF32LE>(StringRef);
-template void SymbolTable::fetchIfLazy<ELF32BE>(StringRef);
-template void SymbolTable::fetchIfLazy<ELF64LE>(StringRef);
-template void SymbolTable::fetchIfLazy<ELF64BE>(StringRef);
diff --git a/ELF/SymbolTable.h b/ELF/SymbolTable.h
index 7937a2a..5e6d44d 100644
--- a/ELF/SymbolTable.h
+++ b/ELF/SymbolTable.h
@@ -77,7 +77,8 @@
uint8_t Visibility, bool CanOmitFromDynSym,
InputFile *File);
- template <class ELFT> void fetchIfLazy(StringRef Name);
+ template <class ELFT> void fetchLazy(Symbol *Sym);
+
void scanVersionScript();
Symbol *find(StringRef Name);
diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp
index 8ac3e5f..f2f9ae0 100644
--- a/ELF/Symbols.cpp
+++ b/ELF/Symbols.cpp
@@ -38,6 +38,7 @@
Defined *ElfSym::MipsGp;
Defined *ElfSym::MipsGpDisp;
Defined *ElfSym::MipsLocalGp;
+Defined *ElfSym::RelaIpltEnd;
static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
switch (Sym.kind()) {
@@ -56,6 +57,8 @@
if (!IS)
return D.Value;
+ IS = IS->Repl;
+
uint64_t Offset = D.Value;
// An object in an SHF_MERGE section might be referenced via a
@@ -94,20 +97,12 @@
}
return VA;
}
- case Symbol::SharedKind: {
- auto &SS = cast<SharedSymbol>(Sym);
- if (SS.CopyRelSec)
- return SS.CopyRelSec->getVA(0);
- if (SS.NeedsPltAddr)
- return Sym.getPltVA();
- return 0;
- }
+ case Symbol::SharedKind:
case Symbol::UndefinedKind:
return 0;
case Symbol::LazyArchiveKind:
case Symbol::LazyObjectKind:
- assert(Sym.IsUsedInRegularObj && "lazy symbol reached writer");
- return 0;
+ llvm_unreachable("lazy symbol reached writer");
}
llvm_unreachable("invalid symbol kind");
}
@@ -130,7 +125,9 @@
}
uint64_t Symbol::getGotPltOffset() const {
- return GotPltIndex * Target->GotPltEntrySize;
+ if (IsInIgot)
+ return PltIndex * Target->GotPltEntrySize;
+ return (PltIndex + Target->GotPltHeaderEntriesNum) * Target->GotPltEntrySize;
}
uint64_t Symbol::getPltVA() const {
@@ -139,6 +136,11 @@
return InX::Plt->getVA() + Target->getPltEntryOffset(PltIndex);
}
+uint64_t Symbol::getPltOffset() const {
+ assert(!this->IsInIplt);
+ return Target->getPltEntryOffset(PltIndex);
+}
+
uint64_t Symbol::getSize() const {
if (const auto *DR = dyn_cast<Defined>(this))
return DR->Size;
@@ -150,16 +152,9 @@
OutputSection *Symbol::getOutputSection() const {
if (auto *S = dyn_cast<Defined>(this)) {
if (auto *Sec = S->Section)
- return Sec->getOutputSection();
+ return Sec->Repl->getOutputSection();
return nullptr;
}
-
- if (auto *S = dyn_cast<SharedSymbol>(this)) {
- if (S->CopyRelSec)
- return S->CopyRelSec->getParent();
- return nullptr;
- }
-
return nullptr;
}
@@ -175,7 +170,7 @@
return;
// Truncate the symbol name so that it doesn't include the version string.
- Name = {S.data(), Pos};
+ NameSize = Pos;
// If this is not in this DSO, it is not a definition.
if (!isDefined())
@@ -201,33 +196,15 @@
// It is an error if the specified version is not defined.
// Usually version script is not provided when linking executable,
// but we may still want to override a versioned symbol from DSO,
- // so we do not report error in this case.
- if (Config->Shared)
+ // so we do not report error in this case. We also do not error
+ // if the symbol has a local version as it won't be in the dynamic
+ // symbol table.
+ if (Config->Shared && VersionId != VER_NDX_LOCAL)
error(toString(File) + ": symbol " + S + " has undefined version " +
Verstr);
}
-InputFile *Lazy::fetch() {
- if (auto *S = dyn_cast<LazyArchive>(this))
- return S->fetch();
- return cast<LazyObject>(this)->fetch();
-}
-
-ArchiveFile &LazyArchive::getFile() { return *cast<ArchiveFile>(File); }
-
-InputFile *LazyArchive::fetch() {
- std::pair<MemoryBufferRef, uint64_t> MBInfo = getFile().getMember(&Sym);
-
- // getMember returns an empty buffer if the member was already
- // read from the library.
- if (MBInfo.first.getBuffer().empty())
- return nullptr;
- return createObjectFile(MBInfo.first, getFile().getName(), MBInfo.second);
-}
-
-LazyObjFile &LazyObject::getFile() { return *cast<LazyObjFile>(File); }
-
-InputFile *LazyObject::fetch() { return getFile().fetch(); }
+InputFile *LazyArchive::fetch() { return cast<ArchiveFile>(File)->fetch(Sym); }
uint8_t Symbol::computeBinding() const {
if (Config->Relocatable)
@@ -268,6 +245,27 @@
message(toString(Sym->File) + S + Sym->getName());
}
+void elf::warnUnorderableSymbol(const Symbol *Sym) {
+ if (!Config->WarnSymbolOrdering)
+ return;
+
+ const InputFile *File = Sym->File;
+ auto *D = dyn_cast<Defined>(Sym);
+
+ auto Warn = [&](StringRef S) { warn(toString(File) + S + Sym->getName()); };
+
+ if (Sym->isUndefined())
+ Warn(": unable to order undefined symbol: ");
+ else if (Sym->isShared())
+ Warn(": unable to order shared symbol: ");
+ else if (D && !D->Section)
+ Warn(": unable to order absolute symbol: ");
+ else if (D && isa<OutputSection>(D->Section))
+ Warn(": unable to order synthetic symbol: ");
+ else if (D && !D->Section->Repl->Live)
+ Warn(": unable to order discarded symbol: ");
+}
+
// Returns a symbol for an error message.
std::string lld::toString(const Symbol &B) {
if (Config->Demangle)
diff --git a/ELF/Symbols.h b/ELF/Symbols.h
index bef5897..f0912d2 100644
--- a/ELF/Symbols.h
+++ b/ELF/Symbols.h
@@ -7,8 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// All symbols are handled as SymbolBodies regardless of their types.
-// This file defines various types of SymbolBodies.
+// This file defines various types of Symbols.
//
//===----------------------------------------------------------------------===//
@@ -33,6 +32,20 @@
class OutputSection;
template <class ELFT> class SharedFile;
+// This is a StringRef-like container that doesn't run strlen().
+//
+// ELF string tables contain a lot of null-terminated strings. Most of them
+// are not necessary for the linker because they are names of local symbols,
+// and the linker doesn't use local symbol names for name resolution. So, we
+// use this class to represents strings read from string tables.
+struct StringRefZ {
+ StringRefZ(const char *S) : Data(S), Size(-1) {}
+ StringRefZ(StringRef S) : Data(S.data()), Size(S.size()) {}
+
+ const char *Data;
+ const uint32_t Size;
+};
+
// The base class for real symbol classes.
class Symbol {
public:
@@ -46,6 +59,25 @@
Kind kind() const { return static_cast<Kind>(SymbolKind); }
+ // The file from which this symbol was created.
+ InputFile *File;
+
+protected:
+ const char *NameData;
+ mutable uint32_t NameSize;
+
+public:
+ uint32_t DynsymIndex = 0;
+ uint32_t GotIndex = -1;
+ uint32_t PltIndex = -1;
+ uint32_t GlobalDynIndex = -1;
+
+ // This field is a index to the symbol's version definition.
+ uint32_t VerdefIndex = -1;
+
+ // Version definition index.
+ uint16_t VersionId;
+
// Symbol binding. This is not overwritten by replaceSymbol to track
// changes during resolution. In particular:
// - An undefined weak is still weak when it resolves to a shared library.
@@ -53,8 +85,11 @@
// remember it is weak.
uint8_t Binding;
- // Version definition index.
- uint16_t VersionId;
+ // The following fields have the same meaning as the ELF symbol attributes.
+ uint8_t Type; // symbol type
+ uint8_t StOther; // st_other field value
+
+ const uint8_t SymbolKind;
// Symbol visibility. This is the computed minimum visibility of all
// observed non-DSO symbols.
@@ -80,9 +115,6 @@
// True if this symbol is specified by --trace-symbol option.
unsigned Traced : 1;
- // The file from which this symbol was created.
- InputFile *File;
-
bool includeInDynsym() const;
uint8_t computeBinding() const;
bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; }
@@ -96,14 +128,15 @@
return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind;
}
- // True if this is an undefined weak symbol. This only works once
- // all input files have been added.
- bool isUndefWeak() const {
- // See comment on Lazy for details.
- return isWeak() && (isUndefined() || isLazy());
+ // True if this is an undefined weak symbol.
+ bool isUndefWeak() const { return isWeak() && isUndefined(); }
+
+ StringRef getName() const {
+ if (NameSize == (uint32_t)-1)
+ NameSize = strlen(NameData);
+ return {NameData, NameSize};
}
- StringRef getName() const { return Name; }
void parseSymbolVersion();
bool isInGot() const { return GotIndex != -1U; }
@@ -116,24 +149,18 @@
uint64_t getGotPltOffset() const;
uint64_t getGotPltVA() const;
uint64_t getPltVA() const;
+ uint64_t getPltOffset() const;
uint64_t getSize() const;
OutputSection *getOutputSection() const;
- uint32_t DynsymIndex = 0;
- uint32_t GotIndex = -1;
- uint32_t GotPltIndex = -1;
- uint32_t PltIndex = -1;
- uint32_t GlobalDynIndex = -1;
-
protected:
Symbol(Kind K, InputFile *File, StringRefZ Name, uint8_t Binding,
uint8_t StOther, uint8_t Type)
- : Binding(Binding), File(File), SymbolKind(K), NeedsPltAddr(false),
+ : File(File), NameData(Name.Data), NameSize(Name.Size), Binding(Binding),
+ Type(Type), StOther(StOther), SymbolKind(K), NeedsPltAddr(false),
IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false),
IsInIgot(false), IsPreemptible(false), Used(!Config->GcSections),
- Type(Type), StOther(StOther), Name(Name) {}
-
- const unsigned SymbolKind : 8;
+ NeedsTocRestore(false) {}
public:
// True the symbol should point to its PLT entry.
@@ -157,9 +184,9 @@
// True if an undefined or shared symbol is used from a live section.
unsigned Used : 1;
- // The following fields have the same meaning as the ELF symbol attributes.
- uint8_t Type; // symbol type
- uint8_t StOther; // st_other field value
+ // True if a call to this symbol needs to be followed by a restore of the
+ // PPC64 toc pointer.
+ unsigned NeedsTocRestore : 1;
// The Type field may also have this value. It means that we have not yet seen
// a non-Lazy symbol with this name, so we don't know what its type is. The
@@ -174,9 +201,6 @@
bool isGnuIFunc() const { return Type == llvm::ELF::STT_GNU_IFUNC; }
bool isObject() const { return Type == llvm::ELF::STT_OBJECT; }
bool isFile() const { return Type == llvm::ELF::STT_FILE; }
-
-protected:
- StringRefZ Name;
};
// Represents a symbol that is defined in the current output file.
@@ -210,8 +234,9 @@
SharedSymbol(InputFile &File, StringRef Name, uint8_t Binding,
uint8_t StOther, uint8_t Type, uint64_t Value, uint64_t Size,
uint32_t Alignment, uint32_t VerdefIndex)
- : Symbol(SharedKind, &File, Name, Binding, StOther, Type), Value(Value),
- Size(Size), VerdefIndex(VerdefIndex), Alignment(Alignment) {
+ : Symbol(SharedKind, &File, Name, Binding, StOther, Type),
+ Alignment(Alignment), Value(Value), Size(Size) {
+ this->VerdefIndex = VerdefIndex;
// GNU ifunc is a mechanism to allow user-supplied functions to
// resolve PLT slot values at load-time. This is contrary to the
// regular symbol resolution scheme in which symbols are resolved just
@@ -236,54 +261,36 @@
return *cast<SharedFile<ELFT>>(File);
}
- // If not null, there is a copy relocation to this section.
- InputSection *CopyRelSec = nullptr;
+ uint32_t Alignment;
uint64_t Value; // st_value
uint64_t Size; // st_size
-
- // This field is a index to the symbol's version definition.
- uint32_t VerdefIndex;
-
- uint32_t Alignment;
};
-// This represents a symbol that is not yet in the link, but we know where to
-// find it if needed. If the resolver finds both Undefined and Lazy for the same
-// name, it will ask the Lazy to load a file.
+// LazyArchive and LazyObject represent a symbols that is not yet in the link,
+// but we know where to find it if needed. If the resolver finds both Undefined
+// and Lazy for the same name, it will ask the Lazy to load a file.
//
// A special complication is the handling of weak undefined symbols. They should
// not load a file, but we have to remember we have seen both the weak undefined
// and the lazy. We represent that with a lazy symbol with a weak binding. This
// means that code looking for undefined symbols normally also has to take lazy
// symbols into consideration.
-class Lazy : public Symbol {
-public:
- static bool classof(const Symbol *S) { return S->isLazy(); }
-
- // Returns an object file for this symbol, or a nullptr if the file
- // was already returned.
- InputFile *fetch();
-
-protected:
- Lazy(Kind K, InputFile &File, StringRef Name, uint8_t Type)
- : Symbol(K, &File, Name, llvm::ELF::STB_GLOBAL, llvm::ELF::STV_DEFAULT,
- Type) {}
-};
// This class represents a symbol defined in an archive file. It is
// created from an archive file header, and it knows how to load an
// object file from an archive to replace itself with a defined
// symbol.
-class LazyArchive : public Lazy {
+class LazyArchive : public Symbol {
public:
- LazyArchive(InputFile &File, const llvm::object::Archive::Symbol S,
- uint8_t Type)
- : Lazy(LazyArchiveKind, File, S.getName(), Type), Sym(S) {}
+ LazyArchive(InputFile &File, uint8_t Type,
+ const llvm::object::Archive::Symbol S)
+ : Symbol(LazyArchiveKind, &File, S.getName(), llvm::ELF::STB_GLOBAL,
+ llvm::ELF::STV_DEFAULT, Type),
+ Sym(S) {}
static bool classof(const Symbol *S) { return S->kind() == LazyArchiveKind; }
- ArchiveFile &getFile();
InputFile *fetch();
private:
@@ -292,15 +299,13 @@
// LazyObject symbols represents symbols in object files between
// --start-lib and --end-lib options.
-class LazyObject : public Lazy {
+class LazyObject : public Symbol {
public:
- LazyObject(InputFile &File, StringRef Name, uint8_t Type)
- : Lazy(LazyObjectKind, File, Name, Type) {}
+ LazyObject(InputFile &File, uint8_t Type, StringRef Name)
+ : Symbol(LazyObjectKind, &File, Name, llvm::ELF::STB_GLOBAL,
+ llvm::ELF::STV_DEFAULT, Type) {}
static bool classof(const Symbol *S) { return S->kind() == LazyObjectKind; }
-
- LazyObjFile &getFile();
- InputFile *fetch();
};
// Some linker-generated symbols need to be created as
@@ -330,6 +335,9 @@
static Defined *MipsGp;
static Defined *MipsGpDisp;
static Defined *MipsLocalGp;
+
+ // __rela_iplt_end or __rel_iplt_end
+ static Defined *RelaIpltEnd;
};
// A buffer class that is large enough to hold any Symbol-derived
@@ -371,6 +379,8 @@
if (S->Traced)
printTraceSymbol(S);
}
+
+void warnUnorderableSymbol(const Symbol *Sym);
} // namespace elf
std::string toString(const elf::Symbol &B);
diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp
index 5c214d0..1c66bcb 100644
--- a/ELF/SyntheticSections.cpp
+++ b/ELF/SyntheticSections.cpp
@@ -56,12 +56,6 @@
constexpr size_t MergeNoTailSection::NumShards;
-uint64_t SyntheticSection::getVA() const {
- if (OutputSection *Sec = getParent())
- return Sec->Addr + OutSecOff;
- return 0;
-}
-
// Returns an LLD version string.
static ArrayRef<uint8_t> getVersion() {
// Check LLD_VERSION first for ease of testing.
@@ -190,8 +184,6 @@
auto *Opt = reinterpret_cast<const Elf_Mips_Options *>(D.data());
if (Opt->kind == ODK_REGINFO) {
- if (Config->Relocatable && Opt->getRegInfo().ri_gp_value)
- error(Filename + ": unsupported non-zero ri_gp_value");
Reginfo.ri_gprmask |= Opt->getRegInfo().ri_gprmask;
Sec->getFile<ELFT>()->MipsGp0 = Opt->getRegInfo().ri_gp_value;
break;
@@ -242,10 +234,8 @@
error(toString(Sec->File) + ": invalid size of .reginfo section");
return nullptr;
}
- auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->Data.data());
- if (Config->Relocatable && R->ri_gp_value)
- error(toString(Sec->File) + ": unsupported non-zero ri_gp_value");
+ auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->Data.data());
Reginfo.ri_gprmask |= R->ri_gprmask;
Sec->getFile<ELFT>()->MipsGp0 = R->ri_gp_value;
};
@@ -431,7 +421,7 @@
// one and associates FDEs to the CIE.
template <class ELFT, class RelTy>
void EhFrameSection::addSectionAux(EhInputSection *Sec, ArrayRef<RelTy> Rels) {
- DenseMap<size_t, CieRecord *> OffsetToCie;
+ OffsetToCie.clear();
for (EhSectionPiece &Piece : Sec->Pieces) {
// The empty record is the end marker.
if (Piece.Size == 4)
@@ -466,10 +456,6 @@
for (auto *DS : Sec->DependentSections)
DependentSections.push_back(DS);
- // .eh_frame is a sequence of CIE or FDE records. This function
- // splits it into pieces so that we can call
- // SplitInputSection::getSectionPiece on the section.
- Sec->split<ELFT>();
if (Sec->Pieces.empty())
return;
@@ -507,10 +493,10 @@
}
// The LSB standard does not allow a .eh_frame section with zero
- // Call Frame Information records. Therefore add a CIE record length
- // 0 as a terminator if this .eh_frame section is empty.
- if (Off == 0)
- Off = 4;
+ // Call Frame Information records. glibc unwind-dw2-fde.c
+ // classify_object_over_fdes expects there is a CIE record length 0 as a
+ // terminator. Thus we add one unconditionally.
+ Off += 4;
this->Size = Off;
}
@@ -888,12 +874,18 @@
}
}
+// On PowerPC the .plt section is used to hold the table of function addresses
+// instead of the .got.plt, and the type is SHT_NOBITS similar to a .bss
+// section. I don't know why we have a BSS style type for the section but it is
+// consitent across both 64-bit PowerPC ABIs as well as the 32-bit PowerPC ABI.
GotPltSection::GotPltSection()
- : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
- Target->GotPltEntrySize, ".got.plt") {}
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE,
+ Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS,
+ Target->GotPltEntrySize,
+ Config->EMachine == EM_PPC64 ? ".plt" : ".got.plt") {}
void GotPltSection::addEntry(Symbol &Sym) {
- Sym.GotPltIndex = Target->GotPltHeaderEntriesNum + Entries.size();
+ assert(Sym.PltIndex == Entries.size());
Entries.push_back(&Sym);
}
@@ -919,16 +911,29 @@
!(ElfSym::GlobalOffsetTable && Target->GotBaseSymInGotPlt);
}
-// On ARM the IgotPltSection is part of the GotSection, on other Targets it is
-// part of the .got.plt
+static StringRef getIgotPltName() {
+ // On ARM the IgotPltSection is part of the GotSection.
+ if (Config->EMachine == EM_ARM)
+ return ".got";
+
+ // On PowerPC64 the GotPltSection is renamed to '.plt' so the IgotPltSection
+ // needs to be named the same.
+ if (Config->EMachine == EM_PPC64)
+ return ".plt";
+
+ return ".got.plt";
+}
+
+// On PowerPC64 the GotPltSection type is SHT_NOBITS so we have to follow suit
+// with the IgotPltSection.
IgotPltSection::IgotPltSection()
- : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
- Target->GotPltEntrySize,
- Config->EMachine == EM_ARM ? ".got" : ".got.plt") {}
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE,
+ Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS,
+ Target->GotPltEntrySize, getIgotPltName()) {}
void IgotPltSection::addEntry(Symbol &Sym) {
Sym.IsInIgot = true;
- Sym.GotPltIndex = Entries.size();
+ assert(Sym.PltIndex == Entries.size());
Entries.push_back(&Sym);
}
@@ -1028,6 +1033,13 @@
}
template <class ELFT>
+void DynamicSection<ELFT>::addInSecRelative(int32_t Tag, InputSection *Sec) {
+ size_t TagOffset = Entries.size() * Entsize;
+ Entries.push_back(
+ {Tag, [=] { return Sec->getVA(0) - (getVA() + TagOffset); }});
+}
+
+template <class ELFT>
void DynamicSection<ELFT>::addOutSec(int32_t Tag, OutputSection *Sec) {
Entries.push_back({Tag, [=] { return Sec->Addr; }});
}
@@ -1180,8 +1192,23 @@
else
addInt(DT_MIPS_GOTSYM, InX::DynSymTab->getNumSymbols());
addInSec(DT_PLTGOT, InX::MipsGot);
- if (InX::MipsRldMap)
- addInSec(DT_MIPS_RLD_MAP, InX::MipsRldMap);
+ if (InX::MipsRldMap) {
+ if (!Config->Pie)
+ addInSec(DT_MIPS_RLD_MAP, InX::MipsRldMap);
+ // Store the offset to the .rld_map section
+ // relative to the address of the tag.
+ addInSecRelative(DT_MIPS_RLD_MAP_REL, InX::MipsRldMap);
+ }
+ }
+
+ // Glink dynamic tag is required by the V2 abi if the plt section isn't empty.
+ if (Config->EMachine == EM_PPC64 && !InX::Plt->empty()) {
+ // The Glink tag points to 32 bytes before the first lazy symbol resolution
+ // stub, which starts directly after the header.
+ Entries.push_back({DT_PPC64_GLINK, [=] {
+ unsigned Offset = Target->PltHeaderSize - 32;
+ return InX::Plt->getVA(0) + Offset;
+ }});
}
addInt(DT_NULL, 0);
@@ -1387,10 +1414,10 @@
NonRelatives.push_back(R);
}
- std::sort(Relatives.begin(), Relatives.end(),
- [](const Elf_Rel &A, const Elf_Rel &B) {
- return A.r_offset < B.r_offset;
- });
+ llvm::sort(Relatives.begin(), Relatives.end(),
+ [](const Elf_Rel &A, const Elf_Rel &B) {
+ return A.r_offset < B.r_offset;
+ });
// Try to find groups of relative relocations which are spaced one word
// apart from one another. These generally correspond to vtable entries. The
@@ -1468,10 +1495,10 @@
}
// Finally the non-relative relocations.
- std::sort(NonRelatives.begin(), NonRelatives.end(),
- [](const Elf_Rela &A, const Elf_Rela &B) {
- return A.r_offset < B.r_offset;
- });
+ llvm::sort(NonRelatives.begin(), NonRelatives.end(),
+ [](const Elf_Rela &A, const Elf_Rela &B) {
+ return A.r_offset < B.r_offset;
+ });
if (!NonRelatives.empty()) {
Add(NonRelatives.size());
Add(HasAddendIfRela);
@@ -1520,39 +1547,60 @@
void SymbolTableBaseSection::finalizeContents() {
getParent()->Link = StrTabSec.getParent()->SectionIndex;
+ if (this->Type != SHT_DYNSYM)
+ return;
+
// If it is a .dynsym, there should be no local symbols, but we need
// to do a few things for the dynamic linker.
- if (this->Type == SHT_DYNSYM) {
- // Section's Info field has the index of the first non-local symbol.
- // Because the first symbol entry is a null entry, 1 is the first.
- getParent()->Info = 1;
- if (InX::GnuHashTab) {
- // NB: It also sorts Symbols to meet the GNU hash table requirements.
- InX::GnuHashTab->addSymbols(Symbols);
- } else if (Config->EMachine == EM_MIPS) {
- std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols);
- }
+ // Section's Info field has the index of the first non-local symbol.
+ // Because the first symbol entry is a null entry, 1 is the first.
+ getParent()->Info = 1;
- size_t I = 0;
- for (const SymbolTableEntry &S : Symbols) S.Sym->DynsymIndex = ++I;
- return;
+ if (InX::GnuHashTab) {
+ // NB: It also sorts Symbols to meet the GNU hash table requirements.
+ InX::GnuHashTab->addSymbols(Symbols);
+ } else if (Config->EMachine == EM_MIPS) {
+ std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols);
}
+
+ size_t I = 0;
+ for (const SymbolTableEntry &S : Symbols)
+ S.Sym->DynsymIndex = ++I;
}
// The ELF spec requires that all local symbols precede global symbols, so we
// sort symbol entries in this function. (For .dynsym, we don't do that because
// symbols for dynamic linking are inherently all globals.)
+//
+// Aside from above, we put local symbols in groups starting with the STT_FILE
+// symbol. That is convenient for purpose of identifying where are local symbols
+// coming from.
void SymbolTableBaseSection::postThunkContents() {
if (this->Type == SHT_DYNSYM)
return;
- // move all local symbols before global symbols.
- auto It = std::stable_partition(
+
+ // Move all local symbols before global symbols.
+ auto E = std::stable_partition(
Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &S) {
return S.Sym->isLocal() || S.Sym->computeBinding() == STB_LOCAL;
});
- size_t NumLocals = It - Symbols.begin();
+ size_t NumLocals = E - Symbols.begin();
getParent()->Info = NumLocals + 1;
+
+ // Assign the growing unique ID for each local symbol's file.
+ DenseMap<InputFile *, unsigned> FileIDs;
+ for (auto I = Symbols.begin(); I != E; ++I)
+ FileIDs.insert({I->Sym->File, FileIDs.size()});
+
+ // Sort the local symbols to group them by file. We do not need to care about
+ // the STT_FILE symbols, they are already naturally placed first in each group.
+ // That happens because STT_FILE is always the first symbol in the object and
+ // hence precede all other local symbols we add for a file.
+ std::stable_sort(Symbols.begin(), E,
+ [&](const SymbolTableEntry &L, const SymbolTableEntry &R) {
+ return FileIDs[L.Sym->File] < FileIDs[R.Sym->File];
+ });
}
void SymbolTableBaseSection::addSymbol(Symbol *B) {
@@ -1619,6 +1667,8 @@
CommonSec = dyn_cast_or_null<BssSection>(D->Section);
if (CommonSec)
ESym->st_shndx = SHN_COMMON;
+ else if (Sym->NeedsPltAddr)
+ ESym->st_shndx = SHN_UNDEF;
else if (const OutputSection *OutSec = Sym->getOutputSection())
ESym->st_shndx = OutSec->SectionIndex;
else if (isa<Defined>(Sym))
@@ -1660,9 +1710,11 @@
ESym->st_other |= STO_MIPS_PLT;
if (isMicroMips()) {
// Set STO_MIPS_MICROMIPS flag and less-significant bit for
- // defined microMIPS symbols and shared symbols with PLT record.
- if ((Sym->isDefined() && (Sym->StOther & STO_MIPS_MICROMIPS)) ||
- (Sym->isShared() && Sym->NeedsPltAddr)) {
+ // a defined microMIPS symbol and symbol should point to its
+ // PLT entry (in case of microMIPS, PLT entries always contain
+ // microMIPS code).
+ if (Sym->isDefined() &&
+ ((Sym->StOther & STO_MIPS_MICROMIPS) || Sym->NeedsPltAddr)) {
if (StrTabSec.isDynamic())
ESym->st_value |= 1;
ESym->st_other |= STO_MIPS_MICROMIPS;
@@ -1804,10 +1856,6 @@
// its type correctly.
std::vector<SymbolTableEntry>::iterator Mid =
std::stable_partition(V.begin(), V.end(), [](const SymbolTableEntry &S) {
- // Shared symbols that this executable preempts are special. The dynamic
- // linker has to look them up, so they have to be in the hash table.
- if (auto *SS = dyn_cast<SharedSymbol>(S.Sym))
- return SS->CopyRelSec == nullptr && !SS->NeedsPltAddr;
return !S.Sym->isDefined();
});
@@ -1880,8 +1928,11 @@
}
}
+// On PowerPC64 the lazy symbol resolvers go into the `global linkage table`
+// in the .glink section, rather then the typical .plt section.
PltSection::PltSection(bool IsIplt)
- : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, ".plt"),
+ : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16,
+ Config->EMachine == EM_PPC64 ? ".glink" : ".plt"),
HeaderSize(IsIplt ? 0 : Target->PltHeaderSize), IsIplt(IsIplt) {
// The PLT needs to be writable on SPARC as the dynamic linker will
// modify the instructions in the PLT entries.
@@ -2332,9 +2383,8 @@
NextIndex = getVerDefNum() + 1;
}
-template <class ELFT>
-void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) {
- SharedFile<ELFT> &File = SS->getFile<ELFT>();
+template <class ELFT> void VersionNeedSection<ELFT>::addSymbol(Symbol *SS) {
+ auto &File = cast<SharedFile<ELFT>>(*SS->File);
if (SS->VerdefIndex == VER_NDX_GLOBAL) {
SS->VersionId = VER_NDX_GLOBAL;
return;
@@ -2513,9 +2563,18 @@
// Debug sections may be compressed by zlib. Decompress if exists.
void elf::decompressSections() {
+ parallelForEach(InputSections,
+ [](InputSectionBase *Sec) { Sec->maybeDecompress(); });
+}
+
+template <class ELFT> void elf::splitSections() {
+ // splitIntoPieces needs to be called on each MergeInputSection
+ // before calling finalizeContents().
parallelForEach(InputSections, [](InputSectionBase *Sec) {
- if (Sec->Live)
- Sec->maybeDecompress();
+ if (auto *S = dyn_cast<MergeInputSection>(Sec))
+ S->splitIntoPieces();
+ else if (auto *Eh = dyn_cast<EhInputSection>(Sec))
+ Eh->split<ELFT>();
});
}
@@ -2527,14 +2586,6 @@
// that it replaces. It then finalizes each synthetic section in order
// to compute an output offset for each piece of each input section.
void elf::mergeSections() {
- // splitIntoPieces needs to be called on each MergeInputSection
- // before calling finalizeContents(). Do that first.
- parallelForEach(InputSections, [](InputSectionBase *Sec) {
- if (Sec->Live)
- if (auto *S = dyn_cast<MergeInputSection>(Sec))
- S->splitIntoPieces();
- });
-
std::vector<MergeSyntheticSection *> MergeSections;
for (InputSectionBase *&S : InputSections) {
MergeInputSection *MS = dyn_cast<MergeInputSection>(S);
@@ -2573,11 +2624,8 @@
}
(*I)->addSection(MS);
}
- for (auto *MS : MergeSections) {
+ for (auto *MS : MergeSections)
MS->finalizeContents();
- parallelForEach(MS->Sections,
- [](MergeInputSection *Sec) { Sec->initOffsetMap(); });
- }
std::vector<InputSectionBase *> &V = InputSections;
V.erase(std::remove(V.begin(), V.end(), nullptr), V.end());
@@ -2683,6 +2731,11 @@
template GdbIndexSection *elf::createGdbIndex<ELF64LE>();
template GdbIndexSection *elf::createGdbIndex<ELF64BE>();
+template void elf::splitSections<ELF32LE>();
+template void elf::splitSections<ELF32BE>();
+template void elf::splitSections<ELF64LE>();
+template void elf::splitSections<ELF64BE>();
+
template void EhFrameSection::addSection<ELF32LE>(InputSectionBase *);
template void EhFrameSection::addSection<ELF32BE>(InputSectionBase *);
template void EhFrameSection::addSection<ELF64LE>(InputSectionBase *);
diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h
index b709f4b..fc5ffa3 100644
--- a/ELF/SyntheticSections.h
+++ b/ELF/SyntheticSections.h
@@ -52,7 +52,6 @@
// If any additional finalization of contents are needed post thunk creation.
virtual void postThunkContents() {}
virtual bool empty() const { return false; }
- uint64_t getVA() const;
static bool classof(const SectionBase *D) {
return D->kind() == InputSectionBase::Synthetic;
@@ -87,6 +86,10 @@
ArrayRef<CieRecord *> getCieRecords() const { return CieRecords; }
private:
+ // This is used only when parsing EhInputSection. We keep it here to avoid
+ // allocating one for each EhInputSection.
+ llvm::DenseMap<size_t, CieRecord *> OffsetToCie;
+
uint64_t Size = 0;
template <class ELFT, class RelTy>
@@ -360,6 +363,7 @@
void add(int32_t Tag, std::function<uint64_t()> Fn);
void addInt(int32_t Tag, uint64_t Val);
void addInSec(int32_t Tag, InputSection *Sec);
+ void addInSecRelative(int32_t Tag, InputSection *Sec);
void addOutSec(int32_t Tag, OutputSection *Sec);
void addSize(int32_t Tag, OutputSection *Sec);
void addSym(int32_t Tag, Symbol *Sym);
@@ -670,7 +674,7 @@
public:
VersionNeedSection();
- void addSymbol(SharedSymbol *SS);
+ void addSymbol(Symbol *Sym);
void finalizeContents() override;
void writeTo(uint8_t *Buf) override;
size_t getSize() const override;
@@ -834,6 +838,7 @@
InputSection *createInterpSection();
MergeInputSection *createCommentSection();
void decompressSections();
+template <class ELFT> void splitSections();
void mergeSections();
Defined *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
diff --git a/ELF/Target.h b/ELF/Target.h
index 698758e..c7d3906 100644
--- a/ELF/Target.h
+++ b/ELF/Target.h
@@ -25,7 +25,6 @@
class TargetInfo {
public:
virtual uint32_t calcEFlags() const { return 0; }
- virtual bool isPicRel(RelType Type) const { return true; }
virtual RelType getDynRel(RelType Type) const { return Type; }
virtual void writeGotPltHeader(uint8_t *Buf) const {}
virtual void writeGotHeader(uint8_t *Buf) const {}
@@ -49,7 +48,7 @@
}
// Returns true if a relocation only uses the low bits of a value such that
- // all those bits are in in the same page. For example, if the relocation
+ // all those bits are in the same page. For example, if the relocation
// only uses the low 12 bits in a system with 4k pages. If this is true, the
// bits will always have the same value at runtime and we don't have to emit
// a dynamic relocation.
diff --git a/ELF/Thunks.cpp b/ELF/Thunks.cpp
index 4db4990..2cd7e51 100644
--- a/ELF/Thunks.cpp
+++ b/ELF/Thunks.cpp
@@ -192,6 +192,23 @@
InputSection *getTargetInputSection() const override;
};
+
+// PPC64 Plt call stubs.
+// Any call site that needs to call through a plt entry needs a call stub in
+// the .text section. The call stub is responsible for:
+// 1) Saving the toc-pointer to the stack.
+// 2) Loading the target functions address from the procedure linkage table into
+// r12 for use by the target functions global entry point, and into the count
+// register.
+// 3) Transfering control to the target function through an indirect branch.
+class PPC64PltCallStub final : public Thunk {
+public:
+ PPC64PltCallStub(Symbol &Dest) : Thunk(Dest) {}
+ uint32_t size() override { return 20; }
+ void writeTo(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+};
+
} // end anonymous namespace
Defined *Thunk::addSymbol(StringRef Name, uint8_t Type, uint64_t Value,
@@ -485,6 +502,25 @@
return dyn_cast<InputSection>(DR.Section);
}
+void PPC64PltCallStub::writeTo(uint8_t *Buf) {
+ int64_t Off = Destination.getGotPltVA() - getPPC64TocBase();
+ // Need to add 0x8000 to offset to account for the low bits being signed.
+ uint16_t OffHa = (Off + 0x8000) >> 16;
+ uint16_t OffLo = Off;
+
+ write32(Buf + 0, 0xf8410018); // std r2,24(r1)
+ write32(Buf + 4, 0x3d820000 | OffHa); // addis r12,r2, X@plt@to@ha
+ write32(Buf + 8, 0xe98c0000 | OffLo); // ld r12,X@plt@toc@l(r12)
+ write32(Buf + 12, 0x7d8903a6); // mtctr r12
+ write32(Buf + 16, 0x4e800420); // bctr
+}
+
+void PPC64PltCallStub::addSymbols(ThunkSection &IS) {
+ Defined *S = addSymbol(Saver.save("__plt_" + Destination.getName()), STT_FUNC,
+ 0, IS);
+ S->NeedsTocRestore = true;
+}
+
Thunk::Thunk(Symbol &D) : Destination(D), Offset(0) {}
Thunk::~Thunk() = default;
@@ -528,15 +564,26 @@
return make<MipsThunk>(S);
}
+static Thunk *addThunkPPC64(RelType Type, Symbol &S) {
+ if (Type == R_PPC64_REL24)
+ return make<PPC64PltCallStub>(S);
+ fatal("unexpected relocation type");
+}
+
Thunk *addThunk(RelType Type, Symbol &S) {
if (Config->EMachine == EM_AARCH64)
return addThunkAArch64(Type, S);
- else if (Config->EMachine == EM_ARM)
+
+ if (Config->EMachine == EM_ARM)
return addThunkArm(Type, S);
- else if (Config->EMachine == EM_MIPS)
+
+ if (Config->EMachine == EM_MIPS)
return addThunkMips(Type, S);
- llvm_unreachable("add Thunk only supported for ARM and Mips");
- return nullptr;
+
+ if (Config->EMachine == EM_PPC64)
+ return addThunkPPC64(Type, S);
+
+ llvm_unreachable("add Thunk only supported for ARM, Mips and PowerPC");
}
} // end namespace elf
diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp
index e685c8e..998b0dc 100644
--- a/ELF/Writer.cpp
+++ b/ELF/Writer.cpp
@@ -9,6 +9,7 @@
#include "Writer.h"
#include "AArch64ErrataFix.h"
+#include "CallGraphSort.h"
#include "Config.h"
#include "Filesystem.h"
#include "LinkerScript.h"
@@ -62,7 +63,7 @@
void assignFileOffsets();
void assignFileOffsetsBinary();
void setPhdrs();
- void checkSectionOverlap();
+ void checkSections();
void fixSectionAlignments();
void openFile();
void writeTrapInstr();
@@ -87,7 +88,11 @@
};
} // anonymous namespace
-StringRef elf::getOutputSectionName(InputSectionBase *S) {
+static bool isSectionPrefix(StringRef Prefix, StringRef Name) {
+ return Name.startswith(Prefix) || Name == Prefix.drop_back();
+}
+
+StringRef elf::getOutputSectionName(const InputSectionBase *S) {
if (Config->Relocatable)
return S->Name;
@@ -103,13 +108,25 @@
}
}
+ // This check is for -z keep-text-section-prefix. This option separates text
+ // sections with prefix ".text.hot", ".text.unlikely", ".text.startup" or
+ // ".text.exit".
+ // When enabled, this allows identifying the hot code region (.text.hot) in
+ // the final binary which can be selectively mapped to huge pages or mlocked,
+ // for instance.
+ if (Config->ZKeepTextSectionPrefix)
+ for (StringRef V :
+ {".text.hot.", ".text.unlikely.", ".text.startup.", ".text.exit."}) {
+ if (isSectionPrefix(V, S->Name))
+ return V.drop_back();
+ }
+
for (StringRef V :
{".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.",
".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.",
".gcc_except_table.", ".tdata.", ".ARM.exidx.", ".ARM.extab."}) {
- StringRef Prefix = V.drop_back();
- if (S->Name.startswith(V) || S->Name == Prefix)
- return Prefix;
+ if (isSectionPrefix(V, S->Name))
+ return V.drop_back();
}
// CommonSection is identified as "COMMON" in linker scripts.
@@ -190,11 +207,12 @@
Symtab->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_GLOBAL);
}
- // The 64-bit PowerOpen ABI defines a TableOfContents (TOC) which combines the
- // typical ELF GOT with the small data sections. It commonly includes .got
- // .toc .sdata .sbss. The .TOC. symbol replaces both _GLOBAL_OFFSET_TABLE_ and
- // _SDA_BASE_ from the 32-bit ABI. It is used to represent the TOC base which
- // is offset by 0x8000 bytes from the start of the .got section.
+ // The Power Architecture 64-bit v2 ABI defines a TableOfContents (TOC) which
+ // combines the typical ELF GOT with the small data sections. It commonly
+ // includes .got .toc .sdata .sbss. The .TOC. symbol replaces both
+ // _GLOBAL_OFFSET_TABLE_ and _SDA_BASE_ from the 32-bit ABI. It is used to
+ // represent the TOC base which is offset by 0x8000 bytes from the start of
+ // the .got section.
ElfSym::GlobalOffsetTable = addOptionalRegular(
(Config->EMachine == EM_PPC64) ? ".TOC." : "_GLOBAL_OFFSET_TABLE_",
Out::ElfHeader, Target->GotBaseSymOff);
@@ -458,7 +476,7 @@
}
if (Config->CheckSections)
- checkSectionOverlap();
+ checkSections();
// It does not make sense try to open the file if we have error already.
if (errorCount())
@@ -494,7 +512,7 @@
static bool shouldKeepInSymtab(SectionBase *Sec, StringRef SymName,
const Symbol &B) {
- if (B.isFile() || B.isSection())
+ if (B.isSection())
return false;
// If sym references a section in a discarded group, don't keep it.
@@ -645,6 +663,9 @@
if (InX::Got && Sec == InX::Got->getParent())
return true;
+ if (Sec->Name.equals(".toc"))
+ return true;
+
// .got.plt contains pointers to external function symbols. They are
// by default resolved lazily, so we usually cannot put it into RELRO.
// However, if "-z now" is given, the lazy symbol resolution is
@@ -680,17 +701,18 @@
RF_NOT_INTERP = 1 << 17,
RF_NOT_ALLOC = 1 << 16,
RF_WRITE = 1 << 15,
- RF_EXEC_WRITE = 1 << 13,
- RF_EXEC = 1 << 12,
- RF_NON_TLS_BSS = 1 << 11,
- RF_NON_TLS_BSS_RO = 1 << 10,
- RF_NOT_TLS = 1 << 9,
+ RF_EXEC_WRITE = 1 << 14,
+ RF_EXEC = 1 << 13,
+ RF_NON_TLS_BSS = 1 << 12,
+ RF_NON_TLS_BSS_RO = 1 << 11,
+ RF_NOT_TLS = 1 << 10,
+ RF_ALLOC_FIRST = 1 << 9,
RF_BSS = 1 << 8,
RF_NOTE = 1 << 7,
RF_PPC_NOT_TOCBSS = 1 << 6,
- RF_PPC_OPD = 1 << 5,
- RF_PPC_TOCL = 1 << 4,
- RF_PPC_TOC = 1 << 3,
+ RF_PPC_TOCL = 1 << 5,
+ RF_PPC_TOC = 1 << 4,
+ RF_PPC_GOT = 1 << 3,
RF_PPC_BRANCH_LT = 1 << 2,
RF_MIPS_GPREL = 1 << 1,
RF_MIPS_NOT_GOT = 1 << 0
@@ -716,6 +738,16 @@
if (!(Sec->Flags & SHF_ALLOC))
return Rank | RF_NOT_ALLOC;
+ // Place .dynsym and .dynstr at the beginning of SHF_ALLOC
+ // sections. We want to do this to mitigate the possibility that
+ // huge .dynsym and .dynstr sections placed between ro-data and text
+ // sections cause relocation overflow. Note: .dynstr has SHT_STRTAB
+ // type and SHF_ALLOC attribute, whereas sections that only have
+ // SHT_STRTAB but without SHF_ALLOC is placed at the end. All "Sec"
+ // reaching here has SHF_ALLOC bit set.
+ if (Sec->Type == SHT_DYNSYM || Sec->Type == SHT_STRTAB)
+ return Rank | RF_ALLOC_FIRST;
+
// Sort sections based on their access permission in the following
// order: R, RX, RWX, RW. This order is based on the following
// considerations:
@@ -793,15 +825,15 @@
if (Name != ".tocbss")
Rank |= RF_PPC_NOT_TOCBSS;
- if (Name == ".opd")
- Rank |= RF_PPC_OPD;
-
if (Name == ".toc1")
Rank |= RF_PPC_TOCL;
if (Name == ".toc")
Rank |= RF_PPC_TOC;
+ if (Name == ".got")
+ Rank |= RF_PPC_GOT;
+
if (Name == ".branch_lt")
Rank |= RF_PPC_BRANCH_LT;
}
@@ -852,7 +884,8 @@
addOptionalRegular(S, InX::RelaIplt, 0, STV_HIDDEN, STB_WEAK);
S = Config->IsRela ? "__rela_iplt_end" : "__rel_iplt_end";
- addOptionalRegular(S, InX::RelaIplt, -1, STV_HIDDEN, STB_WEAK);
+ ElfSym::RelaIpltEnd =
+ addOptionalRegular(S, InX::RelaIplt, 0, STV_HIDDEN, STB_WEAK);
}
template <class ELFT>
@@ -885,6 +918,9 @@
ElfSym::GlobalOffsetTable->Section = GotSection;
}
+ if (ElfSym::RelaIpltEnd)
+ ElfSym::RelaIpltEnd->Value = InX::RelaIplt->getSize();
+
PhdrEntry *Last = nullptr;
PhdrEntry *LastRO = nullptr;
@@ -1029,6 +1065,10 @@
// Builds section order for handling --symbol-ordering-file.
static DenseMap<const InputSectionBase *, int> buildSectionOrder() {
DenseMap<const InputSectionBase *, int> SectionOrder;
+ // Use the rarely used option -call-graph-ordering-file to sort sections.
+ if (!Config->CallGraphProfile.empty())
+ return computeCallGraphProfileOrder();
+
if (Config->SymbolOrderingFile.empty())
return SectionOrder;
@@ -1046,38 +1086,31 @@
SymbolOrder.insert({S, {Priority++, false}});
// Build a map from sections to their priorities.
- for (InputFile *File : ObjectFiles) {
- for (Symbol *Sym : File->getSymbols()) {
- auto It = SymbolOrder.find(Sym->getName());
- if (It == SymbolOrder.end())
- continue;
- SymbolOrderEntry &Ent = It->second;
- Ent.Present = true;
+ auto AddSym = [&](Symbol &Sym) {
+ auto It = SymbolOrder.find(Sym.getName());
+ if (It == SymbolOrder.end())
+ return;
+ SymbolOrderEntry &Ent = It->second;
+ Ent.Present = true;
- auto *D = dyn_cast<Defined>(Sym);
- if (Config->WarnSymbolOrdering) {
- if (Sym->isUndefined())
- warn(File->getName() +
- ": unable to order undefined symbol: " + Sym->getName());
- else if (Sym->isShared())
- warn(File->getName() +
- ": unable to order shared symbol: " + Sym->getName());
- else if (D && !D->Section)
- warn(File->getName() +
- ": unable to order absolute symbol: " + Sym->getName());
- else if (D && !D->Section->Live)
- warn(File->getName() +
- ": unable to order discarded symbol: " + Sym->getName());
- }
- if (!D)
- continue;
+ warnUnorderableSymbol(&Sym);
+ if (auto *D = dyn_cast<Defined>(&Sym)) {
if (auto *Sec = dyn_cast_or_null<InputSectionBase>(D->Section)) {
int &Priority = SectionOrder[cast<InputSectionBase>(Sec->Repl)];
Priority = std::min(Priority, Ent.Priority);
}
}
- }
+ };
+ // We want both global and local symbols. We get the global ones from the
+ // symbol table and iterate the object files for the local ones.
+ for (Symbol *Sym : Symtab->getSymbols())
+ if (!Sym->isLazy())
+ AddSym(*Sym);
+ for (InputFile *File : ObjectFiles)
+ for (Symbol *Sym : File->getSymbols())
+ if (Sym->isLocal())
+ AddSym(*Sym);
if (Config->WarnSymbolOrdering)
for (auto OrderEntry : SymbolOrder)
@@ -1087,6 +1120,75 @@
return SectionOrder;
}
+// Sorts the sections in ISD according to the provided section order.
+static void
+sortISDBySectionOrder(InputSectionDescription *ISD,
+ const DenseMap<const InputSectionBase *, int> &Order) {
+ std::vector<InputSection *> UnorderedSections;
+ std::vector<std::pair<InputSection *, int>> OrderedSections;
+ uint64_t UnorderedSize = 0;
+
+ for (InputSection *IS : ISD->Sections) {
+ auto I = Order.find(IS);
+ if (I == Order.end()) {
+ UnorderedSections.push_back(IS);
+ UnorderedSize += IS->getSize();
+ continue;
+ }
+ OrderedSections.push_back({IS, I->second});
+ }
+ llvm::sort(
+ OrderedSections.begin(), OrderedSections.end(),
+ [&](std::pair<InputSection *, int> A, std::pair<InputSection *, int> B) {
+ return A.second < B.second;
+ });
+
+ // Find an insertion point for the ordered section list in the unordered
+ // section list. On targets with limited-range branches, this is the mid-point
+ // of the unordered section list. This decreases the likelihood that a range
+ // extension thunk will be needed to enter or exit the ordered region. If the
+ // ordered section list is a list of hot functions, we can generally expect
+ // the ordered functions to be called more often than the unordered functions,
+ // making it more likely that any particular call will be within range, and
+ // therefore reducing the number of thunks required.
+ //
+ // For example, imagine that you have 8MB of hot code and 32MB of cold code.
+ // If the layout is:
+ //
+ // 8MB hot
+ // 32MB cold
+ //
+ // only the first 8-16MB of the cold code (depending on which hot function it
+ // is actually calling) can call the hot code without a range extension thunk.
+ // However, if we use this layout:
+ //
+ // 16MB cold
+ // 8MB hot
+ // 16MB cold
+ //
+ // both the last 8-16MB of the first block of cold code and the first 8-16MB
+ // of the second block of cold code can call the hot code without a thunk. So
+ // we effectively double the amount of code that could potentially call into
+ // the hot code without a thunk.
+ size_t InsPt = 0;
+ if (Target->ThunkSectionSpacing && !OrderedSections.empty()) {
+ uint64_t UnorderedPos = 0;
+ for (; InsPt != UnorderedSections.size(); ++InsPt) {
+ UnorderedPos += UnorderedSections[InsPt]->getSize();
+ if (UnorderedPos > UnorderedSize / 2)
+ break;
+ }
+ }
+
+ ISD->Sections.clear();
+ for (InputSection *IS : makeArrayRef(UnorderedSections).slice(0, InsPt))
+ ISD->Sections.push_back(IS);
+ for (std::pair<InputSection *, int> P : OrderedSections)
+ ISD->Sections.push_back(P.first);
+ for (InputSection *IS : makeArrayRef(UnorderedSections).slice(InsPt))
+ ISD->Sections.push_back(IS);
+}
+
static void sortSection(OutputSection *Sec,
const DenseMap<const InputSectionBase *, int> &Order) {
StringRef Name = Sec->Name;
@@ -1113,7 +1215,9 @@
// Sort input sections by priority using the list provided
// by --symbol-ordering-file.
if (!Order.empty())
- Sec->sort([&](InputSectionBase *S) { return Order.lookup(S); });
+ for (BaseCommand *B : Sec->SectionCommands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(B))
+ sortISDBySectionOrder(ISD, Order);
}
// If no layout was provided by linker script, we want to apply default
@@ -1134,22 +1238,29 @@
if (Config->Relocatable)
return;
- for (BaseCommand *Base : Script->SectionCommands)
- if (auto *Sec = dyn_cast<OutputSection>(Base))
- Sec->SortRank = getSectionRank(Sec);
-
sortInputSections();
+ for (BaseCommand *Base : Script->SectionCommands) {
+ auto *OS = dyn_cast<OutputSection>(Base);
+ if (!OS)
+ continue;
+ OS->SortRank = getSectionRank(OS);
+
+ // We want to assign rude approximation values to OutSecOff fields
+ // to know the relative order of the input sections. We use it for
+ // sorting SHF_LINK_ORDER sections. See resolveShfLinkOrder().
+ uint64_t I = 0;
+ for (InputSection *Sec : getInputSections(OS))
+ Sec->OutSecOff = I++;
+ }
+
if (!Script->HasSectionsCommand) {
// We know that all the OutputSections are contiguous in this case.
- auto E = Script->SectionCommands.end();
- auto I = Script->SectionCommands.begin();
auto IsSection = [](BaseCommand *Base) { return isa<OutputSection>(Base); };
- I = std::find_if(I, E, IsSection);
- E = std::find_if(llvm::make_reverse_iterator(E),
- llvm::make_reverse_iterator(I), IsSection)
- .base();
- std::stable_sort(I, E, compareSections);
+ std::stable_sort(
+ llvm::find_if(Script->SectionCommands, IsSection),
+ llvm::find_if(llvm::reverse(Script->SectionCommands), IsSection).base(),
+ compareSections);
return;
}
@@ -1490,9 +1601,9 @@
if (InX::DynSymTab && Sym->includeInDynsym()) {
InX::DynSymTab->addSymbol(Sym);
- if (auto *SS = dyn_cast<SharedSymbol>(Sym))
- if (cast<SharedFile<ELFT>>(Sym->File)->IsNeeded)
- In<ELFT>::VerNeed->addSymbol(SS);
+ if (auto *File = dyn_cast_or_null<SharedFile<ELFT>>(Sym->File))
+ if (File->IsNeeded && !Sym->isUndefined())
+ In<ELFT>::VerNeed->addSymbol(Sym);
}
}
@@ -1518,7 +1629,7 @@
}
// This is a bit of a hack. A value of 0 means undef, so we set it
- // to 1 t make __ehdr_start defined. The section number is not
+ // to 1 to make __ehdr_start defined. The section number is not
// particularly relevant.
Out::ElfHeader->SectionIndex = 1;
@@ -1584,31 +1695,43 @@
} while (Changed);
}
+ // createThunks may have added local symbols to the static symbol table
+ applySynthetic({InX::SymTab},
+ [](SyntheticSection *SS) { SS->postThunkContents(); });
+
// Fill other section headers. The dynamic table is finalized
// at the end because some tags like RELSZ depend on result
// of finalizing other sections.
for (OutputSection *Sec : OutputSections)
Sec->finalize<ELFT>();
-
- // createThunks may have added local symbols to the static symbol table
- applySynthetic({InX::SymTab},
- [](SyntheticSection *SS) { SS->postThunkContents(); });
}
// The linker is expected to define SECNAME_start and SECNAME_end
// symbols for a few sections. This function defines them.
template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
- auto Define = [&](StringRef Start, StringRef End, OutputSection *OS) {
- // These symbols resolve to the image base if the section does not exist.
- // A special value -1 indicates end of the section.
+ // If a section does not exist, there's ambiguity as to how we
+ // define _start and _end symbols for an init/fini section. Since
+ // the loader assume that the symbols are always defined, we need to
+ // always define them. But what value? The loader iterates over all
+ // pointers between _start and _end to run global ctors/dtors, so if
+ // the section is empty, their symbol values don't actually matter
+ // as long as _start and _end point to the same location.
+ //
+ // That said, we don't want to set the symbols to 0 (which is
+ // probably the simplest value) because that could cause some
+ // program to fail to link due to relocation overflow, if their
+ // program text is above 2 GiB. We use the address of the .text
+ // section instead to prevent that failure.
+ OutputSection *Default = findSection(".text");
+ if (!Default)
+ Default = Out::ElfHeader;
+ auto Define = [=](StringRef Start, StringRef End, OutputSection *OS) {
if (OS) {
addOptionalRegular(Start, OS, 0);
addOptionalRegular(End, OS, -1);
} else {
- if (Config->Pic)
- OS = Out::ElfHeader;
- addOptionalRegular(Start, OS, 0);
- addOptionalRegular(End, OS, 0);
+ addOptionalRegular(Start, Default, 0);
+ addOptionalRegular(End, Default, 0);
}
};
@@ -1635,7 +1758,7 @@
}
static bool needsPtLoad(OutputSection *Sec) {
- if (!(Sec->Flags & SHF_ALLOC))
+ if (!(Sec->Flags & SHF_ALLOC) || Sec->Noload)
return false;
// Don't allocate VA space for TLS NOBITS sections. The PT_TLS PHDR is
@@ -1774,7 +1897,7 @@
// Create one PT_NOTE per a group of contiguous .note sections.
PhdrEntry *Note = nullptr;
for (OutputSection *Sec : OutputSections) {
- if (Sec->Type == SHT_NOTE) {
+ if (Sec->Type == SHT_NOTE && (Sec->Flags & SHF_ALLOC)) {
if (!Note || Sec->LMAExpr)
Note = AddHdr(PT_NOTE, PF_R);
Note->add(Sec);
@@ -1917,9 +2040,8 @@
// not do that. Unfortunately, there are apps in the wild, for example, Linux
// kernel, which control segment distribution explicitly and move the counter
// backwards, so we have to allow doing that to support linking them. We
- // perform non-critical checks for overlaps in checkNoOverlappingSections(),
- // but here we want to prevent file size overflows because it would crash the
- // linker.
+ // perform non-critical checks for overlaps in checkSectionOverlap(), but here
+ // we want to prevent file size overflows because it would crash the linker.
for (OutputSection *Sec : OutputSections) {
if (Sec->Type == SHT_NOBITS)
continue;
@@ -1977,10 +2099,10 @@
// Check whether sections overlap for a specific address range (file offsets,
// load and virtual adresses).
static void checkOverlap(StringRef Name, std::vector<SectionOffset> &Sections) {
- std::sort(Sections.begin(), Sections.end(),
- [=](const SectionOffset &A, const SectionOffset &B) {
- return A.Offset < B.Offset;
- });
+ llvm::sort(Sections.begin(), Sections.end(),
+ [=](const SectionOffset &A, const SectionOffset &B) {
+ return A.Offset < B.Offset;
+ });
// Finding overlap is easy given a vector is sorted by start position.
// If an element starts before the end of the previous element, they overlap.
@@ -1996,17 +2118,25 @@
}
}
-// Check for overlapping sections
+// Check for overlapping sections and address overflows.
//
// In this function we check that none of the output sections have overlapping
// file offsets. For SHF_ALLOC sections we also check that the load address
// ranges and the virtual address ranges don't overlap
-template <class ELFT> void Writer<ELFT>::checkSectionOverlap() {
- // First check for overlapping file offsets. In this case we need to skip
- // any section marked as SHT_NOBITS. These sections don't actually occupy
- // space in the file so Sec->Offset + Sec->Size can overlap with others.
- // If --oformat binary is specified only add SHF_ALLOC sections are added to
- // the output file so we skip any non-allocated sections in that case.
+template <class ELFT> void Writer<ELFT>::checkSections() {
+ // First, check that section's VAs fit in available address space for target.
+ for (OutputSection *OS : OutputSections)
+ if ((OS->Addr + OS->Size < OS->Addr) ||
+ (!ELFT::Is64Bits && OS->Addr + OS->Size > UINT32_MAX))
+ errorOrWarn("section " + OS->Name + " at 0x" + utohexstr(OS->Addr) +
+ " of size 0x" + utohexstr(OS->Size) +
+ " exceeds available address space");
+
+ // Check for overlapping file offsets. In this case we need to skip any
+ // section marked as SHT_NOBITS. These sections don't actually occupy space in
+ // the file so Sec->Offset + Sec->Size can overlap with others. If --oformat
+ // binary is specified only add SHF_ALLOC sections are added to the output
+ // file so we skip any non-allocated sections in that case.
std::vector<SectionOffset> FileOffs;
for (OutputSection *Sec : OutputSections)
if (0 < Sec->Size && Sec->Type != SHT_NOBITS &&
@@ -2208,14 +2338,6 @@
template <class ELFT> void Writer<ELFT>::writeSections() {
uint8_t *Buf = Buffer->getBufferStart();
- // PPC64 needs to process relocations in the .opd section
- // before processing relocations in code-containing sections.
- if (auto *OpdCmd = findSection(".opd")) {
- Out::Opd = OpdCmd;
- Out::OpdBuf = Buf + Out::Opd->Offset;
- OpdCmd->template writeTo<ELFT>(Buf + Out::Opd->Offset);
- }
-
OutputSection *EhFrameHdr = nullptr;
if (InX::EhFrameHdr && !InX::EhFrameHdr->empty())
EhFrameHdr = InX::EhFrameHdr->getParent();
@@ -2228,8 +2350,7 @@
Sec->writeTo<ELFT>(Buf + Sec->Offset);
for (OutputSection *Sec : OutputSections)
- if (Sec != Out::Opd && Sec != EhFrameHdr && Sec->Type != SHT_REL &&
- Sec->Type != SHT_RELA)
+ if (Sec != EhFrameHdr && Sec->Type != SHT_REL && Sec->Type != SHT_RELA)
Sec->writeTo<ELFT>(Buf + Sec->Offset);
// The .eh_frame_hdr depends on .eh_frame section contents, therefore
diff --git a/ELF/Writer.h b/ELF/Writer.h
index 41f1e55..7806f82 100644
--- a/ELF/Writer.h
+++ b/ELF/Writer.h
@@ -48,7 +48,7 @@
};
void addReservedSymbols();
-llvm::StringRef getOutputSectionName(InputSectionBase *S);
+llvm::StringRef getOutputSectionName(const InputSectionBase *S);
template <class ELFT> uint32_t calcMipsEFlags();
diff --git a/MinGW/Driver.cpp b/MinGW/Driver.cpp
index 0b7e083..3e285e7 100644
--- a/MinGW/Driver.cpp
+++ b/MinGW/Driver.cpp
@@ -136,6 +136,8 @@
Add("-output-def:" + StringRef(A->getValue()));
if (auto *A = Args.getLastArg(OPT_image_base))
Add("-base:" + StringRef(A->getValue()));
+ if (auto *A = Args.getLastArg(OPT_map))
+ Add("-lldmap:" + StringRef(A->getValue()));
if (auto *A = Args.getLastArg(OPT_o))
Add("-out:" + StringRef(A->getValue()));
@@ -144,14 +146,19 @@
else
Add("-out:a.exe");
+ if (auto *A = Args.getLastArg(OPT_pdb)) {
+ Add("-debug");
+ Add("-pdb:" + StringRef(A->getValue()));
+ } else if (!Args.hasArg(OPT_strip_all)) {
+ Add("-debug:dwarf");
+ }
+
if (Args.hasArg(OPT_shared))
Add("-dll");
if (Args.hasArg(OPT_verbose))
Add("-verbose");
if (Args.hasArg(OPT_export_all_symbols))
Add("-export-all-symbols");
- if (!Args.hasArg(OPT_strip_all))
- Add("-debug:dwarf");
if (Args.hasArg(OPT_large_address_aware))
Add("-largeaddressaware");
if (Args.hasArg(OPT_kill_at))
diff --git a/MinGW/Options.td b/MinGW/Options.td
index 6840471..7e15bcd 100644
--- a/MinGW/Options.td
+++ b/MinGW/Options.td
@@ -18,6 +18,8 @@
def l: JoinedOrSeparate<["-"], "l">, MetaVarName<"<libName>">,
HelpText<"Root name of library to use">;
def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">;
+def map: S<"Map">, HelpText<"Output a linker map">;
+def map_eq: J<"Map=">, Alias<map>;
def no_whole_archive: F<"no-whole-archive">,
HelpText<"No longer include all object files for following archives">;
def large_address_aware: Flag<["--"], "large-address-aware">,
@@ -41,6 +43,7 @@
def _HASH_HASH_HASH : Flag<["-"], "###">,
HelpText<"Print (but do not run) the commands to run for this compilation">;
def mllvm: S<"mllvm">;
+def pdb: S<"pdb">, HelpText<"Specify output PDB debug information file">;
def Xlink : J<"Xlink=">, MetaVarName<"<arg>">,
HelpText<"Pass <arg> to the COFF linker">;
diff --git a/docs/WebAssembly.rst b/docs/WebAssembly.rst
index 1df8fa3..264d221 100644
--- a/docs/WebAssembly.rst
+++ b/docs/WebAssembly.rst
@@ -18,7 +18,7 @@
https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md.
This is object format that the llvm will produce when run with the
-``wasm32-unknown-unknown-wasm`` target. To build llvm with WebAssembly support
+``wasm32-unknown-unknown`` target. To build llvm with WebAssembly support
currently requires enabling the experimental backed using
``-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly``.
diff --git a/docs/ld.lld.1 b/docs/ld.lld.1
index 2ae3cd2..7f3a747 100644
--- a/docs/ld.lld.1
+++ b/docs/ld.lld.1
@@ -3,7 +3,7 @@
.\"
.\" This man page documents only lld's ELF linking support, obtained originally
.\" from FreeBSD.
-.Dd February 9, 2018
+.Dd April 28, 2018
.Dt LD.LLD 1
.Os
.Sh NAME
@@ -289,6 +289,15 @@
List removed unused sections.
.It Fl -print-map
Print a link map to the standard output.
+.It Fl -push-state
+Save the current state of
+.Fl -as-needed ,
+.Fl -static ,
+and
+.Fl -while-archive.
+.It Fl -pop-state
+Undo the effect of
+.Fl -push-state.
.It Fl -relocatable
Create relocatable object file.
.It Fl -reproduce Ns = Ns Ar value
@@ -401,6 +410,10 @@
.It Fl v
Display the version number and proceed with linking if object files are
specified.
+.It Fl -warn-backrefs
+Warn about reverse or cyclic dependencies to or between static archives.
+This can be used to ensure linker invocation remains compatible with
+traditional Unix-like linkers.
.It Fl -warn-common
Warn about duplicate common symbols.
.It Fl -warn-unresolved-symbols
@@ -525,3 +538,8 @@
In practice, large bodies of third party software have been linked with
.Nm
without material issues.
+.Pp
+The
+.Fl -warn-backrefs
+option may be used to identify a linker invocation that may be incompatible
+with traditional Unix-like linker behavior.
diff --git a/include/lld/Common/ErrorHandler.h b/include/lld/Common/ErrorHandler.h
index 8ae6f46..b6c78f1 100644
--- a/include/lld/Common/ErrorHandler.h
+++ b/include/lld/Common/ErrorHandler.h
@@ -34,6 +34,10 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/FileOutputBuffer.h"
+namespace llvm {
+class DiagnosticInfo;
+}
+
namespace lld {
class ErrorHandler {
@@ -74,6 +78,9 @@
LLVM_ATTRIBUTE_NORETURN void exitLld(int Val);
+void diagnosticHandler(const llvm::DiagnosticInfo &DI);
+void checkError(Error E);
+
// check functions are convenient functions to strip errors
// from error-or-value objects.
template <class T> T check(ErrorOr<T> E) {
diff --git a/include/lld/Common/Strings.h b/include/lld/Common/Strings.h
index 3be5eb9..e17b257 100644
--- a/include/lld/Common/Strings.h
+++ b/include/lld/Common/Strings.h
@@ -26,35 +26,8 @@
std::vector<uint8_t> parseHex(llvm::StringRef S);
bool isValidCIdentifier(llvm::StringRef S);
-// This is a lazy version of StringRef. String size is computed lazily
-// when it is needed. It is more efficient than StringRef to instantiate
-// if you have a string whose size is unknown.
-//
-// COFF and ELF string tables contain a lot of null-terminated strings.
-// Most of them are not necessary for the linker because they are names
-// of local symbols and the linker doesn't use local symbol names for
-// name resolution. So, we use this class to represents strings read
-// from string tables.
-class StringRefZ {
-public:
- StringRefZ() : Start(nullptr), Size(0) {}
- StringRefZ(const char *S, size_t Size) : Start(S), Size(Size) {}
-
- /*implicit*/ StringRefZ(const char *S) : Start(S), Size(-1) {}
-
- /*implicit*/ StringRefZ(llvm::StringRef S)
- : Start(S.data()), Size(S.size()) {}
-
- operator llvm::StringRef() const {
- if (Size == (size_t)-1)
- Size = strlen(Start);
- return {Start, Size};
- }
-
-private:
- const char *Start;
- mutable size_t Size;
-};
+// Write the contents of the a buffer to a file
+void saveBuffer(llvm::StringRef Buffer, const llvm::Twine &Path);
// This class represents multiple glob patterns.
class StringMatcher {
@@ -71,6 +44,6 @@
inline llvm::ArrayRef<uint8_t> toArrayRef(llvm::StringRef S) {
return {reinterpret_cast<const uint8_t *>(S.data()), S.size()};
}
-}
+} // namespace lld
#endif
diff --git a/include/lld/Common/Version.h b/include/lld/Common/Version.h
index 93de77d..23a10ed 100644
--- a/include/lld/Common/Version.h
+++ b/include/lld/Common/Version.h
@@ -18,7 +18,7 @@
#include "llvm/ADT/StringRef.h"
namespace lld {
-/// \brief Retrieves a string representing the complete lld version.
+/// Retrieves a string representing the complete lld version.
std::string getLLDVersion();
}
diff --git a/include/lld/Core/DefinedAtom.h b/include/lld/Core/DefinedAtom.h
index 6229d67..ba10b45 100644
--- a/include/lld/Core/DefinedAtom.h
+++ b/include/lld/Core/DefinedAtom.h
@@ -18,7 +18,7 @@
namespace lld {
class File;
-/// \brief The fundamental unit of linking.
+/// The fundamental unit of linking.
///
/// A C function or global variable is an atom. An atom has content and
/// attributes. The content of a function atom is the instructions that
@@ -179,10 +179,10 @@
};
enum DynamicExport {
- /// \brief The linker may or may not export this atom dynamically depending
+ /// The linker may or may not export this atom dynamically depending
/// on the output type and other context of the link.
dynamicExportNormal,
- /// \brief The linker will always export this atom dynamically.
+ /// The linker will always export this atom dynamically.
dynamicExportAlways,
};
@@ -212,26 +212,26 @@
}
};
- /// \brief returns a value for the order of this Atom within its file.
+ /// returns a value for the order of this Atom within its file.
///
/// This is used by the linker to order the layout of Atoms so that the
/// resulting image is stable and reproducible.
virtual uint64_t ordinal() const = 0;
- /// \brief the number of bytes of space this atom's content will occupy in the
+ /// the number of bytes of space this atom's content will occupy in the
/// final linked image.
///
/// For a function atom, it is the number of bytes of code in the function.
virtual uint64_t size() const = 0;
- /// \brief The size of the section from which the atom is instantiated.
+ /// The size of the section from which the atom is instantiated.
///
/// Merge::mergeByLargestSection is defined in terms of section size
/// and not in terms of atom size, so we need this function separate
/// from size().
virtual uint64_t sectionSize() const { return 0; }
- /// \brief The visibility of this atom to other atoms.
+ /// The visibility of this atom to other atoms.
///
/// C static functions have scope scopeTranslationUnit. Regular C functions
/// have scope scopeGlobal. Functions compiled with visibility=hidden have
@@ -239,48 +239,48 @@
/// not by the OS loader.
virtual Scope scope() const = 0;
- /// \brief Whether the linker should use direct or indirect access to this
+ /// Whether the linker should use direct or indirect access to this
/// atom.
virtual Interposable interposable() const = 0;
- /// \brief how the linker should handle if multiple atoms have the same name.
+ /// how the linker should handle if multiple atoms have the same name.
virtual Merge merge() const = 0;
- /// \brief The type of this atom, such as code or data.
+ /// The type of this atom, such as code or data.
virtual ContentType contentType() const = 0;
- /// \brief The alignment constraints on how this atom must be laid out in the
+ /// The alignment constraints on how this atom must be laid out in the
/// final linked image (e.g. 16-byte aligned).
virtual Alignment alignment() const = 0;
- /// \brief Whether this atom must be in a specially named section in the final
+ /// Whether this atom must be in a specially named section in the final
/// linked image, or if the linker can infer the section based on the
/// contentType().
virtual SectionChoice sectionChoice() const = 0;
- /// \brief If sectionChoice() != sectionBasedOnContent, then this return the
+ /// If sectionChoice() != sectionBasedOnContent, then this return the
/// name of the section the atom should be placed into.
virtual StringRef customSectionName() const = 0;
- /// \brief constraints on whether the linker may dead strip away this atom.
+ /// constraints on whether the linker may dead strip away this atom.
virtual DeadStripKind deadStrip() const = 0;
- /// \brief Under which conditions should this atom be dynamically exported.
+ /// Under which conditions should this atom be dynamically exported.
virtual DynamicExport dynamicExport() const {
return dynamicExportNormal;
}
- /// \brief Code model used by the atom.
+ /// Code model used by the atom.
virtual CodeModel codeModel() const { return codeNA; }
- /// \brief Returns the OS memory protections required for this atom's content
+ /// Returns the OS memory protections required for this atom's content
/// at runtime.
///
/// A function atom is R_X, a global variable is RW_, and a read-only constant
/// is R__.
virtual ContentPermissions permissions() const;
- /// \brief returns a reference to the raw (unrelocated) bytes of this Atom's
+ /// returns a reference to the raw (unrelocated) bytes of this Atom's
/// content.
virtual ArrayRef<uint8_t> rawContent() const = 0;
@@ -317,10 +317,10 @@
const void *_it;
};
- /// \brief Returns an iterator to the beginning of this Atom's References.
+ /// Returns an iterator to the beginning of this Atom's References.
virtual reference_iterator begin() const = 0;
- /// \brief Returns an iterator to the end of this Atom's References.
+ /// Returns an iterator to the end of this Atom's References.
virtual reference_iterator end() const = 0;
/// Adds a reference to this atom.
@@ -361,11 +361,11 @@
~DefinedAtom() override = default;
- /// \brief Returns a pointer to the Reference object that the abstract
+ /// Returns a pointer to the Reference object that the abstract
/// iterator "points" to.
virtual const Reference *derefIterator(const void *iter) const = 0;
- /// \brief Adjusts the abstract iterator to "point" to the next Reference
+ /// Adjusts the abstract iterator to "point" to the next Reference
/// object for this Atom.
virtual void incrementIterator(const void *&iter) const = 0;
};
diff --git a/include/lld/Core/File.h b/include/lld/Core/File.h
index 2041868..54f5335 100644
--- a/include/lld/Core/File.h
+++ b/include/lld/Core/File.h
@@ -43,7 +43,7 @@
public:
virtual ~File();
- /// \brief Kinds of files that are supported.
+ /// Kinds of files that are supported.
enum Kind {
kindErrorObject, ///< a error object file (.o)
kindNormalizedObject, ///< a normalized file (.o)
@@ -59,7 +59,7 @@
kindArchiveLibrary ///< archive (.a)
};
- /// \brief Returns file kind. Need for dyn_cast<> on File objects.
+ /// Returns file kind. Need for dyn_cast<> on File objects.
Kind kind() const {
return _kind;
}
@@ -114,10 +114,8 @@
AtomRange(AtomVector<T> &v) : _v(v) {}
AtomRange(const AtomVector<T> &v) : _v(const_cast<AtomVector<T> &>(v)) {}
- typedef std::pointer_to_unary_function<const OwningAtomPtr<T>&,
- const T*> ConstDerefFn;
-
- typedef std::pointer_to_unary_function<OwningAtomPtr<T>&, T*> DerefFn;
+ using ConstDerefFn = const T* (*)(const OwningAtomPtr<T>&);
+ using DerefFn = T* (*)(OwningAtomPtr<T>&);
typedef llvm::mapped_iterator<typename AtomVector<T>::const_iterator,
ConstDerefFn> ConstItTy;
@@ -174,19 +172,19 @@
AtomVector<T> &_v;
};
- /// \brief Must be implemented to return the AtomVector object for
+ /// Must be implemented to return the AtomVector object for
/// all DefinedAtoms in this File.
virtual const AtomRange<DefinedAtom> defined() const = 0;
- /// \brief Must be implemented to return the AtomVector object for
+ /// Must be implemented to return the AtomVector object for
/// all UndefinedAtomw in this File.
virtual const AtomRange<UndefinedAtom> undefined() const = 0;
- /// \brief Must be implemented to return the AtomVector object for
+ /// Must be implemented to return the AtomVector object for
/// all SharedLibraryAtoms in this File.
virtual const AtomRange<SharedLibraryAtom> sharedLibrary() const = 0;
- /// \brief Must be implemented to return the AtomVector object for
+ /// Must be implemented to return the AtomVector object for
/// all AbsoluteAtoms in this File.
virtual const AtomRange<AbsoluteAtom> absolute() const = 0;
@@ -196,7 +194,7 @@
/// of a different file. We need to destruct all atoms before any files.
virtual void clearAtoms() = 0;
- /// \brief If a file is parsed using a different method than doParse(),
+ /// If a file is parsed using a different method than doParse(),
/// one must use this method to set the last error status, so that
/// doParse will not be called twice. Only YAML reader uses this
/// (because YAML reader does not read blobs but structured data).
@@ -214,12 +212,12 @@
}
protected:
- /// \brief only subclasses of File can be instantiated
+ /// only subclasses of File can be instantiated
File(StringRef p, Kind kind)
: _path(p), _kind(kind), _ordinal(UINT64_MAX),
_nextAtomOrdinal(0) {}
- /// \brief Subclasses should override this method to parse the
+ /// Subclasses should override this method to parse the
/// memory buffer passed to this file's constructor.
virtual std::error_code doParse() { return std::error_code(); }
diff --git a/include/lld/Core/Instrumentation.h b/include/lld/Core/Instrumentation.h
index 1623759..939d645 100644
--- a/include/lld/Core/Instrumentation.h
+++ b/include/lld/Core/Instrumentation.h
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// \brief Provide an Instrumentation API that optionally uses VTune interfaces.
+/// Provide an Instrumentation API that optionally uses VTune interfaces.
///
//===----------------------------------------------------------------------===//
@@ -24,7 +24,7 @@
namespace lld {
#ifdef LLD_HAS_VTUNE
-/// \brief A unique global scope for instrumentation data.
+/// A unique global scope for instrumentation data.
///
/// Domains last for the lifetime of the application and cannot be destroyed.
/// Multiple Domains created with the same name represent the same domain.
@@ -38,7 +38,7 @@
__itt_domain *operator->() const { return _domain; }
};
-/// \brief A global reference to a string constant.
+/// A global reference to a string constant.
///
/// These are uniqued by the ITT runtime and cannot be deleted. They are not
/// specific to a domain.
@@ -54,7 +54,7 @@
operator __itt_string_handle *() const { return _handle; }
};
-/// \brief A task on a single thread. Nests within other tasks.
+/// A task on a single thread. Nests within other tasks.
///
/// Each thread has its own task stack and tasks nest recursively on that stack.
/// A task cannot transfer threads.
@@ -68,7 +68,7 @@
ScopedTask &operator=(const ScopedTask &) = delete;
public:
- /// \brief Create a task in Domain \p d named \p s.
+ /// Create a task in Domain \p d named \p s.
ScopedTask(const Domain &d, const StringHandle &s) : _domain(d) {
__itt_task_begin(d, __itt_null, __itt_null, s);
}
@@ -83,7 +83,7 @@
return *this;
}
- /// \brief Prematurely end this task.
+ /// Prematurely end this task.
void end() {
if (_domain)
__itt_task_end(_domain);
@@ -93,7 +93,7 @@
~ScopedTask() { end(); }
};
-/// \brief A specific point in time. Allows metadata to be associated.
+/// A specific point in time. Allows metadata to be associated.
class Marker {
public:
Marker(const Domain &d, const StringHandle &s) {
diff --git a/include/lld/Core/LinkingContext.h b/include/lld/Core/LinkingContext.h
index eb9510c..6dffdd4 100644
--- a/include/lld/Core/LinkingContext.h
+++ b/include/lld/Core/LinkingContext.h
@@ -31,7 +31,7 @@
class Node;
class SharedLibraryFile;
-/// \brief The LinkingContext class encapsulates "what and how" to link.
+/// The LinkingContext class encapsulates "what and how" to link.
///
/// The base class LinkingContext contains the options needed by core linking.
/// Subclasses of LinkingContext have additional options needed by specific
diff --git a/include/lld/Core/PassManager.h b/include/lld/Core/PassManager.h
index 2ea65ae..f2ef10f 100644
--- a/include/lld/Core/PassManager.h
+++ b/include/lld/Core/PassManager.h
@@ -20,7 +20,7 @@
class SimpleFile;
class Pass;
-/// \brief Owns and runs a collection of passes.
+/// Owns and runs a collection of passes.
///
/// This class is currently just a container for passes and a way to run them.
///
@@ -40,7 +40,7 @@
}
private:
- /// \brief Passes in the order they should run.
+ /// Passes in the order they should run.
std::vector<std::unique_ptr<Pass>> _passes;
};
} // end namespace lld
diff --git a/include/lld/Core/Reader.h b/include/lld/Core/Reader.h
index c7baf86..6cf6282 100644
--- a/include/lld/Core/Reader.h
+++ b/include/lld/Core/Reader.h
@@ -32,7 +32,7 @@
class LinkingContext;
class MachOLinkingContext;
-/// \brief An abstract class for reading object files, library files, and
+/// An abstract class for reading object files, library files, and
/// executable files.
///
/// Each file format (e.g. mach-o, etc) has a concrete subclass of Reader.
@@ -46,14 +46,14 @@
/// 2) the whole file content buffer if the above is not enough.
virtual bool canParse(llvm::file_magic magic, MemoryBufferRef mb) const = 0;
- /// \brief Parse a supplied buffer (already filled with the contents of a
+ /// Parse a supplied buffer (already filled with the contents of a
/// file) and create a File object.
/// The resulting File object takes ownership of the MemoryBuffer.
virtual ErrorOr<std::unique_ptr<File>>
loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &) const = 0;
};
-/// \brief An abstract class for handling alternate yaml representations
+/// An abstract class for handling alternate yaml representations
/// of object files.
///
/// The YAML syntax allows "tags" which are used to specify the type of
diff --git a/include/lld/Core/Resolver.h b/include/lld/Core/Resolver.h
index fb62a77..5157c9f 100644
--- a/include/lld/Core/Resolver.h
+++ b/include/lld/Core/Resolver.h
@@ -28,7 +28,7 @@
class Atom;
class LinkingContext;
-/// \brief The Resolver is responsible for merging all input object files
+/// The Resolver is responsible for merging all input object files
/// and producing a merged graph.
class Resolver {
public:
@@ -50,7 +50,7 @@
// Handle a shared library file.
llvm::Error handleSharedLibrary(File &);
- /// @brief do work of merging and resolving and return list
+ /// do work of merging and resolving and return list
bool resolve();
std::unique_ptr<SimpleFile> resultFile() { return std::move(_result); }
@@ -61,7 +61,7 @@
bool undefinesAdded(int begin, int end);
File *getFile(int &index);
- /// \brief The main function that iterates over the files to resolve
+ /// The main function that iterates over the files to resolve
bool resolveUndefines();
void updateReferences();
void deadStripOptimize();
diff --git a/include/lld/Core/Simple.h b/include/lld/Core/Simple.h
index 3aa7abf..feeed6a 100644
--- a/include/lld/Core/Simple.h
+++ b/include/lld/Core/Simple.h
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// \brief Provide simple implementations for Atoms and File.
+/// Provide simple implementations for Atoms and File.
///
//===----------------------------------------------------------------------===//
diff --git a/include/lld/Core/SymbolTable.h b/include/lld/Core/SymbolTable.h
index 603f497..156c56e 100644
--- a/include/lld/Core/SymbolTable.h
+++ b/include/lld/Core/SymbolTable.h
@@ -27,35 +27,35 @@
class SharedLibraryAtom;
class UndefinedAtom;
-/// \brief The SymbolTable class is responsible for coalescing atoms.
+/// The SymbolTable class is responsible for coalescing atoms.
///
/// All atoms coalescable by-name or by-content should be added.
/// The method replacement() can be used to find the replacement atom
/// if an atom has been coalesced away.
class SymbolTable {
public:
- /// @brief add atom to symbol table
+ /// add atom to symbol table
bool add(const DefinedAtom &);
- /// @brief add atom to symbol table
+ /// add atom to symbol table
bool add(const UndefinedAtom &);
- /// @brief add atom to symbol table
+ /// add atom to symbol table
bool add(const SharedLibraryAtom &);
- /// @brief add atom to symbol table
+ /// add atom to symbol table
bool add(const AbsoluteAtom &);
- /// @brief returns atom in symbol table for specified name (or nullptr)
+ /// returns atom in symbol table for specified name (or nullptr)
const Atom *findByName(StringRef sym);
- /// @brief returns vector of remaining UndefinedAtoms
+ /// returns vector of remaining UndefinedAtoms
std::vector<const UndefinedAtom *> undefines();
- /// @brief if atom has been coalesced away, return replacement, else return atom
+ /// if atom has been coalesced away, return replacement, else return atom
const Atom *replacement(const Atom *);
- /// @brief if atom has been coalesced away, return true
+ /// if atom has been coalesced away, return true
bool isCoalescedAway(const Atom *);
private:
diff --git a/include/lld/Core/Writer.h b/include/lld/Core/Writer.h
index 1f0ca4c..1cdfabe 100644
--- a/include/lld/Core/Writer.h
+++ b/include/lld/Core/Writer.h
@@ -20,17 +20,17 @@
class LinkingContext;
class MachOLinkingContext;
-/// \brief The Writer is an abstract class for writing object files, shared
+/// The Writer is an abstract class for writing object files, shared
/// library files, and executable files. Each file format (e.g. mach-o, etc)
/// has a concrete subclass of Writer.
class Writer {
public:
virtual ~Writer();
- /// \brief Write a file from the supplied File object
+ /// Write a file from the supplied File object
virtual llvm::Error writeFile(const File &linkedFile, StringRef path) = 0;
- /// \brief This method is called by Core Linking to give the Writer a chance
+ /// This method is called by Core Linking to give the Writer a chance
/// to add file format specific "files" to set of files to be linked. This is
/// how file format specific atoms can be added to the link.
virtual void createImplicitFiles(std::vector<std::unique_ptr<File>> &) {}
diff --git a/include/lld/ReaderWriter/MachOLinkingContext.h b/include/lld/ReaderWriter/MachOLinkingContext.h
index 9eefa8c..5f9588d 100644
--- a/include/lld/ReaderWriter/MachOLinkingContext.h
+++ b/include/lld/ReaderWriter/MachOLinkingContext.h
@@ -201,7 +201,7 @@
uint32_t swiftVersion() const { return _swiftVersion; }
- /// \brief Checks whether a given path on the filesystem exists.
+ /// Checks whether a given path on the filesystem exists.
///
/// When running in -test_file_usage mode, this method consults an
/// internally maintained list of files that exist (provided by -path_exists)
@@ -211,7 +211,7 @@
/// Like pathExists() but only used on files - not directories.
bool fileExists(StringRef path) const;
- /// \brief Adds any library search paths derived from the given base, possibly
+ /// Adds any library search paths derived from the given base, possibly
/// modified by -syslibroots.
///
/// The set of paths added consists of approximately all syslibroot-prepended
@@ -219,7 +219,7 @@
/// for whatever reason. With various edge-cases for compatibility.
void addModifiedSearchDir(StringRef libPath, bool isSystemPath = false);
- /// \brief Determine whether -lFoo can be resolve within the given path, and
+ /// Determine whether -lFoo can be resolve within the given path, and
/// return the filename if so.
///
/// The -lFoo option is documented to search for libFoo.dylib and libFoo.a in
@@ -228,7 +228,7 @@
llvm::Optional<StringRef> searchDirForLibrary(StringRef path,
StringRef libName) const;
- /// \brief Iterates through all search path entries looking for libName (as
+ /// Iterates through all search path entries looking for libName (as
/// specified by -lFoo).
llvm::Optional<StringRef> searchLibrary(StringRef libName) const;
@@ -236,11 +236,11 @@
/// the path with syslibroot.
void addFrameworkSearchDir(StringRef fwPath, bool isSystemPath = false);
- /// \brief Iterates through all framework directories looking for
+ /// Iterates through all framework directories looking for
/// Foo.framework/Foo (when fwName = "Foo").
llvm::Optional<StringRef> findPathForFramework(StringRef fwName) const;
- /// \brief The dylib's binary compatibility version, in the raw uint32 format.
+ /// The dylib's binary compatibility version, in the raw uint32 format.
///
/// When building a dynamic library, this is the compatibility version that
/// gets embedded into the result. Other Mach-O binaries that link against
@@ -249,28 +249,28 @@
/// installed dynamic library.
uint32_t compatibilityVersion() const { return _compatibilityVersion; }
- /// \brief The dylib's current version, in the the raw uint32 format.
+ /// The dylib's current version, in the the raw uint32 format.
///
/// When building a dynamic library, this is the current version that gets
/// embedded into the result. Other Mach-O binaries that link against
/// this library will store the compatibility version in its load command.
uint32_t currentVersion() const { return _currentVersion; }
- /// \brief The dylib's install name.
+ /// The dylib's install name.
///
/// Binaries that link against the dylib will embed this path into the dylib
/// load command. When loading the binaries at runtime, this is the location
/// on disk that the loader will look for the dylib.
StringRef installName() const { return _installName; }
- /// \brief Whether or not the dylib has side effects during initialization.
+ /// Whether or not the dylib has side effects during initialization.
///
/// Dylibs marked as being dead strippable provide the guarantee that loading
/// the dylib has no side effects, allowing the linker to strip out the dylib
/// when linking a binary that does not use any of its symbols.
bool deadStrippableDylib() const { return _deadStrippableDylib; }
- /// \brief Whether or not to use flat namespace.
+ /// Whether or not to use flat namespace.
///
/// MachO usually uses a two-level namespace, where each external symbol
/// referenced by the target is associated with the dylib that will provide
@@ -282,7 +282,7 @@
/// loaded flat_namespace dylibs must be resolvable at build time.
bool useFlatNamespace() const { return _flatNamespace; }
- /// \brief How to handle undefined symbols.
+ /// How to handle undefined symbols.
///
/// Options are:
/// * error: Report an error and terminate linking.
@@ -294,7 +294,7 @@
/// runtime.
UndefinedMode undefinedMode() const { return _undefinedMode; }
- /// \brief The path to the executable that will load the bundle at runtime.
+ /// The path to the executable that will load the bundle at runtime.
///
/// When building a Mach-O bundle, this executable will be examined if there
/// are undefined symbols after the main link phase. It is expected that this
@@ -331,7 +331,7 @@
/// Add section alignment constraint on final layout.
void addSectionAlignment(StringRef seg, StringRef sect, uint16_t align);
- /// \brief Add a section based on a command-line sectcreate option.
+ /// Add a section based on a command-line sectcreate option.
void addSectCreateSection(StringRef seg, StringRef sect,
std::unique_ptr<MemoryBuffer> content);
diff --git a/lib/Driver/DarwinLdDriver.cpp b/lib/Driver/DarwinLdDriver.cpp
index a019e9c..e016a3d 100644
--- a/lib/Driver/DarwinLdDriver.cpp
+++ b/lib/Driver/DarwinLdDriver.cpp
@@ -1068,7 +1068,7 @@
}
// Parse the LLVM options before we process files in case the file handling
- // makes use of things like DEBUG().
+ // makes use of things like LLVM_DEBUG().
parseLLVMOptions(ctx);
// Handle input files and sectcreate.
diff --git a/lib/ReaderWriter/FileArchive.cpp b/lib/ReaderWriter/FileArchive.cpp
index 04c0bee..2f52d9d 100644
--- a/lib/ReaderWriter/FileArchive.cpp
+++ b/lib/ReaderWriter/FileArchive.cpp
@@ -38,7 +38,7 @@
namespace {
-/// \brief The FileArchive class represents an Archive Library file
+/// The FileArchive class represents an Archive Library file
class FileArchive : public lld::ArchiveLibraryFile {
public:
FileArchive(std::unique_ptr<MemoryBuffer> mb, const Registry ®,
@@ -46,7 +46,7 @@
: ArchiveLibraryFile(path), _mb(std::shared_ptr<MemoryBuffer>(mb.release())),
_registry(reg), _logLoading(logLoading) {}
- /// \brief Check if any member of the archive contains an Atom with the
+ /// Check if any member of the archive contains an Atom with the
/// specified name and return the File object for that member, or nullptr.
File *find(StringRef name) override {
auto member = _symbolMemberMap.find(name);
@@ -77,7 +77,7 @@
return file;
}
- /// \brief parse each member
+ /// parse each member
std::error_code
parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
if (std::error_code ec = parse())
diff --git a/lib/ReaderWriter/MachO/CompactUnwindPass.cpp b/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
index 1e21040..fa0aaa1 100644
--- a/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
+++ b/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
@@ -282,7 +282,7 @@
private:
llvm::Error perform(SimpleFile &mergedFile) override {
- DEBUG(llvm::dbgs() << "MachO Compact Unwind pass\n");
+ LLVM_DEBUG(llvm::dbgs() << "MachO Compact Unwind pass\n");
std::map<const Atom *, CompactUnwindEntry> unwindLocs;
std::map<const Atom *, const Atom *> dwarfFrames;
@@ -319,7 +319,7 @@
// Finally, we can start creating pages based on these entries.
- DEBUG(llvm::dbgs() << " Splitting entries into pages\n");
+ LLVM_DEBUG(llvm::dbgs() << " Splitting entries into pages\n");
// FIXME: we split the entries into pages naively: lots of 4k pages followed
// by a small one. ld64 tried to minimize space and align them to real 4k
// boundaries. That might be worth doing, or perhaps we could perform some
@@ -336,11 +336,13 @@
pages.back().entries = remainingInfos.slice(0, entriesInPage);
remainingInfos = remainingInfos.slice(entriesInPage);
- DEBUG(llvm::dbgs()
- << " Page from " << pages.back().entries[0].rangeStart->name()
- << " to " << pages.back().entries.back().rangeStart->name() << " + "
- << llvm::format("0x%x", pages.back().entries.back().rangeLength)
- << " has " << entriesInPage << " entries\n");
+ LLVM_DEBUG(llvm::dbgs()
+ << " Page from "
+ << pages.back().entries[0].rangeStart->name() << " to "
+ << pages.back().entries.back().rangeStart->name() << " + "
+ << llvm::format("0x%x",
+ pages.back().entries.back().rangeLength)
+ << " has " << entriesInPage << " entries\n");
} while (!remainingInfos.empty());
auto *unwind = new (_file.allocator())
@@ -360,7 +362,7 @@
const SimpleFile &mergedFile,
std::map<const Atom *, CompactUnwindEntry> &unwindLocs,
std::vector<const Atom *> &personalities, uint32_t &numLSDAs) {
- DEBUG(llvm::dbgs() << " Collecting __compact_unwind entries\n");
+ LLVM_DEBUG(llvm::dbgs() << " Collecting __compact_unwind entries\n");
for (const DefinedAtom *atom : mergedFile.defined()) {
if (atom->contentType() != DefinedAtom::typeCompactUnwindInfo)
@@ -369,14 +371,15 @@
auto unwindEntry = extractCompactUnwindEntry(atom);
unwindLocs.insert(std::make_pair(unwindEntry.rangeStart, unwindEntry));
- DEBUG(llvm::dbgs() << " Entry for " << unwindEntry.rangeStart->name()
- << ", encoding="
- << llvm::format("0x%08x", unwindEntry.encoding));
+ LLVM_DEBUG(llvm::dbgs() << " Entry for "
+ << unwindEntry.rangeStart->name() << ", encoding="
+ << llvm::format("0x%08x", unwindEntry.encoding));
if (unwindEntry.personalityFunction)
- DEBUG(llvm::dbgs() << ", personality="
- << unwindEntry.personalityFunction->name()
- << ", lsdaLoc=" << unwindEntry.lsdaLocation->name());
- DEBUG(llvm::dbgs() << '\n');
+ LLVM_DEBUG(llvm::dbgs()
+ << ", personality="
+ << unwindEntry.personalityFunction->name()
+ << ", lsdaLoc=" << unwindEntry.lsdaLocation->name());
+ LLVM_DEBUG(llvm::dbgs() << '\n');
// Count number of LSDAs we see, since we need to know how big the index
// will be while laying out the section.
@@ -454,7 +457,7 @@
const std::map<const Atom *, const Atom *> &dwarfFrames) {
std::vector<CompactUnwindEntry> unwindInfos;
- DEBUG(llvm::dbgs() << " Creating __unwind_info entries\n");
+ LLVM_DEBUG(llvm::dbgs() << " Creating __unwind_info entries\n");
// The final order in the __unwind_info section must be derived from the
// order of typeCode atoms, since that's how they'll be put into the object
// file eventually (yuck!).
@@ -465,10 +468,10 @@
unwindInfos.push_back(finalizeUnwindInfoEntryForAtom(
atom, unwindLocs, personalities, dwarfFrames));
- DEBUG(llvm::dbgs() << " Entry for " << atom->name()
- << ", final encoding="
- << llvm::format("0x%08x", unwindInfos.back().encoding)
- << '\n');
+ LLVM_DEBUG(llvm::dbgs()
+ << " Entry for " << atom->name() << ", final encoding="
+ << llvm::format("0x%08x", unwindInfos.back().encoding)
+ << '\n');
}
return unwindInfos;
diff --git a/lib/ReaderWriter/MachO/LayoutPass.cpp b/lib/ReaderWriter/MachO/LayoutPass.cpp
index 7bca07e..9058e4f 100644
--- a/lib/ReaderWriter/MachO/LayoutPass.cpp
+++ b/lib/ReaderWriter/MachO/LayoutPass.cpp
@@ -191,7 +191,7 @@
// Sort atoms by their ordinal overrides only if they fall in the same
// chain.
if (leftRoot == rightRoot) {
- DEBUG(reason = formatReason("override", lc._override, rc._override));
+ LLVM_DEBUG(reason = formatReason("override", lc._override, rc._override));
return lc._override < rc._override;
}
@@ -200,8 +200,8 @@
DefinedAtom::ContentPermissions rightPerms = rightRoot->permissions();
if (leftPerms != rightPerms) {
- DEBUG(reason =
- formatReason("contentPerms", (int)leftPerms, (int)rightPerms));
+ LLVM_DEBUG(
+ reason = formatReason("contentPerms", (int)leftPerms, (int)rightPerms));
return leftPerms < rightPerms;
}
@@ -210,7 +210,8 @@
DefinedAtom::ContentType rightType = rightRoot->contentType();
if (leftType != rightType) {
- DEBUG(reason = formatReason("contentType", (int)leftType, (int)rightType));
+ LLVM_DEBUG(reason =
+ formatReason("contentType", (int)leftType, (int)rightType));
return leftType < rightType;
}
@@ -226,8 +227,8 @@
const File *rightFile = &rightRoot->file();
if (leftFile != rightFile) {
- DEBUG(reason = formatReason(".o order", (int)leftFile->ordinal(),
- (int)rightFile->ordinal()));
+ LLVM_DEBUG(reason = formatReason(".o order", (int)leftFile->ordinal(),
+ (int)rightFile->ordinal()));
return leftFile->ordinal() < rightFile->ordinal();
}
@@ -236,8 +237,8 @@
uint64_t rightOrdinal = rightRoot->ordinal();
if (leftOrdinal != rightOrdinal) {
- DEBUG(reason = formatReason("ordinal", (int)leftRoot->ordinal(),
- (int)rightRoot->ordinal()));
+ LLVM_DEBUG(reason = formatReason("ordinal", (int)leftRoot->ordinal(),
+ (int)rightRoot->ordinal()));
return leftOrdinal < rightOrdinal;
}
@@ -251,7 +252,7 @@
LayoutPass::SortOverride customSorter) {
std::string reason;
bool result = compareAtomsSub(lc, rc, customSorter, reason);
- DEBUG({
+ LLVM_DEBUG({
StringRef comp = result ? "<" : ">=";
llvm::dbgs() << "Layout: '" << lc._atom.get()->name()
<< "' " << comp << " '"
@@ -441,7 +442,7 @@
/// Perform the actual pass
llvm::Error LayoutPass::perform(SimpleFile &mergedFile) {
- DEBUG(llvm::dbgs() << "******** Laying out atoms:\n");
+ LLVM_DEBUG(llvm::dbgs() << "******** Laying out atoms:\n");
// sort the atoms
ScopedTask task(getDefaultDomain(), "LayoutPass");
File::AtomRange<DefinedAtom> atomRange = mergedFile.defined();
@@ -450,12 +451,12 @@
buildFollowOnTable(atomRange);
// Check the structure of followon graph if running in debug mode.
- DEBUG(checkFollowonChain(atomRange));
+ LLVM_DEBUG(checkFollowonChain(atomRange));
// Build override maps
buildOrdinalOverrideMap(atomRange);
- DEBUG({
+ LLVM_DEBUG({
llvm::dbgs() << "unsorted atoms:\n";
printDefinedAtoms(atomRange);
});
@@ -465,15 +466,15 @@
[&](const LayoutPass::SortKey &l, const LayoutPass::SortKey &r) -> bool {
return compareAtoms(l, r, _customSorter);
});
- DEBUG(checkTransitivity(vec, _customSorter));
+ LLVM_DEBUG(checkTransitivity(vec, _customSorter));
undecorate(atomRange, vec);
- DEBUG({
+ LLVM_DEBUG({
llvm::dbgs() << "sorted atoms:\n";
printDefinedAtoms(atomRange);
});
- DEBUG(llvm::dbgs() << "******** Finished laying out atoms\n");
+ LLVM_DEBUG(llvm::dbgs() << "******** Finished laying out atoms\n");
return llvm::Error::success();
}
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
index 4617d23..473de89 100644
--- a/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
@@ -1431,8 +1431,8 @@
normalizedObjectToAtoms(MachOFile *file,
const NormalizedFile &normalizedFile,
bool copyRefs) {
- DEBUG(llvm::dbgs() << "******** Normalizing file to atoms: "
- << file->path() << "\n");
+ LLVM_DEBUG(llvm::dbgs() << "******** Normalizing file to atoms: "
+ << file->path() << "\n");
bool scatterable = ((normalizedFile.flags & MH_SUBSECTIONS_VIA_SYMBOLS) != 0);
// Create atoms from each section.
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index f9c3983..e5284ca 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -34,7 +34,7 @@
list(APPEND LLD_TEST_DEPS
FileCheck count not llvm-ar llvm-as llvm-dis llvm-dwarfdump llvm-nm
llc llvm-config llvm-objdump llvm-readelf llvm-readobj yaml2obj obj2yaml
- llvm-mc llvm-lib llvm-pdbutil opt
+ llvm-mc llvm-lib llvm-pdbutil opt llvm-bcanalyzer
)
endif()
diff --git a/test/COFF/Inputs/far-arm64-abs.s b/test/COFF/Inputs/far-arm64-abs.s
new file mode 100644
index 0000000..98ccbac
--- /dev/null
+++ b/test/COFF/Inputs/far-arm64-abs.s
@@ -0,0 +1,6 @@
+.global too_far26
+.global too_far19
+.global too_far14
+too_far26 = 0x08011000
+too_far19 = 0x00111000
+too_far14 = 0x00021000
diff --git a/test/COFF/Inputs/pdb-file-statics-a.yaml b/test/COFF/Inputs/pdb-file-statics-a.yaml
index 1a0dbdb..957eb5a 100644
--- a/test/COFF/Inputs/pdb-file-statics-a.yaml
+++ b/test/COFF/Inputs/pdb-file-statics-a.yaml
@@ -1353,7 +1353,7 @@
RegRelativeSym:
Offset: 48
Type: 116
- Register: RSP
+ Register: CVRegRSP
VarName: __formal
- Kind: S_PROC_ID_END
ScopeEndSym:
@@ -1528,13 +1528,13 @@
RegRelativeSym:
Offset: 48
Type: 116
- Register: RSP
+ Register: CVRegRSP
VarName: argc
- Kind: S_REGREL32
RegRelativeSym:
Offset: 56
Type: 4098
- Register: RSP
+ Register: CVRegRSP
VarName: argv
- Kind: S_PROC_ID_END
ScopeEndSym:
diff --git a/test/COFF/Inputs/pdb-file-statics-b.yaml b/test/COFF/Inputs/pdb-file-statics-b.yaml
index f74bab7..8b7a311 100644
--- a/test/COFF/Inputs/pdb-file-statics-b.yaml
+++ b/test/COFF/Inputs/pdb-file-statics-b.yaml
@@ -1328,7 +1328,7 @@
RegRelativeSym:
Offset: 48
Type: 116
- Register: RSP
+ Register: CVRegRSP
VarName: __formal
- Kind: S_PROC_ID_END
ScopeEndSym:
diff --git a/test/COFF/Inputs/pdb-hashes-1.yaml b/test/COFF/Inputs/pdb-hashes-1.yaml
index ba11ed1..158f936 100644
--- a/test/COFF/Inputs/pdb-hashes-1.yaml
+++ b/test/COFF/Inputs/pdb-hashes-1.yaml
@@ -1,13 +1,13 @@
--- !COFF
-header:
+header:
Machine: IMAGE_FILE_MACHINE_I386
Characteristics: [ ]
-sections:
+sections:
- Name: .text
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
Alignment: 16
- SectionData: 5589E55683EC188B450C8B4D088D55F4C745F8000000008B7508894DF089D18934248945ECE80000000083EC048D4DF4890C248945E8E80000000083C4185E5DC3
- Relocations:
+ SectionData: 5589E55683EC188B450C8B4D08C745F8000000008B55088D75F4894DF089F18914248945ECE80000000083EC048D4DF4890C248945E8E80000000083C4185E5DC3
+ Relocations:
- VirtualAddress: 38
SymbolName: '??0Foo@NS@@QAE@H@Z'
Type: IMAGE_REL_I386_REL32
@@ -33,25 +33,25 @@
- Name: '.debug$S'
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
Alignment: 4
- SectionData: 04000000F10000002F0000002D003C1101000000070006000000000000007017000000000000636C616E672076657273696F6E20362E302E30200000F50000008400000000000000000000004100000000000000080000000000000052000000070000000400000001000000400000000000000008000000000000007F0000000600040000000000030000003E000000000000000800000000000000BD0000000400040000000000040000003D000000000000000800000000000000FA0000000300080000000000F1000000960000002A00471100000000000000000000000041000000000000000000000003100000000000000000006D61696E000D003E1174000000010061726763001200451116000000080000001700000000002A000D003E11001000000100617267760012004511160000000C0000001700000000002A000A003E1109100000000066001200451116000000F4FFFFFF1700000000002A0002004F110000F200000030000000000000000000000041000000000000000300000024000000000000000300000017000000040000003000000005000000F1000000100000000E000811091000004E533A3A466F6F00F40000003000000001000000100165C9E387F88362A8EB2B49539DD5A65500002B00000010019303CF100D518DAF59C31DA01FEF4AFC0000F30000004801000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A312E63707000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A2E6800245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200024543020246562702034202B203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200024543020246562702034202B203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D2024657369202454302038202D205E203D2000
- Subsections:
+ SectionData: 04000000F10000002F0000002D003C110100000007000700000000000000581B000000000000636C616E672076657273696F6E20372E302E30200000F50000008400000000000000000000004100000000000000080000000000000052000000070000000400000001000000400000000000000008000000000000007F0000000600040000000000030000003E000000000000000800000000000000BD0000000400040000000000040000003D000000000000000800000000000000FA0000000300080000000000F1000000960000002A00471100000000000000000000000041000000000000000000000003100000000000000000006D61696E000D003E1174000000010061726763001200451116000000080000001400000000002D000D003E11001000000100617267760012004511160000000C0000001400000000002D000A003E1109100000000066001200451116000000F4FFFFFF1400000000002D0002004F110000F200000030000000000000000000000041000000000000000300000024000000000000000300000014000000040000002D00000005000000F1000000100000000E000811091000004E533A3A466F6F00F40000003000000001000000100165C9E387F88362A8EB2B49539DD5A65500002B0000001001D3AE9D06B0C1F06ABE75A0557053ED6B0000F30000004801000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A312E63707000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A2E6800245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200024543020246562702034202B203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200024543020246562702034202B203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D2024657369202454302038202D205E203D2000
+ Subsections:
- !Symbols
- Records:
+ Records:
- Kind: S_COMPILE3
- Compile3Sym:
+ Compile3Sym:
Flags: [ ]
Machine: Pentium3
- FrontendMajor: 6
+ FrontendMajor: 7
FrontendMinor: 0
FrontendBuild: 0
FrontendQFE: 0
- BackendMajor: 6000
+ BackendMajor: 7000
BackendMinor: 0
BackendBuild: 0
BackendQFE: 0
- Version: 'clang version 6.0.0 '
+ Version: 'clang version 7.0.0 '
- !FrameData
- Frames:
+ Frames:
- CodeSize: 65
FrameFunc: '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = '
LocalSize: 0
@@ -85,9 +85,9 @@
RvaStart: 4
SavedRegsSize: 8
- !Symbols
- Records:
+ Records:
- Kind: S_GPROC32_ID
- ProcSym:
+ ProcSym:
CodeSize: 65
DbgStart: 0
DbgEnd: 0
@@ -95,66 +95,96 @@
Flags: [ ]
DisplayName: main
- Kind: S_LOCAL
- LocalSym:
+ LocalSym:
Type: 116
Flags: [ IsParameter ]
VarName: argc
+ - Kind: S_DEFRANGE_REGISTER_REL
+ DefRangeRegisterRelSym:
+ Register: 22
+ Flags: 0
+ BasePointerOffset: 8
+ Range:
+ OffsetStart: 20
+ ISectStart: 0
+ Range: 45
+ Gaps:
- Kind: S_LOCAL
- LocalSym:
+ LocalSym:
Type: 4096
Flags: [ IsParameter ]
VarName: argv
+ - Kind: S_DEFRANGE_REGISTER_REL
+ DefRangeRegisterRelSym:
+ Register: 22
+ Flags: 0
+ BasePointerOffset: 12
+ Range:
+ OffsetStart: 20
+ ISectStart: 0
+ Range: 45
+ Gaps:
- Kind: S_LOCAL
- LocalSym:
+ LocalSym:
Type: 4105
Flags: [ ]
VarName: f
+ - Kind: S_DEFRANGE_REGISTER_REL
+ DefRangeRegisterRelSym:
+ Register: 22
+ Flags: 0
+ BasePointerOffset: -12
+ Range:
+ OffsetStart: 20
+ ISectStart: 0
+ Range: 45
+ Gaps:
- Kind: S_PROC_ID_END
- ScopeEndSym:
+ ScopeEndSym:
- !Lines
CodeSize: 65
Flags: [ ]
RelocOffset: 0
RelocSegment: 0
- Blocks:
+ Blocks:
- FileName: 'D:\src\llvmbuild\clang\Debug\x86\obj1.cpp'
- Lines:
+ Lines:
- Offset: 0
LineStart: 3
IsStatement: false
EndDelta: 0
- - Offset: 23
+ - Offset: 20
LineStart: 4
IsStatement: false
EndDelta: 0
- - Offset: 48
+ - Offset: 45
LineStart: 5
IsStatement: false
EndDelta: 0
- Columns:
+ Columns:
- !Symbols
- Records:
+ Records:
- Kind: S_UDT
- UDTSym:
+ UDTSym:
Type: 4105
UDTName: 'NS::Foo'
- !FileChecksums
- Checksums:
+ Checksums:
- FileName: 'D:\src\llvmbuild\clang\Debug\x86\obj1.cpp'
Kind: MD5
Checksum: 65C9E387F88362A8EB2B49539DD5A655
- FileName: 'D:\src\llvmbuild\clang\Debug\x86\obj.h'
Kind: MD5
- Checksum: 9303CF100D518DAF59C31DA01FEF4AFC
+ Checksum: D3AE9D06B0C1F06ABE75A0557053ED6B
- !StringTable
- Strings:
+ Strings:
- 'D:\src\llvmbuild\clang\Debug\x86\obj1.cpp'
- 'D:\src\llvmbuild\clang\Debug\x86\obj.h'
- '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = '
- '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = '
- '$T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = '
- '$T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $esi $T0 8 - ^ = '
- Relocations:
+ Relocations:
- VirtualAddress: 68
SymbolName: _main
Type: IMAGE_REL_I386_DIR32NB
@@ -192,28 +222,28 @@
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
Alignment: 4
SectionData: 040000000A000210700400000A8000000E0001120200000074000000001000000E0008107400000000000200011000001200011600000000021000006D61696E00F3F2F12A0005150000800200000000000000000000000000004E533A3A466F6F002E3F4155466F6F404E53404000F10A000210041000000A8000000A00011201000000740000001A0009100300000004100000051000000B00010006100000000000001A0003120D15030074000000000058001115030007100000466F6F002A0005150200000208100000000000000000000004004E533A3A466F6F002E3F4155466F6F404E53404000F12E00051600000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A2E6800F10E000616091000000A100000020000000E0002160410000007100000466F6F00
- Types:
+ Types:
- Kind: LF_POINTER
- Pointer:
+ Pointer:
ReferentType: 1136
Attrs: 32778
- Kind: LF_ARGLIST
- ArgList:
+ ArgList:
ArgIndices: [ 116, 4096 ]
- Kind: LF_PROCEDURE
- Procedure:
+ Procedure:
ReturnType: 116
CallConv: NearC
Options: [ None ]
ParameterCount: 2
ArgumentList: 4097
- Kind: LF_FUNC_ID
- FuncId:
+ FuncId:
ParentScope: 0
FunctionType: 4098
Name: main
- Kind: LF_STRUCTURE
- Class:
+ Class:
MemberCount: 0
Options: [ None, ForwardReference, HasUniqueName ]
FieldList: 0
@@ -223,14 +253,14 @@
VTableShape: 0
Size: 0
- Kind: LF_POINTER
- Pointer:
+ Pointer:
ReferentType: 4100
Attrs: 32778
- Kind: LF_ARGLIST
- ArgList:
+ ArgList:
ArgIndices: [ 116 ]
- Kind: LF_MFUNCTION
- MemberFunction:
+ MemberFunction:
ReturnType: 3
ClassType: 4100
ThisType: 4101
@@ -240,21 +270,21 @@
ArgumentList: 4102
ThisPointerAdjustment: 0
- Kind: LF_FIELDLIST
- FieldList:
+ FieldList:
- Kind: LF_MEMBER
- DataMember:
+ DataMember:
Attrs: 3
Type: 116
FieldOffset: 0
Name: X
- Kind: LF_ONEMETHOD
- OneMethod:
+ OneMethod:
Type: 4103
Attrs: 3
VFTableOffset: -1
Name: Foo
- Kind: LF_STRUCTURE
- Class:
+ Class:
MemberCount: 2
Options: [ None, HasUniqueName ]
FieldList: 4104
@@ -264,47 +294,47 @@
VTableShape: 0
Size: 4
- Kind: LF_STRING_ID
- StringId:
+ StringId:
Id: 0
String: 'D:\src\llvmbuild\clang\Debug\x86\obj.h'
- Kind: LF_UDT_SRC_LINE
- UdtSourceLine:
+ UdtSourceLine:
UDT: 4105
SourceFile: 4106
LineNumber: 2
- Kind: LF_MFUNC_ID
- MemberFuncId:
+ MemberFuncId:
ClassType: 4100
FunctionType: 4103
Name: Foo
- Name: '.debug$H'
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
Alignment: 4
- SectionData: C5C93301000000009E56666824DC4B12E25261D4E09E6E9DA0F4EE31FDEC3D2D96287486127C66070B248ED52E421F55074AE5CC2D68AF9F0A3BEF23993968F7FD82CA84BF0439C1A64C9070C6A6ADB0A34D21DAD0FFC3E99E616EF06A14EA74A2420F9062A1FB04917E5975E3A50EABE5E8FE3945468547C19DC681D0BFB3B797DD91CA4D7F1953C314442D5549419E78044E38A0BF16BFFAA5EE9C0103E7DBFE9941E63379C0B0C0A9021B711ACC4F67008974EBF441031BDD653F6935DFF3112C6A5346EF2AC94B9B7EB56EF55CFA0AF6C1846743F43D846BB19517E12E8873BBA90CC41DD1BEAC89CBA8897AC1BA46762E2557A82D894CEAE81AEF8680D723D403D9A4481F0E28683A98
- GlobalHashes:
+ SectionData: C5C9330100000100800309EE1ED8BB5B5397319F1CC14E2CDF04AA3125BBC50E95CEBA304A2C449323ADA4E788EB7A90B5DECADF1A832BA46632585CDC7606E4B97B86241E5F45B0BCD2406E22465E11A528BEF0A7F589C76079F1186C40C2165091EFEBD5B5446B26FFBFD620CFB362
+ GlobalHashes:
Version: 0
- HashAlgorithm: 0
- HashValues:
- - 9E56666824DC4B12E25261D4E09E6E9DA0F4EE31
- - FDEC3D2D96287486127C66070B248ED52E421F55
- - 074AE5CC2D68AF9F0A3BEF23993968F7FD82CA84
- - BF0439C1A64C9070C6A6ADB0A34D21DAD0FFC3E9
- - 9E616EF06A14EA74A2420F9062A1FB04917E5975
- - E3A50EABE5E8FE3945468547C19DC681D0BFB3B7
- - 97DD91CA4D7F1953C314442D5549419E78044E38
- - A0BF16BFFAA5EE9C0103E7DBFE9941E63379C0B0
- - C0A9021B711ACC4F67008974EBF441031BDD653F
- - 6935DFF3112C6A5346EF2AC94B9B7EB56EF55CFA
- - 0AF6C1846743F43D846BB19517E12E8873BBA90C
- - C41DD1BEAC89CBA8897AC1BA46762E2557A82D89
- - 4CEAE81AEF8680D723D403D9A4481F0E28683A98
+ HashAlgorithm: 1
+ HashValues:
+ - 800309EE1ED8BB5B
+ - 5397319F1CC14E2C
+ - DF04AA3125BBC50E
+ - 95CEBA304A2C4493
+ - 23ADA4E788EB7A90
+ - B5DECADF1A832BA4
+ - 6632585CDC7606E4
+ - B97B86241E5F45B0
+ - BCD2406E22465E11
+ - A528BEF0A7F589C7
+ - 6079F1186C40C216
+ - 5091EFEBD5B5446B
+ - 26FFBFD620CFB362
- Name: '.debug$S'
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
Alignment: 4
SectionData: 04000000F500000064000000000000000000000020000000000000000400000000000000520000000600000004000000010000001F0000000000000004000000000000007F0000000500040000000000030000001D000000000000000400000000000000BD0000000300040000000000F10000007B000000320047110000000000000000000000002000000000000000000000000C100000000000000000004E533A3A466F6F3A3A466F6F000D003E1105100000010074686973001200451116000000FCFFFFFF0F000000000011000A003E1174000000010078001200451116000000080000000F0000000000110002004F1100F2000000200000000000000000000000200000001800000001000000140000000000000003000000
- Subsections:
+ Subsections:
- !FrameData
- Frames:
+ Frames:
- CodeSize: 32
FrameFunc: '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = '
LocalSize: 0
@@ -330,9 +360,9 @@
RvaStart: 3
SavedRegsSize: 4
- !Symbols
- Records:
+ Records:
- Kind: S_GPROC32_ID
- ProcSym:
+ ProcSym:
CodeSize: 32
DbgStart: 0
DbgEnd: 0
@@ -340,31 +370,51 @@
Flags: [ ]
DisplayName: 'NS::Foo::Foo'
- Kind: S_LOCAL
- LocalSym:
+ LocalSym:
Type: 4101
Flags: [ IsParameter ]
VarName: this
+ - Kind: S_DEFRANGE_REGISTER_REL
+ DefRangeRegisterRelSym:
+ Register: 22
+ Flags: 0
+ BasePointerOffset: -4
+ Range:
+ OffsetStart: 15
+ ISectStart: 0
+ Range: 17
+ Gaps:
- Kind: S_LOCAL
- LocalSym:
+ LocalSym:
Type: 116
Flags: [ IsParameter ]
VarName: x
+ - Kind: S_DEFRANGE_REGISTER_REL
+ DefRangeRegisterRelSym:
+ Register: 22
+ Flags: 0
+ BasePointerOffset: 8
+ Range:
+ OffsetStart: 15
+ ISectStart: 0
+ Range: 17
+ Gaps:
- Kind: S_PROC_ID_END
- ScopeEndSym:
+ ScopeEndSym:
- !Lines
CodeSize: 32
Flags: [ ]
RelocOffset: 0
RelocSegment: 0
- Blocks:
+ Blocks:
- FileName: 'D:\src\llvmbuild\clang\Debug\x86\obj.h'
- Lines:
+ Lines:
- Offset: 0
LineStart: 3
IsStatement: false
EndDelta: 0
- Columns:
- Relocations:
+ Columns:
+ Relocations:
- VirtualAddress: 12
SymbolName: '??0Foo@NS@@QAE@H@Z'
Type: IMAGE_REL_I386_DIR32NB
@@ -392,18 +442,18 @@
- VirtualAddress: 256
SymbolName: '??0Foo@NS@@QAE@H@Z'
Type: IMAGE_REL_I386_SECTION
-symbols:
+symbols:
- Name: .text
Value: 0
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 65
NumberOfRelocations: 2
NumberOfLinenumbers: 0
- CheckSum: 4176946275
+ CheckSum: 1827148029
Number: 1
- Name: .data
Value: 0
@@ -411,7 +461,7 @@
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 0
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -423,7 +473,7 @@
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 0
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -435,7 +485,7 @@
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 32
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -454,7 +504,7 @@
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 48
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -466,11 +516,11 @@
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 832
NumberOfRelocations: 11
NumberOfLinenumbers: 0
- CheckSum: 4106171226
+ CheckSum: 372945565
Number: 6
- Name: '.debug$S'
Value: 0
@@ -478,7 +528,7 @@
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 284
NumberOfRelocations: 9
NumberOfLinenumbers: 0
@@ -491,7 +541,7 @@
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 316
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -503,11 +553,11 @@
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
- Length: 268
+ SectionDefinition:
+ Length: 112
NumberOfRelocations: 0
NumberOfLinenumbers: 0
- CheckSum: 3965031229
+ CheckSum: 1535721080
Number: 8
- Name: '@feat.00'
Value: 1
diff --git a/test/COFF/Inputs/pdb-hashes-2-missing.yaml b/test/COFF/Inputs/pdb-hashes-2-missing.yaml
index 5b94d7f..41cba50 100644
--- a/test/COFF/Inputs/pdb-hashes-2-missing.yaml
+++ b/test/COFF/Inputs/pdb-hashes-2-missing.yaml
@@ -1,8 +1,8 @@
--- !COFF
-header:
+header:
Machine: IMAGE_FILE_MACHINE_I386
Characteristics: [ ]
-sections:
+sections:
- Name: .text
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
Alignment: 16
@@ -22,25 +22,25 @@
- Name: '.debug$S'
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
Alignment: 4
- SectionData: 04000000F10000002F0000002D003C1101000000070006000000000000007017000000000000636C616E672076657273696F6E20362E302E30200000F5000000640000000000000000000000190000000000000004000000000000002B000000040000000400000001000000180000000000000004000000000000005800000003000400000000000300000016000000000000000400000000000000960000000100040000000000F1000000540000002E0047110000000000000000000000001900000000000000000000000D100000000000000000004E533A3A66756E63000A003E110310000001006600120045111600000008000000070000000000120002004F11F20000002800000000000000000000001900000000000000020000001C00000000000000030000000700000004000000F1000000100000000E0008110A1000004E533A3A466F6F00F40000001800000001000000100159DFAC75D18675AED1AD169FE316317E0000F3000000D400000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A322E63707000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200024543020246562702034202B203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200000
- Subsections:
+ SectionData: 04000000F10000002F0000002D003C110100000007000700000000000000581B000000000000636C616E672076657273696F6E20372E302E30200000F5000000640000000000000000000000190000000000000004000000000000002B000000040000000400000001000000180000000000000004000000000000005800000003000400000000000300000016000000000000000400000000000000960000000100040000000000F1000000540000002E0047110000000000000000000000001900000000000000000000000D100000000000000000004E533A3A66756E63000A003E110310000001006600120045111600000008000000070000000000120002004F11F20000002800000000000000000000001900000000000000020000001C00000000000000030000000700000004000000F1000000100000000E0008110A1000004E533A3A466F6F00F40000001800000001000000100159DFAC75D18675AED1AD169FE316317E0000F3000000D400000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A322E63707000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200024543020246562702034202B203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200000
+ Subsections:
- !Symbols
- Records:
+ Records:
- Kind: S_COMPILE3
- Compile3Sym:
+ Compile3Sym:
Flags: [ ]
Machine: Pentium3
- FrontendMajor: 6
+ FrontendMajor: 7
FrontendMinor: 0
FrontendBuild: 0
FrontendQFE: 0
- BackendMajor: 6000
+ BackendMajor: 7000
BackendMinor: 0
BackendBuild: 0
BackendQFE: 0
- Version: 'clang version 6.0.0 '
+ Version: 'clang version 7.0.0 '
- !FrameData
- Frames:
+ Frames:
- CodeSize: 25
FrameFunc: '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = '
LocalSize: 0
@@ -66,9 +66,9 @@
RvaStart: 3
SavedRegsSize: 4
- !Symbols
- Records:
+ Records:
- Kind: S_GPROC32_ID
- ProcSym:
+ ProcSym:
CodeSize: 25
DbgStart: 0
DbgEnd: 0
@@ -76,20 +76,30 @@
Flags: [ ]
DisplayName: 'NS::func'
- Kind: S_LOCAL
- LocalSym:
+ LocalSym:
Type: 4099
Flags: [ IsParameter ]
VarName: f
+ - Kind: S_DEFRANGE_REGISTER_REL
+ DefRangeRegisterRelSym:
+ Register: 22
+ Flags: 0
+ BasePointerOffset: 8
+ Range:
+ OffsetStart: 7
+ ISectStart: 0
+ Range: 18
+ Gaps:
- Kind: S_PROC_ID_END
- ScopeEndSym:
+ ScopeEndSym:
- !Lines
CodeSize: 25
Flags: [ ]
RelocOffset: 0
RelocSegment: 0
- Blocks:
+ Blocks:
- FileName: 'D:\src\llvmbuild\clang\Debug\x86\obj2.cpp'
- Lines:
+ Lines:
- Offset: 0
LineStart: 3
IsStatement: false
@@ -98,26 +108,26 @@
LineStart: 4
IsStatement: false
EndDelta: 0
- Columns:
+ Columns:
- !Symbols
- Records:
+ Records:
- Kind: S_UDT
- UDTSym:
+ UDTSym:
Type: 4106
UDTName: 'NS::Foo'
- !FileChecksums
- Checksums:
+ Checksums:
- FileName: 'D:\src\llvmbuild\clang\Debug\x86\obj2.cpp'
Kind: MD5
Checksum: 59DFAC75D18675AED1AD169FE316317E
- !StringTable
- Strings:
+ Strings:
- 'D:\src\llvmbuild\clang\Debug\x86\obj2.cpp'
- '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = '
- '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = '
- '$T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = '
- ''
- Relocations:
+ Relocations:
- VirtualAddress: 68
SymbolName: '?func@NS@@YAHABUFoo@1@@Z'
Type: IMAGE_REL_I386_DIR32NB
@@ -143,13 +153,13 @@
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
Alignment: 4
SectionData: 040000000A000516000000004E5300F12A0005150000800200000000000000000000000000004E533A3A466F6F002E3F4155466F6F404E53404000F10A000110011000000100F2F10A000210021000002A8000000A00011201000000031000000E0008107400000000000100041000000A000210011000000A8000000A00011201000000740000001A0009100300000001100000061000000B00010007100000000000001A0003120D15030074000000000058001115030008100000466F6F002A0005150200000209100000000000000000000004004E533A3A466F6F002E3F4155466F6F404E53404000F12E00051600000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A2E6800F10E0006160A1000000B1000000200000012000116001000000510000066756E6300F3F2F1
- Types:
+ Types:
- Kind: LF_STRING_ID
- StringId:
+ StringId:
Id: 0
String: NS
- Kind: LF_STRUCTURE
- Class:
+ Class:
MemberCount: 0
Options: [ None, ForwardReference, HasUniqueName ]
FieldList: 0
@@ -159,32 +169,32 @@
VTableShape: 0
Size: 0
- Kind: LF_MODIFIER
- Modifier:
+ Modifier:
ModifiedType: 4097
Modifiers: [ None, Const ]
- Kind: LF_POINTER
- Pointer:
+ Pointer:
ReferentType: 4098
Attrs: 32810
- Kind: LF_ARGLIST
- ArgList:
+ ArgList:
ArgIndices: [ 4099 ]
- Kind: LF_PROCEDURE
- Procedure:
+ Procedure:
ReturnType: 116
CallConv: NearC
Options: [ None ]
ParameterCount: 1
ArgumentList: 4100
- Kind: LF_POINTER
- Pointer:
+ Pointer:
ReferentType: 4097
Attrs: 32778
- Kind: LF_ARGLIST
- ArgList:
+ ArgList:
ArgIndices: [ 116 ]
- Kind: LF_MFUNCTION
- MemberFunction:
+ MemberFunction:
ReturnType: 3
ClassType: 4097
ThisType: 4102
@@ -194,21 +204,21 @@
ArgumentList: 4103
ThisPointerAdjustment: 0
- Kind: LF_FIELDLIST
- FieldList:
+ FieldList:
- Kind: LF_MEMBER
- DataMember:
+ DataMember:
Attrs: 3
Type: 116
FieldOffset: 0
Name: X
- Kind: LF_ONEMETHOD
- OneMethod:
+ OneMethod:
Type: 4104
Attrs: 3
VFTableOffset: -1
Name: Foo
- Kind: LF_STRUCTURE
- Class:
+ Class:
MemberCount: 2
Options: [ None, HasUniqueName ]
FieldList: 4105
@@ -218,27 +228,27 @@
VTableShape: 0
Size: 4
- Kind: LF_STRING_ID
- StringId:
+ StringId:
Id: 0
String: 'D:\src\llvmbuild\clang\Debug\x86\obj.h'
- Kind: LF_UDT_SRC_LINE
- UdtSourceLine:
+ UdtSourceLine:
UDT: 4106
SourceFile: 4107
LineNumber: 2
- Kind: LF_FUNC_ID
- FuncId:
+ FuncId:
ParentScope: 4096
FunctionType: 4101
Name: func
-symbols:
+symbols:
- Name: .text
Value: 0
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 25
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -250,7 +260,7 @@
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 0
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -262,7 +272,7 @@
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 0
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -274,7 +284,7 @@
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 48
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -286,11 +296,11 @@
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 584
NumberOfRelocations: 7
NumberOfLinenumbers: 0
- CheckSum: 2847177244
+ CheckSum: 917356735
Number: 5
- Name: '.debug$T'
Value: 0
@@ -298,7 +308,7 @@
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 320
NumberOfRelocations: 0
NumberOfLinenumbers: 0
diff --git a/test/COFF/Inputs/pdb-hashes-2.yaml b/test/COFF/Inputs/pdb-hashes-2.yaml
index 46676c4..51ea512 100644
--- a/test/COFF/Inputs/pdb-hashes-2.yaml
+++ b/test/COFF/Inputs/pdb-hashes-2.yaml
@@ -1,8 +1,8 @@
--- !COFF
-header:
+header:
Machine: IMAGE_FILE_MACHINE_I386
Characteristics: [ ]
-sections:
+sections:
- Name: .text
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
Alignment: 16
@@ -22,25 +22,25 @@
- Name: '.debug$S'
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
Alignment: 4
- SectionData: 04000000F10000002F0000002D003C1101000000070006000000000000007017000000000000636C616E672076657273696F6E20362E302E30200000F5000000640000000000000000000000190000000000000004000000000000002B000000040000000400000001000000180000000000000004000000000000005800000003000400000000000300000016000000000000000400000000000000960000000100040000000000F1000000540000002E0047110000000000000000000000001900000000000000000000000D100000000000000000004E533A3A66756E63000A003E110310000001006600120045111600000008000000070000000000120002004F11F20000002800000000000000000000001900000000000000020000001C00000000000000030000000700000004000000F1000000100000000E0008110A1000004E533A3A466F6F00F40000001800000001000000100159DFAC75D18675AED1AD169FE316317E0000F3000000D400000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A322E63707000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200024543020246562702034202B203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200000
- Subsections:
+ SectionData: 04000000F10000002F0000002D003C110100000007000700000000000000581B000000000000636C616E672076657273696F6E20372E302E30200000F5000000640000000000000000000000190000000000000004000000000000002B000000040000000400000001000000180000000000000004000000000000005800000003000400000000000300000016000000000000000400000000000000960000000100040000000000F1000000540000002E0047110000000000000000000000001900000000000000000000000D100000000000000000004E533A3A66756E63000A003E110310000001006600120045111600000008000000070000000000120002004F11F20000002800000000000000000000001900000000000000020000001C00000000000000030000000700000004000000F1000000100000000E0008110A1000004E533A3A466F6F00F40000001800000001000000100159DFAC75D18675AED1AD169FE316317E0000F3000000D400000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A322E63707000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200024543020246562702034202B203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200000
+ Subsections:
- !Symbols
- Records:
+ Records:
- Kind: S_COMPILE3
- Compile3Sym:
+ Compile3Sym:
Flags: [ ]
Machine: Pentium3
- FrontendMajor: 6
+ FrontendMajor: 7
FrontendMinor: 0
FrontendBuild: 0
FrontendQFE: 0
- BackendMajor: 6000
+ BackendMajor: 7000
BackendMinor: 0
BackendBuild: 0
BackendQFE: 0
- Version: 'clang version 6.0.0 '
+ Version: 'clang version 7.0.0 '
- !FrameData
- Frames:
+ Frames:
- CodeSize: 25
FrameFunc: '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = '
LocalSize: 0
@@ -66,9 +66,9 @@
RvaStart: 3
SavedRegsSize: 4
- !Symbols
- Records:
+ Records:
- Kind: S_GPROC32_ID
- ProcSym:
+ ProcSym:
CodeSize: 25
DbgStart: 0
DbgEnd: 0
@@ -76,20 +76,30 @@
Flags: [ ]
DisplayName: 'NS::func'
- Kind: S_LOCAL
- LocalSym:
+ LocalSym:
Type: 4099
Flags: [ IsParameter ]
VarName: f
+ - Kind: S_DEFRANGE_REGISTER_REL
+ DefRangeRegisterRelSym:
+ Register: 22
+ Flags: 0
+ BasePointerOffset: 8
+ Range:
+ OffsetStart: 7
+ ISectStart: 0
+ Range: 18
+ Gaps:
- Kind: S_PROC_ID_END
- ScopeEndSym:
+ ScopeEndSym:
- !Lines
CodeSize: 25
Flags: [ ]
RelocOffset: 0
RelocSegment: 0
- Blocks:
+ Blocks:
- FileName: 'D:\src\llvmbuild\clang\Debug\x86\obj2.cpp'
- Lines:
+ Lines:
- Offset: 0
LineStart: 3
IsStatement: false
@@ -98,26 +108,26 @@
LineStart: 4
IsStatement: false
EndDelta: 0
- Columns:
+ Columns:
- !Symbols
- Records:
+ Records:
- Kind: S_UDT
- UDTSym:
+ UDTSym:
Type: 4106
UDTName: 'NS::Foo'
- !FileChecksums
- Checksums:
+ Checksums:
- FileName: 'D:\src\llvmbuild\clang\Debug\x86\obj2.cpp'
Kind: MD5
Checksum: 59DFAC75D18675AED1AD169FE316317E
- !StringTable
- Strings:
+ Strings:
- 'D:\src\llvmbuild\clang\Debug\x86\obj2.cpp'
- '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = '
- '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = '
- '$T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = '
- ''
- Relocations:
+ Relocations:
- VirtualAddress: 68
SymbolName: '?func@NS@@YAHABUFoo@1@@Z'
Type: IMAGE_REL_I386_DIR32NB
@@ -143,13 +153,13 @@
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
Alignment: 4
SectionData: 040000000A000516000000004E5300F12A0005150000800200000000000000000000000000004E533A3A466F6F002E3F4155466F6F404E53404000F10A000110011000000100F2F10A000210021000002A8000000A00011201000000031000000E0008107400000000000100041000000A000210011000000A8000000A00011201000000740000001A0009100300000001100000061000000B00010007100000000000001A0003120D15030074000000000058001115030008100000466F6F002A0005150200000209100000000000000000000004004E533A3A466F6F002E3F4155466F6F404E53404000F12E00051600000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A2E6800F10E0006160A1000000B1000000200000012000116001000000510000066756E6300F3F2F1
- Types:
+ Types:
- Kind: LF_STRING_ID
- StringId:
+ StringId:
Id: 0
String: NS
- Kind: LF_STRUCTURE
- Class:
+ Class:
MemberCount: 0
Options: [ None, ForwardReference, HasUniqueName ]
FieldList: 0
@@ -159,32 +169,32 @@
VTableShape: 0
Size: 0
- Kind: LF_MODIFIER
- Modifier:
+ Modifier:
ModifiedType: 4097
Modifiers: [ None, Const ]
- Kind: LF_POINTER
- Pointer:
+ Pointer:
ReferentType: 4098
Attrs: 32810
- Kind: LF_ARGLIST
- ArgList:
+ ArgList:
ArgIndices: [ 4099 ]
- Kind: LF_PROCEDURE
- Procedure:
+ Procedure:
ReturnType: 116
CallConv: NearC
Options: [ None ]
ParameterCount: 1
ArgumentList: 4100
- Kind: LF_POINTER
- Pointer:
+ Pointer:
ReferentType: 4097
Attrs: 32778
- Kind: LF_ARGLIST
- ArgList:
+ ArgList:
ArgIndices: [ 116 ]
- Kind: LF_MFUNCTION
- MemberFunction:
+ MemberFunction:
ReturnType: 3
ClassType: 4097
ThisType: 4102
@@ -194,21 +204,21 @@
ArgumentList: 4103
ThisPointerAdjustment: 0
- Kind: LF_FIELDLIST
- FieldList:
+ FieldList:
- Kind: LF_MEMBER
- DataMember:
+ DataMember:
Attrs: 3
Type: 116
FieldOffset: 0
Name: X
- Kind: LF_ONEMETHOD
- OneMethod:
+ OneMethod:
Type: 4104
Attrs: 3
VFTableOffset: -1
Name: Foo
- Kind: LF_STRUCTURE
- Class:
+ Class:
MemberCount: 2
Options: [ None, HasUniqueName ]
FieldList: 4105
@@ -218,49 +228,49 @@
VTableShape: 0
Size: 4
- Kind: LF_STRING_ID
- StringId:
+ StringId:
Id: 0
String: 'D:\src\llvmbuild\clang\Debug\x86\obj.h'
- Kind: LF_UDT_SRC_LINE
- UdtSourceLine:
+ UdtSourceLine:
UDT: 4106
SourceFile: 4107
LineNumber: 2
- Kind: LF_FUNC_ID
- FuncId:
+ FuncId:
ParentScope: 4096
FunctionType: 4101
Name: func
- Name: '.debug$H'
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
Alignment: 4
- SectionData: C5C9330100000000EC145CD76AEFE74E78880D531132B3BB8FFACEF79E616EF06A14EA74A2420F9062A1FB04917E59759949E334BA18509ED692F3C65CE242D8450EBC78B81B63AF8316DC324562EB9F0D4A0D708E8A25C263DB05943C19B84A36719E1E414DDA3EDBDF005322238D70F9058EEDC5C50EF11BC849618B51FD89E3A50EABE5E8FE3945468547C19DC681D0BFB3B797DD91CA4D7F1953C314442D5549419E78044E38A0BF16BFFAA5EE9C0103E7DBFE9941E63379C0B0C0A9021B711ACC4F67008974EBF441031BDD653F6935DFF3112C6A5346EF2AC94B9B7EB56EF55CFA0AF6C1846743F43D846BB19517E12E8873BBA90CC41DD1BEAC89CBA8897AC1BA46762E2557A82D89DCBC783AF285D9DBB672F67A81E36906B2038B57
- GlobalHashes:
+ SectionData: C5C93301000001004A061540B751965F23ADA4E788EB7A9032673B3BABE3CA5356B1521BDAE4BEA70661C95750D0206E896FB09488EE8E1BB5DECADF1A832BA46632585CDC7606E4B97B86241E5F45B0BCD2406E22465E11A528BEF0A7F589C76079F1186C40C2165091EFEBD5B5446B5AAD8721C21DF3E6
+ GlobalHashes:
Version: 0
- HashAlgorithm: 0
- HashValues:
- - EC145CD76AEFE74E78880D531132B3BB8FFACEF7
- - 9E616EF06A14EA74A2420F9062A1FB04917E5975
- - 9949E334BA18509ED692F3C65CE242D8450EBC78
- - B81B63AF8316DC324562EB9F0D4A0D708E8A25C2
- - 63DB05943C19B84A36719E1E414DDA3EDBDF0053
- - 22238D70F9058EEDC5C50EF11BC849618B51FD89
- - E3A50EABE5E8FE3945468547C19DC681D0BFB3B7
- - 97DD91CA4D7F1953C314442D5549419E78044E38
- - A0BF16BFFAA5EE9C0103E7DBFE9941E63379C0B0
- - C0A9021B711ACC4F67008974EBF441031BDD653F
- - 6935DFF3112C6A5346EF2AC94B9B7EB56EF55CFA
- - 0AF6C1846743F43D846BB19517E12E8873BBA90C
- - C41DD1BEAC89CBA8897AC1BA46762E2557A82D89
- - DCBC783AF285D9DBB672F67A81E36906B2038B57
-symbols:
+ HashAlgorithm: 1
+ HashValues:
+ - 4A061540B751965F
+ - 23ADA4E788EB7A90
+ - 32673B3BABE3CA53
+ - 56B1521BDAE4BEA7
+ - 0661C95750D0206E
+ - 896FB09488EE8E1B
+ - B5DECADF1A832BA4
+ - 6632585CDC7606E4
+ - B97B86241E5F45B0
+ - BCD2406E22465E11
+ - A528BEF0A7F589C7
+ - 6079F1186C40C216
+ - 5091EFEBD5B5446B
+ - 5AAD8721C21DF3E6
+symbols:
- Name: .text
Value: 0
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 25
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -272,7 +282,7 @@
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 0
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -284,7 +294,7 @@
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 0
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -296,7 +306,7 @@
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 48
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -308,11 +318,11 @@
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 584
NumberOfRelocations: 7
NumberOfLinenumbers: 0
- CheckSum: 2847177244
+ CheckSum: 917356735
Number: 5
- Name: '.debug$T'
Value: 0
@@ -320,7 +330,7 @@
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
+ SectionDefinition:
Length: 320
NumberOfRelocations: 0
NumberOfLinenumbers: 0
@@ -332,11 +342,11 @@
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
- Length: 288
+ SectionDefinition:
+ Length: 120
NumberOfRelocations: 0
NumberOfLinenumbers: 0
- CheckSum: 2348181452
+ CheckSum: 358820662
Number: 7
- Name: '@feat.00'
Value: 1
diff --git a/test/COFF/Inputs/pdb-scopes-a.yaml b/test/COFF/Inputs/pdb-scopes-a.yaml
index e422a62..0fc4172 100644
--- a/test/COFF/Inputs/pdb-scopes-a.yaml
+++ b/test/COFF/Inputs/pdb-scopes-a.yaml
@@ -53,7 +53,7 @@
RegRelativeSym:
Offset: 8
Type: 116
- Register: RSP
+ Register: CVRegRSP
VarName: x
- Kind: S_PROC_ID_END
ScopeEndSym:
@@ -93,7 +93,7 @@
RegRelativeSym:
Offset: 64
Type: 116
- Register: RSP
+ Register: CVRegRSP
VarName: argc
- Kind: S_BLOCK32
BlockSym:
@@ -104,7 +104,7 @@
RegRelativeSym:
Offset: 32
Type: 116
- Register: RSP
+ Register: CVRegRSP
VarName: x
- Kind: S_END
ScopeEndSym:
@@ -117,7 +117,7 @@
RegRelativeSym:
Offset: 36
Type: 116
- Register: RSP
+ Register: CVRegRSP
VarName: y
- Kind: S_END
ScopeEndSym:
diff --git a/test/COFF/Inputs/pdb-scopes-b.yaml b/test/COFF/Inputs/pdb-scopes-b.yaml
index b1c6021..c0ee98b 100644
--- a/test/COFF/Inputs/pdb-scopes-b.yaml
+++ b/test/COFF/Inputs/pdb-scopes-b.yaml
@@ -53,7 +53,7 @@
RegRelativeSym:
Offset: 64
Type: 116
- Register: RSP
+ Register: CVRegRSP
VarName: x
- Kind: S_BLOCK32
BlockSym:
@@ -64,7 +64,7 @@
RegRelativeSym:
Offset: 32
Type: 116
- Register: RSP
+ Register: CVRegRSP
VarName: y
- Kind: S_END
ScopeEndSym:
@@ -77,7 +77,7 @@
RegRelativeSym:
Offset: 36
Type: 116
- Register: RSP
+ Register: CVRegRSP
VarName: w
- Kind: S_END
ScopeEndSym:
diff --git a/test/COFF/Inputs/pdb-type-server-simple-a.yaml b/test/COFF/Inputs/pdb-type-server-simple-a.yaml
index 78c6816..8425c4f 100644
--- a/test/COFF/Inputs/pdb-type-server-simple-a.yaml
+++ b/test/COFF/Inputs/pdb-type-server-simple-a.yaml
@@ -53,7 +53,7 @@
RegRelativeSym:
Offset: 32
Type: 4102
- Register: RSP
+ Register: CVRegRSP
VarName: f
- Kind: S_PROC_ID_END
ScopeEndSym:
diff --git a/test/COFF/Inputs/pdb-type-server-simple-b.yaml b/test/COFF/Inputs/pdb-type-server-simple-b.yaml
index 56e97d5..3b511cb 100644
--- a/test/COFF/Inputs/pdb-type-server-simple-b.yaml
+++ b/test/COFF/Inputs/pdb-type-server-simple-b.yaml
@@ -53,7 +53,7 @@
RegRelativeSym:
Offset: 8
Type: 4097
- Register: RSP
+ Register: CVRegRSP
VarName: p
- Kind: S_PROC_ID_END
ScopeEndSym:
diff --git a/test/COFF/arm64-branch-range.test b/test/COFF/arm64-branch-range.test
new file mode 100644
index 0000000..0b581e9
--- /dev/null
+++ b/test/COFF/arm64-branch-range.test
@@ -0,0 +1,16 @@
+// REQUIRES: aarch64
+
+// RUN: echo -e '.globl _start\n _start:\n bl too_far26\n' > %t.main26.s
+// RUN: echo -e '.globl _start\n _start:\n b.ne too_far19\n' > %t.main19.s
+// RUN: echo -e '.globl _start\n _start:\n tbz x0, #0, too_far14\n' > %t.main14.s
+
+// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %t.main26.s -o %t.main26.obj
+// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %t.main19.s -o %t.main19.obj
+// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %t.main14.s -o %t.main14.obj
+// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/far-arm64-abs.s -o %t.far.obj
+
+// RUN: not lld-link -base:0x10000 -entry:_start -subsystem:console %t.main26.obj %t.far.obj -out:%t.exe 2>&1 | FileCheck %s
+// RUN: not lld-link -base:0x10000 -entry:_start -subsystem:console %t.main19.obj %t.far.obj -out:%t.exe 2>&1 | FileCheck %s
+// RUN: not lld-link -base:0x10000 -entry:_start -subsystem:console %t.main14.obj %t.far.obj -out:%t.exe 2>&1 | FileCheck %s
+
+// CHECK: relocation out of range
diff --git a/test/COFF/arm64-relocs-imports.test b/test/COFF/arm64-relocs-imports.test
index 5680530..c7b8b7c 100644
--- a/test/COFF/arm64-relocs-imports.test
+++ b/test/COFF/arm64-relocs-imports.test
@@ -41,46 +41,54 @@
# BEFORE: 80: 00 00 00 91 add x0, x0, #0
# BEFORE: 84: 00 00 40 91 add x0, x0, #0, lsl #12
# BEFORE: 88: 00 00 40 f9 ldr x0, [x0]
+# BEFORE: 8c: 01 00 00 00 <unknown>
+# BEFORE: 90: 20 1a 09 30 adr x0, #74565
+# BEFORE: 94: 01 00 00 54 b.ne #0
+# BEFORE: 98: 00 00 00 36 tbz w0, #0, #0
# AFTER: Disassembly of section .text:
-# AFTER: 140002000: fe 0f 1f f8 str x30, [sp, #-16]!
-# AFTER: 140002004: e0 ff ff f0 adrp x0, #-4096
-# AFTER: 140002008: 00 18 00 91 add x0, x0, #6
-# AFTER: 14000200c: 20 00 00 94 bl #128
-# AFTER: 140002010: 00 21 40 39 ldrb w0, [x8, #8]
-# AFTER: 140002014: 00 11 40 79 ldrh w0, [x8, #8]
-# AFTER: 140002018: 00 09 40 b9 ldr w0, [x8, #8]
-# AFTER: 14000201c: 00 05 40 f9 ldr x0, [x8, #8]
-# AFTER: 140002020: 00 21 00 39 strb w0, [x8, #8]
-# AFTER: 140002024: 00 11 00 79 strh w0, [x8, #8]
-# AFTER: 140002028: 00 09 00 b9 str w0, [x8, #8]
-# AFTER: 14000202c: 00 05 00 f9 str x0, [x8, #8]
-# AFTER: 140002030: 00 41 40 3d ldr b0, [x8, #16]
-# AFTER: 140002034: 00 21 40 7d ldr h0, [x8, #16]
-# AFTER: 140002038: 00 11 40 bd ldr s0, [x8, #16]
-# AFTER: 14000203c: 00 09 40 fd ldr d0, [x8, #16]
-# AFTER: 140002040: 00 05 c0 3d ldr q0, [x8, #16]
-# AFTER: 140002044: 00 41 00 3d str b0, [x8, #16]
-# AFTER: 140002048: 00 21 00 7d str h0, [x8, #16]
-# AFTER: 14000204c: 00 11 00 bd str s0, [x8, #16]
-# AFTER: 140002050: 00 09 00 fd str d0, [x8, #16]
-# AFTER: 140002054: 00 05 80 3d str q0, [x8, #16]
-# AFTER: 140002058: 00 09 40 f9 ldr x0, [x8, #16]
-# AFTER: 14000205c: 00 00 00 b0 adrp x0, #4096
-# AFTER: 140002060: 00 fc 47 f9 ldr x0, [x0, #4088]
-# AFTER: 140002064: e0 03 1f 2a mov w0, wzr
-# AFTER: 140002068: fe 07 41 f8 ldr x30, [sp], #16
-# AFTER: 14000206c: c0 03 5f d6 ret
-# AFTER: 140002070: 10 10 00 40 <unknown>
-# AFTER: 140002074: 01 00 00 00 <unknown>
-# AFTER: 140002078: 09 10 00 00 <unknown>
-# AFTER: 14000207c: 09 00 00 00 <unknown>
-# AFTER: 140002080: 00 20 0e 91 add x0, x0, #904
-# AFTER: 140002084: 00 04 40 91 add x0, x0, #1, lsl #12
-# AFTER: 140002088: 00 c4 41 f9 ldr x0, [x0, #904]
-# AFTER: 14000208c: 10 00 00 b0 adrp x16, #4096
-# AFTER: 140002090: 10 1e 40 f9 ldr x16, [x16, #56]
-# AFTER: 140002094: 00 02 1f d6 br x16
+# AFTER: 140001000: fe 0f 1f f8 str x30, [sp, #-16]!
+# AFTER: 140001004: 00 00 00 b0 adrp x0, #4096
+# AFTER: 140001008: 00 18 00 91 add x0, x0, #6
+# AFTER: 14000100c: 24 00 00 94 bl #144
+# AFTER: 140001010: 00 21 40 39 ldrb w0, [x8, #8]
+# AFTER: 140001014: 00 11 40 79 ldrh w0, [x8, #8]
+# AFTER: 140001018: 00 09 40 b9 ldr w0, [x8, #8]
+# AFTER: 14000101c: 00 05 40 f9 ldr x0, [x8, #8]
+# AFTER: 140001020: 00 21 00 39 strb w0, [x8, #8]
+# AFTER: 140001024: 00 11 00 79 strh w0, [x8, #8]
+# AFTER: 140001028: 00 09 00 b9 str w0, [x8, #8]
+# AFTER: 14000102c: 00 05 00 f9 str x0, [x8, #8]
+# AFTER: 140001030: 00 41 40 3d ldr b0, [x8, #16]
+# AFTER: 140001034: 00 21 40 7d ldr h0, [x8, #16]
+# AFTER: 140001038: 00 11 40 bd ldr s0, [x8, #16]
+# AFTER: 14000103c: 00 09 40 fd ldr d0, [x8, #16]
+# AFTER: 140001040: 00 05 c0 3d ldr q0, [x8, #16]
+# AFTER: 140001044: 00 41 00 3d str b0, [x8, #16]
+# AFTER: 140001048: 00 21 00 7d str h0, [x8, #16]
+# AFTER: 14000104c: 00 11 00 bd str s0, [x8, #16]
+# AFTER: 140001050: 00 09 00 fd str d0, [x8, #16]
+# AFTER: 140001054: 00 05 80 3d str q0, [x8, #16]
+# AFTER: 140001058: 00 09 40 f9 ldr x0, [x8, #16]
+# AFTER: 14000105c: 00 00 00 f0 adrp x0, #12288
+# AFTER: 140001060: 00 fc 47 f9 ldr x0, [x0, #4088]
+# AFTER: 140001064: e0 03 1f 2a mov w0, wzr
+# AFTER: 140001068: fe 07 41 f8 ldr x30, [sp], #16
+# AFTER: 14000106c: c0 03 5f d6 ret
+# AFTER: 140001070: 10 20 00 40 <unknown>
+# AFTER: 140001074: 01 00 00 00 <unknown>
+# AFTER: 140001078: 09 20 00 00 <unknown>
+# AFTER: 14000107c: 09 00 00 00 <unknown>
+# AFTER: 140001080: 00 20 0e 91 add x0, x0, #904
+# AFTER: 140001084: 00 04 40 91 add x0, x0, #1, lsl #12
+# AFTER: 140001088: 00 c4 41 f9 ldr x0, [x0, #904]
+# AFTER: 14000108c: 03 00 00 00 <unknown>
+# AFTER: 140001090: e0 95 09 30 adr x0, #78525
+# AFTER: 140001094: 41 00 00 54 b.ne #8
+# AFTER: 140001098: 20 00 00 36 tbz w0, #0, #4
+# AFTER: 14000109c: 10 00 00 b0 adrp x16, #4096
+# AFTER: 1400010a0: 10 2a 40 f9 ldr x16, [x16, #80]
+# AFTER: 1400010a4: 00 02 1f d6 br x16
--- !COFF
header:
@@ -90,7 +98,7 @@
- Name: .text
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
Alignment: 4
- SectionData: FE0F1FF80000009000080091000000940001403900014079000140B9000140F90001003900010079000100B9000100F90001403D0001407D000140BD000140FD0001C03D0001003D0001007D000100BD000100FD0001803D000540F9201A01B000FC4FF9E0031F2AFE0741F8C0035FD6080000000000000001000000010000000000009100004091000040f9
+ SectionData: FE0F1FF80000009000080091000000940001403900014079000140B9000140F90001003900010079000100B9000100F90001403D0001407D000140BD000140FD0001C03D0001003D0001007D000100BD000100FD0001803D000540F9201A01B000FC4FF9E0031F2AFE0741F8C0035FD6080000000000000001000000010000000000009100004091000040f901000000201a09300100005400000036
Relocations:
- VirtualAddress: 4
SymbolName: .Lstr
@@ -182,6 +190,18 @@
- VirtualAddress: 136
SymbolName: .Lglobal5000
Type: IMAGE_REL_ARM64_SECREL_LOW12L
+ - VirtualAddress: 140
+ SymbolName: .Lglobal
+ Type: IMAGE_REL_ARM64_SECTION
+ - VirtualAddress: 144
+ SymbolName: .Lglobal
+ Type: IMAGE_REL_ARM64_REL21
+ - VirtualAddress: 148
+ SymbolName: function
+ Type: IMAGE_REL_ARM64_BRANCH19
+ - VirtualAddress: 152
+ SymbolName: function
+ Type: IMAGE_REL_ARM64_BRANCH14
- Name: .data
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
Alignment: 4
diff --git a/test/COFF/armnt-movt32t.test b/test/COFF/armnt-movt32t.test
index 7c6965e..6a0640c 100644
--- a/test/COFF/armnt-movt32t.test
+++ b/test/COFF/armnt-movt32t.test
@@ -11,7 +11,7 @@
# BEFORE: 8: 70 47 bx lr
# AFTER: Disassembly of section .text:
-# AFTER: 0: 41 f2 00 00 movw r0, #4096
+# AFTER: 0: 42 f2 00 00 movw r0, #8192
# AFTER: 4: c0 f2 40 00 movt r0, #64
# AFTER: 8: 70 47 bx lr
diff --git a/test/COFF/associative-comdat.s b/test/COFF/associative-comdat.s
index dd54195..a2c3bea 100644
--- a/test/COFF/associative-comdat.s
+++ b/test/COFF/associative-comdat.s
@@ -9,14 +9,15 @@
# CHECK: Sections [
# CHECK: Section {
-# CHECK: Number: 1
-# CHECK-LABEL: Name: .data (2E 64 61 74 61 00 00 00)
-# CHECK-NEXT: VirtualSize: 0x4
-# CHECK: Section {
+# CHECK: Number: 2
# CHECK-LABEL: Name: .rdata (2E 72 64 61 74 61 00 00)
# This is the critical check to show that only *one* definition of
# foo_assoc was retained. This *must* be 8, not 16.
# CHECK-NEXT: VirtualSize: 0x8
+# CHECK: Section {
+# CHECK: Number: 3
+# CHECK-LABEL: Name: .data (2E 64 61 74 61 00 00 00)
+# CHECK-NEXT: VirtualSize: 0x4
.text
.def main;
diff --git a/test/COFF/baserel.test b/test/COFF/baserel.test
index ce0b276..6441bb2 100644
--- a/test/COFF/baserel.test
+++ b/test/COFF/baserel.test
@@ -9,35 +9,35 @@
# BASEREL: BaseReloc [
# BASEREL-NEXT: Entry {
# BASEREL-NEXT: Type: DIR64
-# BASEREL-NEXT: Address: 0x2007
+# BASEREL-NEXT: Address: 0x1007
# BASEREL-NEXT: }
# BASEREL-NEXT: Entry {
# BASEREL-NEXT: Type: DIR64
-# BASEREL-NEXT: Address: 0x200C
+# BASEREL-NEXT: Address: 0x100C
# BASEREL-NEXT: }
# BASEREL-NEXT: Entry {
# BASEREL-NEXT: Type: DIR64
-# BASEREL-NEXT: Address: 0x201E
+# BASEREL-NEXT: Address: 0x101E
# BASEREL-NEXT: }
# BASEREL-NEXT: Entry {
# BASEREL-NEXT: Type: ABSOLUTE
-# BASEREL-NEXT: Address: 0x2000
+# BASEREL-NEXT: Address: 0x1000
# BASEREL-NEXT: }
# BASEREL-NEXT: Entry {
# BASEREL-NEXT: Type: DIR64
-# BASEREL-NEXT: Address: 0x3007
+# BASEREL-NEXT: Address: 0x4007
# BASEREL-NEXT: }
# BASEREL-NEXT: Entry {
# BASEREL-NEXT: Type: DIR64
-# BASEREL-NEXT: Address: 0x300C
+# BASEREL-NEXT: Address: 0x400C
# BASEREL-NEXT: }
# BASEREL-NEXT: Entry {
# BASEREL-NEXT: Type: DIR64
-# BASEREL-NEXT: Address: 0x301E
+# BASEREL-NEXT: Address: 0x401E
# BASEREL-NEXT: }
# BASEREL-NEXT: Entry {
# BASEREL-NEXT: Type: ABSOLUTE
-# BASEREL-NEXT: Address: 0x3000
+# BASEREL-NEXT: Address: 0x4000
# BASEREL-NEXT: }
#
# NOBASEREL: BaseReloc [
diff --git a/test/COFF/combined-resources.test b/test/COFF/combined-resources.test
index e8d5d65..37dfc57 100644
--- a/test/COFF/combined-resources.test
+++ b/test/COFF/combined-resources.test
@@ -11,8 +11,8 @@
# RUN: llvm-readobj -coff-resources -file-headers -section-data %t.exe | \
# RUN: FileCheck %s
-CHECK: ResourceTableRVA: 0x1000
-CHECK-NEXT: ResourceTableSize: 0xC1C
+CHECK: ResourceTableRVA: 0x2000
+CHECK-NEXT: ResourceTableSize: 0xC20
CHECK-DAG: Resources [
CHECK-NEXT: Total Number of Resources: 13
CHECK-DAG: .rsrc Data (
@@ -49,19 +49,19 @@
CHECK-NEXT: 01E0: 09040000 A0020000 00000000 00000000 |................|
CHECK-NEXT: 01F0: 00000000 00000300 09040000 B0020000 |................|
CHECK-NEXT: 0200: 04080000 C0020000 07100000 D0020000 |................|
-CHECK-NEXT: 0210: FC1A0000 39000000 00000000 00000000 |....9...........|
-CHECK-NEXT: 0220: C4130000 28030000 00000000 00000000 |....(...........|
-CHECK-NEXT: 0230: EC160000 28030000 00000000 00000000 |....(...........|
-CHECK-NEXT: 0240: CC1A0000 30000000 00000000 00000000 |....0...........|
-CHECK-NEXT: 0250: 141A0000 2E000000 00000000 00000000 |................|
-CHECK-NEXT: 0260: 441A0000 6C000000 00000000 00000000 |D...l...........|
-CHECK-NEXT: 0270: 7C130000 2A000000 00000000 00000000 ||...*...........|
-CHECK-NEXT: 0280: AC130000 18000000 00000000 00000000 |................|
-CHECK-NEXT: 0290: 041C0000 18000000 00000000 00000000 |................|
-CHECK-NEXT: 02A0: B41A0000 18000000 00000000 00000000 |................|
-CHECK-NEXT: 02B0: 3C1B0000 36000000 00000000 00000000 |<...6...........|
-CHECK-NEXT: 02C0: 741B0000 43000000 00000000 00000000 |t...C...........|
-CHECK-NEXT: 02D0: BC1B0000 42000000 00000000 00000000 |....B...........|
+CHECK-NEXT: 0210: 002B0000 39000000 00000000 00000000 |.+..9...........|
+CHECK-NEXT: 0220: C8230000 28030000 00000000 00000000 |.#..(...........|
+CHECK-NEXT: 0230: F0260000 28030000 00000000 00000000 |.&..(...........|
+CHECK-NEXT: 0240: D02A0000 30000000 00000000 00000000 |.*..0...........|
+CHECK-NEXT: 0250: 182A0000 2E000000 00000000 00000000 |.*..............|
+CHECK-NEXT: 0260: 482A0000 6C000000 00000000 00000000 |H*..l...........|
+CHECK-NEXT: 0270: 80230000 2A000000 00000000 00000000 |.#..*...........|
+CHECK-NEXT: 0280: B0230000 18000000 00000000 00000000 |.#..............|
+CHECK-NEXT: 0290: 082C0000 18000000 00000000 00000000 |.,..............|
+CHECK-NEXT: 02A0: B82A0000 18000000 00000000 00000000 |.*..............|
+CHECK-NEXT: 02B0: 402B0000 36000000 00000000 00000000 |@+..6...........|
+CHECK-NEXT: 02C0: 782B0000 43000000 00000000 00000000 |x+..C...........|
+CHECK-NEXT: 02D0: C02B0000 42000000 00000000 00000000 |.+..B...........|
CHECK-NEXT: 02E0: 0E004D00 59004100 43004300 45004C00 |..M.Y.A.C.C.E.L.|
CHECK-NEXT: 02F0: 45005200 41005400 4F005200 53000600 |E.R.A.T.O.R.S...|
CHECK-NEXT: 0300: 43005500 52005300 4F005200 04004F00 |C.U.R.S.O.R...O.|
@@ -71,14 +71,14 @@
CHECK-NEXT: 0340: 49004E00 47004100 52005200 41005900 |I.N.G.A.R.R.A.Y.|
CHECK-NEXT: 0350: 0A004D00 59005200 45005300 4F005500 |..M.Y.R.E.S.O.U.|
CHECK-NEXT: 0360: 52004300 45000900 52004100 4E004400 |R.C.E...R.A.N.D.|
-CHECK-NEXT: 0370: 4F004D00 44004100 54000000 00000500 |O.M.D.A.T.......|
-CHECK-NEXT: 0380: 48006500 6C006C00 6F000000 00000000 |H.e.l.l.o.......|
+CHECK-NEXT: 0370: 4F004D00 44004100 54000000 00000000 |O.M.D.A.T.......|
+CHECK-NEXT: 0380: 00000500 48006500 6C006C00 6F000000 |....H.e.l.l.o...|
CHECK-NEXT: 0390: 00000000 00000000 00000000 00000000 |................|
-CHECK-NEXT: 03A0: 00000000 00000000 00000000 11000300 |................|
-CHECK-NEXT: 03B0: E7030000 0D004400 4C040000 82001200 |......D.L.......|
-CHECK-NEXT: 03C0: BC010000 28000000 10000000 10000000 |....(...........|
-CHECK-NEXT: 03D0: 01001800 00000000 00030000 C40E0000 |................|
-CHECK-NEXT: 03E0: C40E0000 00000000 00000000 FFFFFFFF |................|
+CHECK-NEXT: 03A0: 00000000 00000000 00000000 00000000 |................|
+CHECK-NEXT: 03B0: 11000300 E7030000 0D004400 4C040000 |..........D.L...|
+CHECK-NEXT: 03C0: 82001200 BC010000 28000000 10000000 |........(.......|
+CHECK-NEXT: 03D0: 10000000 01001800 00000000 00030000 |................|
+CHECK-NEXT: 03E0: C40E0000 C40E0000 00000000 00000000 |................|
CHECK-NEXT: 03F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 0400: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 0410: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
@@ -86,50 +86,50 @@
CHECK-NEXT: 0430: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 0440: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 0450: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0460: FF7F7F7F 7C7C7C78 78787575 75FFFFFF |....|||xxxuuu...|
-CHECK-NEXT: 0470: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0480: FFFFFFFF FFFFFFFF 979797FF FFFFFFFF |................|
-CHECK-NEXT: 0490: FF838383 AAAAAADB DBDB7979 79757575 |..........yyyuuu|
-CHECK-NEXT: 04A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 04B0: FFFFFFFF FFFFFFFF 9C9C9C98 9898FFFF |................|
-CHECK-NEXT: 04C0: FF888888 DBDBDBB7 B7B77D7D 7DFFFFFF |..........}}}...|
-CHECK-NEXT: 04D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 04E0: FFFFFFFF FFFFFFFF A0A0A09C 9C9C9393 |................|
-CHECK-NEXT: 04F0: 93ADADAD F2F2F284 84848181 81FFFFFF |................|
-CHECK-NEXT: 0500: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0510: FFFFFFFF FFFFFFFF A4A4A4D7 D7D79D9D |................|
-CHECK-NEXT: 0520: 9DD0D0D0 EEEEEE91 91918D8D 8DFFFFFF |................|
-CHECK-NEXT: 0530: FFFFFF81 81817E7E 7EFFFFFF FFFFFFFF |......~~~.......|
-CHECK-NEXT: 0540: FFFFFFFF FFFFFFFF A9A9A9F2 F2F2E5E5 |................|
-CHECK-NEXT: 0550: E5E2E2E2 95959591 91918D8D 8D898989 |................|
-CHECK-NEXT: 0560: 868686FF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0570: FFFFFFFF FFFFFFFF ADADADF2 F2F2E1E1 |................|
-CHECK-NEXT: 0580: E1DFDFDF E7E7E7E4 E4E4BBBB BB8E8E8E |................|
-CHECK-NEXT: 0590: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 05A0: FFFFFFFF FFFFFFFF B5B5B5F2 F2F2E8E8 |................|
-CHECK-NEXT: 05B0: E8E7E7E7 EAEAEAC6 C6C69E9E 9EFFFFFF |................|
-CHECK-NEXT: 05C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 05D0: FFFFFFFF FFFFFFFF B9B9B9F4 F4F4ECEC |................|
-CHECK-NEXT: 05E0: ECEDEDED CBCBCBA7 A7A7FFFF FFFFFFFF |................|
+CHECK-NEXT: 0460: FFFFFFFF FF7F7F7F 7C7C7C78 78787575 |........|||xxxuu|
+CHECK-NEXT: 0470: 75FFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |u...............|
+CHECK-NEXT: 0480: FFFFFFFF FFFFFFFF FFFFFFFF 979797FF |................|
+CHECK-NEXT: 0490: FFFFFFFF FF838383 AAAAAADB DBDB7979 |..............yy|
+CHECK-NEXT: 04A0: 79757575 FFFFFFFF FFFFFFFF FFFFFFFF |yuuu............|
+CHECK-NEXT: 04B0: FFFFFFFF FFFFFFFF FFFFFFFF 9C9C9C98 |................|
+CHECK-NEXT: 04C0: 9898FFFF FF888888 DBDBDBB7 B7B77D7D |..............}}|
+CHECK-NEXT: 04D0: 7DFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |}...............|
+CHECK-NEXT: 04E0: FFFFFFFF FFFFFFFF FFFFFFFF A0A0A09C |................|
+CHECK-NEXT: 04F0: 9C9C9393 93ADADAD F2F2F284 84848181 |................|
+CHECK-NEXT: 0500: 81FFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 0510: FFFFFFFF FFFFFFFF FFFFFFFF A4A4A4D7 |................|
+CHECK-NEXT: 0520: D7D79D9D 9DD0D0D0 EEEEEE91 91918D8D |................|
+CHECK-NEXT: 0530: 8DFFFFFF FFFFFF81 81817E7E 7EFFFFFF |..........~~~...|
+CHECK-NEXT: 0540: FFFFFFFF FFFFFFFF FFFFFFFF A9A9A9F2 |................|
+CHECK-NEXT: 0550: F2F2E5E5 E5E2E2E2 95959591 91918D8D |................|
+CHECK-NEXT: 0560: 8D898989 868686FF FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 0570: FFFFFFFF FFFFFFFF FFFFFFFF ADADADF2 |................|
+CHECK-NEXT: 0580: F2F2E1E1 E1DFDFDF E7E7E7E4 E4E4BBBB |................|
+CHECK-NEXT: 0590: BB8E8E8E FFFFFFFF FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 05A0: FFFFFFFF FFFFFFFF FFFFFFFF B5B5B5F2 |................|
+CHECK-NEXT: 05B0: F2F2E8E8 E8E7E7E7 EAEAEAC6 C6C69E9E |................|
+CHECK-NEXT: 05C0: 9EFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 05D0: FFFFFFFF FFFFFFFF FFFFFFFF B9B9B9F4 |................|
+CHECK-NEXT: 05E0: F4F4ECEC ECEDEDED CBCBCBA7 A7A7FFFF |................|
CHECK-NEXT: 05F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0600: FFFFFFFF FFFFFFFF BDBDBDF7 F7F7EFEF |................|
-CHECK-NEXT: 0610: EFD0D0D0 AFAFAFFF FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 0600: FFFFFFFF FFFFFFFF FFFFFFFF BDBDBDF7 |................|
+CHECK-NEXT: 0610: F7F7EFEF EFD0D0D0 AFAFAFFF FFFFFFFF |................|
CHECK-NEXT: 0620: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0630: FFFFFFFF FFFFFFFF C1C1C1F7 F7F7D5D5 |................|
-CHECK-NEXT: 0640: D5B6B6B6 FFFFFFFF FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 0630: FFFFFFFF FFFFFFFF FFFFFFFF C1C1C1F7 |................|
+CHECK-NEXT: 0640: F7F7D5D5 D5B6B6B6 FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 0650: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0660: FFFFFFFF FFFFFFFF C4C4C4D9 D9D9BEBE |................|
-CHECK-NEXT: 0670: BEFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 0660: FFFFFFFF FFFFFFFF FFFFFFFF C4C4C4D9 |................|
+CHECK-NEXT: 0670: D9D9BEBE BEFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 0680: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0690: FFFFFFFF FFFFFFFF C8C8C8C5 C5C5FFFF |................|
-CHECK-NEXT: 06A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 0690: FFFFFFFF FFFFFFFF FFFFFFFF C8C8C8C5 |................|
+CHECK-NEXT: 06A0: C5C5FFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 06B0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 06C0: FFFFFFFF FFFFFFFF CBCBCBFF FFFFFFFF |................|
+CHECK-NEXT: 06C0: FFFFFFFF FFFFFFFF FFFFFFFF CBCBCBFF |................|
CHECK-NEXT: 06D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 06E0: FFFFFFFF FFFFFFFF FFFFFFFF 28000000 |............(...|
-CHECK-NEXT: 06F0: 10000000 10000000 01001800 00000000 |................|
-CHECK-NEXT: 0700: 00030000 C40E0000 C40E0000 00000000 |................|
-CHECK-NEXT: 0710: 00000000 FFFFFFFF FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 06E0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 06F0: 28000000 10000000 10000000 01001800 |(...............|
+CHECK-NEXT: 0700: 00000000 00030000 C40E0000 C40E0000 |................|
+CHECK-NEXT: 0710: 00000000 00000000 FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 0720: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 0730: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 0740: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
@@ -142,29 +142,29 @@
CHECK-NEXT: 07B0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 07C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 07D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 07E0: A0E3A901 B31801B3 1801B318 01B31801 |................|
-CHECK-NEXT: 07F0: B31801B3 1861D06F FFFFFFFF FFFFFFFF |.....a.o........|
+CHECK-NEXT: 07E0: FFFFFFFF A0E3A901 B31801B3 1801B318 |................|
+CHECK-NEXT: 07F0: 01B31801 B31801B3 1861D06F FFFFFFFF |.........a.o....|
CHECK-NEXT: 0800: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0810: 01B31800 D7331CDB 49DBF9E2 9BEFAF00 |.....3..I.......|
-CHECK-NEXT: 0820: D73300D7 3301B318 FFFFFFFF FFFFFFFF |.3..3...........|
+CHECK-NEXT: 0810: FFFFFFFF 01B31800 D7331CDB 49DBF9E2 |.........3..I...|
+CHECK-NEXT: 0820: 9BEFAF00 D73300D7 3301B318 FFFFFFFF |.....3..3.......|
CHECK-NEXT: 0830: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0840: 01B31800 DE55F6FE F9DBFAE7 FEFFFE86 |.....U..........|
-CHECK-NEXT: 0850: EFAE00DE 5501B318 FFFFFFFF FFFFFFFF |....U...........|
+CHECK-NEXT: 0840: FFFFFFFF 01B31800 DE55F6FE F9DBFAE7 |.........U......|
+CHECK-NEXT: 0850: FEFFFE86 EFAE00DE 5501B318 FFFFFFFF |........U.......|
CHECK-NEXT: 0860: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0870: 01B31800 E676DBFB EC00E676 57EFA5FB |.....v.....vW...|
-CHECK-NEXT: 0880: FFFD55EE A401B318 FFFFFFFF FFFFFFFF |..U.............|
+CHECK-NEXT: 0870: FFFFFFFF 01B31800 E676DBFB EC00E676 |.........v.....v|
+CHECK-NEXT: 0880: 57EFA5FB FFFD55EE A401B318 FFFFFFFF |W.....U.........|
CHECK-NEXT: 0890: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 08A0: 01B31800 ED9800ED 9800ED98 00ED9887 |................|
-CHECK-NEXT: 08B0: F7CFFEFF FF01B318 FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 08A0: FFFFFFFF 01B31800 ED9800ED 9800ED98 |................|
+CHECK-NEXT: 08B0: 00ED9887 F7CFFEFF FF01B318 FFFFFFFF |................|
CHECK-NEXT: 08C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 08D0: 01B31800 F4BA00F4 BA00F4BA 00F4BA00 |................|
-CHECK-NEXT: 08E0: F4BA9CFB E401B318 FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 08D0: FFFFFFFF 01B31800 F4BA00F4 BA00F4BA |................|
+CHECK-NEXT: 08E0: 00F4BA00 F4BA9CFB E401B318 FFFFFFFF |................|
CHECK-NEXT: 08F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0900: 01B31800 FBDB00FB DB00FBDB 00FBDB00 |................|
-CHECK-NEXT: 0910: FBDB00FB DB01B318 FFFFFFFF FFFFFFFF |................|
+CHECK-NEXT: 0900: FFFFFFFF 01B31800 FBDB00FB DB00FBDB |................|
+CHECK-NEXT: 0910: 00FBDB00 FBDB00FB DB01B318 FFFFFFFF |................|
CHECK-NEXT: 0920: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0930: 9FE2A801 B31801B3 1801B318 01B31801 |................|
-CHECK-NEXT: 0940: B31801B3 1861D06F FFFFFFFF FFFFFFFF |.....a.o........|
+CHECK-NEXT: 0930: FFFFFFFF 9FE2A801 B31801B3 1801B318 |................|
+CHECK-NEXT: 0940: 01B31801 B31801B3 1861D06F FFFFFFFF |.........a.o....|
CHECK-NEXT: 0950: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 0960: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 0970: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
@@ -177,37 +177,37 @@
CHECK-NEXT: 09E0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 09F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
CHECK-NEXT: 0A00: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
-CHECK-NEXT: 0A10: FFFFFFFF 00000000 00006400 79007500 |..........d.y.u.|
-CHECK-NEXT: 0A20: 00000000 65007300 68006100 6C006100 |....e.s.h.a.l.a.|
-CHECK-NEXT: 0A30: 00008000 66006B00 61006F00 79006100 |....f.k.a.o.y.a.|
-CHECK-NEXT: 0A40: 00000000 0000C080 00000000 02000A00 |................|
-CHECK-NEXT: 0A50: 0A00C800 2C010000 00005400 65007300 |....,.....T.e.s.|
-CHECK-NEXT: 0A60: 74000000 01000250 00000000 0A000A00 |t......P........|
-CHECK-NEXT: 0A70: E6000E00 0100FFFF 82004300 6F006E00 |..........C.o.n.|
-CHECK-NEXT: 0A80: 74006900 6E007500 65003A00 00000000 |t.i.n.u.e.:.....|
-CHECK-NEXT: 0A90: 00000150 00000000 42008600 A1000D00 |...P....B.......|
-CHECK-NEXT: 0AA0: 0200FFFF 80002600 4F004B00 00000000 |......&.O.K.....|
-CHECK-NEXT: 0AB0: 00000000 11005800 A4000000 0D004800 |......X.......H.|
-CHECK-NEXT: 0AC0: 2E160000 82001200 BC010000 00000000 |................|
-CHECK-NEXT: 0AD0: 00006400 66006900 73006800 00000000 |..d.f.i.s.h.....|
-CHECK-NEXT: 0AE0: 65007300 61006C00 61006400 00008000 |e.s.a.l.a.d.....|
-CHECK-NEXT: 0AF0: 66006400 75006300 6B000000 74686973 |f.d.u.c.k...this|
-CHECK-NEXT: 0B00: 20697320 61207573 65722064 6566696E | is a user defin|
-CHECK-NEXT: 0B10: 65642072 65736F75 72636500 69742063 |ed resource.it c|
-CHECK-NEXT: 0B20: 6F6E7461 696E7320 6D616E79 20737472 |ontains many str|
-CHECK-NEXT: 0B30: 696E6773 00000000 00000000 74686973 |ings........this|
-CHECK-NEXT: 0B40: 20697320 61207261 6E646F6D 20626974 | is a random bit|
-CHECK-NEXT: 0B50: 206F6620 64617461 20746861 74206D65 | of data that me|
-CHECK-NEXT: 0B60: 616E7320 6E6F7468 696E6700 A9230E14 |ans nothing..#..|
-CHECK-NEXT: 0B70: F4F60000 7A686534 20736869 34207969 |....zhe4 shi4 yi|
-CHECK-NEXT: 0B80: 31676534 20737569 326A6931 20646520 |1ge4 sui2ji1 de |
-CHECK-NEXT: 0B90: 73687534 6A75342C 207A6865 34207969 |shu4ju4, zhe4 yi|
-CHECK-NEXT: 0BA0: 34776569 347A6865 20736865 6E326D65 |4wei4zhe shen2me|
-CHECK-NEXT: 0BB0: 00A9230E 14F4F600 00000000 44696573 |..#.........Dies|
-CHECK-NEXT: 0BC0: 20697374 2065696E 207A7566 C3A46C6C | ist ein zuf..ll|
-CHECK-NEXT: 0BD0: 69676573 20426974 20766F6E 20446174 |iges Bit von Dat|
-CHECK-NEXT: 0BE0: 656E2C20 64696520 6E696368 74732062 |en, die nichts b|
-CHECK-NEXT: 0BF0: 65646575 74657400 A9230E14 F4F60000 |edeutet..#......|
-CHECK-NEXT: 0C00: 00000000 11000300 E7030000 0D004400 |..............D.|
-CHECK-NEXT: 0C10: 4C040000 82001200 BC010000 |L...........|
+CHECK-NEXT: 0A10: FFFFFFFF FFFFFFFF 00000000 00006400 |..............d.|
+CHECK-NEXT: 0A20: 79007500 00000000 65007300 68006100 |y.u.....e.s.h.a.|
+CHECK-NEXT: 0A30: 6C006100 00008000 66006B00 61006F00 |l.a.....f.k.a.o.|
+CHECK-NEXT: 0A40: 79006100 00000000 0000C080 00000000 |y.a.............|
+CHECK-NEXT: 0A50: 02000A00 0A00C800 2C010000 00005400 |........,.....T.|
+CHECK-NEXT: 0A60: 65007300 74000000 01000250 00000000 |e.s.t......P....|
+CHECK-NEXT: 0A70: 0A000A00 E6000E00 0100FFFF 82004300 |..............C.|
+CHECK-NEXT: 0A80: 6F006E00 74006900 6E007500 65003A00 |o.n.t.i.n.u.e.:.|
+CHECK-NEXT: 0A90: 00000000 00000150 00000000 42008600 |.......P....B...|
+CHECK-NEXT: 0AA0: A1000D00 0200FFFF 80002600 4F004B00 |..........&.O.K.|
+CHECK-NEXT: 0AB0: 00000000 00000000 11005800 A4000000 |..........X.....|
+CHECK-NEXT: 0AC0: 0D004800 2E160000 82001200 BC010000 |..H.............|
+CHECK-NEXT: 0AD0: 00000000 00006400 66006900 73006800 |......d.f.i.s.h.|
+CHECK-NEXT: 0AE0: 00000000 65007300 61006C00 61006400 |....e.s.a.l.a.d.|
+CHECK-NEXT: 0AF0: 00008000 66006400 75006300 6B000000 |....f.d.u.c.k...|
+CHECK-NEXT: 0B00: 74686973 20697320 61207573 65722064 |this is a user d|
+CHECK-NEXT: 0B10: 6566696E 65642072 65736F75 72636500 |efined resource.|
+CHECK-NEXT: 0B20: 69742063 6F6E7461 696E7320 6D616E79 |it contains many|
+CHECK-NEXT: 0B30: 20737472 696E6773 00000000 00000000 | strings........|
+CHECK-NEXT: 0B40: 74686973 20697320 61207261 6E646F6D |this is a random|
+CHECK-NEXT: 0B50: 20626974 206F6620 64617461 20746861 | bit of data tha|
+CHECK-NEXT: 0B60: 74206D65 616E7320 6E6F7468 696E6700 |t means nothing.|
+CHECK-NEXT: 0B70: A9230E14 F4F60000 7A686534 20736869 |.#......zhe4 shi|
+CHECK-NEXT: 0B80: 34207969 31676534 20737569 326A6931 |4 yi1ge4 sui2ji1|
+CHECK-NEXT: 0B90: 20646520 73687534 6A75342C 207A6865 | de shu4ju4, zhe|
+CHECK-NEXT: 0BA0: 34207969 34776569 347A6865 20736865 |4 yi4wei4zhe she|
+CHECK-NEXT: 0BB0: 6E326D65 00A9230E 14F4F600 00000000 |n2me..#.........|
+CHECK-NEXT: 0BC0: 44696573 20697374 2065696E 207A7566 |Dies ist ein zuf|
+CHECK-NEXT: 0BD0: C3A46C6C 69676573 20426974 20766F6E |..lliges Bit von|
+CHECK-NEXT: 0BE0: 20446174 656E2C20 64696520 6E696368 | Daten, die nich|
+CHECK-NEXT: 0BF0: 74732062 65646575 74657400 A9230E14 |ts bedeutet..#..|
+CHECK-NEXT: 0C00: F4F60000 00000000 11000300 E7030000 |................|
+CHECK-NEXT: 0C10: 0D004400 4C040000 82001200 BC010000 |..D.L...........|
CHECK-NEXT: )
diff --git a/test/COFF/common-alignment.test b/test/COFF/common-alignment.test
index a4ee157..db02d91 100644
--- a/test/COFF/common-alignment.test
+++ b/test/COFF/common-alignment.test
@@ -4,8 +4,8 @@
# RUN: llvm-objdump -d %t.exe | FileCheck %s
# Operands of B8 (MOV EAX) are common symbols
-# CHECK: 3000: b8 00 10 00 40
-# CHECK: 3005: b8 10 10 00 40
+# CHECK: 1000: b8 00 20 00 40
+# CHECK: 1005: b8 10 20 00 40
--- !COFF
header:
@@ -23,10 +23,6 @@
- VirtualAddress: 6
SymbolName: bssdata4_align16
Type: IMAGE_REL_AMD64_ADDR32
- - Name: .data
- Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
- Alignment: 4
- SectionData: 03000000
- Name: .drectve
Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
Alignment: 1
@@ -45,18 +41,6 @@
NumberOfLinenumbers: 0
CheckSum: 0
Number: 0
- - Name: .data
- Value: 0
- SectionNumber: 2
- SimpleType: IMAGE_SYM_TYPE_NULL
- ComplexType: IMAGE_SYM_DTYPE_NULL
- StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
- Length: 4
- NumberOfRelocations: 0
- NumberOfLinenumbers: 0
- CheckSum: 0
- Number: 0
- Name: main
Value: 0
SectionNumber: 1
diff --git a/test/COFF/common.test b/test/COFF/common.test
index 4a00153..7d11da2 100644
--- a/test/COFF/common.test
+++ b/test/COFF/common.test
@@ -4,11 +4,11 @@
# RUN: llvm-objdump -d %t.exe | FileCheck %s
# Operands of B8 (MOV EAX) are common symbols
-# CHECK: 3000: b8 00 10 00 40
-# CHECK: 3005: b8 04 10 00 40
-# CHECK: 300a: b8 20 10 00 40
-# CHECK: 300f: b8 60 10 00 40
-# CHECK: 3014: b8 70 10 00 40
+# CHECK: 1000: b8 00 20 00 40
+# CHECK: 1005: b8 04 20 00 40
+# CHECK: 100a: b8 20 20 00 40
+# CHECK: 100f: b8 60 20 00 40
+# CHECK: 1014: b8 70 20 00 40
--- !COFF
header:
@@ -35,10 +35,6 @@
- VirtualAddress: 21
SymbolName: bssdata16
Type: IMAGE_REL_AMD64_ADDR32
- - Name: .data
- Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
- Alignment: 4
- SectionData: 03000000
symbols:
- Name: .text
Value: 0
@@ -52,18 +48,6 @@
NumberOfLinenumbers: 0
CheckSum: 0
Number: 0
- - Name: .data
- Value: 0
- SectionNumber: 2
- SimpleType: IMAGE_SYM_TYPE_NULL
- ComplexType: IMAGE_SYM_DTYPE_NULL
- StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
- Length: 4
- NumberOfRelocations: 0
- NumberOfLinenumbers: 0
- CheckSum: 0
- Number: 0
- Name: main
Value: 0
SectionNumber: 1
diff --git a/test/COFF/crt-chars.test b/test/COFF/crt-chars.test
new file mode 100644
index 0000000..e685631
--- /dev/null
+++ b/test/COFF/crt-chars.test
@@ -0,0 +1,32 @@
+# RUN: yaml2obj %s > %t.obj
+# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj
+# RUN: llvm-readobj -sections -section-data %t.dll | FileCheck %s
+
+# CHECK: Name: .CRT
+# CHECK: Characteristics [
+# CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+# CHECK-NEXT: IMAGE_SCN_MEM_READ
+# CHECK-NEXT: ]
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT: 010203
+# CHECK-NEXT: )
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: .CRT$XCZ
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 03
+ - Name: .CRT$XCU
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 1
+ SectionData: 02
+ - Name: .CRT$XCA
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 01
+symbols:
+...
diff --git a/test/COFF/ctors_dtors_priority.s b/test/COFF/ctors_dtors_priority.s
index 60562ba..efa0354 100644
--- a/test/COFF/ctors_dtors_priority.s
+++ b/test/COFF/ctors_dtors_priority.s
@@ -22,9 +22,9 @@
.quad 2
# CHECK: Contents of section .ctors:
-# CHECK-NEXT: 140001000 01000000 00000000 02000000 00000000
-# CHECK-NEXT: 140001010 03000000 00000000
-
-# CHECK: Contents of section .dtors:
# CHECK-NEXT: 140002000 01000000 00000000 02000000 00000000
# CHECK-NEXT: 140002010 03000000 00000000
+
+# CHECK: Contents of section .dtors:
+# CHECK-NEXT: 140003000 01000000 00000000 02000000 00000000
+# CHECK-NEXT: 140003010 03000000 00000000
diff --git a/test/COFF/default-alignment.test b/test/COFF/default-alignment.test
new file mode 100644
index 0000000..da8ea06
--- /dev/null
+++ b/test/COFF/default-alignment.test
@@ -0,0 +1,21 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe %t.obj /entry:__ImageBase /subsystem:console
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+
+# CHECK: Contents of section .rdata:
+# CHECK-NEXT: 01000000 00000000 00000000 00000000
+# CHECK-NEXT: 02
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: []
+sections:
+ - Name: .rdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ SectionData: 01
+ - Name: .rdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ SectionData: 02
+symbols:
+...
diff --git a/test/COFF/delayimports-armnt.yaml b/test/COFF/delayimports-armnt.yaml
index 231b4bc..a080d02 100644
--- a/test/COFF/delayimports-armnt.yaml
+++ b/test/COFF/delayimports-armnt.yaml
@@ -20,7 +20,7 @@
# IMPORT-NEXT: UnloadDelayImportTable: 0x0
# IMPORT-NEXT: Import {
# IMPORT-NEXT: Symbol: function (0)
-# IMPORT-NEXT: Address: 0x401019
+# IMPORT-NEXT: Address: 0x40100D
# IMPORT-NEXT: }
# IMPORT-NEXT: }
#
@@ -35,11 +35,11 @@
# BASEREL-NEXT: }
# BASEREL-NEXT: Entry {
# BASEREL-NEXT: Type: ARM_MOV32(T)
-# BASEREL-NEXT: Address: 0x1018
+# BASEREL-NEXT: Address: 0x1022
# BASEREL-NEXT: }
# BASEREL-NEXT: Entry {
-# BASEREL-NEXT: Type: ARM_MOV32(T)
-# BASEREL-NEXT: Address: 0x102E
+# BASEREL-NEXT: Type: ABSOLUTE
+# BASEREL-NEXT: Address: 0x1000
# BASEREL-NEXT: }
# BASEREL-NEXT: Entry {
# BASEREL-NEXT: Type: HIGHLOW
@@ -51,19 +51,19 @@
# BASEREL-NEXT: }
# BASEREL-NEXT: ]
#
-# DISASM: 401018: 43 f2 08 0c movw r12, #12296
-# DISASM-NEXT: 40101c: c0 f2 40 0c movt r12, #64
-# DISASM-NEXT: 401020: 2d e9 0f 48 push.w {r0, r1, r2, r3, r11, lr}
-# DISASM-NEXT: 401024: 0d f2 10 0b addw r11, sp, #16
-# DISASM-NEXT: 401028: 2d ed 10 0b vpush {d0, d1, d2, d3, d4, d5, d6, d7}
-# DISASM-NEXT: 40102c: 61 46 mov r1, r12
-# DISASM-NEXT: 40102e: 42 f2 00 00 movw r0, #8192
-# DISASM-NEXT: 401032: c0 f2 40 00 movt r0, #64
-# DISASM-NEXT: 401036: ff f7 e3 ff bl #-58
-# DISASM-NEXT: 40103a: 84 46 mov r12, r0
-# DISASM-NEXT: 40103c: bd ec 10 0b vpop {d0, d1, d2, d3, d4, d5, d6, d7}
-# DISASM-NEXT: 401040: bd e8 0f 48 pop.w {r0, r1, r2, r3, r11, lr}
-# DISASM-NEXT: 401044: 60 47 bx r12
+# DISASM: 40100c: 43 f2 08 0c movw r12, #12296
+# DISASM-NEXT: c0 f2 40 0c movt r12, #64
+# DISASM-NEXT: 2d e9 0f 48 push.w {r0, r1, r2, r3, r11, lr}
+# DISASM-NEXT: 0d f2 10 0b addw r11, sp, #16
+# DISASM-NEXT: 2d ed 10 0b vpush {d0, d1, d2, d3, d4, d5, d6, d7}
+# DISASM-NEXT: 61 46 mov r1, r12
+# DISASM-NEXT: 42 f2 00 00 movw r0, #8192
+# DISASM-NEXT: c0 f2 40 00 movt r0, #64
+# DISASM-NEXT: ff f7 e9 ff bl #-46
+# DISASM-NEXT: 84 46 mov r12, r0
+# DISASM-NEXT: bd ec 10 0b vpop {d0, d1, d2, d3, d4, d5, d6, d7}
+# DISASM-NEXT: bd e8 0f 48 pop.w {r0, r1, r2, r3, r11, lr}
+# DISASM-NEXT: 60 47 bx r12
--- !COFF
header:
diff --git a/test/COFF/delayimports.test b/test/COFF/delayimports.test
index 2c27d58..c6888b3 100644
--- a/test/COFF/delayimports.test
+++ b/test/COFF/delayimports.test
@@ -7,35 +7,35 @@
IMPORT: DelayImport {
IMPORT-NEXT: Name: std64.dll
IMPORT-NEXT: Attributes: 0x1
-IMPORT-NEXT: ModuleHandle: 0x1018
-IMPORT-NEXT: ImportAddressTable: 0x1020
-IMPORT-NEXT: ImportNameTable: 0x3040
+IMPORT-NEXT: ModuleHandle: 0x3018
+IMPORT-NEXT: ImportAddressTable: 0x3020
+IMPORT-NEXT: ImportNameTable: 0x2040
IMPORT-NEXT: BoundDelayImportTable: 0x0
IMPORT-NEXT: UnloadDelayImportTable: 0x0
IMPORT-NEXT: Import {
IMPORT-NEXT: Symbol: ExitProcess (0)
-IMPORT-NEXT: Address: 0x140002066
+IMPORT-NEXT: Address: 0x140001066
IMPORT-NEXT: }
IMPORT-NEXT: Import {
IMPORT-NEXT: Symbol: (50)
-IMPORT-NEXT: Address: 0x1400020BD
+IMPORT-NEXT: Address: 0x1400010BD
IMPORT-NEXT: }
IMPORT-NEXT: Import {
IMPORT-NEXT: Symbol: MessageBoxA (0)
-IMPORT-NEXT: Address: 0x140002114
+IMPORT-NEXT: Address: 0x140001114
IMPORT-NEXT: }
IMPORT-NEXT: }
BASEREL: BaseReloc [
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: DIR64
-BASEREL-NEXT: Address: 0x1020
+BASEREL-NEXT: Address: 0x3020
BASEREL-NEXT: }
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: DIR64
-BASEREL-NEXT: Address: 0x1028
+BASEREL-NEXT: Address: 0x3028
BASEREL-NEXT: }
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: DIR64
-BASEREL-NEXT: Address: 0x1030
+BASEREL-NEXT: Address: 0x3030
BASEREL-NEXT: }
diff --git a/test/COFF/delayimports32.test b/test/COFF/delayimports32.test
index 006eecf..9aa8f86 100644
--- a/test/COFF/delayimports32.test
+++ b/test/COFF/delayimports32.test
@@ -2,7 +2,7 @@
# RUN: yaml2obj < %p/Inputs/hello32.yaml > %t.obj
# RUN: lld-link %t.obj %p/Inputs/std32.lib /subsystem:console \
# RUN: /entry:main@0 /alternatename:___delayLoadHelper2@8=_main@0 \
-# RUN: /debug /delayload:std32.dll /out:%t.exe
+# RUN: /delayload:std32.dll /out:%t.exe
# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s
# RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s
# RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=DISASM %s
@@ -13,75 +13,75 @@
IMPORT-NEXT: DelayImport {
IMPORT-NEXT: Name: std32.dll
IMPORT-NEXT: Attributes: 0x1
-IMPORT-NEXT: ModuleHandle: 0x1018
-IMPORT-NEXT: ImportAddressTable: 0x1020
-IMPORT-NEXT: ImportNameTable: 0x4040
+IMPORT-NEXT: ModuleHandle: 0x3018
+IMPORT-NEXT: ImportAddressTable: 0x3020
+IMPORT-NEXT: ImportNameTable: 0x2040
IMPORT-NEXT: BoundDelayImportTable: 0x0
IMPORT-NEXT: UnloadDelayImportTable: 0x0
IMPORT-NEXT: Import {
IMPORT-NEXT: Symbol: ExitProcess (0)
-IMPORT-NEXT: Address: 0x402029
+IMPORT-NEXT: Address: 0x401029
IMPORT-NEXT: }
IMPORT-NEXT: Import {
IMPORT-NEXT: Symbol: MessageBoxA (0)
-IMPORT-NEXT: Address: 0x40203E
+IMPORT-NEXT: Address: 0x40103E
IMPORT-NEXT: }
IMPORT-NEXT: }
BASEREL: BaseReloc [
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: HIGHLOW
-BASEREL-NEXT: Address: 0x1020
+BASEREL-NEXT: Address: 0x1005
BASEREL-NEXT: }
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: HIGHLOW
-BASEREL-NEXT: Address: 0x1024
+BASEREL-NEXT: Address: 0x100C
BASEREL-NEXT: }
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: HIGHLOW
-BASEREL-NEXT: Address: 0x2005
+BASEREL-NEXT: Address: 0x101F
BASEREL-NEXT: }
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: HIGHLOW
-BASEREL-NEXT: Address: 0x200C
+BASEREL-NEXT: Address: 0x1025
BASEREL-NEXT: }
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: HIGHLOW
-BASEREL-NEXT: Address: 0x201F
+BASEREL-NEXT: Address: 0x102C
BASEREL-NEXT: }
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: HIGHLOW
-BASEREL-NEXT: Address: 0x2025
+BASEREL-NEXT: Address: 0x1031
BASEREL-NEXT: }
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: HIGHLOW
-BASEREL-NEXT: Address: 0x202C
+BASEREL-NEXT: Address: 0x1041
BASEREL-NEXT: }
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: HIGHLOW
-BASEREL-NEXT: Address: 0x2031
+BASEREL-NEXT: Address: 0x1046
BASEREL-NEXT: }
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: HIGHLOW
-BASEREL-NEXT: Address: 0x2041
+BASEREL-NEXT: Address: 0x3020
BASEREL-NEXT: }
BASEREL-NEXT: Entry {
BASEREL-NEXT: Type: HIGHLOW
-BASEREL-NEXT: Address: 0x2046
+BASEREL-NEXT: Address: 0x3024
BASEREL-NEXT: }
BASEREL-NEXT: ]
-DISASM: 202b: 68 20 10 40 00 pushl $4198432
-DISASM-NEXT: 2030: 68 00 40 40 00 pushl $4210688
-DISASM-NEXT: 2035: e8 c6 ff ff ff calll -58 <.text>
-DISASM-NEXT: 203a: 5a popl %edx
-DISASM-NEXT: 203b: 59 popl %ecx
-DISASM-NEXT: 203c: ff e0 jmpl *%eax
-DISASM-NEXT: 203e: 51 pushl %ecx
-DISASM-NEXT: 203f: 52 pushl %edx
-DISASM-NEXT: 2040: 68 24 10 40 00 pushl $4198436
-DISASM-NEXT: 2045: 68 00 40 40 00 pushl $4210688
-DISASM-NEXT: 204a: e8 b1 ff ff ff calll -79 <.text>
-DISASM-NEXT: 204f: 5a popl %edx
-DISASM-NEXT: 2050: 59 popl %ecx
-DISASM-NEXT: 2051: ff e0 jmpl *%eax
+DISASM: 102b: 68 20 30 40 00 pushl $4206624
+DISASM-NEXT: 1030: 68 00 20 40 00 pushl $4202496
+DISASM-NEXT: 1035: e8 c6 ff ff ff calll -58 <.text>
+DISASM-NEXT: 103a: 5a popl %edx
+DISASM-NEXT: 103b: 59 popl %ecx
+DISASM-NEXT: 103c: ff e0 jmpl *%eax
+DISASM-NEXT: 103e: 51 pushl %ecx
+DISASM-NEXT: 103f: 52 pushl %edx
+DISASM-NEXT: 1040: 68 24 30 40 00 pushl $4206628
+DISASM-NEXT: 1045: 68 00 20 40 00 pushl $4202496
+DISASM-NEXT: 104a: e8 b1 ff ff ff calll -79 <.text>
+DISASM-NEXT: 104f: 5a popl %edx
+DISASM-NEXT: 1050: 59 popl %ecx
+DISASM-NEXT: 1051: ff e0 jmpl *%eax
diff --git a/test/COFF/export-armnt.yaml b/test/COFF/export-armnt.yaml
index 367dabf..88d198c 100644
--- a/test/COFF/export-armnt.yaml
+++ b/test/COFF/export-armnt.yaml
@@ -9,10 +9,10 @@
# CHECK: DLL name: export-armnt.yaml.tmp.dll
# CHECK: Ordinal RVA Name
# CHECK-NEXT: 0 0
-# CHECK-NEXT: 1 0x1000 exportdata
-# CHECK-NEXT: 2 0x2005 exportfn1
-# CHECK-NEXT: 3 0x2009 exportfn2
-# CHECK-NEXT: 4 0x2009 exportfn3
+# CHECK-NEXT: 1 0x3000 exportdata
+# CHECK-NEXT: 2 0x1005 exportfn1
+# CHECK-NEXT: 3 0x1009 exportfn2
+# CHECK-NEXT: 4 0x1009 exportfn3
--- !COFF
header:
diff --git a/test/COFF/export.test b/test/COFF/export.test
index 174f4ac..a00a29c 100644
--- a/test/COFF/export.test
+++ b/test/COFF/export.test
@@ -86,6 +86,10 @@
# RUN: lld-link /out:%t.dll /dll %t.obj /export:foo=kernel32.foobar
# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=FORWARDER %s
+# RUN: echo "EXPORTS foo=kernel32.foobar" > %t.def
+# RUN: lld-link /out:%t.dll /dll %t.obj /def:%t.def
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=FORWARDER %s
+
FORWARDER: Export Table:
FORWARDER: DLL name: export.test.tmp.dll
FORWARDER: Ordinal base: 0
diff --git a/test/COFF/export32.test b/test/COFF/export32.test
index 34cd1a7..9218ac2 100644
--- a/test/COFF/export32.test
+++ b/test/COFF/export32.test
@@ -2,6 +2,10 @@
#
# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2
# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK1 %s
+#
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 /merge:.edata=.rdata
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK1 %s
+# RUN: llvm-readobj -file-headers -sections %t.dll | FileCheck -check-prefix=HEADER-MERGE %s
# CHECK1: Export Table:
# CHECK1: DLL name: export32.test.tmp.dll
@@ -10,6 +14,12 @@
# CHECK1-NEXT: 1 0x1008 exportfn1
# CHECK1-NEXT: 2 0x1010 exportfn2
+# HEADER-MERGE: ExportTableRVA: 0x2000
+# HEADER-MERGE-NEXT: ExportTableSize: 0x7E
+# HEADER-MERGE: Name: .rdata
+# HEADER-MERGE-NEXT: VirtualSize: 0x7E
+# HEADER-MERGE-NEXT: VirtualAddress: 0x2000
+
# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1,@5 \
# RUN: /export:exportfn2 /export:mangled
# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK2 %s
diff --git a/test/COFF/filename-casing.s b/test/COFF/filename-casing.s
index e210aea..0834c03 100644
--- a/test/COFF/filename-casing.s
+++ b/test/COFF/filename-casing.s
@@ -6,8 +6,10 @@
# RUN: llvm-lib /out:%T/MixedCase.lib %T/MixedCase.obj
# RUN: not lld-link /machine:x64 /entry:main %T/MixedCase.lib 2>&1 | FileCheck -check-prefix=ARCHIVE %s
-# OBJECT: MixedCase.obj: undefined symbol: f
-# ARCHIVE: MixedCase.lib(MixedCase.obj): undefined symbol: f
+# OBJECT: undefined symbol: f
+# OBJECT-NEXT: >>> referenced by {{.*}}MixedCase.obj:(main)
+# ARCHIVE: undefined symbol: f
+# ARCHIVE-NEXT: >>> referenced by {{.*}}MixedCase.lib(MixedCase.obj):(main)
.globl main
main:
diff --git a/test/COFF/force.test b/test/COFF/force.test
index b96c1f8..20c4e1a 100644
--- a/test/COFF/force.test
+++ b/test/COFF/force.test
@@ -4,8 +4,10 @@
# RUN: lld-link /out:%t.exe /entry:main %t.obj /force >& %t.log
# RUN: FileCheck -check-prefix=WARN %s < %t.log
-# ERROR: error: {{.*}}.obj: undefined symbol: foo
-# WARN: warning: {{.*}}.obj: undefined symbol: foo
+# ERROR: error: undefined symbol: foo
+# ERROR-NEXT: >>> referenced by {{.*}}.obj
+# WARN: warning: undefined symbol: foo
+# WARN-NEXT: >>> referenced by {{.*}}.obj
--- !COFF
header:
diff --git a/test/COFF/gfids-gc.s b/test/COFF/gfids-gc.s
index 1e2e72a..1ae348c 100644
--- a/test/COFF/gfids-gc.s
+++ b/test/COFF/gfids-gc.s
@@ -1,6 +1,8 @@
# RUN: llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o %t.obj
# RUN: lld-link %t.obj -guard:nolongjmp -out:%t.exe -opt:noref -entry:main
# RUN: llvm-readobj -file-headers -coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-NOGC
+# RUN: lld-link %t.obj -guard:nolongjmp -out:%t.exe -opt:noref -entry:main -debug:dwarf
+# RUN: llvm-readobj -file-headers -coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-NOGC
# RUN: lld-link %t.obj -guard:nolongjmp -out:%t.exe -opt:ref -entry:main
# RUN: llvm-readobj -file-headers -coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-GC
diff --git a/test/COFF/hello32.test b/test/COFF/hello32.test
index 9f3cadc..87c5879 100644
--- a/test/COFF/hello32.test
+++ b/test/COFF/hello32.test
@@ -27,8 +27,8 @@
HEADER-NEXT: SizeOfCode: 512
HEADER-NEXT: SizeOfInitializedData: 1536
HEADER-NEXT: SizeOfUninitializedData: 0
-HEADER-NEXT: AddressOfEntryPoint: 0x2000
-HEADER-NEXT: BaseOfCode: 0x2000
+HEADER-NEXT: AddressOfEntryPoint: 0x1000
+HEADER-NEXT: BaseOfCode: 0x1000
HEADER-NEXT: BaseOfData: 0x0
HEADER-NEXT: ImageBase: 0x400000
HEADER-NEXT: SectionAlignment: 4096
@@ -57,7 +57,7 @@
HEADER-NEXT: DataDirectory {
HEADER-NEXT: ExportTableRVA: 0x0
HEADER-NEXT: ExportTableSize: 0x0
-HEADER-NEXT: ImportTableRVA: 0x3000
+HEADER-NEXT: ImportTableRVA: 0x2000
HEADER-NEXT: ImportTableSize: 0x28
HEADER-NEXT: ResourceTableRVA: 0x0
HEADER-NEXT: ResourceTableSize: 0x0
@@ -79,7 +79,7 @@
HEADER-NEXT: LoadConfigTableSize: 0x0
HEADER-NEXT: BoundImportRVA: 0x0
HEADER-NEXT: BoundImportSize: 0x0
-HEADER-NEXT: IATRVA: 0x3034
+HEADER-NEXT: IATRVA: 0x2034
HEADER-NEXT: IATSize: 0xC
HEADER-NEXT: DelayImportDescriptorRVA: 0x0
HEADER-NEXT: DelayImportDescriptorSize: 0x0
@@ -114,8 +114,8 @@
IMPORTS: AddressSize: 32bit
IMPORTS: Import {
IMPORTS: Name: std32.dll
-IMPORTS: ImportLookupTableRVA: 0x3028
-IMPORTS: ImportAddressTableRVA: 0x3034
+IMPORTS: ImportLookupTableRVA: 0x2028
+IMPORTS: ImportAddressTableRVA: 0x2034
IMPORTS: Symbol: ExitProcess (0)
IMPORTS: Symbol: MessageBoxA (1)
IMPORTS: }
@@ -123,10 +123,10 @@
BASEREL: BaseReloc [
BASEREL: Entry {
BASEREL: Type: HIGHLOW
-BASEREL: Address: 0x2005
+BASEREL: Address: 0x1005
BASEREL: }
BASEREL: Entry {
BASEREL: Type: HIGHLOW
-BASEREL: Address: 0x200C
+BASEREL: Address: 0x100C
BASEREL: }
BASEREL: ]
diff --git a/test/COFF/icf-different-align.test b/test/COFF/icf-different-align.test
index 3502ed3..0e2fce9 100644
--- a/test/COFF/icf-different-align.test
+++ b/test/COFF/icf-different-align.test
@@ -2,9 +2,14 @@
# RUN: lld-link /entry:foo /out:%t.exe /subsystem:console /include:bar \
# RUN: /verbose %t.obj > %t.log 2>&1
# RUN: FileCheck %s < %t.log
+# RUN: llvm-objdump -s %t.exe | FileCheck --check-prefix=OBJDUMP %s
-# CHECK-NOT: Selected foo
-# CHECK-NOT: Removed bar
+# CHECK: Selected foo
+# CHECK: Removed bar
+
+# OBJDUMP: Contents of section .text:
+# OBJDUMP-NEXT: 140001000 00cccccc cccccccc cccccccc cccccccc
+# OBJDUMP-NEXT: 140001010 4883ec28 e8000000 004883c4 28c3
--- !COFF
header:
@@ -19,6 +24,10 @@
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
Alignment: 16
SectionData: 4883EC28E8000000004883C428C3
+ - Name: '.text'
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 00
symbols:
- Name: '.text$mn'
Value: 0
diff --git a/test/COFF/icf-pdata.s b/test/COFF/icf-pdata.s
new file mode 100644
index 0000000..ebd8479
--- /dev/null
+++ b/test/COFF/icf-pdata.s
@@ -0,0 +1,97 @@
+# RUN: llvm-mc %s -triple x86_64-windows-msvc -filetype=obj -o %t.obj
+# RUN: lld-link %t.obj -dll -noentry -out:%t.dll -merge:.xdata=.xdata
+# RUN: llvm-readobj -sections -coff-exports %t.dll | FileCheck %s
+
+# CHECK: Name: .pdata
+# CHECK-NEXT: VirtualSize: 0x18
+# CHECK: Name: .xdata
+# CHECK-NEXT: VirtualSize: 0x10
+
+# CHECK: Name: xdata1
+# CHECK-NEXT: RVA: 0x1010
+# CHECK: Name: xdata1a
+# CHECK-NEXT: RVA: 0x1010
+# CHECK: Name: xdata1b
+# CHECK-NEXT: RVA: 0x1030
+
+ .text
+callee:
+ ret
+
+ .def xdata1;
+ .scl 2;
+ .type 32;
+ .endef
+ .section .text,"xr",one_only,xdata1
+ .globl xdata1 # -- Begin function xdata1
+ .p2align 4, 0x90
+xdata1: # @xdata1
+.seh_proc xdata1
+# BB#0: # %entry
+ subq $40, %rsp
+ .seh_stackalloc 40
+ .seh_endprologue
+ callq callee
+ nop
+ addq $40, %rsp
+ jmp callee # TAILCALL
+ .seh_handlerdata
+ .section .text,"xr",one_only,xdata1
+ .seh_endproc
+ # -- End function
+
+# xdata1a is identical to xdata1, so it should be ICFd, and so should its pdata.
+# It also has associative debug and CFG sections which should be ignored by ICF.
+ .def xdata1a;
+ .scl 2;
+ .type 32;
+ .endef
+ .section .text,"xr",one_only,xdata1a
+ .globl xdata1a # -- Begin function xdata1a
+ .p2align 4, 0x90
+xdata1a: # @xdata1a
+.seh_proc xdata1a
+# BB#0: # %entry
+ subq $40, %rsp
+ .seh_stackalloc 40
+ .seh_endprologue
+ callq callee
+ nop
+ addq $40, %rsp
+ jmp callee # TAILCALL
+ .seh_handlerdata
+ .section .text,"xr",one_only,xdata1a
+ .seh_endproc
+
+ .section .debug$S,"r",associative,xdata1a
+ .section .gfids$y,"r",associative,xdata1a
+ .section .gljmp$y,"r",associative,xdata1a
+
+# xdata1b's text is identical to xdata1, but its xdata specifies a different
+# stack size, so it cannot be ICFd with xdata1.
+ .def xdata1b;
+ .scl 2;
+ .type 32;
+ .endef
+ .section .text,"xr",one_only,xdata1b
+ .globl xdata1b # -- Begin function xdata1b
+ .p2align 4, 0x90
+xdata1b: # @xdata1b
+.seh_proc xdata1b
+# BB#0: # %entry
+ subq $40, %rsp
+ .seh_stackalloc 48
+ .seh_endprologue
+ callq callee
+ nop
+ addq $40, %rsp
+ jmp callee # TAILCALL
+ .seh_handlerdata
+ .section .text,"xr",one_only,xdata1b
+ .seh_endproc
+ # -- End function
+
+ .section .drectve,"yn"
+ .ascii " -export:xdata1"
+ .ascii " -export:xdata1a"
+ .ascii " -export:xdata1b"
diff --git a/test/COFF/icf-vtables.s b/test/COFF/icf-vtables.s
new file mode 100644
index 0000000..6500247
--- /dev/null
+++ b/test/COFF/icf-vtables.s
@@ -0,0 +1,28 @@
+# REQUIRES: x86
+# RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t.obj %s
+# RUN: lld-link %t.obj /out:%t.exe /entry:main /subsystem:console
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+
+# CHECK: Contents of section .text:
+.globl main
+main:
+# CHECK-NEXT: 140001000 00200040 01000000 01200040 01000000
+.8byte "??_"
+.8byte "??_7"
+# CHECK-NEXT: 140001010 01200040 01000000
+.8byte "??_7a"
+
+.section .rdata,"dr",discard,"??_"
+.globl "??_"
+"??_":
+.byte 42
+
+.section .rdata,"dr",discard,"??_7"
+.globl "??_7"
+"??_7":
+.byte 42
+
+.section .rdata,"dr",discard,"??_7a"
+.globl "??_7a"
+"??_7a":
+.byte 42
diff --git a/test/COFF/icf-xdata.s b/test/COFF/icf-xdata.s
index 8fb4bad..ec7f625 100644
--- a/test/COFF/icf-xdata.s
+++ b/test/COFF/icf-xdata.s
@@ -1,13 +1,25 @@
# RUN: llvm-mc %s -triple x86_64-windows-msvc -filetype=obj -o %t.obj
+# RUN: lld-link %t.obj -dll -noentry -out:%t.dll -merge:.xdata=.xdata 2>&1 \
+# RUN: | FileCheck %s --check-prefix=WARN
+# RUN: llvm-readobj -sections %t.dll | FileCheck %s --check-prefix=XDATA
# RUN: lld-link %t.obj -dll -noentry -out:%t.dll
-# RUN: llvm-readobj -sections %t.dll | FileCheck %s
+# RUN: llvm-readobj -sections %t.dll | FileCheck %s --check-prefix=RDATA
# There shouldn't be much xdata, because all three .pdata entries (12 bytes
# each) should use the same .xdata unwind info.
-# CHECK: Name: .pdata
-# CHECK-NEXT: VirtualSize: 0x24
-# CHECK: Name: .xdata
-# CHECK-NEXT: VirtualSize: 0x8
+# XDATA: Name: .rdata
+# XDATA-NEXT: VirtualSize: 0x73
+# XDATA: Name: .pdata
+# XDATA-NEXT: VirtualSize: 0x24
+# XDATA: Name: .xdata
+# XDATA-NEXT: VirtualSize: 0x8
+#
+# WARN: warning: .xdata=.rdata: already merged into .xdata
+#
+# RDATA: Name: .rdata
+# RDATA-NEXT: VirtualSize: 0x7C
+# RDATA: Name: .pdata
+# RDATA-NEXT: VirtualSize: 0x24
.text
callee:
diff --git a/test/COFF/imports.test b/test/COFF/imports.test
index 326bfbe..64f3900 100644
--- a/test/COFF/imports.test
+++ b/test/COFF/imports.test
@@ -15,8 +15,8 @@
TEXT-NEXT: .text:
TEXT-NEXT: subq $40, %rsp
TEXT-NEXT: movq $0, %rcx
-TEXT-NEXT: leaq -4108(%rip), %rdx
-TEXT-NEXT: leaq -4121(%rip), %r8
+TEXT-NEXT: leaq 8180(%rip), %rdx
+TEXT-NEXT: leaq 8167(%rip), %r8
TEXT-NEXT: movl $0, %r9d
TEXT-NEXT: callq 60
TEXT-NEXT: movl $0, %ecx
@@ -28,8 +28,8 @@
IMPORT: Import {
IMPORT-NEXT: Name: std64.dll
-IMPORT-NEXT: ImportLookupTableRVA: 0x3028
-IMPORT-NEXT: ImportAddressTableRVA: 0x3048
+IMPORT-NEXT: ImportLookupTableRVA: 0x2028
+IMPORT-NEXT: ImportAddressTableRVA: 0x2048
IMPORT-NEXT: Symbol: ExitProcess (0)
IMPORT-NEXT: Symbol: (50)
IMPORT-NEXT: Symbol: MessageBoxA (1)
diff --git a/test/COFF/loadcfg.ll b/test/COFF/loadcfg.ll
index c49ae2f..139ec74 100644
--- a/test/COFF/loadcfg.ll
+++ b/test/COFF/loadcfg.ll
@@ -2,7 +2,7 @@
; RUN: lld-link /out:%t.exe %t.obj /entry:main /subsystem:console
; RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
-; CHECK: LoadConfigTableRVA: 0x1000
+; CHECK: LoadConfigTableRVA: 0x2000
; CHECK: LoadConfigTableSize: 0x70
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/test/COFF/loadcfg.test b/test/COFF/loadcfg.test
index 072ee6b..2e226f4 100644
--- a/test/COFF/loadcfg.test
+++ b/test/COFF/loadcfg.test
@@ -2,7 +2,7 @@
# RUN: lld-link /out:%t.exe %t.obj /entry:main /subsystem:console
# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
-# CHECK: LoadConfigTableRVA: 0x1000
+# CHECK: LoadConfigTableRVA: 0x2000
# CHECK: LoadConfigTableSize: 0x70
--- !COFF
diff --git a/test/COFF/loadcfg32.test b/test/COFF/loadcfg32.test
index 03a066c..9485aa0 100644
--- a/test/COFF/loadcfg32.test
+++ b/test/COFF/loadcfg32.test
@@ -2,7 +2,7 @@
# RUN: lld-link /out:%t.exe %t.obj /entry:main /subsystem:console
# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
-# CHECK: LoadConfigTableRVA: 0x1000
+# CHECK: LoadConfigTableRVA: 0x2000
# CHECK: LoadConfigTableSize: 0x40
--- !COFF
diff --git a/test/COFF/lto-comdat.ll b/test/COFF/lto-comdat.ll
index 9594d30..9ff3776 100644
--- a/test/COFF/lto-comdat.ll
+++ b/test/COFF/lto-comdat.ll
@@ -45,7 +45,7 @@
; TEXT-11-NEXT: xorl %eax, %eax
; TEXT-11-NEXT: retq
-; HEADERS-01: AddressOfEntryPoint: 0x2000
+; HEADERS-01: AddressOfEntryPoint: 0x1000
; TEXT-01: Disassembly of section .text:
; TEXT-01-NEXT: .text:
; TEXT-01-NEXT: subq $40, %rsp
@@ -62,7 +62,7 @@
; TEXT-01: int3
; TEXT-01-NOT: {{.}}
-; HEADERS-10: AddressOfEntryPoint: 0x2020
+; HEADERS-10: AddressOfEntryPoint: 0x1020
; TEXT-10: Disassembly of section .text:
; TEXT-10-NEXT: .text:
; TEXT-10-NEXT: subq $40, %rsp
diff --git a/test/COFF/lto.ll b/test/COFF/lto.ll
index 587ca5d..4e16c9b 100644
--- a/test/COFF/lto.ll
+++ b/test/COFF/lto.ll
@@ -52,7 +52,7 @@
; TEXT-11-NEXT: movl $2, %eax
; TEXT-11-NEXT: retq
-; HEADERS-01: AddressOfEntryPoint: 0x2000
+; HEADERS-01: AddressOfEntryPoint: 0x1000
; TEXT-01: Disassembly of section .text:
; TEXT-01-NEXT: .text:
; TEXT-01-NEXT: subq $40, %rsp
@@ -78,7 +78,7 @@
; TEXT-01-NEXT: int3
; TEXT-01-NEXT: retq
-; HEADERS-10: AddressOfEntryPoint: 0x2020
+; HEADERS-10: AddressOfEntryPoint: 0x1020
; TEXT-10: Disassembly of section .text:
; TEXT-10-NEXT: .text:
; TEXT-10-NEXT: retq
diff --git a/test/COFF/manifestinput-error.test b/test/COFF/manifestinput-error.test
index eca7d0d..22ddc67 100644
--- a/test/COFF/manifestinput-error.test
+++ b/test/COFF/manifestinput-error.test
@@ -7,4 +7,4 @@
# RUN: /manifestuac:"level='requireAdministrator'" \
# RUN: /manifestinput:%p/Inputs/manifestinput.test %t.obj 2>&1 | FileCheck %s
-# CHECK: error: unable to find mt.exe in PATH: No such file or directory
+# CHECK: error: unable to find mt.exe in PATH: {{[Nn]}}o such file or directory
diff --git a/test/COFF/manifestinput.test b/test/COFF/manifestinput.test
index 51c1890..33f14d8 100644
--- a/test/COFF/manifestinput.test
+++ b/test/COFF/manifestinput.test
@@ -8,8 +8,8 @@
# RUN: llvm-readobj -coff-resources -file-headers %t.exe | FileCheck %s \
# RUN: -check-prefix TEST_EMBED
-TEST_EMBED: ResourceTableRVA: 0x1000
-TEST_EMBED-NEXT: ResourceTableSize: 0x298
+TEST_EMBED: ResourceTableRVA: 0x2000
+TEST_EMBED-NEXT: ResourceTableSize: 0x2A0
TEST_EMBED-DAG: Resources [
TEST_EMBED-NEXT: Total Number of Resources: 1
TEST_EMBED-DAG: Number of String Entries: 0
diff --git a/test/COFF/merge.test b/test/COFF/merge.test
index 4b5c100..10a5672 100644
--- a/test/COFF/merge.test
+++ b/test/COFF/merge.test
@@ -3,9 +3,35 @@
# RUN: /merge:.foo=.abc /merge:.bar=.def %t.obj /debug
# RUN: llvm-readobj -sections %t.exe | FileCheck %s
+# RUN: lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN: /merge:.foo=.bar /merge:.bar=.abc %t.obj /debug
+# RUN: llvm-readobj -sections %t.exe | FileCheck --check-prefix=CHECK2 %s
+
+# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN: /merge:.rsrc=.foo %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-RSRC %s
+# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN: /merge:.foo=.rsrc %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-RSRC %s
+# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN: /merge:.reloc=.foo %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-RELOC %s
+# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN: /merge:.foo=.reloc %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-RELOC %s
+# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN: /merge:.foo=.foo1 /merge:.foo1=.foo %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-CYCLE %s
+# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN: /merge:.foo=.foo1 /merge:.foo1=.foo2 /merge:.foo2=.foo1 %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-CYCLE %s
+
# CHECK: Name: .def
# CHECK: Name: .abc
+# CHECK2-NOT: Name: .bar
+# CHECK2: Name: .abc
+# CHECK2-NOT: Name: .bar
+
+# NO-RSRC: /merge: cannot merge '.rsrc' with any section
+# NO-RELOC: /merge: cannot merge '.reloc' with any section
+
+# NO-CYCLE: /merge: cycle found for section '.foo'
+
--- !COFF
header:
Machine: IMAGE_FILE_MACHINE_AMD64
diff --git a/test/COFF/nodefaultlib.test b/test/COFF/nodefaultlib.test
index c0f8d50..8f4da3a 100644
--- a/test/COFF/nodefaultlib.test
+++ b/test/COFF/nodefaultlib.test
@@ -21,7 +21,8 @@
CHECK1: error: could not open hello64.obj: {{[Nn]}}o such file or directory
CHECK2: error: could not open hello64: {{[Nn]}}o such file or directory
-CHECK3: error: {{.*}}hello64.obj: undefined symbol: MessageBoxA
+CHECK3: error: undefined symbol: MessageBoxA
+CHECK3-NEXT: >>> referenced by {{.*}}hello64.obj:(main)
# RUN: lld-link /libpath:%T /out:%t.exe /entry:main \
# RUN: /subsystem:console hello64.obj /defaultlib:std64.lib
diff --git a/test/COFF/options.test b/test/COFF/options.test
index 39f944b..6b9f2ca 100644
--- a/test/COFF/options.test
+++ b/test/COFF/options.test
@@ -30,6 +30,16 @@
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOENT %s
NOENT-NOT: IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA
+# RUN: lld-link /out:%t.exe /entry:main /integritycheck %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=INT %s
+INT: IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOINT %s
+# RUN: lld-link /out:%t.exe /integritycheck:no /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOINT %s
+NOINT-NOT: IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY
+
# RUN: lld-link /out:%t.exe /entry:main %t.obj
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NXCOMPAT %s
# RUN: lld-link /out:%t.exe /entry:main /nxcompat %t.obj
@@ -48,4 +58,8 @@
# RUN: lld-link /tsaware:no /out:%t.exe /entry:main %t.obj
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOTSAWARE %s
+# RUN: lld-link /dll /out:%t.dll /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.dll | FileCheck -check-prefix=NOTSAWARE %s
+# RUN: lld-link /tsaware /dll /out:%t.dll /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.dll | FileCheck -check-prefix=NOTSAWARE %s
NOTSAWARE-NOT: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE
diff --git a/test/COFF/output-chars.test b/test/COFF/output-chars.test
new file mode 100644
index 0000000..2ccb084
--- /dev/null
+++ b/test/COFF/output-chars.test
@@ -0,0 +1,109 @@
+# RUN: yaml2obj %s > %t.obj
+# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj
+# RUN: llvm-readobj -sections %t.dll | FileCheck %s
+# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj /section:.foo,rwe
+# RUN: llvm-readobj -sections %t.dll | FileCheck --check-prefix=SECTION %s
+# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj /merge:.foo=.bar
+# RUN: llvm-readobj -sections -section-data %t.dll | FileCheck --check-prefix=MERGE %s
+# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj /merge:.foo=.bar /section:.foo,rwe
+# RUN: llvm-readobj -sections %t.dll | FileCheck --check-prefix=MERGE-SECTION %s
+
+# CHECK: Name: .foo
+# CHECK: Characteristics [
+# CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+# CHECK-NEXT: IMAGE_SCN_MEM_READ
+# CHECK-NEXT: ]
+
+# CHECK: Name: .foo
+# CHECK: Characteristics [
+# CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+# CHECK-NEXT: IMAGE_SCN_MEM_READ
+# CHECK-NEXT: IMAGE_SCN_MEM_WRITE
+# CHECK-NEXT: ]
+
+# SECTION: Name: .foo
+# SECTION: Characteristics [
+# SECTION-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+# SECTION-NEXT: IMAGE_SCN_MEM_EXECUTE
+# SECTION-NEXT: IMAGE_SCN_MEM_READ
+# SECTION-NEXT: IMAGE_SCN_MEM_WRITE
+# SECTION-NEXT: ]
+
+# SECTION: Name: .foo
+# SECTION: Characteristics [
+# SECTION-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+# SECTION-NEXT: IMAGE_SCN_MEM_EXECUTE
+# SECTION-NEXT: IMAGE_SCN_MEM_READ
+# SECTION-NEXT: IMAGE_SCN_MEM_WRITE
+# SECTION-NEXT: ]
+
+# MERGE: Name: .bar
+# MERGE: Characteristics [
+# MERGE-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+# MERGE-NEXT: IMAGE_SCN_MEM_READ
+# MERGE-NEXT: ]
+# MERGE-NEXT: SectionData (
+# MERGE-NEXT: 0000: 0301
+
+# MERGE: Name: .bar
+# MERGE: Characteristics [
+# MERGE-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+# MERGE-NEXT: IMAGE_SCN_MEM_READ
+# MERGE-NEXT: IMAGE_SCN_MEM_WRITE
+# MERGE-NEXT: ]
+# MERGE-NEXT: SectionData (
+# MERGE-NEXT: 0000: 04
+
+# MERGE: Name: .foo
+# MERGE: Characteristics [
+# MERGE-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+# MERGE-NEXT: IMAGE_SCN_MEM_READ
+# MERGE-NEXT: IMAGE_SCN_MEM_WRITE
+# MERGE-NEXT: ]
+# MERGE-NEXT: SectionData (
+# MERGE-NEXT: 0000: 02
+
+# MERGE-SECTION: Name: .bar
+# MERGE-SECTION: Characteristics [
+# MERGE-SECTION-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+# MERGE-SECTION-NEXT: IMAGE_SCN_MEM_READ
+# MERGE-SECTION-NEXT: ]
+
+# MERGE-SECTION: Name: .bar
+# MERGE-SECTION: Characteristics [
+# MERGE-SECTION-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+# MERGE-SECTION-NEXT: IMAGE_SCN_MEM_READ
+# MERGE-SECTION-NEXT: IMAGE_SCN_MEM_WRITE
+# MERGE-SECTION-NEXT: ]
+
+# MERGE-SECTION: Name: .foo
+# MERGE-SECTION: Characteristics [
+# MERGE-SECTION-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+# MERGE-SECTION-NEXT: IMAGE_SCN_MEM_EXECUTE
+# MERGE-SECTION-NEXT: IMAGE_SCN_MEM_READ
+# MERGE-SECTION-NEXT: IMAGE_SCN_MEM_WRITE
+# MERGE-SECTION-NEXT: ]
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: .foo
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 01
+ - Name: .foo
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 1
+ SectionData: 02
+ - Name: .bar
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 03
+ - Name: .bar
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 1
+ SectionData: 04
+symbols:
+...
diff --git a/test/COFF/pdata-arm64.yaml b/test/COFF/pdata-arm64.yaml
index f21749b..4f5210c 100644
--- a/test/COFF/pdata-arm64.yaml
+++ b/test/COFF/pdata-arm64.yaml
@@ -3,7 +3,7 @@
# RUN: lld-link /out:%t.exe /entry:func1 /subsystem:console %t.obj
# RUN: llvm-objdump -s -section=.pdata %t.exe | FileCheck -check-prefix=PDATA %s
-# PDATA: 00200000 2500a100 24200000 31002201
+# PDATA: 00100000 2500a100 24100000 31002201
--- !COFF
header:
diff --git a/test/COFF/pdb-comdat.test b/test/COFF/pdb-comdat.test
index 655f215..1659f98 100644
--- a/test/COFF/pdb-comdat.test
+++ b/test/COFF/pdb-comdat.test
@@ -61,7 +61,7 @@
CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1
CHECK: flags = security checks | hot patchable
CHECK: 120 | S_GPROC32 [size = 44] `main`
-CHECK: parent = 0, end = 196, addr = 0002:0000, code size = 24
+CHECK: parent = 0, end = 196, addr = 0001:0000, code size = 24
CHECK: debug start = 4, debug end = 19, flags = none
CHECK: 164 | S_FRAMEPROC [size = 32]
CHECK: size = 40, padding size = 0, offset to padding = 0
@@ -70,7 +70,7 @@
CHECK: 196 | S_END [size = 4]
CHECK: 200 | S_BUILDINFO [size = 8] BuildId = `0x100A`
CHECK: 208 | S_GPROC32 [size = 44] `foo`
-CHECK: parent = 0, end = 284, addr = 0002:0032, code size = 15
+CHECK: parent = 0, end = 284, addr = 0001:0032, code size = 15
CHECK: debug start = 0, debug end = 14, flags = none
CHECK: 252 | S_FRAMEPROC [size = 32]
CHECK: size = 0, padding size = 0, offset to padding = 0
@@ -84,7 +84,7 @@
CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1
CHECK: flags = security checks | hot patchable
CHECK: 120 | S_GPROC32 [size = 44] `bar`
-CHECK: parent = 0, end = 196, addr = 0002:0048, code size = 14
+CHECK: parent = 0, end = 196, addr = 0001:0048, code size = 14
CHECK: debug start = 4, debug end = 9, flags = none
CHECK: 164 | S_FRAMEPROC [size = 32]
CHECK: size = 40, padding size = 0, offset to padding = 0
diff --git a/test/COFF/pdb-global-hashes.test b/test/COFF/pdb-global-hashes.test
index b47e438..238613c 100644
--- a/test/COFF/pdb-global-hashes.test
+++ b/test/COFF/pdb-global-hashes.test
@@ -83,7 +83,7 @@
CHECK-NEXT: Showing 6 records
CHECK-NEXT: 0x1000 | LF_FUNC_ID [size = 20]
CHECK-NEXT: name = main, type = 0x1002, parent scope = <no type>
-CHECK-NEXT: 0x1001 | LF_STRING_ID [size = 48] ID: <no type>, String: D:\src\llvmbuild\clang\Debug\x86\obj.h
+CHECK-NEXT: 0x1001 | LF_STRING_ID [size = {{.*}}] ID: <no type>, String: {{.*}}obj.h
CHECK-NEXT: 0x1002 | LF_UDT_SRC_LINE [size = 16]
CHECK-NEXT: udt = 0x1008, file = 4097, line = 2
CHECK-NEXT: 0x1003 | LF_MFUNC_ID [size = 16]
diff --git a/test/COFF/pdb-globals.test b/test/COFF/pdb-globals.test
index b5e4f49..3eee76a 100644
--- a/test/COFF/pdb-globals.test
+++ b/test/COFF/pdb-globals.test
@@ -24,9 +24,9 @@
CHECK-NEXT: 312 | S_PROCREF [size = 40] `HelloPoint::HelloPoint`
CHECK-NEXT: module = 1, sum name = 0, offset = 376
CHECK-NEXT: 232 | S_GDATA32 [size = 28] `__purecall`
-CHECK-NEXT: type = 0x0403 (void*), addr = 0000:0000
+CHECK-NEXT: type = 0x0403 (void*), addr = 0003:0004
CHECK-NEXT: 260 | S_GDATA32 [size = 24] `GlobalVar`
-CHECK-NEXT: type = 0x100B (const int*), addr = 0001:0000
+CHECK-NEXT: type = 0x100B (const int*), addr = 0003:0000
CHECK-NEXT: 284 | S_LDATA32 [size = 28] `ConstantVar`
CHECK-NEXT: type = 0x100A (const int), addr = 0002:0000
diff --git a/test/COFF/pdb-heapsite.yaml b/test/COFF/pdb-heapsite.yaml
index 966ae42..bfdd7b4 100644
--- a/test/COFF/pdb-heapsite.yaml
+++ b/test/COFF/pdb-heapsite.yaml
@@ -69,7 +69,7 @@
RegRelativeSym:
Offset: 8
Type: 35
- Register: RSP
+ Register: CVRegRSP
VarName: __formal
- Kind: S_PROC_ID_END
ScopeEndSym:
diff --git a/test/COFF/pdb-procid-remapping.test b/test/COFF/pdb-procid-remapping.test
index cb61240..e42616d 100644
--- a/test/COFF/pdb-procid-remapping.test
+++ b/test/COFF/pdb-procid-remapping.test
@@ -9,7 +9,7 @@
CHECK-NEXT: ============================================================
CHECK-LABEL: Mod 0000 |
CHECK: 92 | S_GPROC32 [size = 44] `main`
-CHECK-NEXT: parent = 0, end = 168, addr = 0002:0000, code size = 14
+CHECK-NEXT: parent = 0, end = 168, addr = 0001:0000, code size = 14
CHECK-NEXT: type = `0x1004 (int (<no type>))`, debug start = 4, debug end = 9, flags = none
CHECK-NEXT: 136 | S_FRAMEPROC [size = 32]
CHECK-NEXT: size = 40, padding size = 0, offset to padding = 0
@@ -18,7 +18,7 @@
CHECK-NEXT: 168 | S_END [size = 4]
CHECK-LABEL: Mod 0001 |
CHECK: 92 | S_GPROC32 [size = 44] `foo`
-CHECK-NEXT: parent = 0, end = 168, addr = 0002:0016, code size = 6
+CHECK-NEXT: parent = 0, end = 168, addr = 0001:0016, code size = 6
CHECK-NEXT: type = `0x1001 (int ())`, debug start = 0, debug end = 5, flags = none
CHECK-NEXT: 136 | S_FRAMEPROC [size = 32]
CHECK-NEXT: size = 0, padding size = 0, offset to padding = 0
diff --git a/test/COFF/pdb-publics-import.test b/test/COFF/pdb-publics-import.test
index 1c75e90..a1fe7d0 100644
--- a/test/COFF/pdb-publics-import.test
+++ b/test/COFF/pdb-publics-import.test
@@ -6,7 +6,8 @@
RUN: lld-link /out:%t1.dll /dll %t1.obj /implib:%t1.lib \
RUN: /export:exportfn1 /export:exportfn2
RUN: yaml2obj < %p/Inputs/import.yaml > %t2.obj
-RUN: lld-link /out:%t2.exe /pdb:%t2.pdb /debug /entry:main %t2.obj %t1.lib
+RUN: lld-link /out:%t2.exe /pdb:%t2.pdb /pdbaltpath:test.pdb \
+RUN: /debug /entry:main %t2.obj %t1.lib
RUN: llvm-pdbutil dump %t2.pdb -publics -section-contribs | FileCheck %s
CHECK: Public Symbols
@@ -19,9 +20,9 @@
CHECK-NEXT: 88 | S_PUB32 [size = 24] `exportfn2`
CHECK-NEXT: flags = function, addr = 0001:0032
CHECK-NEXT: 32 | S_PUB32 [size = 32] `__imp_exportfn2`
-CHECK-NEXT: flags = none, addr = 0003:0072
+CHECK-NEXT: flags = none, addr = 0002:0136
CHECK-NEXT: 0 | S_PUB32 [size = 32] `__imp_exportfn1`
-CHECK-NEXT: flags = none, addr = 0003:0064
+CHECK-NEXT: flags = none, addr = 0002:0128
CHECK: Section Contributions
CHECK-NEXT: ============================================================
@@ -38,5 +39,5 @@
.rdata debug directory data chunks
CHECK-NEXT: SC[.rdata] | mod = 1, 0002:0000, size = 28, data crc = 0, reloc crc = 0
CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
-CHECK-NEXT: SC[.rdata] | mod = 1, 0002:0028, size = {{.*}}, data crc = 0, reloc crc = 0
+CHECK-NEXT: SC[.rdata] | mod = 1, 0002:0028, size = 33, data crc = 0, reloc crc = 0
CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
diff --git a/test/COFF/pdb-scopes.test b/test/COFF/pdb-scopes.test
index 2649167..f0381f1 100644
--- a/test/COFF/pdb-scopes.test
+++ b/test/COFF/pdb-scopes.test
@@ -35,39 +35,39 @@
CHECK-LABEL: Mod 0000 | `{{.*}}pdb-scopes.test.tmp-a.obj`:
CHECK: 104 | S_GPROC32 [size = 44] `g`
-CHECK: parent = 0, end = 196, addr = 0002:0000, code size = 5
+CHECK: parent = 0, end = 196, addr = 0001:0000, code size = 5
CHECK: debug start = 4, debug end = 4, flags = none
CHECK: 180 | S_REGREL32 [size = 16] `x`
CHECK: 196 | S_END [size = 4]
CHECK: 200 | S_GPROC32 [size = 44] `main`
-CHECK: parent = 0, end = 384, addr = 0002:0016, code size = 58
+CHECK: parent = 0, end = 384, addr = 0001:0016, code size = 58
CHECK: debug start = 8, debug end = 53, flags = none
CHECK: 276 | S_REGREL32 [size = 20] `argc`
CHECK: 296 | S_BLOCK32 [size = 24] ``
CHECK: parent = 200, end = 336
-CHECK: code size = 17, addr = 0002:0031
+CHECK: code size = 17, addr = 0001:0031
CHECK: 320 | S_REGREL32 [size = 16] `x`
CHECK: 336 | S_END [size = 4]
CHECK: 340 | S_BLOCK32 [size = 24] ``
CHECK: parent = 200, end = 380
-CHECK: code size = 17, addr = 0002:0050
+CHECK: code size = 17, addr = 0001:0050
CHECK: 364 | S_REGREL32 [size = 16] `y`
CHECK: 380 | S_END [size = 4]
CHECK: 384 | S_END [size = 4]
CHECK-LABEL: Mod 0001 | `{{.*}}pdb-scopes.test.tmp-b.obj`:
CHECK: 104 | S_GPROC32 [size = 44] `f`
-CHECK: parent = 0, end = 284, addr = 0002:0080, code size = 62
+CHECK: parent = 0, end = 284, addr = 0001:0080, code size = 62
CHECK: debug start = 8, debug end = 57, flags = none
CHECK: 180 | S_REGREL32 [size = 16] `x`
CHECK: 196 | S_BLOCK32 [size = 24] ``
CHECK: parent = 104, end = 236
-CHECK: code size = 20, addr = 0002:0095
+CHECK: code size = 20, addr = 0001:0095
CHECK: 220 | S_REGREL32 [size = 16] `y`
CHECK: 236 | S_END [size = 4]
CHECK: 240 | S_BLOCK32 [size = 24] ``
CHECK: parent = 104, end = 280
-CHECK: code size = 20, addr = 0002:0117
+CHECK: code size = 20, addr = 0001:0117
CHECK: 264 | S_REGREL32 [size = 16] `w`
CHECK: 280 | S_END [size = 4]
CHECK: 284 | S_END [size = 4]
diff --git a/test/COFF/pdb-source-lines.test b/test/COFF/pdb-source-lines.test
index 3b8dff9..416cab0 100644
--- a/test/COFF/pdb-source-lines.test
+++ b/test/COFF/pdb-source-lines.test
@@ -26,11 +26,11 @@
CHECK-LABEL: DbiStream:
CHECK-NEXT: VerHeader: V70
CHECK-NEXT: Age: 1
-CHECK-NEXT: BuildNumber: 0
+CHECK-NEXT: BuildNumber: 36363
CHECK-NEXT: PdbDllVersion: 0
CHECK-NEXT: PdbDllRbld: 0
CHECK-NEXT: Flags: 0
-CHECK-NEXT: MachineType: x86
+CHECK-NEXT: MachineType: Amd64
CHECK-NEXT: Modules:
CHECK-LABEL: - Module: {{.*}}pdb_lines_1.obj
@@ -43,7 +43,7 @@
CHECK-NEXT: CodeSize: 19
CHECK-NEXT: Flags: [ ]
CHECK-NEXT: RelocOffset: 0
-CHECK-NEXT: RelocSegment: 2
+CHECK-NEXT: RelocSegment: 1
CHECK-NEXT: Blocks:
CHECK-NEXT: - FileName: '{{.*}}pdb_lines_1.c'
CHECK-NEXT: Lines:
@@ -68,7 +68,7 @@
CHECK-NEXT: CodeSize: 14
CHECK-NEXT: Flags: [ ]
CHECK-NEXT: RelocOffset: 32
-CHECK-NEXT: RelocSegment: 2
+CHECK-NEXT: RelocSegment: 1
CHECK-NEXT: Blocks:
CHECK-NEXT: - FileName: '{{.*}}foo.h'
CHECK-NEXT: Lines:
@@ -103,7 +103,7 @@
CHECK-NEXT: CodeSize: 1
CHECK-NEXT: Flags: [ ]
CHECK-NEXT: RelocOffset: 48
-CHECK-NEXT: RelocSegment: 2
+CHECK-NEXT: RelocSegment: 1
CHECK-NEXT: Blocks:
CHECK-NEXT: - FileName: '{{.*}}pdb_lines_2.c'
CHECK-NEXT: Lines:
diff --git a/test/COFF/pdb-symbol-types.yaml b/test/COFF/pdb-symbol-types.yaml
index 9dad72d..0ed1215 100644
--- a/test/COFF/pdb-symbol-types.yaml
+++ b/test/COFF/pdb-symbol-types.yaml
@@ -19,7 +19,7 @@
# CHECK-NEXT: 48 | S_PROCREF [size = 20] `main`
# CHECK-NEXT: module = 1, sum name = 0, offset = 116
# CHECK-NEXT: 68 | S_GDATA32 [size = 28] `global_foo`
-# CHECK-NEXT: type = 0x1004 (Foo), addr = 0001:0000
+# CHECK-NEXT: type = 0x1004 (Foo), addr = 0003:0000
# CHECK: Symbols
# CHECK: ============================================================
@@ -30,7 +30,7 @@
# CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1
# CHECK: flags = security checks | hot patchable
# CHECK: 116 | S_GPROC32 [size = 44] `main`
-# CHECK: parent = 0, end = 192, addr = 0002:0000, code size = 7
+# CHECK: parent = 0, end = 192, addr = 0001:0000, code size = 7
# CHECK: debug start = 0, debug end = 6, flags = none
# CHECK: 160 | S_FRAMEPROC [size = 32]
# CHECK: size = 0, padding size = 0, offset to padding = 0
diff --git a/test/COFF/pdb-thunk.yaml b/test/COFF/pdb-thunk.yaml
index 6435a17..444800f 100644
--- a/test/COFF/pdb-thunk.yaml
+++ b/test/COFF/pdb-thunk.yaml
@@ -84,7 +84,7 @@
RegRelativeSym:
Offset: 8
Type: 4097
- Register: RSP
+ Register: CVRegRSP
VarName: this
- Kind: S_PROC_ID_END
ScopeEndSym:
@@ -124,7 +124,7 @@
RegRelativeSym:
Offset: 8
Type: 4121
- Register: RSP
+ Register: CVRegRSP
VarName: this
- Kind: S_PROC_ID_END
ScopeEndSym:
@@ -164,7 +164,7 @@
RegRelativeSym:
Offset: 48
Type: 4143
- Register: RSP
+ Register: CVRegRSP
VarName: this
- Kind: S_PROC_ID_END
ScopeEndSym:
@@ -208,7 +208,7 @@
RegRelativeSym:
Offset: 8
Type: 4143
- Register: RSP
+ Register: CVRegRSP
VarName: this
- Kind: S_PROC_ID_END
ScopeEndSym:
@@ -2176,7 +2176,7 @@
RegRelativeSym:
Offset: 8
Type: 4097
- Register: RSP
+ Register: CVRegRSP
VarName: this
- Kind: S_PROC_ID_END
ScopeEndSym:
@@ -2222,7 +2222,7 @@
RegRelativeSym:
Offset: 8
Type: 4121
- Register: RSP
+ Register: CVRegRSP
VarName: this
- Kind: S_PROC_ID_END
ScopeEndSym:
diff --git a/test/COFF/pdb-type-server-simple.test b/test/COFF/pdb-type-server-simple.test
index 898c5d4..51a92db 100644
--- a/test/COFF/pdb-type-server-simple.test
+++ b/test/COFF/pdb-type-server-simple.test
@@ -72,7 +72,7 @@
CHECK-LABEL: Mod 0000 | `{{.*}}a.obj`:
CHECK: 4 | S_OBJNAME [size = 40] sig=0, `C:\src\llvm-project\build\a.obj`
CHECK: 104 | S_GPROC32 [size = 44] `main`
-CHECK: parent = 0, end = 196, addr = 0002:0000, code size = 27
+CHECK: parent = 0, end = 196, addr = 0001:0000, code size = 27
CHECK: type = {{.*}}, debug start = 4, debug end = 22, flags = none
CHECK: 200 | S_BUILDINFO [size = 8] BuildId = `[[A_BUILD]]`
CHECK-LABEL: Mod 0001 | `{{.*}}b.obj`:
@@ -82,14 +82,14 @@
CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1
CHECK: flags = security checks | hot patchable
CHECK: 104 | S_GPROC32 [size = 44] `g`
-CHECK: parent = 0, end = 196, addr = 0002:0032, code size = 13
+CHECK: parent = 0, end = 196, addr = 0001:0032, code size = 13
CHECK: type = {{.*}}, debug start = 5, debug end = 12, flags = none
CHECK: 148 | S_FRAMEPROC [size = 32]
CHECK: size = 0, padding size = 0, offset to padding = 0
CHECK: bytes of callee saved registers = 0, exception handler addr = 0000:0000
CHECK: flags = has async eh | opt speed
CHECK: 180 | S_REGREL32 [size = 16] `p`
-CHECK: type = [[FOO_PTR]] (Foo*), register = RSP, offset = 8
+CHECK: type = [[FOO_PTR]] (Foo*), register = CVRegRSP, offset = 8
CHECK: 196 | S_END [size = 4]
CHECK: 200 | S_BUILDINFO [size = 8] BuildId = `[[B_BUILD]]`
CHECK-LABEL: Mod 0002 | `* Linker *`:
diff --git a/test/COFF/pdb.test b/test/COFF/pdb.test
index faab5fe..5788b51 100644
--- a/test/COFF/pdb.test
+++ b/test/COFF/pdb.test
@@ -1,8 +1,8 @@
# RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj
# RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj
# RUN: rm -f %t.dll %t.pdb
-# RUN: lld-link /debug /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \
-# RUN: %t1.obj %t2.obj
+# RUN: lld-link /debug /pdb:%t.pdb /pdbaltpath:test.pdb /dll /out:%t.dll \
+# RUN: /entry:main /nodefaultlib %t1.obj %t2.obj
# RUN: llvm-pdbutil pdb2yaml -stream-metadata -stream-directory -pdb-stream \
# RUN: -dbi-stream -ipi-stream -tpi-stream %t.pdb | FileCheck %s
@@ -34,11 +34,11 @@
# CHECK-NEXT: DbiStream:
# CHECK-NEXT: VerHeader: V70
# CHECK-NEXT: Age: 1
-# CHECK-NEXT: BuildNumber: 0
+# CHECK-NEXT: BuildNumber: 36363
# CHECK-NEXT: PdbDllVersion: 0
# CHECK-NEXT: PdbDllRbld: 0
# CHECK-NEXT: Flags: 0
-# CHECK-NEXT: MachineType: x86
+# CHECK-NEXT: MachineType: Amd64
# CHECK-NEXT: TpiStream:
# CHECK-NEXT: Version: VC80
# CHECK-NEXT: Records:
@@ -120,14 +120,22 @@
RAW: Modules
RAW-NEXT: ============================================================
RAW-NEXT: Mod 0000 | `{{.*}}pdb.test.tmp1.obj`:
+RAW-NEXT: SC[.text] | mod = 0, 0001:0000, size = 14, data crc = 1682752513, reloc crc = 0
+RAW-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_ALIGN_16BYTES | IMAGE_SCN_MEM_EXECUTE |
+RAW-NEXT: IMAGE_SCN_MEM_READ
RAW-NEXT: Obj: `{{.*}}pdb.test.tmp1.obj`:
RAW-NEXT: debug stream: 11, # files: 1, has ec info: false
RAW-NEXT: pdb file ni: 0 ``, src file ni: 0 ``
RAW-NEXT: Mod 0001 | `{{.*}}pdb.test.tmp2.obj`:
+RAW-NEXT: SC[.text] | mod = 1, 0001:0016, size = 6, data crc = 2139436471, reloc crc = 0
+RAW-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_ALIGN_16BYTES | IMAGE_SCN_MEM_EXECUTE |
+RAW-NEXT: IMAGE_SCN_MEM_READ
RAW-NEXT: Obj: `{{.*}}pdb.test.tmp2.obj`:
RAW-NEXT: debug stream: 12, # files: 1, has ec info: false
RAW-NEXT: pdb file ni: 0 ``, src file ni: 0 ``
RAW-NEXT: Mod 0002 | `* Linker *`:
+RAW-NEXT: SC[???] | mod = 2, 0000:0000, size = 0, data crc = 0, reloc crc = 0
+RAW-NEXT: none
RAW-NEXT: Obj: ``:
RAW-NEXT: debug stream: 13, # files: 0, has ec info: false
RAW-NEXT: pdb file ni: 1 `{{.*pdb.test.tmp.pdb}}`, src file ni: 0 ``
@@ -181,9 +189,9 @@
RAW-NEXT: sig = 0xFFFFFFFF, hdr = 0xF12F091A, hr size = 16, num buckets = 524
RAW-NEXT: Records
RAW-NEXT: 20 | S_PUB32 [size = 20] `main`
-RAW-NEXT: flags = function, addr = 0002:0000
+RAW-NEXT: flags = function, addr = 0001:0000
RAW-NEXT: 0 | S_PUB32 [size = 20] `foo`
-RAW-NEXT: flags = function, addr = 0002:0016
+RAW-NEXT: flags = function, addr = 0001:0016
RAW-NOT: S_PUB32
RAW-NEXT: Hash Entries
RAW-NEXT: off = 21, refcnt = 1
@@ -196,93 +204,80 @@
RAW-NEXT: off = 0
RAW: Section Headers
RAW-NEXT: ============================================================
+
RAW: SECTION HEADER #1
-RAW-NEXT: .pdata name
-RAW-NEXT: virtual size
-RAW-NEXT: 1000 virtual address
-RAW-NEXT: 200 size of raw data
-RAW-NEXT: 400 file pointer to raw data
-RAW-NEXT: 0 file pointer to relocation table
-RAW-NEXT: 0 file pointer to line numbers
-RAW-NEXT: 0 number of relocations
-RAW-NEXT: 0 number of line numbers
-RAW-NEXT: 40000040 flags
-RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
-RAW-NEXT: IMAGE_SCN_MEM_READ
+RAW-NEXT: .text name
+RAW-NEXT: 16 virtual size
+RAW-NEXT: 1000 virtual address
+RAW-NEXT: 200 size of raw data
+RAW-NEXT: 400 file pointer to raw data
+RAW-NEXT: 0 file pointer to relocation table
+RAW-NEXT: 0 file pointer to line numbers
+RAW-NEXT: 0 number of relocations
+RAW-NEXT: 0 number of line numbers
+RAW-NEXT: 60000020 flags
+RAW-NEXT: IMAGE_SCN_CNT_CODE
+RAW-NEXT: IMAGE_SCN_MEM_EXECUTE
+RAW-NEXT: IMAGE_SCN_MEM_READ
RAW: SECTION HEADER #2
-RAW-NEXT: .text name
-RAW-NEXT: virtual size
-RAW-NEXT: 2000 virtual address
-RAW-NEXT: 200 size of raw data
-RAW-NEXT: 600 file pointer to raw data
-RAW-NEXT: 0 file pointer to relocation table
-RAW-NEXT: 0 file pointer to line numbers
-RAW-NEXT: 0 number of relocations
-RAW-NEXT: 0 number of line numbers
-RAW-NEXT: 60000020 flags
-RAW-NEXT: IMAGE_SCN_CNT_CODE
-RAW-NEXT: IMAGE_SCN_MEM_EXECUTE
-RAW-NEXT: IMAGE_SCN_MEM_READ
+RAW-NEXT: .rdata name
+RAW-NEXT: virtual size
+RAW-NEXT: 2000 virtual address
+RAW-NEXT: 200 size of raw data
+RAW-NEXT: 600 file pointer to raw data
+RAW-NEXT: 0 file pointer to relocation table
+RAW-NEXT: 0 file pointer to line numbers
+RAW-NEXT: 0 number of relocations
+RAW-NEXT: 0 number of line numbers
+RAW-NEXT: 40000040 flags
+RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+RAW-NEXT: IMAGE_SCN_MEM_READ
RAW: SECTION HEADER #3
-RAW-NEXT: .xdata name
-RAW-NEXT: virtual size
-RAW-NEXT: 3000 virtual address
-RAW-NEXT: 200 size of raw data
-RAW-NEXT: 800 file pointer to raw data
-RAW-NEXT: 0 file pointer to relocation table
-RAW-NEXT: 0 file pointer to line numbers
-RAW-NEXT: 0 number of relocations
-RAW-NEXT: 0 number of line numbers
-RAW-NEXT: 40000040 flags
-RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
-RAW-NEXT: IMAGE_SCN_MEM_READ
-RAW: SECTION HEADER #4
-RAW-NEXT: .rdata name
-RAW-NEXT: virtual size
-RAW-NEXT: 4000 virtual address
-RAW-NEXT: 200 size of raw data
-RAW-NEXT: A00 file pointer to raw data
-RAW-NEXT: 0 file pointer to relocation table
-RAW-NEXT: 0 file pointer to line numbers
-RAW-NEXT: 0 number of relocations
-RAW-NEXT: 0 number of line numbers
-RAW-NEXT: 40000040 flags
-RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
-RAW-NEXT: IMAGE_SCN_MEM_READ
+RAW-NEXT: .pdata name
+RAW-NEXT: C virtual size
+RAW-NEXT: 3000 virtual address
+RAW-NEXT: 200 size of raw data
+RAW-NEXT: 800 file pointer to raw data
+RAW-NEXT: 0 file pointer to relocation table
+RAW-NEXT: 0 file pointer to line numbers
+RAW-NEXT: 0 number of relocations
+RAW-NEXT: 0 number of line numbers
+RAW-NEXT: 40000040 flags
+RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+RAW-NEXT: IMAGE_SCN_MEM_READ
RAW: Original Section Headers
RAW-NEXT: ============================================================
RAW-NEXT: PDB does not contain the requested image section header type
RAW: Section Contributions
RAW-NEXT: ============================================================
-RAW-NEXT: SC[.pdata] | mod = 0, 0001:0000, size = 12, data crc = 361370162, reloc crc = 0
-RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ
-RAW-NEXT: SC[.text] | mod = 0, 0002:0000, size = 14, data crc = 1682752513, reloc crc = 0
+
+RAW-NEXT: SC[.text] | mod = 0, 0001:0000, size = 14, data crc = 1682752513, reloc crc = 0
RAW-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_ALIGN_16BYTES | IMAGE_SCN_MEM_EXECUTE |
RAW-NEXT: IMAGE_SCN_MEM_READ
-RAW-NEXT: SC[.text] | mod = 1, 0002:0016, size = 6, data crc = 2139436471, reloc crc = 0
+RAW-NEXT: SC[.text] | mod = 1, 0001:0016, size = 6, data crc = 2139436471, reloc crc = 0
RAW-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_ALIGN_16BYTES | IMAGE_SCN_MEM_EXECUTE |
RAW-NEXT: IMAGE_SCN_MEM_READ
-RAW-NEXT: SC[.xdata] | mod = 0, 0003:0000, size = 8, data crc = 264583633, reloc crc = 0
+RAW-NEXT: SC[.rdata] | mod = 2, 0002:0000, size = {{[0-9]+}}, data crc = 0, reloc crc = 0
+RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
+RAW-NEXT: SC[.rdata] | mod = 2, 0002:0028, size = {{[0-9]+}}, data crc = 0, reloc crc = 0
+RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
+RAW-NEXT: SC[.rdata] | mod = 0, 0002:0064, size = {{[0-9]+}}, data crc = 264583633, reloc crc = 0
RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ
-RAW-NEXT: SC[???] | mod = 2, 0004:0000, size = {{[0-9]+}}, data crc = 0, reloc crc = 0
-RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
-RAW-NEXT: SC[???] | mod = 2, 0004:0028, size = {{[0-9]+}}, data crc = 0, reloc crc = 0
-RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
+RAW-NEXT: SC[.pdata] | mod = 0, 0003:0000, size = 12, data crc = 361370162, reloc crc = 0
+RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ
RAW-NOT: SC[
RAW: Section Map
RAW-NEXT: ============================================================
+
RAW-NEXT: Section 0000 | ovl = 0, group = 0, frame = 1, name = 65535
RAW-NEXT: class = 65535, offset = 0, size =
-RAW-NEXT: flags = read | 32 bit addr | selector
+RAW-NEXT: flags = read | execute | 32 bit addr | selector
RAW-NEXT: Section 0001 | ovl = 0, group = 0, frame = 2, name = 65535
RAW-NEXT: class = 65535, offset = 0, size =
-RAW-NEXT: flags = read | execute | 32 bit addr | selector
+RAW-NEXT: flags = read | 32 bit addr | selector
RAW-NEXT: Section 0002 | ovl = 0, group = 0, frame = 3, name = 65535
RAW-NEXT: class = 65535, offset = 0, size =
RAW-NEXT: flags = read | 32 bit addr | selector
RAW-NEXT: Section 0003 | ovl = 0, group = 0, frame = 4, name = 65535
-RAW-NEXT: class = 65535, offset = 0, size =
-RAW-NEXT: flags = read | 32 bit addr | selector
-RAW-NEXT: Section 0004 | ovl = 0, group = 0, frame = 5, name = 65535
-RAW-NEXT: class = 65535, offset = 0, size =
+RAW-NEXT: class = 65535, offset = 0, size = 4294967295
RAW-NEXT: flags = 32 bit addr | absolute addr
diff --git a/test/COFF/reloc-arm.test b/test/COFF/reloc-arm.test
index 872e6d5..87d93ed 100644
--- a/test/COFF/reloc-arm.test
+++ b/test/COFF/reloc-arm.test
@@ -3,14 +3,14 @@
# RUN: llvm-objdump -s %t.exe | FileCheck %s
# CHECK: .text:
-# CHECK: 402000 01104000 00000000 00000000 00000000
-# CHECK: 402010 01100000 00000000 00000000 00000000
-# CHECK: 402020 41f20009 c0f24009 00000000 00000000
-# CHECK: 402030 fe07e62f 00000000 00000000 00000000
-# CHECK: 402040 3e04de2f 00000000 00000000 00000000
-# CHECK: 402050 fe07d62f 00000000 00000000 00000000
-# CHECK: 402060 fef0cef7 00000000 00000000 00000000
-# CHECK: 402070 00005000 00000000 00000000 00000000
+# CHECK: 401000 01204000 00000000 00000000 00000000
+# CHECK: 401010 01200000 00000000 00000000 00000000
+# CHECK: 401020 42f20009 c0f24009 00000000 00000000
+# CHECK: 401030 0000e62f 00000000 00000000 00000000
+# CHECK: 401040 0000de07 00000000 00000000 00000000
+# CHECK: 401050 0000d62f 00000000 00000000 00000000
+# CHECK: 401060 00f1cef7 00000000 00000000 00000000
+# CHECK: 401070 00005000 00000000 00000000 00000000
--- !COFF
header:
diff --git a/test/COFF/resource.test b/test/COFF/resource.test
index 53242cd..4108957 100644
--- a/test/COFF/resource.test
+++ b/test/COFF/resource.test
@@ -10,11 +10,11 @@
# RUN: llvm-readobj -file-headers -coff-resources -section-data %t.exe | \
# RUN: FileCheck --check-prefix=RESOURCE_INFO %s
-RESOURCE_INFO: ResourceTableRVA: 0x1000
-RESOURCE_INFO-NEXT: ResourceTableSize: 0x88
+RESOURCE_INFO: ResourceTableRVA: 0x2000
+RESOURCE_INFO-NEXT: ResourceTableSize: 0x90
RESOURCE_INFO-DAG: Resources [
RESOURCE_INFO-NEXT: Total Number of Resources: 1
-RESOURCE_INFO-NEXT: Base Table Address: 0x400
+RESOURCE_INFO-NEXT: Base Table Address: 0x600
RESOURCE_INFO-DAG: Number of String Entries: 0
RESOURCE_INFO-NEXT: Number of ID Entries: 1
RESOURCE_INFO-NEXT: Type: kRT_STRING (ID 6) [
@@ -36,9 +36,9 @@
RESOURCE_INFO-NEXT: 0010: 06000000 18000080 00000000 00000000 |................|
RESOURCE_INFO-NEXT: 0020: 00000000 00000100 01000000 30000080 |............0...|
RESOURCE_INFO-NEXT: 0030: 00000000 00000000 00000000 00000100 |................|
-RESOURCE_INFO-NEXT: 0040: 09040000 48000000 58100000 2A000000 |....H...X...*...|
-RESOURCE_INFO-NEXT: 0050: 00000000 00000000 00000500 48006500 |............H.e.|
-RESOURCE_INFO-NEXT: 0060: 6C006C00 6F000000 00000000 00000000 |l.l.o...........|
+RESOURCE_INFO-NEXT: 0040: 09040000 48000000 60200000 2A000000 |....H...` ..*...|
+RESOURCE_INFO-NEXT: 0050: 00000000 00000000 00000000 00000000 |................|
+RESOURCE_INFO-NEXT: 0060: 00000500 48006500 6C006C00 6F000000 |....H.e.l.l.o...|
RESOURCE_INFO-NEXT: 0070: 00000000 00000000 00000000 00000000 |................|
-RESOURCE_INFO-NEXT: 0080: 00000000 00000000 |........|
+RESOURCE_INFO-NEXT: 0080: 00000000 00000000 00000000 00000000 |................|
RESOURCE_INFO-NEXT: )
diff --git a/test/COFF/rsds.test b/test/COFF/rsds.test
index 10c2c56..6ce92a9 100644
--- a/test/COFF/rsds.test
+++ b/test/COFF/rsds.test
@@ -1,16 +1,16 @@
# RUN: yaml2obj %s > %t.obj
# RUN: rm -f %t.dll %t.pdb
-# RUN: lld-link /debug /dll /out:%t.dll /entry:DllMain %t.obj
+# RUN: lld-link /debug /pdbaltpath:test1.pdb /dll /out:%t.dll /entry:DllMain %t.obj
# RUN: llvm-readobj -coff-debug-directory %t.dll > %t.1.txt
-# RUN: lld-link /debug /dll /out:%t.dll /entry:DllMain %t.obj
+# RUN: lld-link /debug /pdbaltpath:test2.pdb /dll /out:%t.dll /entry:DllMain %t.obj
# RUN: llvm-readobj -coff-debug-directory %t.dll > %t.2.txt
# RUN: cat %t.1.txt %t.2.txt | FileCheck %s
# RUN: rm -f %t.dll %t.pdb
-# RUN: lld-link /debug /pdb:%t.pdb /dll /out:%t.dll /entry:DllMain %t.obj
+# RUN: lld-link /debug /pdb:%t1.pdb /dll /out:%t.dll /entry:DllMain %t.obj
# RUN: llvm-readobj -coff-debug-directory %t.dll > %t.3.txt
-# RUN: lld-link /debug /pdb:%t.pdb /dll /out:%t.dll /entry:DllMain %t.obj
+# RUN: lld-link /debug /pdb:%t2.pdb /dll /out:%t.dll /entry:DllMain %t.obj
# RUN: llvm-readobj -coff-debug-directory %t.dll > %t.4.txt
# RUN: cat %t.3.txt %t.4.txt | FileCheck %s
@@ -29,7 +29,7 @@
# CHECK: PDBSignature: 0x53445352
# CHECK: PDBGUID: [[GUID:\(([A-Za-z0-9]{2} ?){16}\)]]
# CHECK: PDBAge: 1
-# CHECK: PDBFileName: {{.*}}.pdb
+# CHECK: PDBFileName: {{.*}}1.pdb
# CHECK: }
# CHECK: }
# CHECK: ]
@@ -48,7 +48,7 @@
# CHECK: PDBSignature: 0x53445352
# CHECK: PDBGUID: [[GUID]]
# CHECK: PDBAge: 2
-# CHECK: PDBFileName: {{.*}}.pdb
+# CHECK: PDBFileName: {{.*}}2.pdb
# CHECK: }
# CHECK: }
# CHECK: ]
diff --git a/test/COFF/safeseh-notable.s b/test/COFF/safeseh-notable.s
new file mode 100644
index 0000000..1f00cb2
--- /dev/null
+++ b/test/COFF/safeseh-notable.s
@@ -0,0 +1,43 @@
+# RUN: llvm-mc -triple i686-windows-msvc %s -filetype=obj -o %t.obj
+# RUN: lld-link %t.obj -safeseh -out:%t.exe -entry:main
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+# This object lacks a _load_config_used global, so we set
+# IMAGE_DLL_CHARACTERISTICS_NO_SEH even though there is an exception handler.
+# This is a more secure default. If someone wants to use a CRT without a load
+# config and they want to use 32-bit SEH, they will need to provide a
+# safeseh-compatible load config.
+
+# CHECK-LABEL: Characteristics [
+# CHECK: IMAGE_DLL_CHARACTERISTICS_NO_SEH
+# CHECK: ]
+
+# CHECK-LABEL: DataDirectory {
+# CHECK: LoadConfigTableRVA: 0x0
+# CHECK: LoadConfigTableSize: 0x0
+# CHECK: }
+
+# CHECK-NOT: LoadConfig
+# CHECK-NOT: SEHTable
+
+ .def @feat.00;
+ .scl 3;
+ .type 0;
+ .endef
+ .globl @feat.00
+@feat.00 = 1
+
+ .text
+ .def _main; .scl 2; .type 32; .endef
+ .globl _main
+_main:
+ pushl $_my_handler
+ movl $42, %eax
+ popl %ecx
+ ret
+
+ .def _my_handler; .scl 3; .type 32; .endef
+_my_handler:
+ ret
+
+.safeseh _my_handler
diff --git a/test/COFF/safeseh.s b/test/COFF/safeseh.s
index 35f54c5..efe20fb 100644
--- a/test/COFF/safeseh.s
+++ b/test/COFF/safeseh.s
@@ -1,27 +1,35 @@
# RUN: llvm-mc -triple i686-windows-msvc %s -filetype=obj -o %t.obj
# RUN: lld-link %t.obj -safeseh -out:%t.exe -opt:noref -entry:main
# RUN: llvm-readobj -coff-basereloc -coff-load-config -file-headers %t.exe | FileCheck %s --check-prefix=CHECK-NOGC
+# RUN: lld-link %t.obj -safeseh -out:%t.exe -opt:noref -entry:main -debug:dwarf
+# RUN: llvm-readobj -coff-basereloc -coff-load-config -file-headers %t.exe | FileCheck %s --check-prefix=CHECK-NOGC
# RUN: lld-link %t.obj -safeseh -out:%t.exe -opt:ref -entry:main
# RUN: llvm-readobj -coff-basereloc -coff-load-config -file-headers %t.exe | FileCheck %s --check-prefix=CHECK-GC
# __safe_se_handler_table needs to be relocated against ImageBase.
# check that the relocation is present.
+#
# CHECK-NOGC-NOT: IMAGE_DLL_CHARACTERISTICS_NO_SEH
# CHECK-NOGC: BaseReloc [
# CHECK-NOGC: Entry {
# CHECK-NOGC: Type: HIGHLOW
# CHECK-NOGC: LoadConfig [
# CHECK-NOGC: Size: 0x48
-# CHECK-NOGC: SEHandlerTable: 0x401048
+# CHECK-NOGC: SEHandlerTable: 0x
# CHECK-NOGC: SEHandlerCount: 1
# CHECK-NOGC: ]
# CHECK-NOGC: SEHTable [
-# CHECK-NOGC-NEXT: 0x402006
+# CHECK-NOGC-NEXT: 0x401006
# CHECK-NOGC-NEXT: ]
-# Without the SEH table, the address is absolute, so check that we do
-# not have a relocation for it.
-# CHECK-GC-NOT: IMAGE_DLL_CHARACTERISTICS_NO_SEH
+# If we enable GC, the exception handler should be removed, and we should add
+# the DLL characteristic flag that indicates that there are no exception
+# handlers in this DLL. The exception handler table in the load config should
+# be empty and there should be no relocations for it.
+#
+# CHECK-GC: Characteristics [
+# CHECK-GC: IMAGE_DLL_CHARACTERISTICS_NO_SEH
+# CHECK-GC: ]
# CHECK-GC: BaseReloc [
# CHECK-GC-NEXT: ]
# CHECK-GC: LoadConfig [
diff --git a/test/COFF/secidx-absolute.s b/test/COFF/secidx-absolute.s
index bfe7136..a62d2c7 100644
--- a/test/COFF/secidx-absolute.s
+++ b/test/COFF/secidx-absolute.s
@@ -16,18 +16,18 @@
# CHECK: Sections [
# CHECK: Section {
# CHECK: Number: 1
-# CHECK: Name: .rdata (2E 72 64 61 74 61 00 00)
-# CHECK: SectionData (
-# CHECK: 0000: 0300 |..|
-# CHECK: )
-# CHECK: }
-# CHECK: Section {
-# CHECK: Number: 2
# CHECK: Name: .text (2E 74 65 78 74 00 00 00)
# CHECK: VirtualSize: 0x1
# CHECK: SectionData (
# CHECK: 0000: C3 |.|
# CHECK: )
# CHECK: }
+# CHECK: Section {
+# CHECK: Number: 2
+# CHECK: Name: .rdata (2E 72 64 61 74 61 00 00)
+# CHECK: SectionData (
+# CHECK: 0000: 0300 |..|
+# CHECK: )
+# CHECK: }
# CHECK-NOT: Section
# CHECK: ]
diff --git a/test/COFF/secrel-common.s b/test/COFF/secrel-common.s
index 0188f6c..85cb10d 100644
--- a/test/COFF/secrel-common.s
+++ b/test/COFF/secrel-common.s
@@ -2,29 +2,30 @@
# RUN: lld-link -entry:main -nodefaultlib %t.obj -out:%t.exe
# RUN: llvm-readobj %t.exe -sections -section-data | FileCheck %s
-# Section relocations against common symbols resolve to .bss.
+# Section relocations against common symbols resolve to .bss (merged into .data).
# CHECK: Sections [
# CHECK: Section {
# CHECK: Number: 1
-# CHECK: Name: .bss (2E 62 73 73 00 00 00 00)
-# CHECK: VirtualSize: 0x4
-# CHECK: }
-# CHECK: Section {
-# CHECK: Number: 2
-# CHECK: Name: .rdata (2E 72 64 61 74 61 00 00)
-# CHECK: SectionData (
-# CHECK: 0000: 00000000 01000000 |........|
-# CHECK: )
-# CHECK: }
-# CHECK: Section {
-# CHECK: Number: 3
# CHECK: Name: .text (2E 74 65 78 74 00 00 00)
# CHECK: VirtualSize: 0x1
# CHECK: SectionData (
# CHECK: 0000: C3 |.|
# CHECK: )
# CHECK: }
+# CHECK: Section {
+# CHECK: Number: 2
+# CHECK: Name: .rdata (2E 72 64 61 74 61 00 00)
+# CHECK: SectionData (
+# CHECK: 0000: 00020000 03000000 |........|
+# CHECK: )
+# CHECK: }
+# CHECK: Section {
+# CHECK: Number: 3
+# CHECK: Name: .data (2E 64 61 74 61 00 00 00)
+# CHECK: VirtualSize: 0x204
+# CHECK: RawDataSize: 512
+# CHECK: }
# CHECK-NOT: Section
# CHECK: ]
@@ -39,3 +40,6 @@
.secrel32 common_global
.secidx common_global
.short 0
+
+.section .data,"drw"
+.zero 512
diff --git a/test/COFF/section-size.s b/test/COFF/section-size.s
index 28f3f4a..d971b6e 100644
--- a/test/COFF/section-size.s
+++ b/test/COFF/section-size.s
@@ -7,7 +7,7 @@
# Run: lld-link -entry:main %tmain.obj %t3.obj -out:%t.exe
# RUN: not lld-link -entry:main %tmain.obj %t1.obj %t2.obj -out:%t.exe 2>&1 | FileCheck %s
-# CHECK: error: section larger than 4 GiB: .bss
+# CHECK: error: section larger than 4 GiB: .data
.globl main
main:
diff --git a/test/COFF/section.test b/test/COFF/section.test
index 591c04d..5e1162e 100644
--- a/test/COFF/section.test
+++ b/test/COFF/section.test
@@ -16,18 +16,22 @@
# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=S %s
# R: Characteristics [
+# R-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
# R-NEXT: IMAGE_SCN_MEM_READ
# R-NEXT: ]
# W: Characteristics [
+# W-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
# W-NEXT: IMAGE_SCN_MEM_WRITE
# W-NEXT: ]
# E: Characteristics [
+# E-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
# E-NEXT: IMAGE_SCN_MEM_EXECUTE
# E-NEXT: ]
# S: Characteristics [
+# S-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
# S-NEXT: IMAGE_SCN_MEM_SHARED
# S-NEXT: ]
diff --git a/test/COFF/string-tail-merge.s b/test/COFF/string-tail-merge.s
index f55041f..2e3b735 100644
--- a/test/COFF/string-tail-merge.s
+++ b/test/COFF/string-tail-merge.s
@@ -2,29 +2,48 @@
# RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t.obj %s
# RUN: lld-link %t.obj /out:%t.exe /entry:main /subsystem:console
# RUN: llvm-objdump -s %t.exe | FileCheck %s
+# RUN: lld-link %t.obj /out:%t.exe /entry:main /subsystem:console /opt:noicf /opt:lldtailmerge
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+# RUN: lld-link %t.obj /out:%t.exe /entry:main /subsystem:console /opt:noicf
+# RUN: llvm-objdump -s %t.exe | FileCheck --check-prefix=NOSTM %s
+# RUN: lld-link %t.obj /out:%t.exe /entry:main /subsystem:console /opt:nolldtailmerge
+# RUN: llvm-objdump -s %t.exe | FileCheck --check-prefix=NOSTM %s
+
+# CHECK: Contents of section .text:
+# NOSTM: Contents of section .text:
+.globl main
+main:
+# CHECK-NEXT: 140001000 11200040 01000000 17200040 01000000
+# NOSTM-NEXT: 140001000 00200040 01000000 0c200040 01000000
+.8byte "??_C@_0M@LACCCNMM@hello?5world?$AA@"
+.8byte "??_C@_05MCBCHHEJ@world?$AA@"
+# CHECK-NEXT: 140001010 2a200040 01000000 36200040 01000000
+# NOSTM-NEXT: 140001010 12200040 01000000 2a200040 01000000
+.8byte "??_C@_1BI@HHJHKLLN@?$AAh?$AAe?$AAl?$AAl?$AAo?$AA?5?$AAw?$AAo?$AAr?$AAl?$AAd?$AA?$AA@"
+.8byte "??_C@_1M@NBBDDHIO@?$AAw?$AAo?$AAr?$AAl?$AAd?$AA?$AA@"
+# CHECK-NEXT: 140001020 00200040 01000000 0c200040 01000000
+# NOSTM-NEXT: 140001020 36200040 01000000 42200040 01000000
+.8byte "??_D@not_a_string_literal"
+.8byte "??_C@string_literal_with_relocs"
+# CHECK-NEXT: 140001030 00300040 01000000 1e200040 01000000
+# NOSTM-NEXT: 140001030 00300040 01000000 48200040 01000000
+.8byte "??_C@string_literal_in_wrong_section"
+.8byte "??_C@overaligned_string_literal"
# CHECK: Contents of section .rdata:
-# CHECK-NEXT: 140002000 68656c6c 6f20776f 726c6400 6fa26ca4 hello world.o.l.
+# CHECK-NEXT: 140002000 68656c6c 6f20776f 726c6400 6f826ca4 hello world.o.l.
# CHECK-NEXT: 140002010 0068656c 6c6f2077 6f726c64 00006865 .hello world..he
# CHECK-NEXT: 140002020 6c6c6f20 776f726c 64006800 65006c00 llo world.h.e.l.
# CHECK-NEXT: 140002030 6c006f00 20007700 6f007200 6c006400 l.o. .w.o.r.l.d.
# CHECK-NEXT: 140002040 0000 ..
-# CHECK: Contents of section .text:
-.globl main
-main:
-# CHECK-NEXT: 140003000 11200040 01000000 17200040 01000000
-.8byte "??_C@_0M@LACCCNMM@hello?5world?$AA@"
-.8byte "??_C@_05MCBCHHEJ@world?$AA@"
-# CHECK-NEXT: 140003010 2a200040 01000000 36200040 01000000
-.8byte "??_C@_1BI@HHJHKLLN@?$AAh?$AAe?$AAl?$AAl?$AAo?$AA?5?$AAw?$AAo?$AAr?$AAl?$AAd?$AA?$AA@"
-.8byte "??_C@_1M@NBBDDHIO@?$AAw?$AAo?$AAr?$AAl?$AAd?$AA?$AA@"
-# CHECK-NEXT: 140003020 00200040 01000000 0c200040 01000000
-.8byte "??_D@not_a_string_literal"
-.8byte "??_C@string_literal_with_relocs"
-# CHECK-NEXT: 140003030 00100040 01000000 1e200040 01000000
-.8byte "??_C@string_literal_in_wrong_section"
-.8byte "??_C@overaligned_string_literal"
+# NOSTM: Contents of section .rdata:
+# NOSTM-NEXT: 140002000 68656c6c 6f20776f 726c6400 776f726c hello world.worl
+# NOSTM-NEXT: 140002010 64006800 65006c00 6c006f00 20007700 d.h.e.l.l.o. .w.
+# NOSTM-NEXT: 140002020 6f007200 6c006400 00007700 6f007200 o.r.l.d...w.o.r.
+# NOSTM-NEXT: 140002030 6c006400 00006865 6c6c6f20 776f726c l.d...hello worl
+# NOSTM-NEXT: 140002040 64006f82 6ca40000 68656c6c 6f20776f d.o.l...hello wo
+# NOSTM-NEXT: 140002050 726c6400 rld.
.section .rdata,"dr",discard,"??_C@_0M@LACCCNMM@hello?5world?$AA@"
.globl "??_C@_0M@LACCCNMM@hello?5world?$AA@"
diff --git a/test/COFF/symtab.test b/test/COFF/symtab.test
index 4e46e33..49302d7 100644
--- a/test/COFF/symtab.test
+++ b/test/COFF/symtab.test
@@ -11,7 +11,7 @@
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: .text
# CHECK-NEXT: Value: 0
-# CHECK-NEXT: Section: .text (2)
+# CHECK-NEXT: Section: .text (1)
# CHECK-NEXT: BaseType: Null (0x0)
# CHECK-NEXT: ComplexType: Null (0x0)
# CHECK-NEXT: StorageClass: Static (0x3)
@@ -20,7 +20,7 @@
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: .text2
# CHECK-NEXT: Value: 0
-# CHECK-NEXT: Section: .text (2)
+# CHECK-NEXT: Section: .text (1)
# CHECK-NEXT: BaseType: Null (0x0)
# CHECK-NEXT: ComplexType: Null (0x0)
# CHECK-NEXT: StorageClass: Static (0x3)
@@ -29,7 +29,7 @@
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: .data
# CHECK-NEXT: Value: 0
-# CHECK-NEXT: Section: .data (1)
+# CHECK-NEXT: Section: .data (3)
# CHECK-NEXT: BaseType: Null (0x0)
# CHECK-NEXT: ComplexType: Null (0x0)
# CHECK-NEXT: StorageClass: Static (0x3)
@@ -38,7 +38,7 @@
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: MessageBoxA
# CHECK-NEXT: Value: 80
-# CHECK-NEXT: Section: .text (2)
+# CHECK-NEXT: Section: .text (1)
# CHECK-NEXT: BaseType: Null (0x0)
# CHECK-NEXT: ComplexType: Null (0x0)
# CHECK-NEXT: StorageClass: External (0x2)
@@ -47,7 +47,7 @@
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: ExitProcess
# CHECK-NEXT: Value: 64
-# CHECK-NEXT: Section: .text (2)
+# CHECK-NEXT: Section: .text (1)
# CHECK-NEXT: BaseType: Null (0x0)
# CHECK-NEXT: ComplexType: Null (0x0)
# CHECK-NEXT: StorageClass: External (0x2)
@@ -56,7 +56,7 @@
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: message
# CHECK-NEXT: Value: 6
-# CHECK-NEXT: Section: .text2 (3)
+# CHECK-NEXT: Section: .text2
# CHECK-NEXT: BaseType: Null (0x0)
# CHECK-NEXT: ComplexType: Null (0x0)
# CHECK-NEXT: StorageClass: Static (0x3)
@@ -65,7 +65,7 @@
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: main
# CHECK-NEXT: Value: 0
-# CHECK-NEXT: Section: .text (2)
+# CHECK-NEXT: Section: .text (1)
# CHECK-NEXT: BaseType: Null (0x0)
# CHECK-NEXT: ComplexType: Null (0x0)
# CHECK-NEXT: StorageClass: External (0x2)
@@ -74,7 +74,7 @@
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: caption
# CHECK-NEXT: Value: 0
-# CHECK-NEXT: Section: .text2 (3)
+# CHECK-NEXT: Section: .text2
# CHECK-NEXT: BaseType: Null (0x0)
# CHECK-NEXT: ComplexType: Null (0x0)
# CHECK-NEXT: StorageClass: Static (0x3)
diff --git a/test/COFF/timestamp.test b/test/COFF/timestamp.test
new file mode 100644
index 0000000..7e5f79f
--- /dev/null
+++ b/test/COFF/timestamp.test
@@ -0,0 +1,18 @@
+rm %t.*.exe
+RUN: yaml2obj %p/Inputs/generic.yaml > %t.obj
+RUN: lld-link %t.obj /debug /Brepro /entry:main /nodefaultlib /out:%t.1.exe
+RUN: lld-link %t.obj /debug /Brepro /entry:main /nodefaultlib /out:%t.2.exe
+RUN: lld-link %t.obj /debug /timestamp:0 /entry:main /nodefaultlib /out:%t.3.exe
+RUN: llvm-readobj -file-headers -coff-debug-directory %t.1.exe | FileCheck %s --check-prefix=HASH
+RUN: llvm-readobj -file-headers -coff-debug-directory %t.2.exe | FileCheck %s --check-prefix=HASH
+RUN: llvm-readobj -file-headers -coff-debug-directory %t.3.exe | FileCheck %s --check-prefix=ZERO
+
+HASH: ImageFileHeader {
+HASH: TimeDateStamp: [[STAMP:.*]]
+HASH: DebugDirectory [
+HASH: TimeDateStamp: [[STAMP]]
+
+ZERO: ImageFileHeader {
+ZERO: TimeDateStamp: 1970-01-01 00:00:00 (0x0)
+ZERO: DebugDirectory [
+ZERO: TimeDateStamp: 1970-01-01 00:00:00 (0x0)
diff --git a/test/COFF/undefined-symbol-cv.s b/test/COFF/undefined-symbol-cv.s
new file mode 100644
index 0000000..be57832
--- /dev/null
+++ b/test/COFF/undefined-symbol-cv.s
@@ -0,0 +1,61 @@
+# RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t.obj %s
+# RUN: not lld-link /out:%t.exe %t.obj 2>&1 | FileCheck %s
+
+# CHECK: error: undefined symbol: ?foo@@YAHXZ
+# CHECK-NEXT: >>> referenced by file1.cpp:1
+# CHECK-NEXT: >>> {{.*}}.obj:(main)
+# CHECK-NEXT: >>> referenced by file1.cpp:2
+# CHECK-NEXT: >>> {{.*}}.obj:(main)
+
+# CHECK: error: undefined symbol: ?bar@@YAHXZ
+# CHECK-NEXT: >>> referenced by file2.cpp:3
+# CHECK-NEXT: >>> {{.*}}.obj:(main)
+# CHECK-NEXT: >>> referenced by file1.cpp:4
+# CHECK-NEXT: >>> {{.*}}.obj:(f1)
+
+# CHECK: error: undefined symbol: ?baz@@YAHXZ
+# CHECK-NEXT: >>> referenced by file1.cpp:5
+# CHECK-NEXT: >>> {{.*}}.obj:(f2)
+
+ .cv_file 1 "file1.cpp" "EDA15C78BB573E49E685D8549286F33C" 1
+ .cv_file 2 "file2.cpp" "EDA15C78BB573E49E685D8549286F33D" 1
+
+ .section .text,"xr",one_only,main
+.globl main
+main:
+ .cv_func_id 0
+ .cv_loc 0 1 1 0 is_stmt 0
+ call "?foo@@YAHXZ"
+ .cv_loc 0 1 2 0
+ call "?foo@@YAHXZ"
+ .cv_loc 0 2 3 0
+ call "?bar@@YAHXZ"
+.Lfunc_end0:
+
+f1:
+ .cv_func_id 1
+ .cv_loc 1 1 4 0 is_stmt 0
+ call "?bar@@YAHXZ"
+.Lfunc_end1:
+
+ .section .text,"xr",one_only,f2
+.globl f2
+f2:
+ .cv_func_id 2
+ .cv_loc 2 1 5 0 is_stmt 0
+ call "?baz@@YAHXZ"
+.Lfunc_end2:
+
+ .section .debug$S,"dr",associative,main
+ .long 4
+ .cv_linetable 0, main, .Lfunc_end0
+ .cv_linetable 1, f1, .Lfunc_end1
+
+ .section .debug$S,"dr",associative,f2
+ .long 4
+ .cv_linetable 2, f2, .Lfunc_end2
+
+ .section .debug$S,"dr"
+ .long 4
+ .cv_filechecksums
+ .cv_stringtable
diff --git a/test/COFF/undefined-symbol.s b/test/COFF/undefined-symbol.s
new file mode 100644
index 0000000..ee146ad
--- /dev/null
+++ b/test/COFF/undefined-symbol.s
@@ -0,0 +1,29 @@
+# RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t.obj %s
+# RUN: not lld-link /out:%t.exe %t.obj 2>&1 | FileCheck %s
+
+# CHECK: error: undefined symbol: ?foo@@YAHXZ
+# CHECK-NEXT: >>> referenced by {{.*}}.obj:(main)
+# CHECK-NEXT: >>> referenced by {{.*}}.obj:(main)
+
+# CHECK: error: undefined symbol: ?bar@@YAHXZ
+# CHECK-NEXT: >>> referenced by {{.*}}.obj:(main)
+# CHECK-NEXT: >>> referenced by {{.*}}.obj:(f1)
+
+# CHECK: error: undefined symbol: ?baz@@YAHXZ
+# CHECK-NEXT: >>> referenced by {{.*}}.obj:(f2)
+
+ .section .text,"xr",one_only,main
+.globl main
+main:
+ call "?foo@@YAHXZ"
+ call "?foo@@YAHXZ"
+ call "?bar@@YAHXZ"
+
+f1:
+ call "?bar@@YAHXZ"
+.Lfunc_end1:
+
+ .section .text,"xr",one_only,f2
+.globl f2
+f2:
+ call "?baz@@YAHXZ"
diff --git a/test/COFF/unwind.test b/test/COFF/unwind.test
index 2415b05..5b74aa7 100644
--- a/test/COFF/unwind.test
+++ b/test/COFF/unwind.test
@@ -4,12 +4,24 @@
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=HEADER %s
# RUN: llvm-objdump -unwind-info %t.exe | FileCheck -check-prefix=UNWIND %s
#
-# HEADER: ExceptionTableRVA: 0x1000
+# RUN: lld-link /merge:.pdata=.rdata /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers -sections %t.exe | FileCheck -check-prefix=HEADER-MERGE %s
+#
+# HEADER: ExceptionTableRVA: 0x3000
+#
+# FIXME: llvm-readobj currently does not understand files with .pdata merged
+# into .rdata. But we can at least check that the section headers look correct.
+#
+# HEADER-MERGE: ExceptionTableRVA: 0x2004
+# HEADER-MERGE-NEXT: ExceptionTableSize: 0x30
+# HEADER-MERGE: Name: .rdata
+# HEADER-MERGE-NEXT: VirtualSize: 0x78
+# HEADER-MERGE-NEXT: VirtualAddress: 0x2000
#
# UNWIND: Function Table:
-# UNWIND: Start Address: 0x2000
-# UNWIND: End Address: 0x201b
-# UNWIND: Unwind Info Address: 0x3000
+# UNWIND: Start Address: 0x1000
+# UNWIND: End Address: 0x101b
+# UNWIND: Unwind Info Address: 0x2004
# UNWIND: Version: 1
# UNWIND: Flags: 1 UNW_ExceptionHandler
# UNWIND: Size of prolog: 18
@@ -24,27 +36,27 @@
# UNWIND: 0x04: UOP_AllocSmall 24
# UNWIND: 0x00: UOP_PushMachFrame w/o error code
# UNWIND: Function Table:
-# UNWIND: Start Address: 0x2012
-# UNWIND: End Address: 0x2012
-# UNWIND: Unwind Info Address: 0x301c
+# UNWIND: Start Address: 0x1012
+# UNWIND: End Address: 0x1012
+# UNWIND: Unwind Info Address: 0x2020
# UNWIND: Version: 1
# UNWIND: Flags: 4 UNW_ChainInfo
# UNWIND: Size of prolog: 0
# UNWIND: Number of Codes: 0
# UNWIND: No frame pointer used
# UNWIND: Function Table:
-# UNWIND: Start Address: 0x201b
-# UNWIND: End Address: 0x201c
-# UNWIND: Unwind Info Address: 0x302c
+# UNWIND: Start Address: 0x101b
+# UNWIND: End Address: 0x101c
+# UNWIND: Unwind Info Address: 0x2030
# UNWIND: Version: 1
# UNWIND: Flags: 0
# UNWIND: Size of prolog: 0
# UNWIND: Number of Codes: 0
# UNWIND: No frame pointer used
# UNWIND: Function Table:
-# UNWIND: Start Address: 0x201c
-# UNWIND: End Address: 0x2039
-# UNWIND: Unwind Info Address: 0x3034
+# UNWIND: Start Address: 0x101c
+# UNWIND: End Address: 0x1039
+# UNWIND: Unwind Info Address: 0x2038
# UNWIND: Version: 1
# UNWIND: Flags: 0
# UNWIND: Size of prolog: 14
@@ -122,6 +134,10 @@
- VirtualAddress: 44
SymbolName: .xdata
Type: IMAGE_REL_AMD64_ADDR32NB
+ - Name: .rdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 00000000
symbols:
- Name: .text
Value: 0
diff --git a/test/ELF/Inputs/mips-micro-gp0-non-zero.o b/test/ELF/Inputs/mips-micro-gp0-non-zero.o
new file mode 100644
index 0000000..abd67bc
--- /dev/null
+++ b/test/ELF/Inputs/mips-micro-gp0-non-zero.o
Binary files differ
diff --git a/test/ELF/Inputs/mips-n64-gp0-non-zero.o b/test/ELF/Inputs/mips-n64-gp0-non-zero.o
new file mode 100644
index 0000000..43b930b
--- /dev/null
+++ b/test/ELF/Inputs/mips-n64-gp0-non-zero.o
Binary files differ
diff --git a/test/ELF/Inputs/ppc64-func-global-entry.s b/test/ELF/Inputs/ppc64-func-global-entry.s
new file mode 100644
index 0000000..5987db6
--- /dev/null
+++ b/test/ELF/Inputs/ppc64-func-global-entry.s
@@ -0,0 +1,35 @@
+ .text
+ .abiversion 2
+ .globl foo_external_diff # -- Begin function foo_external_diff
+ .p2align 4
+ .type foo_external_diff,@function
+foo_external_diff: # @foo_external_diff
+.Lfunc_begin0:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry foo_external_diff, .Lfunc_lep0-.Lfunc_gep0
+# %bb.0: # %entry
+ addis 5, 2, .LC0@toc@ha
+ add 3, 4, 3
+ ld 5, .LC0@toc@l(5)
+ lwz 5, 0(5)
+ add 3, 3, 5
+ extsw 3, 3
+ blr
+ .long 0
+ .quad 0
+.Lfunc_end0:
+ .size foo_external_diff, .Lfunc_end0-.Lfunc_begin0
+ # -- End function
+ .section .toc,"aw",@progbits
+.LC0:
+ .tc glob2[TC],glob2
+ .type glob2,@object # @glob2
+ .data
+ .globl glob2
+ .p2align 2
+glob2:
+ .long 10 # 0xa
+ .size glob2, 4
diff --git a/test/ELF/Inputs/ppc64-func-local-entry.s b/test/ELF/Inputs/ppc64-func-local-entry.s
new file mode 100644
index 0000000..fc0a72d
--- /dev/null
+++ b/test/ELF/Inputs/ppc64-func-local-entry.s
@@ -0,0 +1,16 @@
+ .text
+ .abiversion 2
+ .globl foo_external_same # -- Begin function foo_external_same
+ .p2align 4
+ .type foo_external_same,@function
+foo_external_same: # @foo_external_same
+.Lfunc_begin0:
+# %bb.0: # %entry
+ add 3, 4, 3
+ extsw 3, 3
+ blr
+ .long 0
+ .quad 0
+.Lfunc_end0:
+ .size foo_external_same, .Lfunc_end0-.Lfunc_begin0
+ # -- End function
diff --git a/test/ELF/Inputs/ppc64-func.s b/test/ELF/Inputs/ppc64-func.s
new file mode 100644
index 0000000..745faf8
--- /dev/null
+++ b/test/ELF/Inputs/ppc64-func.s
@@ -0,0 +1,14 @@
+ .text
+ .abiversion 2
+ .globl foo_not_shared
+ .p2align 4
+ .type foo_not_shared,@function
+
+foo_not_shared:
+.Lfunc_begin0:
+ li 3, 55
+ blr
+ .long 0
+ .quad 0
+.Lfunc_end0:
+ .size foo_not_shared, .Lfunc_end0-.Lfunc_begin0
diff --git a/test/ELF/Inputs/ppc64-tls.s b/test/ELF/Inputs/ppc64-tls.s
new file mode 100644
index 0000000..11d1d12
--- /dev/null
+++ b/test/ELF/Inputs/ppc64-tls.s
@@ -0,0 +1,20 @@
+ .text
+ .abiversion 2
+ .type a,@object # @a
+ .type b,@object # @a
+ .type c,@object # @a
+ .section .tdata,"awT",@progbits
+ .globl a
+a:
+ .long 10 # 0xa
+ .size a, 4
+
+ .globl b
+b:
+ .long 10 # 0xa
+ .size b, 4
+
+ .globl c
+c:
+ .long 10 # 0xa
+ .size c, 4
diff --git a/test/ELF/Inputs/shared-ppc64.s b/test/ELF/Inputs/shared-ppc64.s
index b0117ac..0e1ecf7 100644
--- a/test/ELF/Inputs/shared-ppc64.s
+++ b/test/ELF/Inputs/shared-ppc64.s
@@ -1,9 +1,14 @@
-.section ".opd","aw"
-.global bar
-bar:
-.quad .Lbar,.TOC.@tocbase,0
-.quad .Lbar,0,0
+ .text
+ .abiversion 2
+ .globl foo
+ .p2align 4
+ .type foo,@function
-.text
-.Lbar:
- blr
+foo:
+.Lfunc_begin0:
+ li 3, 55
+ blr
+ .long 0
+ .quad 0
+.Lfunc_end0:
+ .size foo, .Lfunc_end0-.Lfunc_begin0
diff --git a/test/ELF/Inputs/undef-bad-debug.s b/test/ELF/Inputs/undef-bad-debug.s
index c887b28..e3e9f5e 100644
--- a/test/ELF/Inputs/undef-bad-debug.s
+++ b/test/ELF/Inputs/undef-bad-debug.s
@@ -1,7 +1,77 @@
.section .text,"ax"
sym:
.quad zed6
-
+sym2:
+ .quad zed7
+
+.section .debug_line,"",@progbits
+.Lunit:
+ .long .Lunit_end - .Lunit_start # unit length
+.Lunit_start:
+ .short 4 # version
+ .long .Lprologue_end - .Lprologue_start # prologue length
+.Lprologue_start:
+ .byte 1 # minimum instruction length
+ .byte 1 # maximum operatiosn per instruction
+ .byte 1 # default is_stmt
+ .byte -5 # line base
+ .byte 14 # line range
+ .byte 13 # opcode base
+ .byte 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 # standard opcode lengths
+ .asciz "dir" # include directories
+ .byte 0
+ .asciz "undef-bad-debug.s" # file names
+ .byte 1, 0, 0
+ .byte 0
+ .byte 0 # extraneous byte
+.Lprologue_end:
+ .byte 0, 9, 2 # DW_LNE_set_address
+ .quad sym
+ .byte 3 # DW_LNS_advance_line
+ .byte 10
+ .byte 1 # DW_LNS_copy
+ .byte 2 # DW_LNS_advance_pc
+ .byte 8
+ .byte 0, 1, 1 # DW_LNE_end_sequence
+.Lunit_end:
+
+.Lunit2:
+ .long .Lunit2_end - .Lunit2_start # unit length
+.Lunit2_start:
+ .short 4 # version
+ .long .Lprologue2_end - .Lprologue2_start # prologue length
+.Lprologue2_start:
+ .byte 1 # minimum instruction length
+ .byte 1 # maximum operatiosn per instruction
+ .byte 1 # default is_stmt
+ .byte -5 # line base
+ .byte 14 # line range
+ .byte 13 # opcode base
+ .byte 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 # standard opcode lengths
+ .asciz "dir2" # include directories
+ .byte 0
+ .asciz "undef-bad-debug2.s" # file names
+ .byte 1, 0, 0
+ .byte 0
+.Lprologue2_end:
+ .byte 0, 9, 2 # DW_LNE_set_address
+ .quad sym2
+ .byte 3 # DW_LNS_advance_line
+ .byte 10
+ .byte 1 # DW_LNS_copy
+ .byte 2 # DW_LNS_advance_pc
+ .byte 8
+ .byte 0, 1, 1 # DW_LNE_end_sequence
+ .byte 0, 9, 2 # DW_LNE_set_address
+ .quad 0x0badbeef
+ .byte 3 # DW_LNS_advance_line
+ .byte 99
+ .byte 1 # DW_LNS_copy
+ .byte 99 # DW_LNS_advance_pc
+ .byte 119
+ # Missing end of sequence.
+.Lunit2_end:
+
.section .debug_info,"",@progbits
.long .Lcu_end - .Lcu_start # Length of Unit
.Lcu_start:
@@ -9,6 +79,7 @@
.long .Lsection_abbrev # Offset Into Abbrev. Section
.byte 8 # Address Size (in bytes)
.byte 1 # Abbrev [1] 0xb:0x79 DW_TAG_compile_unit
+ .long .Lunit # DW_AT_stmt_list
.byte 2 # Abbrev [2] 0x2a:0x15 DW_TAG_variable
.long .Linfo_string # DW_AT_name
# DW_AT_external
@@ -17,11 +88,28 @@
.byte 0 # End Of Children Mark
.Lcu_end:
+ .long .Lcu2_end - .Lcu2_start # Length of Unit
+.Lcu2_start:
+ .short 4 # DWARF version number
+ .long .Lsection_abbrev # Offset Into Abbrev. Section
+ .byte 8 # Address Size (in bytes)
+ .byte 1 # Abbrev [1] 0xb:0x79 DW_TAG_compile_unit
+ .long .Lunit2 # DW_AT_stmt_list
+ .byte 2 # Abbrev [2] 0x2a:0x15 DW_TAG_variable
+ .long .Linfo2_string # DW_AT_name
+ # DW_AT_external
+ .byte 1 # DW_AT_decl_file
+ .byte 3 # DW_AT_decl_line
+ .byte 0 # End Of Children Mark
+.Lcu2_end:
+
.section .debug_abbrev,"",@progbits
.Lsection_abbrev:
.byte 1 # Abbreviation Code
.byte 17 # DW_TAG_compile_unit
.byte 1 # DW_CHILDREN_yes
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 2 # Abbreviation Code
@@ -42,3 +130,5 @@
.section .debug_str,"MS",@progbits,1
.Linfo_string:
.asciz "sym"
+.Linfo2_string:
+ .asciz "sym2"
diff --git a/test/ELF/Inputs/versiondef.s b/test/ELF/Inputs/versiondef.s
new file mode 100644
index 0000000..911cc14
--- /dev/null
+++ b/test/ELF/Inputs/versiondef.s
@@ -0,0 +1,9 @@
+.text
+.globl func_impl
+func_impl:
+ ret
+.globl func_impl2
+func_impl2:
+ ret
+.symver func_impl, func@@VER2
+.symver func_impl2, func@VER
diff --git a/test/ELF/Inputs/weak-and-strong-undef.s b/test/ELF/Inputs/weak-and-strong-undef.s
deleted file mode 100644
index a5e476d..0000000
--- a/test/ELF/Inputs/weak-and-strong-undef.s
+++ /dev/null
@@ -1 +0,0 @@
- .weak foo
diff --git a/test/ELF/aarch64-copy.s b/test/ELF/aarch64-copy.s
index ffecf2f..ffdb01b 100644
--- a/test/ELF/aarch64-copy.s
+++ b/test/ELF/aarch64-copy.s
@@ -1,7 +1,7 @@
// REQUIRES: aarch64
// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %s -o %t.o
// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %p/Inputs/relocation-copy.s -o %t2.o
-// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld -shared %t2.o -soname fixed-length-string.so -o %t2.so
// RUN: ld.lld %t.o %t2.so -o %t3
// RUN: llvm-readobj -s -r --expand-relocs -symbols %t3 | FileCheck %s
// RUN: llvm-objdump -d %t3 | FileCheck -check-prefix=CODE %s
@@ -90,4 +90,4 @@
// RODATA: Contents of section .rodata:
// S(z) = 0x40014
-// RODATA-NEXT: 101c8 14000400
+// RODATA-NEXT: 10246 14000400
diff --git a/test/ELF/aarch64-cortex-a53-843419-recognize.s b/test/ELF/aarch64-cortex-a53-843419-recognize.s
index be71c29..a9d0692 100644
--- a/test/ELF/aarch64-cortex-a53-843419-recognize.s
+++ b/test/ELF/aarch64-cortex-a53-843419-recognize.s
@@ -262,7 +262,7 @@
// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 3BFFC in unpatched output.
// CHECK: t3_ffc_st1singlepost:
// CHECK-NEXT: 3bffc: 37 01 00 b0 adrp x23, #151552
-// CHECK-NEXT: 3c000: 20 70 82 4c st1 { v0.16b }, [x1], x2
+// CHECK-NEXT: 3c000: 20 04 82 0d st1 { v0.b }[1], [x1], x2
// CHECK-FIX: 3c004: 1c 50 00 14 b #82032
// CHECK-NOFIX: 3c004: f6 06 40 f9 ldr x22, [x23, #8]
// CHECK-NEXT: 3c008: c0 03 5f d6 ret
@@ -273,7 +273,7 @@
.space 4096 - 4
t3_ffc_st1singlepost:
adrp x23, dat2
- st1 { v0.16b }, [x1], x2
+ st1 { v0.b }[1], [x1], x2
ldr x22, [x23, :lo12:dat2]
ret
@@ -438,7 +438,7 @@
// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 4DFFC in unpatched output.
// CHECK: t4_ffc_st1:
// CHECK-NEXT: 4dffc: 98 00 00 f0 adrp x24, #77824
-// CHECK-NEXT: 4e000: 20 70 00 4c st1 { v0.16b }, [x1]
+// CHECK-NEXT: 4e000: 20 80 00 4d st1 { v0.s }[2], [x1]
// CHECK-NEXT: 4e004: f6 06 40 f9 ldr x22, [x23, #8]
// CHECK-FIX: 4e008: 2d 08 00 14 b #8372
// CHECK-NOFIX: 4e008: 18 ff 3f f9 str x24, [x24, #32760]
@@ -450,7 +450,7 @@
.space 4096 - 4
t4_ffc_st1:
adrp x24, dat2
- st1 { v0.16b }, [x1]
+ st1 { v0.s }[2], [x1]
ldr x22, [x23, :got_lo12:dat2]
str x24, [x24, #32760]
ret
diff --git a/test/ELF/aarch64-thunk-pi.s b/test/ELF/aarch64-thunk-pi.s
index 91e2b7f..ddd5897 100644
--- a/test/ELF/aarch64-thunk-pi.s
+++ b/test/ELF/aarch64-thunk-pi.s
@@ -33,13 +33,13 @@
// Expect range extension thunks for .text_low
// adrp calculation is (PC + signed immediate) & (!0xfff)
// CHECK: __AArch64ADRPThunk_high_target:
-// CHECK-NEXT: 10: 10 00 08 90 adrp x16, #268435456
-// CHECK-NEXT: 14: 10 82 04 91 add x16, x16, #288
-// CHECK-NEXT: 18: 00 02 1f d6 br x16
+// CHECK-NEXT: 70: 10 00 08 90 adrp x16, #268435456
+// CHECK-NEXT: 74: 10 02 03 91 add x16, x16, #192
+// CHECK-NEXT: 78: 00 02 1f d6 br x16
// CHECK: __AArch64ADRPThunk_high_target2:
-// CHECK-NEXT: 1c: 10 00 08 90 adrp x16, #268435456
-// CHECK-NEXT: 20: 10 22 00 91 add x16, x16, #8
-// CHECK-NEXT: 24: 00 02 1f d6 br x16
+// CHECK-NEXT: 7c: 10 00 08 90 adrp x16, #268435456
+// CHECK-NEXT: 80: 10 22 00 91 add x16, x16, #8
+// CHECK-NEXT: 84: 00 02 1f d6 br x16
.section .text_high, "ax", %progbits
@@ -50,7 +50,7 @@
bl low_target
ret
// CHECK: high_target:
-// CHECK-NEXT: 10000000: 4c 00 00 94 bl #304
+// CHECK-NEXT: 10000000: 34 00 00 94 bl #208
// CHECK-NEXT: 10000004: c0 03 5f d6 ret
.hidden high_target2
@@ -68,24 +68,24 @@
// CHECK: __AArch64ADRPThunk_low_target2:
// CHECK-NEXT: 10000010: 10 00 f8 90 adrp x16, #-268435456
-// CHECK-NEXT: 10000014: 10 22 00 91 add x16, x16, #8
+// CHECK-NEXT: 10000014: 10 a2 01 91 add x16, x16, #104
// CHECK-NEXT: 10000018: 00 02 1f d6 br x16
// CHECK: Disassembly of section .plt:
// CHECK-NEXT: .plt:
-// CHECK-NEXT: 10000100: f0 7b bf a9 stp x16, x30, [sp, #-16]!
-// CHECK-NEXT: 10000104: 10 00 00 90 adrp x16, #0
-// CHECK-NEXT: 10000108: 11 aa 40 f9 ldr x17, [x16, #336]
-// CHECK-NEXT: 1000010c: 10 42 05 91 add x16, x16, #336
-// CHECK-NEXT: 10000110: 20 02 1f d6 br x17
-// CHECK-NEXT: 10000114: 1f 20 03 d5 nop
-// CHECK-NEXT: 10000118: 1f 20 03 d5 nop
-// CHECK-NEXT: 1000011c: 1f 20 03 d5 nop
-// CHECK-NEXT: 10000120: 10 00 00 90 adrp x16, #0
-// CHECK-NEXT: 10000124: 11 ae 40 f9 ldr x17, [x16, #344]
-// CHECK-NEXT: 10000128: 10 62 05 91 add x16, x16, #344
-// CHECK-NEXT: 1000012c: 20 02 1f d6 br x17
-// CHECK-NEXT: 10000130: 10 00 00 90 adrp x16, #0
-// CHECK-NEXT: 10000134: 11 b2 40 f9 ldr x17, [x16, #352]
-// CHECK-NEXT: 10000138: 10 82 05 91 add x16, x16, #352
-// CHECK-NEXT: 1000013c: 20 02 1f d6 br x17
+// CHECK-NEXT: 100000a0: f0 7b bf a9 stp x16, x30, [sp, #-16]!
+// CHECK-NEXT: 100000a4: 10 00 00 90 adrp x16, #0
+// CHECK-NEXT: 100000a8: 11 7a 40 f9 ldr x17, [x16, #240]
+// CHECK-NEXT: 100000ac: 10 c2 03 91 add x16, x16, #240
+// CHECK-NEXT: 100000b0: 20 02 1f d6 br x17
+// CHECK-NEXT: 100000b4: 1f 20 03 d5 nop
+// CHECK-NEXT: 100000b8: 1f 20 03 d5 nop
+// CHECK-NEXT: 100000bc: 1f 20 03 d5 nop
+// CHECK-NEXT: 100000c0: 10 00 00 90 adrp x16, #0
+// CHECK-NEXT: 100000c4: 11 7e 40 f9 ldr x17, [x16, #248]
+// CHECK-NEXT: 100000c8: 10 e2 03 91 add x16, x16, #248
+// CHECK-NEXT: 100000cc: 20 02 1f d6 br x17
+// CHECK-NEXT: 100000d0: 10 00 00 90 adrp x16, #0
+// CHECK-NEXT: 100000d4: 11 82 40 f9 ldr x17, [x16, #256]
+// CHECK-NEXT: 100000d8: 10 02 04 91 add x16, x16, #256
+// CHECK-NEXT: 100000dc: 20 02 1f d6 br x17
diff --git a/test/ELF/aarch64-tlsld-ldst.s b/test/ELF/aarch64-tlsld-ldst.s
new file mode 100644
index 0000000..7b9798c
--- /dev/null
+++ b/test/ELF/aarch64-tlsld-ldst.s
@@ -0,0 +1,85 @@
+// RUN: llvm-mc -triple=aarch64-linux-gnu -filetype=obj %s -o %t.o
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-objdump -d %t | FileCheck %s
+// RUN: llvm-readelf --symbols %t | FileCheck -check-prefix CHECK-SYMS %s
+// REQUIRES: aarch64
+
+ .text
+ .globl _start
+ .type _start, %function
+_start: mrs x8, TPIDR_EL0
+
+ add x8, x8, :tprel_hi12:var0
+ ldr q20, [x8, :tprel_lo12_nc:var0]
+
+ add x8, x8, :tprel_hi12:var1
+ ldr x0, [x8, :tprel_lo12_nc:var1]
+
+ add x8, x8, :tprel_hi12:var2
+ ldr w0, [x8, :tprel_lo12_nc:var2]
+
+ add x8, x8, :tprel_hi12:var3
+ ldrh w0, [x8, :tprel_lo12_nc:var3]
+
+ add x8, x8, :tprel_hi12:var4
+ ldrb w0, [x8, :tprel_lo12_nc:var4]
+
+// CHECK: _start:
+// CHECK-NEXT: 20000: 48 d0 3b d5 mrs x8, TPIDR_EL0
+// 0x0 + c10 = 0xc10 = tcb (16-bytes) + var0
+// CHECK-NEXT: 20004: 08 01 40 91 add x8, x8, #0, lsl #12
+// CHECK-NEXT: 20008: 14 05 c3 3d ldr q20, [x8, #3088]
+// 0x1000 + 0x820 = 0x1820 = tcb + var1
+// CHECK-NEXT: 2000c: 08 05 40 91 add x8, x8, #1, lsl #12
+// CHECK-NEXT: 20010: 00 11 44 f9 ldr x0, [x8, #2080]
+// 0x2000 + 0x428 = 0x2428 = tcb + var2
+// CHECK-NEXT: 20014: 08 09 40 91 add x8, x8, #2, lsl #12
+// CHECK-NEXT: 20018: 00 29 44 b9 ldr w0, [x8, #1064]
+// 0x3000 + 0x2c = 0x302c = tcb + var3
+// CHECK-NEXT: 2001c: 08 0d 40 91 add x8, x8, #3, lsl #12
+// CHECK-NEXT: 20020: 00 59 40 79 ldrh w0, [x8, #44]
+// 0x3000 + 0xc2e = 0x32ce = tcb + var4
+// CHECK-NEXT: 20024: 08 0d 40 91 add x8, x8, #3, lsl #12
+// CHECK-NEXT: 20028: 00 b9 70 39 ldrb w0, [x8, #3118]
+
+// CHECK-SYMS: 0000000000000c00 0 TLS GLOBAL DEFAULT 2 var0
+// CHECK-SYMS-NEXT: 0000000000001810 4 TLS GLOBAL DEFAULT 2 var1
+// CHECK-SYMS-NEXT: 0000000000002418 2 TLS GLOBAL DEFAULT 2 var2
+// CHECK-SYMS-NEXT: 000000000000301c 1 TLS GLOBAL DEFAULT 2 var3
+// CHECK-SYMS-NEXT: 0000000000003c1e 0 TLS GLOBAL DEFAULT 2 var4
+
+ .globl var0
+ .globl var1
+ .globl var2
+ .globl var3
+ .globl var4
+ .type var0,@object
+ .type var1,@object
+ .type var2,@object
+ .type var3,@object
+
+.section .tbss,"awT",@nobits
+ .balign 16
+ .space 1024 * 3
+var0:
+ .quad 0
+ .quad 0
+ .size var1, 16
+ .space 1024 * 3
+var1:
+ .quad 0
+ .size var1, 8
+ .space 1024 * 3
+var2:
+ .word 0
+ .size var1, 4
+
+ .space 1024 * 3
+var3:
+ .hword 0
+ .size var2, 2
+ .space 1024 * 3
+var4:
+ .byte 0
+ .size var3, 1
+ .space 1024 * 3
diff --git a/test/ELF/arm-copy.s b/test/ELF/arm-copy.s
index dc9e362..6e304b6 100644
--- a/test/ELF/arm-copy.s
+++ b/test/ELF/arm-copy.s
@@ -1,7 +1,7 @@
// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/relocation-copy-arm.s -o %t2.o
-// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld -shared %t2.o -soname fixed-length-string.so -o %t2.so
// RUN: ld.lld --hash-style=sysv %t.o %t2.so -o %t3
// RUN: llvm-readobj -s -r --expand-relocs -symbols %t3 | FileCheck %s
// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t3 | FileCheck -check-prefix=CODE %s
@@ -78,4 +78,4 @@
// RODATA: Contents of section .rodata:
// S(z) = 0x13004
-// RODATA-NEXT: 10114 04300100
+// RODATA-NEXT: 10160 04300100
diff --git a/test/ELF/arm-execute-only.s b/test/ELF/arm-execute-only.s
index 655a2c6..b278e07 100644
--- a/test/ELF/arm-execute-only.s
+++ b/test/ELF/arm-execute-only.s
@@ -14,24 +14,24 @@
// RUN: llvm-readelf -l %t.so | FileCheck --check-prefix=DIFF %s
// CHECK-NOT: LOAD
-// CHECK: LOAD 0x000000 0x00000000 0x00000000 0x0016d 0x0016d R 0x1000
+// CHECK: LOAD 0x000000 0x00000000 0x00000000 0x00170 0x00170 R 0x1000
// CHECK: LOAD 0x001000 0x00001000 0x00001000 0x{{.*}} 0x{{.*}} R E 0x1000
// CHECK: LOAD 0x002000 0x00002000 0x00002000 0x{{.*}} 0x{{.*}} E 0x1000
// CHECK: LOAD 0x003000 0x00003000 0x00003000 0x00038 0x00038 RW 0x1000
// CHECK-NOT: LOAD
-// CHECK: 01 .dynsym .gnu.hash .hash .dynstr
+// CHECK: 01 .dynsym .dynstr .gnu.hash .hash
// CHECK: 02 .text
// CHECK: 03 .foo
// CHECK: 04 .dynamic
// DIFF-NOT: LOAD
-// DIFF: LOAD 0x000000 0x00000000 0x00000000 0x0014d 0x0014d R 0x1000
+// DIFF: LOAD 0x000000 0x00000000 0x00000000 0x00150 0x00150 R 0x1000
// DIFF: LOAD 0x001000 0x00001000 0x00001000 0x0000c 0x0000c R E 0x1000
// DIFF: LOAD 0x002000 0x00002000 0x00002000 0x00038 0x00038 RW 0x1000
// DIFF-NOT: LOAD
-// DIFF: 01 .dynsym .gnu.hash .hash .dynstr
+// DIFF: 01 .dynsym .dynstr .gnu.hash .hash
// DIFF: 02 .text .foo
// DIFF: 03 .dynamic
diff --git a/test/ELF/arm-exidx-shared.s b/test/ELF/arm-exidx-shared.s
index bf7c2dc..bcf2955 100644
--- a/test/ELF/arm-exidx-shared.s
+++ b/test/ELF/arm-exidx-shared.s
@@ -41,5 +41,5 @@
// CHECK-NEXT: 0x200C R_ARM_JUMP_SLOT __gxx_personality_v0
// CHECK-EXTAB: Contents of section .ARM.extab:
-// 014c + 0ee4 = 0x1030 = __gxx_personality_v0(PLT)
-// CHECK-EXTAB-NEXT: 014c e40e0000 b0b0b000 00000000
+// 01d8 + 0e58 = 0x1030 = __gxx_personality_v0(PLT)
+// CHECK-EXTAB-NEXT: 01d8 580e0000 b0b0b000 00000000
diff --git a/test/ELF/arm-symbol-ordering-file.s b/test/ELF/arm-symbol-ordering-file.s
new file mode 100644
index 0000000..fe3de0d
--- /dev/null
+++ b/test/ELF/arm-symbol-ordering-file.s
@@ -0,0 +1,32 @@
+# REQUIRES: arm
+# RUN: llvm-mc -filetype=obj -triple=armv7-unknown-linux %s -o %t.o
+
+# RUN: echo ordered > %t_order.txt
+# RUN: ld.lld --symbol-ordering-file %t_order.txt %t.o -o %t2.out
+# RUN: llvm-nm -n %t2.out | FileCheck %s
+
+# CHECK: unordered1
+# CHECK-NEXT: unordered2
+# CHECK-NEXT: unordered3
+# CHECK-NEXT: ordered
+# CHECK-NEXT: unordered4
+
+.section .foo,"ax",%progbits,unique,1
+unordered1:
+.zero 1
+
+.section .foo,"ax",%progbits,unique,2
+unordered2:
+.zero 1
+
+.section .foo,"ax",%progbits,unique,3
+unordered3:
+.zero 2
+
+.section .foo,"ax",%progbits,unique,4
+unordered4:
+.zero 4
+
+.section .foo,"ax",%progbits,unique,5
+ordered:
+.zero 1
diff --git a/test/ELF/arm-thunk-nosuitable.s b/test/ELF/arm-thunk-nosuitable.s
new file mode 100644
index 0000000..1fac4a5
--- /dev/null
+++ b/test/ELF/arm-thunk-nosuitable.s
@@ -0,0 +1,33 @@
+// RUN: llvm-mc %s --arm-add-build-attributes --triple=armv7a-linux-gnueabihf --filetype=obj -o %t.o
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-objdump -triple=thumbv7a-linux-gnueabihf -d -start-address=2166784 -stop-address=2166794 %t | FileCheck %s
+// REQUIRES: ARM
+
+ // Create a conditional branch too far away from a precreated thunk
+ // section. This will need a thunk section created within range.
+ .syntax unified
+ .thumb
+
+ .section .text.0, "ax", %progbits
+ .space 2 * 1024 * 1024
+ .globl _start
+ .type _start, %function
+_start:
+ // Range of +/- 1 Megabyte, new ThunkSection will need creating after
+ // .text.1
+ beq.w target
+ .section .text.1, "ax", %progbits
+ bx lr
+
+// CHECK: _start:
+// CHECK-NEXT: 211000: 00 f0 00 80 beq.w #0
+// CHECK: __Thumbv7ABSLongThunk_target:
+// CHECK-NEXT: 211004: 00 f0 01 90 b.w #12582914
+// CHECK: $t.1:
+// CHECK-NEXT: 211008: 70 47 bx lr
+
+ .section .text.2, "ax", %progbits
+ .space 12 * 1024 * 1024
+ .globl target
+ .type target, %function
+target: bx lr
diff --git a/test/ELF/arm-thunk-section-too-large.s b/test/ELF/arm-thunk-section-too-large.s
new file mode 100644
index 0000000..2b2d0d3
--- /dev/null
+++ b/test/ELF/arm-thunk-section-too-large.s
@@ -0,0 +1,21 @@
+// RUN: llvm-mc %s -triple=armv7a-linux-gnueabihf -arm-add-build-attributes -filetype=obj -o %t.o
+// RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
+// REQUIRES: ARM
+
+// CHECK: InputSection too large for range extension thunk
+ .syntax unified
+ .thumb
+ .text
+ .globl _start
+ .type _start, %function
+_start:
+ .space 2 * 1024 * 1024
+ // conditional branch has range of 1 Mb expect error as we can't place
+ // a thunk in range of the branch.
+ beq target
+ .space 2 * 1024 * 1024
+
+ .section .text.2, "ax", %progbits
+ .globl target
+ .type target, %function
+target: bx lr
diff --git a/test/ELF/as-needed-weak.s b/test/ELF/as-needed-weak.s
new file mode 100644
index 0000000..f009c72
--- /dev/null
+++ b/test/ELF/as-needed-weak.s
@@ -0,0 +1,22 @@
+# REQUIRES: x86
+
+# RUN: echo '.globl foo; .type foo, @function; foo:' | \
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t1.o
+# RUN: ld.lld -shared -o %t1.so -soname libfoo %t1.o
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2.o
+# RUN: ld.lld -o %t.exe %t2.o --as-needed %t1.so
+# RUN: llvm-readelf -dynamic-table -dyn-symbols %t.exe | FileCheck %s
+
+# CHECK-NOT: libfoo
+
+# CHECK: Symbol table of .hash for image:
+# CHECK-NEXT: Num Buc: Value Size Type Bind Vis Ndx Name
+# CHECK-NEXT: 1 1: 0000000000000000 0 FUNC WEAK DEFAULT UND foo@
+
+.globl _start
+.weak foo
+
+_start:
+ mov $foo, %eax
+ callq foo
diff --git a/test/ELF/basic-ppc.s b/test/ELF/basic-ppc.s
index cda3224..2e52514 100644
--- a/test/ELF/basic-ppc.s
+++ b/test/ELF/basic-ppc.s
@@ -65,7 +65,7 @@
// CHECK-NEXT: Address: 0x114
// CHECK-NEXT: Offset: 0x114
// CHECK-NEXT: Size: 16
-// CHECK-NEXT: Link: 3
+// CHECK-NEXT: Link: 2
// CHECK-NEXT: Info: 1
// CHECK-NEXT: AddressAlignment: 4
// CHECK-NEXT: EntrySize: 16
@@ -75,31 +75,13 @@
// CHECK-NEXT: }
// CHECK-NEXT: Section {
// CHECK-NEXT: Index: 2
-// CHECK-NEXT: Name: .hash
-// CHECK-NEXT: Type: SHT_HASH (0x5)
-// CHECK-NEXT: Flags [ (0x2)
-// CHECK-NEXT: SHF_ALLOC (0x2)
-// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x124
-// CHECK-NEXT: Offset: 0x124
-// CHECK-NEXT: Size: 16
-// CHECK-NEXT: Link: 1
-// CHECK-NEXT: Info: 0
-// CHECK-NEXT: AddressAlignment: 4
-// CHECK-NEXT: EntrySize: 4
-// CHECK-NEXT: SectionData (
-// CHECK-NEXT: 0000: 00000001 00000001 00000000 00000000 |................|
-// CHECK-NEXT: )
-// CHECK-NEXT: }
-// CHECK-NEXT: Section {
-// CHECK-NEXT: Index: 3
// CHECK-NEXT: Name: .dynstr
// CHECK-NEXT: Type: SHT_STRTAB (0x3)
// CHECK-NEXT: Flags [ (0x2)
// CHECK-NEXT: SHF_ALLOC (0x2)
// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x134
-// CHECK-NEXT: Offset: 0x134
+// CHECK-NEXT: Address: 0x124
+// CHECK-NEXT: Offset: 0x124
// CHECK-NEXT: Size: 1
// CHECK-NEXT: Link: 0
// CHECK-NEXT: Info: 0
@@ -110,6 +92,24 @@
// CHECK-NEXT: )
// CHECK-NEXT: }
// CHECK-NEXT: Section {
+// CHECK-NEXT: Index: 3
+// CHECK-NEXT: Name: .hash
+// CHECK-NEXT: Type: SHT_HASH (0x5)
+// CHECK-NEXT: Flags [ (0x2)
+// CHECK-NEXT: SHF_ALLOC (0x2)
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x128
+// CHECK-NEXT: Offset: 0x128
+// CHECK-NEXT: Size: 16
+// CHECK-NEXT: Link: 1
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 4
+// CHECK-NEXT: EntrySize: 4
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT: 0000: 00000001 00000001 00000000 00000000 |................|
+// CHECK-NEXT: )
+// CHECK-NEXT: }
+// CHECK-NEXT: Section {
// CHECK-NEXT: Index: 4
// CHECK-NEXT: Name: .text
// CHECK-NEXT: Type: SHT_PROGBITS (0x1)
@@ -139,14 +139,14 @@
// CHECK-NEXT: Address: 0x2000
// CHECK-NEXT: Offset: 0x2000
// CHECK-NEXT: Size: 48
-// CHECK-NEXT: Link: 3
+// CHECK-NEXT: Link: 2
// CHECK-NEXT: Info: 0
// CHECK-NEXT: AddressAlignment: 4
// CHECK-NEXT: EntrySize: 8
// CHECK-NEXT: SectionData (
// CHECK-NEXT: 0000: 00000006 00000114 0000000B 00000010 |................|
-// CHECK-NEXT: 0010: 00000005 00000134 0000000A 00000001 |.......4........|
-// CHECK-NEXT: 0020: 00000004 00000124 00000000 00000000 |.......$........|
+// CHECK-NEXT: 0010: 00000005 00000124 0000000A 00000001 |.......$........|
+// CHECK-NEXT: 0020: 00000004 00000128 00000000 00000000 |.......(........|
// CHECK-NEXT: )
// CHECK-NEXT: }
// CHECK-NEXT: Section {
@@ -165,7 +165,7 @@
// CHECK-NEXT: AddressAlignment: 1
// CHECK-NEXT: EntrySize: 1
// CHECK-NEXT: SectionData (
-// CHECK-NEXT: 0000: 4C4C4420 312E3000 |LLD 1.0.|
+// CHECK-NEXT: 0000: 4C4C4420 312E3000 |LLD 1.0.|
// CHECK-NEXT: )
// CHECK-NEXT: }
// CHECK-NEXT: Section {
@@ -200,8 +200,8 @@
// CHECK-NEXT: AddressAlignment: 1
// CHECK-NEXT: EntrySize: 0
// CHECK-NEXT: SectionData (
-// CHECK-NEXT: 0000: 002E6479 6E73796D 002E6861 7368002E |..dynsym..hash..|
-// CHECK-NEXT: 0010: 64796E73 7472002E 74657874 002E6479 |dynstr..text..dy|
+// CHECK-NEXT: 0000: 002E6479 6E73796D 002E6479 6E737472 |..dynsym..dynstr|
+// CHECK-NEXT: 0010: 002E6861 7368002E 74657874 002E6479 |..hash..text..dy|
// CHECK-NEXT: 0020: 6E616D69 63002E63 6F6D6D65 6E74002E |namic..comment..|
// CHECK-NEXT: 0030: 73796D74 6162002E 73687374 72746162 |symtab..shstrtab|
// CHECK-NEXT: 0040: 002E7374 72746162 00 |..strtab.|
@@ -215,7 +215,7 @@
// CHECK-NEXT: ]
// CHECK-NEXT: Address: 0x0
// CHECK-NEXT: Offset: 0x20A1
-// CHECK-NEXT: Size: 1
+// CHECK-NEXT: Size: 10
// CHECK-NEXT: Link: 0
// CHECK-NEXT: Info: 0
// CHECK-NEXT: AddressAlignment: 1
@@ -243,8 +243,8 @@
// CHECK-NEXT: Offset: 0x0
// CHECK-NEXT: VirtualAddress: 0x0
// CHECK-NEXT: PhysicalAddress: 0x0
-// CHECK-NEXT: FileSize: 309
-// CHECK-NEXT: MemSize: 309
+// CHECK-NEXT: FileSize: 312
+// CHECK-NEXT: MemSize: 312
// CHECK-NEXT: Flags [ (0x4)
// CHECK-NEXT: PF_R (0x4)
// CHECK-NEXT: ]
diff --git a/test/ELF/basic-ppc64.s b/test/ELF/basic-ppc64.s
index 5b9896d..fd933b8 100644
--- a/test/ELF/basic-ppc64.s
+++ b/test/ELF/basic-ppc64.s
@@ -66,7 +66,7 @@
// CHECK-NEXT: Address: 0x1C8
// CHECK-NEXT: Offset: 0x1C8
// CHECK-NEXT: Size: 24
-// CHECK-NEXT: Link: 3
+// CHECK-NEXT: Link: 2
// CHECK-NEXT: Info: 1
// CHECK-NEXT: AddressAlignment: 8
// CHECK-NEXT: EntrySize: 24
@@ -77,31 +77,13 @@
// CHECK-NEXT: }
// CHECK-NEXT: Section {
// CHECK-NEXT: Index: 2
-// CHECK-NEXT: Name: .hash (9)
-// CHECK-NEXT: Type: SHT_HASH (0x5)
+// CHECK-NEXT: Name: .dynstr (9)
+// CHECK-NEXT: Type: SHT_STRTAB (0x3)
// CHECK-NEXT: Flags [ (0x2)
// CHECK-NEXT: SHF_ALLOC (0x2)
// CHECK-NEXT: ]
// CHECK-NEXT: Address: 0x1E0
// CHECK-NEXT: Offset: 0x1E0
-// CHECK-NEXT: Size: 16
-// CHECK-NEXT: Link: 1
-// CHECK-NEXT: Info: 0
-// CHECK-NEXT: AddressAlignment: 4
-// CHECK-NEXT: EntrySize: 4
-// CHECK-NEXT: SectionData (
-// CHECK-NEXT: 0000: 01000000 01000000 00000000 00000000 |................|
-// CHECK-NEXT: )
-// CHECK-NEXT: }
-// CHECK-NEXT: Section {
-// CHECK-NEXT: Index: 3
-// CHECK-NEXT: Name: .dynstr (15)
-// CHECK-NEXT: Type: SHT_STRTAB (0x3)
-// CHECK-NEXT: Flags [ (0x2)
-// CHECK-NEXT: SHF_ALLOC (0x2)
-// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x1F0
-// CHECK-NEXT: Offset: 0x1F0
// CHECK-NEXT: Size: 1
// CHECK-NEXT: Link: 0
// CHECK-NEXT: Info: 0
@@ -112,6 +94,24 @@
// CHECK-NEXT: )
// CHECK-NEXT: }
// CHECK-NEXT: Section {
+// CHECK-NEXT: Index: 3
+// CHECK-NEXT: Name: .hash (17)
+// CHECK-NEXT: Type: SHT_HASH (0x5)
+// CHECK-NEXT: Flags [ (0x2)
+// CHECK-NEXT: SHF_ALLOC (0x2)
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1E4
+// CHECK-NEXT: Offset: 0x1E4
+// CHECK-NEXT: Size: 16
+// CHECK-NEXT: Link: 1
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 4
+// CHECK-NEXT: EntrySize: 4
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT: 0000: 01000000 01000000 00000000 00000000 |................|
+// CHECK-NEXT: )
+// CHECK-NEXT: }
+// CHECK-NEXT: Section {
// CHECK-NEXT: Index: 4
// CHECK-NEXT: Name: .text (23)
// CHECK-NEXT: Type: SHT_PROGBITS (0x1)
@@ -141,16 +141,16 @@
// CHECK-NEXT: Address: 0x20000
// CHECK-NEXT: Offset: 0x20000
// CHECK-NEXT: Size: 96
-// CHECK-NEXT: Link: 3
+// CHECK-NEXT: Link: 2
// CHECK-NEXT: Info: 0
// CHECK-NEXT: AddressAlignment: 8
// CHECK-NEXT: EntrySize: 16
// CHECK-NEXT: SectionData (
// CHECK-NEXT: 0000: 06000000 00000000 C8010000 00000000 |................|
// CHECK-NEXT: 0010: 0B000000 00000000 18000000 00000000 |................|
-// CHECK-NEXT: 0020: 05000000 00000000 F0010000 00000000 |................|
+// CHECK-NEXT: 0020: 05000000 00000000 E0010000 00000000 |................|
// CHECK-NEXT: 0030: 0A000000 00000000 01000000 00000000 |................|
-// CHECK-NEXT: 0040: 04000000 00000000 E0010000 00000000 |................|
+// CHECK-NEXT: 0040: 04000000 00000000 E4010000 00000000 |................|
// CHECK-NEXT: 0050: 00000000 00000000 00000000 00000000 |................|
// CHECK-NEXT: )
// CHECK-NEXT: }
@@ -170,7 +170,7 @@
// CHECK-NEXT: AddressAlignment: 1
// CHECK-NEXT: EntrySize: 1
// CHECK-NEXT: SectionData (
-// CHECK-NEXT: 0000: 4C4C4420 312E3000 |LLD 1.0.|
+// CHECK-NEXT: 0000: 4C4C4420 312E3000 |LLD 1.0.|
// CHECK-NEXT: )
// CHECK-NEXT: }
// CHECK-NEXT: Section {
@@ -206,8 +206,8 @@
// CHECK-NEXT: AddressAlignment: 1
// CHECK-NEXT: EntrySize: 0
// CHECK-NEXT: SectionData (
-// CHECK-NEXT: 0000: 002E6479 6E73796D 002E6861 7368002E |..dynsym..hash..|
-// CHECK-NEXT: 0010: 64796E73 7472002E 74657874 002E6479 |dynstr..text..dy|
+// CHECK-NEXT: 0000: 002E6479 6E73796D 002E6479 6E737472 |..dynsym..dynstr|
+// CHECK-NEXT: 0010: 002E6861 7368002E 74657874 002E6479 |..hash..text..dy|
// CHECK-NEXT: 0020: 6E616D69 63002E63 6F6D6D65 6E74002E |namic..comment..|
// CHECK-NEXT: 0030: 73796D74 6162002E 73687374 72746162 |symtab..shstrtab|
// CHECK-NEXT: 0040: 002E7374 72746162 00 |..strtab.|
@@ -249,8 +249,8 @@
// CHECK-NEXT: Offset: 0x0
// CHECK-NEXT: VirtualAddress: 0x0
// CHECK-NEXT: PhysicalAddress: 0x0
-// CHECK-NEXT: FileSize: 497
-// CHECK-NEXT: MemSize: 497
+// CHECK-NEXT: FileSize: 500
+// CHECK-NEXT: MemSize: 500
// CHECK-NEXT: Flags [ (0x4)
// CHECK-NEXT: PF_R (0x4)
// CHECK-NEXT: ]
diff --git a/test/ELF/basic64be.s b/test/ELF/basic64be.s
index 03a4a1f..670bc0b 100644
--- a/test/ELF/basic64be.s
+++ b/test/ELF/basic64be.s
@@ -4,26 +4,11 @@
# REQUIRES: ppc
# exits with return code 42 on linux
-.section ".opd","aw"
-.global _start
-_start:
-.quad .Lfoo,.TOC.@tocbase,0
-
-# generate .toc and .toc1 sections to make sure that the ordering is as
-# intended (.toc before .toc1, and both before .opd).
-.section ".toc1","aw"
-.quad 22, 37, 89, 47
-
-.section ".toc","aw"
-.quad 45, 86, 72, 24
-
.text
-.Lfoo:
li 0,1
li 3,42
sc
-
-# CHECK: ElfHeader {
+# CHECK: ElfHeader {
# CHECK-NEXT: Ident {
# CHECK-NEXT: Magic: (7F 45 4C 46)
# CHECK-NEXT: Class: 64-bit (0x2)
@@ -36,18 +21,18 @@
# CHECK-NEXT: Type: Executable (0x2)
# CHECK-NEXT: Machine: EM_PPC64 (0x15)
# CHECK-NEXT: Version: 1
-# CHECK-NEXT: Entry: 0x10020040
+# CHECK-NEXT: Entry: 0x10010000
# CHECK-NEXT: ProgramHeaderOffset: 0x40
-# CHECK-NEXT: SectionHeaderOffset: 0x30080
-# CHECK-NEXT: Flags [ (0x1)
-# CHECK-NEXT: 0x1
+# CHECK-NEXT: SectionHeaderOffset: 0x11050
+# CHECK-NEXT: Flags [ (0x2)
+# CHECK-NEXT: 0x2
# CHECK-NEXT: ]
# CHECK-NEXT: HeaderSize: 64
# CHECK-NEXT: ProgramHeaderEntrySize: 56
-# CHECK-NEXT: ProgramHeaderCount: 6
+# CHECK-NEXT: ProgramHeaderCount: 4
# CHECK-NEXT: SectionHeaderEntrySize: 64
-# CHECK-NEXT: SectionHeaderCount: 10
-# CHECK-NEXT: StringTableSectionIndex: 8
+# CHECK-NEXT: SectionHeaderCount: 6
+# CHECK-NEXT: StringTableSectionIndex: 4
# CHECK-NEXT: }
# CHECK-NEXT: Sections [
# CHECK-NEXT: Section {
@@ -68,7 +53,7 @@
# CHECK-NEXT: }
# CHECK-NEXT: Section {
# CHECK-NEXT: Index: 1
-# CHECK-NEXT: Name: .text
+# CHECK-NEXT: Name: .text (1)
# CHECK-NEXT: Type: SHT_PROGBITS (0x1)
# CHECK-NEXT: Flags [ (0x6)
# CHECK-NEXT: SHF_ALLOC (0x2)
@@ -82,152 +67,80 @@
# CHECK-NEXT: AddressAlignment: 4
# CHECK-NEXT: EntrySize: 0
# CHECK-NEXT: SectionData (
-# CHECK: )
+# CHECK-NEXT: 0000: 38000001 3860002A 44000002 |8...8`.*D...|
+# CHECK-NEXT: )
# CHECK-NEXT: }
# CHECK-NEXT: Section {
# CHECK-NEXT: Index: 2
-# CHECK-NEXT: Name: .toc
-# CHECK-NEXT: Type: SHT_PROGBITS (0x1)
-# CHECK-NEXT: Flags [ (0x3)
-# CHECK-NEXT: SHF_ALLOC (0x2)
-# CHECK-NEXT: SHF_WRITE (0x1)
-# CHECK-NEXT: ]
-# CHECK-NEXT: Address: 0x10020000
-# CHECK-NEXT: Offset: 0x20000
-# CHECK-NEXT: Size: 32
-# CHECK-NEXT: Link: 0
-# CHECK-NEXT: Info: 0
-# CHECK-NEXT: AddressAlignment: 1
-# CHECK-NEXT: EntrySize: 0
-# CHECK-NEXT: SectionData (
-# CHECK-NEXT: 0000: 00000000 0000002D 00000000 00000056 |.......-.......V|
-# CHECK-NEXT: 0010: 00000000 00000048 00000000 00000018 |.......H........|
-# CHECK-NEXT: )
-# CHECK-NEXT: }
-# CHECK-NEXT: Section {
-# CHECK-NEXT: Index: 3
-# CHECK-NEXT: Name: .toc1
-# CHECK-NEXT: Type: SHT_PROGBITS (0x1)
-# CHECK-NEXT: Flags [ (0x3)
-# CHECK-NEXT: SHF_ALLOC (0x2)
-# CHECK-NEXT: SHF_WRITE (0x1)
-# CHECK-NEXT: ]
-# CHECK-NEXT: Address: 0x10020020
-# CHECK-NEXT: Offset: 0x20020
-# CHECK-NEXT: Size: 32
-# CHECK-NEXT: Link: 0
-# CHECK-NEXT: Info: 0
-# CHECK-NEXT: AddressAlignment: 1
-# CHECK-NEXT: EntrySize: 0
-# CHECK-NEXT: SectionData (
-# CHECK-NEXT: 0000: 00000000 00000016 00000000 00000025 |...............%|
-# CHECK-NEXT: 0010: 00000000 00000059 00000000 0000002F |.......Y......./|
-# CHECK-NEXT: )
-# CHECK-NEXT: }
-# CHECK-NEXT: Section {
-# CHECK-NEXT: Index: 4
-# CHECK-NEXT: Name: .opd
-# CHECK-NEXT: Type: SHT_PROGBITS (0x1)
-# CHECK-NEXT: Flags [ (0x3)
-# CHECK-NEXT: SHF_ALLOC (0x2)
-# CHECK-NEXT: SHF_WRITE (0x1)
-# CHECK-NEXT: ]
-# CHECK-NEXT: Address: 0x10020040
-# CHECK-NEXT: Offset: 0x20040
-# CHECK-NEXT: Size: 24
-# CHECK-NEXT: Link: 0
-# CHECK-NEXT: Info: 0
-# CHECK-NEXT: AddressAlignment: 1
-# CHECK-NEXT: EntrySize: 0
-# CHECK-NEXT: SectionData (
-# CHECK-NEXT: 0000: 00000000 10010000 00000000 10038000 |................|
-# CHECK-NEXT: 0010: 00000000 00000000 |........|
-# CHECK-NEXT: )
-# CHECK-NEXT: }
-# CHECK-NEXT: Section {
-# CHECK-NEXT: Index: 5
-# CHECK-NEXT: Name: .got
-# CHECK-NEXT: Type: SHT_PROGBITS
-# CHECK-NEXT: Flags [
-# CHECK-NEXT: SHF_ALLOC
-# CHECK-NEXT: SHF_WRITE
-# CHECK-NEXT: ]
-# CHECK-NEXT: Address: 0x10030000
-# CHECK-NEXT: Offset: 0x30000
-# CHECK-NEXT: Size: 0
-# CHECK-NEXT: Link: 0
-# CHECK-NEXT: Info: 0
-# CHECK-NEXT: AddressAlignment: 8
-# CHECK-NEXT: EntrySize: 0
-# CHECK-NEXT: SectionData (
-# CHECK-NEXT: )
-# CHECK-NEXT: }
-# CHECK-NEXT: Section {
-# CHECK-NEXT: Index: 6
-# CHECK-NEXT: Name: .comment
+# CHECK-NEXT: Name: .comment (7)
# CHECK-NEXT: Type: SHT_PROGBITS (0x1)
# CHECK-NEXT: Flags [ (0x30)
# CHECK-NEXT: SHF_MERGE (0x10)
# CHECK-NEXT: SHF_STRINGS (0x20)
# CHECK-NEXT: ]
# CHECK-NEXT: Address: 0x0
-# CHECK-NEXT: Offset: 0x30000
+# CHECK-NEXT: Offset: 0x11000
# CHECK-NEXT: Size: 8
# CHECK-NEXT: Link: 0
# CHECK-NEXT: Info: 0
# CHECK-NEXT: AddressAlignment: 1
# CHECK-NEXT: EntrySize: 1
# CHECK-NEXT: SectionData (
-# CHECK-NEXT: 0000: 4C4C4420 312E3000 |LLD 1.0.|
+# CHECK-NEXT: 0000: 4C4C4420 312E3000 |LLD 1.0.|
# CHECK-NEXT: )
# CHECK-NEXT: }
# CHECK-NEXT: Section {
-# CHECK-NEXT: Index: 7
-# CHECK-NEXT: Name: .symtab
+# CHECK-NEXT: Index: 3
+# CHECK-NEXT: Name: .symtab (16)
# CHECK-NEXT: Type: SHT_SYMTAB (0x2)
# CHECK-NEXT: Flags [ (0x0)
# CHECK-NEXT: ]
# CHECK-NEXT: Address: 0x0
-# CHECK-NEXT: Offset: 0x30008
-# CHECK-NEXT: Size: 48
-# CHECK-NEXT: Link: 9
+# CHECK-NEXT: Offset: 0x11008
+# CHECK-NEXT: Size: 24
+# CHECK-NEXT: Link: 5
# CHECK-NEXT: Info: 1
# CHECK-NEXT: AddressAlignment: 8
# CHECK-NEXT: EntrySize: 24
# CHECK-NEXT: SectionData (
-# CHECK: )
+# CHECK-NEXT: 0000: 00000000 00000000 00000000 00000000 |................|
+# CHECK-NEXT: 0010: 00000000 00000000 |........|
+# CHECK-NEXT: )
# CHECK-NEXT: }
# CHECK-NEXT: Section {
-# CHECK-NEXT: Index: 8
-# CHECK-NEXT: Name: .shstrtab
-# CHECK-NEXT: Type: SHT_STRTAB
-# CHECK-NEXT: Flags [
-# CHECK-NEXT: ]
-# CHECK-NEXT: Address: 0x0
-# CHECK-NEXT: Offset: 0x30038
-# CHECK-NEXT: Size: 63
-# CHECK-NEXT: Link: 0
-# CHECK-NEXT: Info: 0
-# CHECK-NEXT: AddressAlignment: 1
-# CHECK-NEXT: EntrySize: 0
-# CHECK-NEXT: SectionData (
-# CHECK: )
-# CHECK-NEXT: }
-# CHECK-NEXT: Section {
-# CHECK-NEXT: Index: 9
-# CHECK-NEXT: Name: .strtab
-# CHECK-NEXT: Type: SHT_STRTAB
+# CHECK-NEXT: Index: 4
+# CHECK-NEXT: Name: .shstrtab (24)
+# CHECK-NEXT: Type: SHT_STRTAB (0x3)
# CHECK-NEXT: Flags [ (0x0)
# CHECK-NEXT: ]
# CHECK-NEXT: Address: 0x0
-# CHECK-NEXT: Offset: 0x30077
-# CHECK-NEXT: Size: 8
+# CHECK-NEXT: Offset: 0x11020
+# CHECK-NEXT: Size: 42
# CHECK-NEXT: Link: 0
# CHECK-NEXT: Info: 0
# CHECK-NEXT: AddressAlignment: 1
# CHECK-NEXT: EntrySize: 0
# CHECK-NEXT: SectionData (
-# CHECK-NEXT: 0000: 005F7374 61727400 |._start.|
+# CHECK-NEXT: 0000: 002E7465 7874002E 636F6D6D 656E7400 |..text..comment.|
+# CHECK-NEXT: 0010: 2E73796D 74616200 2E736873 74727461 |.symtab..shstrta|
+# CHECK-NEXT: 0020: 62002E73 74727461 6200 |b..strtab.|
+# CHECK-NEXT: )
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT: Index: 5
+# CHECK-NEXT: Name: .strtab (34)
+# CHECK-NEXT: Type: SHT_STRTAB (0x3)
+# CHECK-NEXT: Flags [ (0x0)
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x0
+# CHECK-NEXT: Offset: 0x1104A
+# CHECK-NEXT: Size: 1
+# CHECK-NEXT: Link: 0
+# CHECK-NEXT: Info: 0
+# CHECK-NEXT: AddressAlignment: 1
+# CHECK-NEXT: EntrySize: 0
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT: 0000: 00 |.|
# CHECK-NEXT: )
# CHECK-NEXT: }
# CHECK-NEXT: ]
@@ -237,74 +150,49 @@
# CHECK-NEXT: Offset: 0x40
# CHECK-NEXT: VirtualAddress: 0x10000040
# CHECK-NEXT: PhysicalAddress: 0x10000040
-# CHECK-NEXT: FileSize: 336
-# CHECK-NEXT: MemSize: 336
-# CHECK-NEXT: Flags [
-# CHECK-NEXT: PF_R
+# CHECK-NEXT: FileSize: 224
+# CHECK-NEXT: MemSize: 224
+# CHECK-NEXT: Flags [ (0x4)
+# CHECK-NEXT: PF_R (0x4)
# CHECK-NEXT: ]
# CHECK-NEXT: Alignment: 8
# CHECK-NEXT: }
-# CHECK-NEXT: ProgramHeader {
-# CHECK-NEXT: Type: PT_LOAD (0x1)
-# CHECK-NEXT: Offset: 0x0
-# CHECK-NEXT: VirtualAddress: 0x10000000
-# CHECK-NEXT: PhysicalAddress: 0x10000000
-# CHECK-NEXT: FileSize: 400
-# CHECK-NEXT: MemSize: 400
-# CHECK-NEXT: Flags [
-# CHECK-NEXT: PF_R
-# CHECK-NEXT: ]
-# CHECK-NEXT: Alignment: 65536
-# CHECK-NEXT: }
-# CHECK-NEXT: ProgramHeader {
-# CHECK-NEXT: Type: PT_LOAD (0x1)
-# CHECK-NEXT: Offset: 0x10000
-# CHECK-NEXT: VirtualAddress: 0x10010000
-# CHECK-NEXT: PhysicalAddress: 0x10010000
-# CHECK-NEXT: FileSize: 12
-# CHECK-NEXT: MemSize: 12
-# CHECK-NEXT: Flags [ (0x5)
-# CHECK-NEXT: PF_R (0x4)
-# CHECK-NEXT: PF_X (0x1)
-# CHECK-NEXT: ]
-# CHECK-NEXT: Alignment: 65536
-# CHECK-NEXT: }
-# CHECK-NEXT: ProgramHeader {
-# CHECK-NEXT: Type: PT_LOAD (0x1)
-# CHECK-NEXT: Offset: 0x20000
-# CHECK-NEXT: VirtualAddress: 0x10020000
-# CHECK-NEXT: PhysicalAddress: 0x10020000
-# CHECK-NEXT: FileSize: 65536
-# CHECK-NEXT: MemSize: 65536
-# CHECK-NEXT: Flags [ (0x6)
-# CHECK-NEXT: PF_R (0x4)
-# CHECK-NEXT: PF_W (0x2)
-# CHECK-NEXT: ]
-# CHECK-NEXT: Alignment: 65536
-# CHECK-NEXT: }
-# CHECK-NEXT: ProgramHeader {
-# CHECK-NEXT: Type: PT_GNU_RELRO
-# CHECK-NEXT: Offset: 0x30000
-# CHECK-NEXT: VirtualAddress: 0x10030000
-# CHECK-NEXT: PhysicalAddress: 0x10030000
-# CHECK-NEXT: FileSize: 0
-# CHECK-NEXT: MemSize: 0
-# CHECK-NEXT: Flags [ (0x4)
-# CHECK-NEXT: PF_R (0x4)
-# CHECK-NEXT: ]
-# CHECK-NEXT: Alignment: 1
-# CHECK-NEXT: }
-# CHECK-NEXT: ProgramHeader {
-# CHECK-NEXT: Type: PT_GNU_STACK (0x6474E551)
-# CHECK-NEXT: Offset: 0x0
-# CHECK-NEXT: VirtualAddress: 0x0
-# CHECK-NEXT: PhysicalAddress: 0x0
-# CHECK-NEXT: FileSize: 0
-# CHECK-NEXT: MemSize: 0
-# CHECK-NEXT: Flags [ (0x6)
-# CHECK-NEXT: PF_R (0x4)
-# CHECK-NEXT: PF_W (0x2)
-# CHECK-NEXT: ]
-# CHECK-NEXT: Alignment: 0
-# CHECK-NEXT: }
+# CHECK-NEXT: ProgramHeader {
+# CHECK-NEXT: Type: PT_LOAD (0x1)
+# CHECK-NEXT: Offset: 0x0
+# CHECK-NEXT: VirtualAddress: 0x10000000
+# CHECK-NEXT: PhysicalAddress: 0x10000000
+# CHECK-NEXT: FileSize: 288
+# CHECK-NEXT: MemSize: 288
+# CHECK-NEXT: Flags [ (0x4)
+# CHECK-NEXT: PF_R (0x4)
+# CHECK-NEXT: ]
+# CHECK-NEXT: Alignment: 65536
+# CHECK-NEXT: }
+# CHECK-NEXT: ProgramHeader {
+# CHECK-NEXT: Type: PT_LOAD (0x1)
+# CHECK-NEXT: Offset: 0x10000
+# CHECK-NEXT: VirtualAddress: 0x10010000
+# CHECK-NEXT: PhysicalAddress: 0x10010000
+# CHECK-NEXT: FileSize: 4096
+# CHECK-NEXT: MemSize: 4096
+# CHECK-NEXT: Flags [ (0x5)
+# CHECK-NEXT: PF_R (0x4)
+# CHECK-NEXT: PF_X (0x1)
+# CHECK-NEXT: ]
+# CHECK-NEXT: Alignment: 65536
+# CHECK-NEXT: }
+# CHECK-NEXT: ProgramHeader {
+# CHECK-NEXT: Type: PT_GNU_STACK (0x6474E551)
+# CHECK-NEXT: Offset: 0x0
+# CHECK-NEXT: VirtualAddress: 0x0
+# CHECK-NEXT: PhysicalAddress: 0x0
+# CHECK-NEXT: FileSize: 0
+# CHECK-NEXT: MemSize: 0
+# CHECK-NEXT: Flags [ (0x6)
+# CHECK-NEXT: PF_R (0x4)
+# CHECK-NEXT: PF_W (0x2)
+# CHECK-NEXT: ]
+# CHECK-NEXT: Alignment: 0
+# CHECK-NEXT: }
# CHECK-NEXT: ]
diff --git a/test/ELF/cgprofile-bad-clusters.s b/test/ELF/cgprofile-bad-clusters.s
new file mode 100644
index 0000000..77bfe69
--- /dev/null
+++ b/test/ELF/cgprofile-bad-clusters.s
@@ -0,0 +1,71 @@
+# This test checks that CallGraphSort ignores edges that would form "bad"
+# clusters.
+
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "A C 1" > %t.call_graph
+# RUN: echo "E B 4" >> %t.call_graph
+# RUN: echo "C D 2" >> %t.call_graph
+# RUN: echo "B D 1" >> %t.call_graph
+# RUN: echo "F G 6" >> %t.call_graph
+# RUN: echo "G H 5" >> %t.call_graph
+# RUN: echo "H I 4" >> %t.call_graph
+# RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o %t2
+# RUN: llvm-readobj -symbols %t2 | FileCheck %s
+
+ .section .text.A,"ax",@progbits
+ .globl A
+A:
+ retq
+
+ .section .text.D,"ax",@progbits
+D:
+ .fill 1000, 1, 0
+
+ .section .text.E,"ax",@progbits
+E:
+ retq
+
+ .section .text.C,"ax",@progbits
+C:
+ retq
+
+ .section .text.B,"ax",@progbits
+B:
+ .fill 1000, 1, 0
+
+ .section .text.F,"ax",@progbits
+F:
+ .fill (1024 * 1024) - 1, 1, 0
+
+ .section .text.G,"ax",@progbits
+G:
+ retq
+
+ .section .text.H,"ax",@progbits
+H:
+ retq
+
+ .section .text.I,"ax",@progbits
+I:
+ .fill 13, 1, 0
+
+# CHECK: Name: B
+# CHECK-NEXT: Value: 0x201011
+# CHECK: Name: C
+# CHECK-NEXT: Value: 0x20100F
+# CHECK: Name: D
+# CHECK-NEXT: Value: 0x2013F9
+# CHECK: Name: E
+# CHECK-NEXT: Value: 0x201010
+# CHECK: Name: F
+# CHECK-NEXT: Value: 0x2017E1
+# CHECK: Name: G
+# CHECK-NEXT: Value: 0x3017E0
+# CHECK: Name: H
+# CHECK-NEXT: Value: 0x201000
+# CHECK: Name: I
+# CHECK-NEXT: Value: 0x201001
+# CHECK: Name: A
+# CHECK-NEXT: Value: 0x20100E
diff --git a/test/ELF/cgprofile-icf.s b/test/ELF/cgprofile-icf.s
new file mode 100644
index 0000000..93b7274
--- /dev/null
+++ b/test/ELF/cgprofile-icf.s
@@ -0,0 +1,53 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "A B 100" > %t.call_graph
+# RUN: echo "A C 40" >> %t.call_graph
+# RUN: echo "C D 61" >> %t.call_graph
+# RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o %t.out -icf=all
+# RUN: llvm-readobj -symbols %t.out | FileCheck %s
+# RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o %t2.out
+# RUN: llvm-readobj -symbols %t2.out | FileCheck %s --check-prefix=NOICF
+
+ .section .text.D,"ax",@progbits
+ .globl D
+D:
+ mov $60, %rax
+ retq
+
+ .section .text.C,"ax",@progbits
+ .globl C
+C:
+ mov $60, %rax
+ retq
+
+ .section .text.B,"ax",@progbits
+ .globl B
+B:
+ mov $2, %rax
+ retq
+
+ .section .text.A,"ax",@progbits
+ .globl A
+A:
+ mov $42, %rax
+ retq
+
+# CHECK: Name: A
+# CHECK-NEXT: Value: 0x201000
+# CHECK: Name: B
+# CHECK-NEXT: Value: 0x201010
+# CHECK: Name: C
+# CHECK-NEXT: Value: 0x201008
+# CHECK: Name: D
+# CHECK-NEXT: Value: 0x201008
+
+# NOICF: Name: A
+# NOICF-NEXT: Value: 0x201000
+# NOICF: Name: B
+# NOICF-NEXT: Value: 0x201008
+# NOICF: Name: C
+# NOICF-NEXT: Value: 0x201010
+# NOICF: Name: D
+# NOICF-NEXT: Value: 0x201018
diff --git a/test/ELF/cgprofile-txt.s b/test/ELF/cgprofile-txt.s
new file mode 100644
index 0000000..ee5149a
--- /dev/null
+++ b/test/ELF/cgprofile-txt.s
@@ -0,0 +1,185 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld -e A %t -o %t2
+# RUN: llvm-readobj -symbols %t2 | FileCheck %s --check-prefix=NOSORT
+
+# RUN: echo "A B 10" > %t.call_graph
+# RUN: echo "A B 10" >> %t.call_graph
+# RUN: echo "Aa B 80" >> %t.call_graph
+# RUN: echo "A C 40" >> %t.call_graph
+# RUN: echo "B C 30" >> %t.call_graph
+# RUN: echo "C D 90" >> %t.call_graph
+# RUN: echo "PP TS 100" >> %t.call_graph
+# RUN: echo "_init2 _init 24567837" >> %t.call_graph
+# RUN: echo "TS QC 9001" >> %t.call_graph
+# RUN: echo "TooManyPreds0 TooManyPreds 10" >> %t.call_graph
+# RUN: echo "TooManyPreds1 TooManyPreds 10" >> %t.call_graph
+# RUN: echo "TooManyPreds2 TooManyPreds 10" >> %t.call_graph
+# RUN: echo "TooManyPreds3 TooManyPreds 10" >> %t.call_graph
+# RUN: echo "TooManyPreds4 TooManyPreds 10" >> %t.call_graph
+# RUN: echo "TooManyPreds5 TooManyPreds 10" >> %t.call_graph
+# RUN: echo "TooManyPreds6 TooManyPreds 10" >> %t.call_graph
+# RUN: echo "TooManyPreds7 TooManyPreds 10" >> %t.call_graph
+# RUN: echo "TooManyPreds8 TooManyPreds 10" >> %t.call_graph
+# RUN: echo "TooManyPreds9 TooManyPreds 10" >> %t.call_graph
+# RUN: echo "TooManyPreds10 TooManyPreds 11" >> %t.call_graph
+# RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o %t2
+# RUN: llvm-readobj -symbols %t2 | FileCheck %s
+
+ .section .text.D,"ax",@progbits
+D:
+ retq
+
+ .section .text.C,"ax",@progbits
+ .globl C
+C:
+ retq
+
+ .section .text.B,"ax",@progbits
+ .globl B
+B:
+ retq
+
+ .section .text.A,"ax",@progbits
+ .globl A
+A:
+Aa:
+ retq
+
+ .section .ponies,"ax",@progbits,unique,1
+ .globl TS
+TS:
+ retq
+
+ .section .ponies,"ax",@progbits,unique,2
+ .globl PP
+PP:
+ retq
+
+ .section .other,"ax",@progbits,unique,1
+ .globl QC
+QC:
+ retq
+
+ .section .other,"ax",@progbits,unique,2
+ .globl GB
+GB:
+ retq
+
+ .section .init,"ax",@progbits,unique,1
+ .globl _init
+_init:
+ retq
+
+ .section .init,"ax",@progbits,unique,2
+ .globl _init2
+_init2:
+ retq
+
+ .section .text.TooManyPreds,"ax",@progbits
+TooManyPreds:
+ retq
+ retq
+ retq
+ retq
+ retq
+ retq
+ retq
+ retq
+ retq
+ retq
+
+ .section .text.TooManyPreds0,"ax",@progbits
+TooManyPreds0:
+ retq
+
+ .section .text.TooManyPreds1,"ax",@progbits
+TooManyPreds1:
+ retq
+
+ .section .text.TooManyPreds2,"ax",@progbits
+TooManyPreds2:
+ retq
+
+ .section .text.TooManyPreds3,"ax",@progbits
+TooManyPreds3:
+ retq
+
+ .section .text.TooManyPreds4,"ax",@progbits
+TooManyPreds4:
+ retq
+
+ .section .text.TooManyPreds5,"ax",@progbits
+TooManyPreds5:
+ retq
+
+ .section .text.TooManyPreds6,"ax",@progbits
+TooManyPreds6:
+ retq
+
+ .section .text.TooManyPreds7,"ax",@progbits
+TooManyPreds7:
+ retq
+
+ .section .text.TooManyPreds8,"ax",@progbits
+TooManyPreds8:
+ retq
+
+ .section .text.TooManyPreds9,"ax",@progbits
+TooManyPreds9:
+ retq
+
+ .section .text.TooManyPreds10,"ax",@progbits
+TooManyPreds10:
+ retq
+
+# CHECK: Name: D
+# CHECK-NEXT: Value: 0x201003
+# CHECK: Name: TooManyPreds
+# CHECK-NEXT: Value: 0x201004
+# CHECK: Name: TooManyPreds10
+# CHECK-NEXT: Value: 0x201018
+# CHECK: Name: A
+# CHECK-NEXT: Value: 0x201000
+# CHECK: Name: B
+# CHECK-NEXT: Value: 0x201001
+# CHECK: Name: C
+# CHECK-NEXT: Value: 0x201002
+# CHECK: Name: GB
+# CHECK-NEXT: Value: 0x20101F
+# CHECK: Name: PP
+# CHECK-NEXT: Value: 0x20101C
+# CHECK: Name: QC
+# CHECK-NEXT: Value: 0x20101E
+# CHECK: Name: TS
+# CHECK-NEXT: Value: 0x20101D
+# CHECK: Name: _init
+# CHECK-NEXT: Value: 0x201020
+# CHECK: Name: _init2
+# CHECK-NEXT: Value: 0x201021
+
+# NOSORT: Name: D
+# NOSORT-NEXT: Value: 0x201000
+# NOSORT: Name: TooManyPreds
+# NOSORT-NEXT: Value: 0x201004
+# NOSORT: Name: TooManyPreds10
+# NOSORT-NEXT: Value: 0x201018
+# NOSORT: Name: A
+# NOSORT-NEXT: Value: 0x201003
+# NOSORT: Name: B
+# NOSORT-NEXT: Value: 0x201002
+# NOSORT: Name: C
+# NOSORT-NEXT: Value: 0x201001
+# NOSORT: Name: GB
+# NOSORT-NEXT: Value: 0x20101C
+# NOSORT: Name: PP
+# NOSORT-NEXT: Value: 0x20101A
+# NOSORT: Name: QC
+# NOSORT-NEXT: Value: 0x20101B
+# NOSORT: Name: TS
+# NOSORT-NEXT: Value: 0x201019
+# NOSORT: Name: _init
+# NOSORT-NEXT: Value: 0x20101D
+# NOSORT: Name: _init2
+# NOSORT-NEXT: Value: 0x20101E
diff --git a/test/ELF/cgprofile-warn.s b/test/ELF/cgprofile-warn.s
new file mode 100644
index 0000000..2b30a1a
--- /dev/null
+++ b/test/ELF/cgprofile-warn.s
@@ -0,0 +1,29 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "A B 100" > %t.call_graph
+# RUN: echo "A C 40" >> %t.call_graph
+# RUN: echo "B C 30" >> %t.call_graph
+# RUN: echo "adena A 30" >> %t.call_graph
+# RUN: echo "poppy A 30" >> %t.call_graph
+# RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o %t.out \
+# RUN: -noinhibit-exec -icf=all 2>&1 | FileCheck %s
+
+ .section .text.C,"ax",@progbits
+ .globl C
+C:
+ mov poppy, %rax
+ retq
+
+B = 0x1234
+
+ .section .text.A,"ax",@progbits
+ .globl A
+A:
+ mov poppy, %rax
+ retq
+
+# CHECK: unable to order absolute symbol: B
+# CHECK: call graph file: no such symbol: adena
+# CHECK: unable to order undefined symbol: poppy
diff --git a/test/ELF/combrelocs.s b/test/ELF/combrelocs.s
index 3c8be80..595f604 100644
--- a/test/ELF/combrelocs.s
+++ b/test/ELF/combrelocs.s
@@ -4,6 +4,9 @@
# RUN: ld.lld -shared %t.o -o %t.out
# RUN: llvm-readobj -r --expand-relocs --dynamic-table %t.out | FileCheck %s
+# RUN: ld.lld -shared %t.o -o %t.out -z combreloc
+# RUN: llvm-readobj -r --expand-relocs --dynamic-table %t.out | FileCheck %s
+
# CHECK: Relocations [
# CHECK-NEXT: Section ({{.*}}) .rela.dyn {
# CHECK-NEXT: Relocation {
diff --git a/test/ELF/cref.s b/test/ELF/cref.s
index 01516fa..2a82f42 100644
--- a/test/ELF/cref.s
+++ b/test/ELF/cref.s
@@ -2,9 +2,12 @@
// RUN: echo '.global foo; foo:' | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t1.o
// RUN: echo '.global foo, bar; bar:' | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t2.o
+// RUN: echo '.global zed; zed:' | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %ta.o
+// RUN: rm -f %t.a
+// RUN: llvm-ar rcs %t.a %ta.o
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t3.o
-// RUN: ld.lld -shared -o %t1.so %t1.o -gc-sections
-// RUN: ld.lld -o /dev/null %t1.so %t2.o %t3.o -cref | FileCheck -strict-whitespace %s
+// RUN: ld.lld -shared -o %t1.so %t1.o
+// RUN: ld.lld -o /dev/null %t1.so %t2.o %t3.o %t.a -gc-sections -cref | FileCheck -strict-whitespace %s
// CHECK: Symbol File
// CHECK-NEXT: bar {{.*}}2.o
@@ -14,11 +17,15 @@
// CHECK-NEXT: {{.*}}3.o
// CHECK-NEXT: _start {{.*}}3.o
// CHECK-NEXT: baz {{.*}}3.o
+// CHECK-NEXT: zed {{.*}}.a({{.*}}a.o)
+// CHECK-NEXT: {{.*}}3.o
+// CHECK-NOT: discarded
-.global _start, foo, bar, baz
+.global _start, foo, bar, baz, discarded
_start:
call foo
call bar
+ call zed
localsym:
baz:
diff --git a/test/ELF/dt_flags.s b/test/ELF/dt_flags.s
index 431f83d..dffaec8 100644
--- a/test/ELF/dt_flags.s
+++ b/test/ELF/dt_flags.s
@@ -2,9 +2,14 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
# RUN: ld.lld -shared %t -o %t.so
+
# RUN: ld.lld -z now -z nodelete -z nodlopen -z origin -Bsymbolic %t %t.so -o %t1
-# RUN: ld.lld %t %t.so -o %t2
# RUN: llvm-readobj -dynamic-table %t1 | FileCheck -check-prefix=FLAGS %s
+
+# RUN: ld.lld %t %t.so -o %t2
+# RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s
+
+# RUN: ld.lld -z lazy %t %t.so -o %t2
# RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s
# FLAGS: DynamicSection [
diff --git a/test/ELF/dynamic-no-rosegment.s b/test/ELF/dynamic-no-rosegment.s
index f2b5f35..b65e37d 100644
--- a/test/ELF/dynamic-no-rosegment.s
+++ b/test/ELF/dynamic-no-rosegment.s
@@ -7,9 +7,9 @@
# CHECK-NEXT: Tag Type Name/Value
# CHECK-NEXT: 0x0000000000000006 SYMTAB 0x120
# CHECK-NEXT: 0x000000000000000B SYMENT 24 (bytes)
-# CHECK-NEXT: 0x0000000000000005 STRTAB 0x1D8
+# CHECK-NEXT: 0x0000000000000005 STRTAB 0x138
# CHECK-NEXT: 0x000000000000000A STRSZ 1 (bytes)
-# CHECK-NEXT: 0x000000006FFFFEF5 GNU_HASH 0x138
-# CHECK-NEXT: 0x0000000000000004 HASH 0x154
+# CHECK-NEXT: 0x000000006FFFFEF5 GNU_HASH 0x140
+# CHECK-NEXT: 0x0000000000000004 HASH 0x15C
# CHECK-NEXT: 0x0000000000000000 NULL 0x0
# CHECK-NEXT: ]
diff --git a/test/ELF/dynsec-at-beginning.s b/test/ELF/dynsec-at-beginning.s
new file mode 100644
index 0000000..90504c9
--- /dev/null
+++ b/test/ELF/dynsec-at-beginning.s
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+
+# RUN: ld.lld --hash-style=gnu -o %t1 %t -shared
+# RUN: llvm-readobj -elf-output-style=GNU -s %t1 | FileCheck %s
+
+# Dynamic symbol and dynamic strtab sections are at the beginning of
+# SHF_ALLOC sections.
+# CHECK: .dynsym {{.*}} A
+# CHECK-NEXT: .dynstr {{.*}} A
+# CHECK-NEXT: foo {{.*}} A
+# CHECK-NEXT: .hash {{.*}} A
+# CHECK-NEXT: .text {{.*}} AX
+
+.section foo, "a"
+.byte 0
diff --git a/test/ELF/eh-frame-hdr-icf-fde.s b/test/ELF/eh-frame-hdr-icf-fde.s
index 54c2cd8..68de65d 100644
--- a/test/ELF/eh-frame-hdr-icf-fde.s
+++ b/test/ELF/eh-frame-hdr-icf-fde.s
@@ -52,7 +52,7 @@
# CHECK-NEXT: ]
# CHECK-NEXT: Address: 0x200178
# CHECK-NEXT: Offset: 0x178
-# CHECK-NEXT: Size: 72
+# CHECK-NEXT: Size: 76
# CHECK-NEXT: Link: 0
# CHECK-NEXT: Info: 0
# CHECK-NEXT: AddressAlignment: 8
@@ -62,7 +62,7 @@
# CHECK-NEXT: 0010: 1B0C0708 90010000 14000000 1C000000
# CHECK-NEXT: 0020: 680E0000 01000000 00000000 00000000
# CHECK-NEXT: 0030: 14000000 34000000 520E0000 01000000
-# CHECK-NEXT: 0040: 00000000 00000000
+# CHECK-NEXT: 0040: 00000000 00000000 00000000
# CHECK-NEXT: )
# CHECK-NEXT: }
diff --git a/test/ELF/eh-frame-hdr.s b/test/ELF/eh-frame-hdr.s
index aaeccda..0c33bc6 100644
--- a/test/ELF/eh-frame-hdr.s
+++ b/test/ELF/eh-frame-hdr.s
@@ -92,7 +92,7 @@
// HDR-NEXT: ]
// HDR-NEXT: Address: 0x200180
// HDR-NEXT: Offset: 0x180
-// HDR-NEXT: Size: 96
+// HDR-NEXT: Size: 100
// HDR-NEXT: Link: 0
// HDR-NEXT: Info: 0
// HDR-NEXT: AddressAlignment: 8
@@ -104,6 +104,7 @@
// HDR-NEXT: 0030: 14000000 34000000 490E0000 01000000
// HDR-NEXT: 0040: 00000000 00000000 14000000 4C000000
// HDR-NEXT: 0050: 320E0000 01000000 00000000 00000000
+// HDR-NEXT: 0060: 00000000
// HDR-NEXT: )
// CIE: 14000000 00000000 017A5200 01781001 1B0C0708 90010000
// FDE(1): 14000000 1C000000 600E0000 01000000 00000000 00000000
diff --git a/test/ELF/eh-frame-merge.s b/test/ELF/eh-frame-merge.s
index 4b54c17..6731d90 100644
--- a/test/ELF/eh-frame-merge.s
+++ b/test/ELF/eh-frame-merge.s
@@ -27,7 +27,7 @@
// CHECK-NEXT: ]
// CHECK-NEXT: Address:
// CHECK-NEXT: Offset:
-// CHECK-NEXT: Size: 96
+// CHECK-NEXT: Size: 100
// CHECK-NEXT: Link: 0
// CHECK-NEXT: Info: 0
// CHECK-NEXT: AddressAlignment: 8
@@ -39,6 +39,7 @@
// CHECK-NEXT: 0030: 14000000 34000000 D20D0000 02000000 |
// CHECK-NEXT: 0040: 00000000 00000000 14000000 4C000000 |
// CHECK-NEXT: 0050: B90D0000 01000000 00000000 00000000 |
+// CHECK-NEXT: 0060: 00000000
// CHECK-NEXT: )
// CHECK: Name: foo
diff --git a/test/ELF/eh-frame-padding-no-rosegment.s b/test/ELF/eh-frame-padding-no-rosegment.s
index e106f29..6805de1 100644
--- a/test/ELF/eh-frame-padding-no-rosegment.s
+++ b/test/ELF/eh-frame-padding-no-rosegment.s
@@ -58,7 +58,7 @@
// CHECK-NEXT: EntrySize:
// CHECK-NEXT: SectionData (
// CHECK-NEXT: 0000: 1C000000 00000000 017A5052 00017810
-// CHECK-NEXT: 0010: 061BBEFF FFFF1B0C 07089001 00000000
-// CHECK-NEXT: 0020: 14000000 24000000 A8FFFFFF 00000000
+// CHECK-NEXT: 0010: 061BDAFF FFFF1B0C 07089001 00000000
+// CHECK-NEXT: 0020: 14000000 24000000 C4FFFFFF 00000000
// CHECK-NEXT: 0030: 00000000 00000000
// CHECK-NEXT: )
diff --git a/test/ELF/ehframe-relocation.s b/test/ELF/ehframe-relocation.s
index 0213b1b..4ab44c2 100644
--- a/test/ELF/ehframe-relocation.s
+++ b/test/ELF/ehframe-relocation.s
@@ -12,7 +12,7 @@
// CHECK-NEXT: ]
// CHECK-NEXT: Address: 0x200120
// CHECK-NEXT: Offset:
-// CHECK-NEXT: Size: 48
+// CHECK-NEXT: Size: 52
// CHECK-NOT: .eh_frame
// 0x200120 = 2097440
diff --git a/test/ELF/emulation.s b/test/ELF/emulation.s
index c176cc1..1a2af0f 100644
--- a/test/ELF/emulation.s
+++ b/test/ELF/emulation.s
@@ -208,8 +208,8 @@
# PPC64-NEXT: Entry:
# PPC64-NEXT: ProgramHeaderOffset: 0x40
# PPC64-NEXT: SectionHeaderOffset:
-# PPC64-NEXT: Flags [ (0x1)
-# PPC64-NEXT: 0x1
+# PPC64-NEXT: Flags [ (0x2)
+# PPC64-NEXT: 0x2
# PPC64-NEXT: ]
# PPC64-NEXT: HeaderSize: 64
# PPC64-NEXT: ProgramHeaderEntrySize: 56
@@ -366,8 +366,12 @@
# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %taarch64
# RUN: ld.lld -m aarch64linux %taarch64 -o %t2aarch64
# RUN: llvm-readobj -file-headers %t2aarch64 | FileCheck --check-prefix=AARCH64 %s
-# RUN: ld.lld %taarch64 -o %t3aarch64
+# RUN: ld.lld -m aarch64elf %taarch64 -o %t3aarch64
# RUN: llvm-readobj -file-headers %t3aarch64 | FileCheck --check-prefix=AARCH64 %s
+# RUN: ld.lld -m aarch64_elf64_le_vec %taarch64 -o %t4aarch64
+# 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
# AARCH64: ElfHeader {
# AARCH64-NEXT: Ident {
# AARCH64-NEXT: Magic: (7F 45 4C 46)
diff --git a/test/ELF/file-sym.s b/test/ELF/file-sym.s
deleted file mode 100644
index c349226..0000000
--- a/test/ELF/file-sym.s
+++ /dev/null
@@ -1,12 +0,0 @@
-# Check that we do not keep STT_FILE symbols in the symbol table
-
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
-# RUN: ld.lld %t.o -shared -o %t.so
-# RUN: llvm-readobj -symbols %t.so | FileCheck %s
-
-# REQUIRES: x86
-
-# CHECK-NOT: Name: xxx
-
-.file "xxx"
-.file ""
diff --git a/test/ELF/fill-trap-ppc.s b/test/ELF/fill-trap-ppc.s
new file mode 100644
index 0000000..da7d7cb
--- /dev/null
+++ b/test/ELF/fill-trap-ppc.s
@@ -0,0 +1,31 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.ppc64le
+# RUN: llvm-readobj -program-headers %t.ppc64le | FileCheck %s
+# RUN: od -Ax -t x1 -N16 -j0x10ff0 %t.ppc64le | FileCheck %s -check-prefix=LE
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.ppc64
+# RUN: llvm-readobj -program-headers %t.ppc64 | FileCheck %s
+# RUN: od -Ax -t x1 -N16 -j0x10ff0 %t.ppc64 | FileCheck %s -check-prefix=BE
+
+# CHECK: ProgramHeader {
+# CHECK: Type: PT_LOAD
+# CHECK: Offset: 0x10000{{$}}
+# CHECK-NEXT: VirtualAddress:
+# CHECK-NEXT: PhysicalAddress:
+# CHECK-NEXT: FileSize: 4096
+# CHECK-NEXT: MemSize:
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: PF_R
+# CHECK-NEXT: PF_X
+# CHECK-NEXT: ]
+
+## Check that executable page is filled with traps at its end.
+# LE: 010ff0 08 00 e0 7f 08 00 e0 7f 08 00 e0 7f 08 00 e0 7f
+# BE: 010ff0 7f e0 00 08 7f e0 00 08 7f e0 00 08 7f e0 00 08
+
+.globl _start
+_start:
+ nop
diff --git a/test/ELF/format-binary-non-ascii.s b/test/ELF/format-binary-non-ascii.s
index 5a3ad96..36263e5 100644
--- a/test/ELF/format-binary-non-ascii.s
+++ b/test/ELF/format-binary-non-ascii.s
@@ -4,9 +4,9 @@
# RUN: ld.lld -o %t.elf %t£.o --format=binary %t£.o
# RUN: llvm-readobj -symbols %t.elf | FileCheck %s
-# CHECK: Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_non_ascii_s_tmp___o_start
-# CHECK: Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_non_ascii_s_tmp___o_end
-# CHECK: Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_non_ascii_s_tmp___o_size
+# CHECK: Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_non_ascii_s_tmp_{{[_]+}}o_start
+# CHECK: Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_non_ascii_s_tmp_{{[_]+}}o_end
+# CHECK: Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_non_ascii_s_tmp_{{[_]+}}o_size
.text
.align 4
diff --git a/test/ELF/gc-merge-local-sym.s b/test/ELF/gc-merge-local-sym.s
index b02a3a4..9cb4907 100644
--- a/test/ELF/gc-merge-local-sym.s
+++ b/test/ELF/gc-merge-local-sym.s
@@ -9,7 +9,7 @@
// CHECK-NEXT: SHF_MERGE
// CHECK-NEXT: SHF_STRINGS
// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x1C8
+// CHECK-NEXT: Address: 0x1FD
// CHECK-NEXT: Offset:
// CHECK-NEXT: Size: 4
// CHECK-NEXT: Link: 0
diff --git a/test/ELF/gc-sections-shared.s b/test/ELF/gc-sections-shared.s
index 55b3ef5..c0ebf40 100644
--- a/test/ELF/gc-sections-shared.s
+++ b/test/ELF/gc-sections-shared.s
@@ -25,6 +25,15 @@
# CHECK-NEXT: Section: Undefined (0x0)
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: qux
+# CHECK-NEXT: Value:
+# CHECK-NEXT: Size:
+# CHECK-NEXT: Binding: Weak
+# CHECK-NEXT: Type:
+# CHECK-NEXT: Other:
+# CHECK-NEXT: Section: Undefined
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: bar
# CHECK-NEXT: Value:
# CHECK-NEXT: Size:
@@ -51,15 +60,6 @@
# CHECK-NEXT: Other:
# CHECK-NEXT: Section: .text
# CHECK-NEXT: }
-# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: qux
-# CHECK-NEXT: Value:
-# CHECK-NEXT: Size:
-# CHECK-NEXT: Binding: Weak
-# CHECK-NEXT: Type:
-# CHECK-NEXT: Other:
-# CHECK-NEXT: Section: Undefined
-# CHECK-NEXT: }
# CHECK-NEXT: ]
# CHECK-NOT: NEEDED
@@ -68,59 +68,7 @@
# Test with %t.o at the end too.
# RUN: ld.lld --gc-sections --export-dynamic-symbol foo -o %t --as-needed %t2.so %t3.so %t4.so %t.o
-# RUN: llvm-readobj --dynamic-table --dyn-symbols %t | FileCheck --check-prefix=CHECK2 %s
-
-# CHECK2: DynamicSymbols [
-# CHECK2-NEXT: Symbol {
-# CHECK2-NEXT: Name:
-# CHECK2-NEXT: Value:
-# CHECK2-NEXT: Size:
-# CHECK2-NEXT: Binding: Local
-# CHECK2-NEXT: Type:
-# CHECK2-NEXT: Other:
-# CHECK2-NEXT: Section: Undefined (0x0)
-# CHECK2-NEXT: }
-# CHECK2-NEXT: Symbol {
-# CHECK2-NEXT: Name: bar
-# CHECK2-NEXT: Value:
-# CHECK2-NEXT: Size:
-# CHECK2-NEXT: Binding: Global
-# CHECK2-NEXT: Type:
-# CHECK2-NEXT: Other:
-# CHECK2-NEXT: Section: .text
-# CHECK2-NEXT: }
-# CHECK2-NEXT: Symbol {
-# CHECK2-NEXT: Name: baz
-# CHECK2-NEXT: Value:
-# CHECK2-NEXT: Size:
-# CHECK2-NEXT: Binding: Global
-# CHECK2-NEXT: Type:
-# CHECK2-NEXT: Other:
-# CHECK2-NEXT: Section: Undefined
-# CHECK2-NEXT: }
-# CHECK2-NEXT: Symbol {
-# CHECK2-NEXT: Name: qux
-# CHECK2-NEXT: Value:
-# CHECK2-NEXT: Size:
-# CHECK2-NEXT: Binding: Weak
-# CHECK2-NEXT: Type:
-# CHECK2-NEXT: Other:
-# CHECK2-NEXT: Section: Undefined
-# CHECK2-NEXT: }
-# CHECK2-NEXT: Symbol {
-# CHECK2-NEXT: Name: foo
-# CHECK2-NEXT: Value:
-# CHECK2-NEXT: Size:
-# CHECK2-NEXT: Binding: Global
-# CHECK2-NEXT: Type:
-# CHECK2-NEXT: Other:
-# CHECK2-NEXT: Section: .text
-# CHECK2-NEXT: }
-# CHECK2-NEXT: ]
-
-# CHECK2-NOT: NEEDED
-# CHECK2: NEEDED Shared library: [{{.*}}3.so]
-# CHECK2-NOT: NEEDED
+# RUN: llvm-readobj --dynamic-table --dyn-symbols %t | FileCheck --check-prefix=CHECK %s
.section .text.foo, "ax"
.globl foo
diff --git a/test/ELF/gnu-hash-table.s b/test/ELF/gnu-hash-table.s
index e8fd059..ffbf19f 100644
--- a/test/ELF/gnu-hash-table.s
+++ b/test/ELF/gnu-hash-table.s
@@ -4,30 +4,36 @@
# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %te.s -o %te-i386.o
# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t-i386.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t-x86_64.o
-# RUN: llvm-mc -filetype=obj -triple=powerpc64-pc-linux %s -o %t-ppc64.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t-ppc64le.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t-ppc64.o
# RUN: echo ".global zed; zed:" > %t2.s
# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %t2.s -o %t2-i386.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %t2.s -o %t2-x86_64.o
-# RUN: llvm-mc -filetype=obj -triple=powerpc64-pc-linux %t2.s -o %t2-ppc64.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %t2.s -o %t2-ppc64le.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %t2.s -o %t2-ppc64.o
# RUN: rm -f %t2-i386.a %t2-x86_64.a %t2-ppc64.a
# RUN: llvm-ar rc %t2-i386.a %t2-i386.o
# RUN: llvm-ar rc %t2-x86_64.a %t2-x86_64.o
+# RUN: llvm-ar rc %t2-ppc64le.a %t2-ppc64le.o
# RUN: llvm-ar rc %t2-ppc64.a %t2-ppc64.o
# RUN: echo ".global xyz; xyz:" > %t3.s
# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %t3.s -o %t3-i386.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %t3.s -o %t3-x86_64.o
-# RUN: llvm-mc -filetype=obj -triple=powerpc64-pc-linux %t3.s -o %t3-ppc64.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %t3.s -o %t3-ppc64le.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %t3.s -o %t3-ppc64.o
# RUN: ld.lld -shared %t3-i386.o -o %t3-i386.so
# RUN: ld.lld -shared %t3-x86_64.o -o %t3-x86_64.so
+# RUN: ld.lld -shared %t3-ppc64le.o -o %t3-ppc64le.so
# RUN: ld.lld -shared %t3-ppc64.o -o %t3-ppc64.so
# RUN: ld.lld -shared --hash-style=gnu -o %te-i386.so %te-i386.o
# RUN: ld.lld -shared -hash-style=gnu -o %t-i386.so %t-i386.o %t2-i386.a %t3-i386.so
# RUN: ld.lld -shared -hash-style=gnu -o %t-x86_64.so %t-x86_64.o %t2-x86_64.a %t3-x86_64.so
+# RUN: ld.lld -shared --hash-style both -o %t-ppc64le.so %t-ppc64le.o %t2-ppc64le.a %t3-ppc64le.so
# RUN: ld.lld -shared --hash-style both -o %t-ppc64.so %t-ppc64.o %t2-ppc64.a %t3-ppc64.so
# RUN: llvm-readobj -dyn-symbols -gnu-hash-table %te-i386.so \
@@ -36,6 +42,8 @@
# RUN: | FileCheck %s -check-prefix=I386
# RUN: llvm-readobj -sections -dyn-symbols -gnu-hash-table %t-x86_64.so \
# RUN: | FileCheck %s -check-prefix=X86_64
+# RUN: llvm-readobj -sections -dyn-symbols -gnu-hash-table %t-ppc64le.so \
+# RUN: | FileCheck %s -check-prefix=PPC64
# RUN: llvm-readobj -sections -dyn-symbols -gnu-hash-table %t-ppc64.so \
# RUN: | FileCheck %s -check-prefix=PPC64
diff --git a/test/ELF/gnu-ifunc-dyntags.s b/test/ELF/gnu-ifunc-dyntags.s
index 81bd338..37d46d2 100644
--- a/test/ELF/gnu-ifunc-dyntags.s
+++ b/test/ELF/gnu-ifunc-dyntags.s
@@ -8,7 +8,7 @@
## when there are no other relocations except R_*_IRELATIVE.
# CHECK: Name Size Address
-# CHECK: .rela.plt 00000030 0000000000000210
+# CHECK: .rela.plt 00000030 0000000000000218
# CHECK: .got.plt 00000010 0000000000002000
# TAGS: Relocations [
@@ -19,7 +19,7 @@
# TAGS-NEXT: ]
# TAGS: Tag Type Name/Value
-# TAGS: 0x0000000000000017 JMPREL 0x210
+# TAGS: 0x0000000000000017 JMPREL 0x218
# TAGS: 0x0000000000000002 PLTRELSZ 48
# TAGS: 0x0000000000000003 PLTGOT 0x2000
# TAGS: 0x0000000000000014 PLTREL RELA
diff --git a/test/ELF/gnustack.s b/test/ELF/gnustack.s
index c506fb8..3ab6f16 100644
--- a/test/ELF/gnustack.s
+++ b/test/ELF/gnustack.s
@@ -1,10 +1,15 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
+
# RUN: ld.lld %t1 -z execstack -o %t
# RUN: llvm-readobj --program-headers -s %t | FileCheck --check-prefix=RWX %s
+
# RUN: ld.lld %t1 -o %t
# RUN: llvm-readobj --program-headers -s %t | FileCheck --check-prefix=RW %s
+# RUN: ld.lld %t1 -o %t -z noexecstack
+# RUN: llvm-readobj --program-headers -s %t | FileCheck --check-prefix=RW %s
+
# RW: Type: PT_GNU_STACK
# RW-NEXT: Offset: 0x0
# RW-NEXT: VirtualAddress: 0x0
diff --git a/test/ELF/got32-i386-pie-rw.s b/test/ELF/got32-i386-pie-rw.s
index 0938148..45d2ec1 100644
--- a/test/ELF/got32-i386-pie-rw.s
+++ b/test/ELF/got32-i386-pie-rw.s
@@ -7,8 +7,8 @@
# CHECK: .foobar PROGBITS 00001000
# CHECK: .got PROGBITS [[GOT:[0-9a-z]*]]
-# CHECK: 00001002 00000008 R_386_RELATIVE
-# CHECK: [[GOT]] 00000008 R_386_RELATIVE
+# CHECK-DAG: 00001002 00000008 R_386_RELATIVE
+# CHECK-DAG: [[GOT]] 00000008 R_386_RELATIVE
foo:
.section .foobar, "awx"
diff --git a/test/ELF/help.s b/test/ELF/help.s
index 2554531..aca2ceb 100644
--- a/test/ELF/help.s
+++ b/test/ELF/help.s
@@ -1,5 +1,5 @@
# RUN: ld.lld --help 2>&1 | FileCheck %s
# CHECK: OPTIONS:
-# CHECK: --output=<value> Path to file to write output
-# CHECK: --output <value> Path to file to write output
+# CHECK: --output=<value> Alias for -o
+# CHECK: --output <value> Alias for -o
# CHECK: -o <path> Path to file to write output
diff --git a/test/ELF/i386-merge.s b/test/ELF/i386-merge.s
index 00c9549..91a153e 100644
--- a/test/ELF/i386-merge.s
+++ b/test/ELF/i386-merge.s
@@ -9,7 +9,7 @@
// CHECK-NEXT: SHF_ALLOC
// CHECK-NEXT: SHF_MERGE
// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x114
+// CHECK-NEXT: Address: 0x128
// CHECK-NEXT: Offset:
// CHECK-NEXT: Size:
// CHECK-NEXT: Link:
@@ -35,7 +35,7 @@
// CHECK-NEXT: AddressAlignment: 1
// CHECK-NEXT: EntrySize: 0
// CHECK-NEXT: SectionData (
-// CHECK-NEXT: 0000: 14010000 |
+// CHECK-NEXT: 0000: 28010000 |
// CHECK-NEXT: )
// The content of .data should be the address of .mysec. 14010000 is 0x114 in
diff --git a/test/ELF/i386-reloc-16-large-addend.s b/test/ELF/i386-reloc-16-large-addend.s
new file mode 100644
index 0000000..ceb4862
--- /dev/null
+++ b/test/ELF/i386-reloc-16-large-addend.s
@@ -0,0 +1,12 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t
+# RUN: ld.lld -Ttext 0x7c00 %t -o %t2
+# RUN: llvm-objdump -s %t2 | FileCheck %s
+
+# CHECK: Contents of section .text:
+# CHECK-NEXT: 7c00 b800ff
+
+.code16
+.global _start
+_start:
+ movw $_start+0x8300,%ax
diff --git a/test/ELF/i386-reloc-16.s b/test/ELF/i386-reloc-16.s
index e9d4fbb..33b6c44 100644
--- a/test/ELF/i386-reloc-16.s
+++ b/test/ELF/i386-reloc-16.s
@@ -10,6 +10,6 @@
// CHECK-NEXT: 1000 42
// RUN: not ld.lld -shared %t %t2 -o %t4 2>&1 | FileCheck --check-prefix=ERROR %s
-// ERROR: relocation R_386_16 out of range: 65536 is not in [0, 65535]
+// ERROR: relocation R_386_16 out of range: 65536 is not in [-32768, 32767]
.short foo
diff --git a/test/ELF/i386-reloc-8-large-addend.s b/test/ELF/i386-reloc-8-large-addend.s
new file mode 100644
index 0000000..61d6380
--- /dev/null
+++ b/test/ELF/i386-reloc-8-large-addend.s
@@ -0,0 +1,12 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t
+# RUN: ld.lld -Ttext 0x7c %t -o %t2
+# RUN: llvm-objdump -s %t2 | FileCheck %s
+
+# CHECK: Contents of section .text:
+# CHECK-NEXT: 007c b4ff
+
+.code16
+.global _start
+_start:
+ movb $_start+0x83,%ah
diff --git a/test/ELF/i386-reloc-8.s b/test/ELF/i386-reloc-8.s
index e0e255b..9e9f0cc 100644
--- a/test/ELF/i386-reloc-8.s
+++ b/test/ELF/i386-reloc-8.s
@@ -10,6 +10,6 @@
// CHECK-NEXT: 1000 ff
// RUN: not ld.lld -shared %t %t2 -o %t4 2>&1 | FileCheck --check-prefix=ERROR %s
-// ERROR: relocation R_386_8 out of range: 256 is not in [0, 255]
+// ERROR: relocation R_386_8 out of range: 256 is not in [-128, 127]
.byte foo
diff --git a/test/ELF/i386-retpoline-nopic-linkerscript.s b/test/ELF/i386-retpoline-nopic-linkerscript.s
index 0c7d1fc..88fbfe9 100644
--- a/test/ELF/i386-retpoline-nopic-linkerscript.s
+++ b/test/ELF/i386-retpoline-nopic-linkerscript.s
@@ -14,9 +14,9 @@
// CHECK: Disassembly of section .plt:
// CHECK-NEXT: .plt:
-// CHECK-NEXT: 10: ff 35 fc 00 00 00 pushl 252
+// CHECK-NEXT: 10: ff 35 cc 00 00 00 pushl 204
// CHECK-NEXT: 16: 50 pushl %eax
-// CHECK-NEXT: 17: a1 00 01 00 00 movl 256, %eax
+// CHECK-NEXT: 17: a1 d0 00 00 00 movl 208, %eax
// CHECK-NEXT: 1c: e8 0f 00 00 00 calll 15 <.plt+0x20>
// CHECK-NEXT: 21: f3 90 pause
// CHECK-NEXT: 23: 0f ae e8 lfence
@@ -37,7 +37,7 @@
// CHECK-NEXT: 3e: c3 retl
// CHECK-NEXT: 3f: cc int3
// CHECK-NEXT: 40: 50 pushl %eax
-// CHECK-NEXT: 41: a1 04 01 00 00 movl 260, %eax
+// CHECK-NEXT: 41: a1 d4 00 00 00 movl 212, %eax
// CHECK-NEXT: 46: e8 e5 ff ff ff calll -27 <.plt+0x20>
// CHECK-NEXT: 4b: e9 d1 ff ff ff jmp -47 <.plt+0x11>
// CHECK-NEXT: 50: 68 00 00 00 00 pushl $0
@@ -49,7 +49,7 @@
// CHECK-NEXT: 5e: cc int3
// CHECK-NEXT: 5f: cc int3
// CHECK-NEXT: 60: 50 pushl %eax
-// CHECK-NEXT: 61: a1 08 01 00 00 movl 264, %eax
+// CHECK-NEXT: 61: a1 d8 00 00 00 movl 216, %eax
// CHECK-NEXT: 66: e8 c5 ff ff ff calll -59 <.plt+0x20>
// CHECK-NEXT: 6b: e9 b1 ff ff ff jmp -79 <.plt+0x11>
// CHECK-NEXT: 70: 68 08 00 00 00 pushl $8
diff --git a/test/ELF/i386-retpoline-pic-linkerscript.s b/test/ELF/i386-retpoline-pic-linkerscript.s
index 049e53f..a502f3f 100644
--- a/test/ELF/i386-retpoline-pic-linkerscript.s
+++ b/test/ELF/i386-retpoline-pic-linkerscript.s
@@ -14,9 +14,9 @@
// CHECK: Disassembly of section .plt:
// CHECK-NEXT: .plt:
-// CHECK-NEXT: 10: ff b3 fc 00 00 00 pushl 252(%ebx)
+// CHECK-NEXT: 10: ff b3 cc 00 00 00 pushl 204(%ebx)
// CHECK-NEXT: 16: 50 pushl %eax
-// CHECK-NEXT: 17: 8b 83 00 01 00 00 movl 256(%ebx), %eax
+// CHECK-NEXT: 17: 8b 83 d0 00 00 00 movl 208(%ebx), %eax
// CHECK-NEXT: 1d: e8 0e 00 00 00 calll 14 <.plt+0x20>
// CHECK-NEXT: 22: f3 90 pause
// CHECK-NEXT: 24: 0f ae e8 lfence
@@ -36,7 +36,7 @@
// CHECK-NEXT: 3e: c3 retl
// CHECK-NEXT: 3f: cc int3
// CHECK-NEXT: 40: 50 pushl %eax
-// CHECK-NEXT: 41: 8b 83 04 01 00 00 movl 260(%ebx), %eax
+// CHECK-NEXT: 41: 8b 83 d4 00 00 00 movl 212(%ebx), %eax
// CHECK-NEXT: 47: e8 e4 ff ff ff calll -28 <.plt+0x20>
// CHECK-NEXT: 4c: e9 d1 ff ff ff jmp -47 <.plt+0x12>
// CHECK-NEXT: 51: 68 00 00 00 00 pushl $0
@@ -47,7 +47,7 @@
// CHECK-NEXT: 5e: cc int3
// CHECK-NEXT: 5f: cc int3
// CHECK-NEXT: 60: 50 pushl %eax
-// CHECK-NEXT: 61: 8b 83 08 01 00 00 movl 264(%ebx), %eax
+// CHECK-NEXT: 61: 8b 83 d8 00 00 00 movl 216(%ebx), %eax
// CHECK-NEXT: 67: e8 c4 ff ff ff calll -60 <.plt+0x20>
// CHECK-NEXT: 6c: e9 b1 ff ff ff jmp -79 <.plt+0x12>
// CHECK-NEXT: 71: 68 08 00 00 00 pushl $8
diff --git a/test/ELF/icf-c-identifier.s b/test/ELF/icf-c-identifier.s
new file mode 100644
index 0000000..b1bd934
--- /dev/null
+++ b/test/ELF/icf-c-identifier.s
@@ -0,0 +1,9 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2 --icf=all --print-icf-sections | count 0
+
+.section foo,"ax",@progbits,unique,0
+.byte 42
+
+.section foo,"ax",@progbits,unique,1
+.byte 42
diff --git a/test/ELF/icf-different-output-sections.s b/test/ELF/icf-different-output-sections.s
new file mode 100644
index 0000000..5f44f9b
--- /dev/null
+++ b/test/ELF/icf-different-output-sections.s
@@ -0,0 +1,9 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2 --icf=all --print-icf-sections | count 0
+
+.section .foo,"ax"
+.byte 42
+
+.section .bar,"ax"
+.byte 42
diff --git a/test/ELF/icf-keep-unique.s b/test/ELF/icf-keep-unique.s
new file mode 100644
index 0000000..a6f883f
--- /dev/null
+++ b/test/ELF/icf-keep-unique.s
@@ -0,0 +1,43 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2 --icf=all --print-icf-sections | FileCheck %s
+# RUN: ld.lld %t -o %t2 --keep-unique f2 --keep-unique f4 --keep-unique f5 --icf=all --print-icf-sections 2>&1 | FileCheck %s -check-prefix=CHECK-KEEP
+
+// Base case, expect only .text.f1 to be kept
+// CHECK: selected section {{.*}}:(.text.f1)
+// CHECK-NEXT: removing identical section {{.*}}:(.text.f2)
+// CHECK-NEXT: removing identical section {{.*}}:(.text.f3)
+// CHECK-NEXT: removing identical section {{.*}}:(.text.f4)
+// CHECK-NEXT: removing identical section {{.*}}:(.text.f5)
+
+// With --keep-unique f2, f4 and f5 we expect only f3 and f5 to be removed.
+// f5 is not matched by --keep-unique as it is a local symbol.
+// CHECK-KEEP: warning: could not find symbol f5 to keep unique
+// CHECK-KEEP: selected section {{.*}}:(.text.f1)
+// CHECK-KEEP-NEXT: removing identical section {{.*}}:(.text.f3)
+// CHECK-KEEP-NEXT: removing identical section {{.*}}:(.text.f5)
+ .globl _start, f1, f2, f3, f4
+_start:
+ ret
+
+ .section .text.f1, "ax"
+f1:
+ nop
+
+ .section .text.f2, "ax"
+f2:
+ nop
+
+.section .text.f3, "ax"
+f3:
+ nop
+
+.section .text.f4, "ax"
+f4:
+ nop
+
+# f5 is local, not found by --keep-unique f5
+.section .text.f5, "ax"
+f5:
+ nop
diff --git a/test/ELF/icf-relro.s b/test/ELF/icf-relro.s
new file mode 100644
index 0000000..492c042
--- /dev/null
+++ b/test/ELF/icf-relro.s
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2 --icf=all --ignore-data-address-equality --print-icf-sections | FileCheck %s
+
+# CHECK: selected section {{.*}}:(.data.rel.ro)
+# CHECK: removing identical section {{.*}}:(.data.rel.ro.foo)
+
+.section .data.rel.ro,"aw"
+.quad foo
+
+.section .data.rel.ro.foo,"aw"
+foo:
+.quad foo
diff --git a/test/ELF/ignore-plugin.test b/test/ELF/ignore-plugin.test
new file mode 100644
index 0000000..fcd3fa6
--- /dev/null
+++ b/test/ELF/ignore-plugin.test
@@ -0,0 +1,2 @@
+RUN: not ld.lld --plugin foo 2>&1 | FileCheck %s
+CHECK: no input files
diff --git a/test/ELF/invalid-fde-rel.s b/test/ELF/invalid-fde-rel.s
index f43b9da..f651322 100644
--- a/test/ELF/invalid-fde-rel.s
+++ b/test/ELF/invalid-fde-rel.s
@@ -33,4 +33,4 @@
.long 0x0
.long 0x0
-// CHECK: 1 .eh_frame 00000018
+// CHECK: 1 .eh_frame 0000001c
diff --git a/test/ELF/linkerscript/Inputs/map-file2.s b/test/ELF/linkerscript/Inputs/map-file2.s
new file mode 100644
index 0000000..daf994e
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/map-file2.s
@@ -0,0 +1,19 @@
+.global _start
+_start:
+.global _Z1fi
+_Z1fi:
+.cfi_startproc
+nop
+.cfi_endproc
+
+.section .aaa, "a";
+.quad 1;
+
+.section .bbb, "a";
+.quad 2;
+
+.section .ccc, "a";
+.quad 3;
+
+.section .ddd, "a";
+.quad 4
diff --git a/test/ELF/linkerscript/addr-zero.test b/test/ELF/linkerscript/addr-zero.test
index 77adebc..0133fc0 100644
--- a/test/ELF/linkerscript/addr-zero.test
+++ b/test/ELF/linkerscript/addr-zero.test
@@ -8,7 +8,7 @@
# CHECK: Symbol {
# CHECK: Name: foo
-# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Value: 0x38
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Global
# CHECK-NEXT: Type: None
diff --git a/test/ELF/linkerscript/align-empty.test b/test/ELF/linkerscript/align-empty.test
index deb8268..9f879dd 100644
--- a/test/ELF/linkerscript/align-empty.test
+++ b/test/ELF/linkerscript/align-empty.test
@@ -15,4 +15,6 @@
# CHECK: Sections:
# CHECK-NEXT: Idx Name Size Address
# CHECK-NEXT: 0 00000000 0000000000000000
-# CHECK-NEXT: 1 foo 00000001 0000000000001000
+# CHECK-NEXT: 1 .dynsym 00000018 0000000000000190
+# CHECK-NEXT: 2 .dynstr 00000001 00000000000001a8
+# CHECK-NEXT: 3 foo 00000001 0000000000001000
diff --git a/test/ELF/linkerscript/align-r.test b/test/ELF/linkerscript/align-r.test
new file mode 100644
index 0000000..684ac1e
--- /dev/null
+++ b/test/ELF/linkerscript/align-r.test
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+
+## Check output section ALIGN modifier with -r
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/align.s -o %t1.o
+# RUN: ld.lld -r -o %t2.o --script %s %t1.o
+# RUN: llvm-readelf -s %t2.o | FileCheck %s
+
+# CHECK: Section Headers:
+# CHECK-NEXT: Name Type Address Off Size ES Flg Lk Inf Al
+# CHECK-NEXT: NULL 0000000000000000 000000 000000 00
+# CHECK-NEXT: .aaa PROGBITS 0000000000000000 000040 000008 00 A 0 0 1
+# CHECK-NEXT: .bbb PROGBITS 0000000000000000 001000 000008 00 A 0 0 4096
+# CHECK-NEXT: .ccc PROGBITS 0000000000000000 004000 000008 00 A 0 0 16384
+
+SECTIONS {
+ . = 0x10000;
+ .aaa : { *(.aaa) }
+ .bbb : ALIGN(4096) { *(.bbb) }
+ .ccc : ALIGN(4096 * 4) { *(.ccc) }
+}
diff --git a/test/ELF/linkerscript/assert.s b/test/ELF/linkerscript/assert.s
index 73cc940..100631a 100644
--- a/test/ELF/linkerscript/assert.s
+++ b/test/ELF/linkerscript/assert.s
@@ -30,10 +30,11 @@
# RUN: ld.lld -shared -o %t6 --script %t6.script %t1.o
# RUN: llvm-readobj %t6 > /dev/null
+## Unlike the GNU ld, we accept the ASSERT without the semicolon.
+## It is consistent with how ASSERT can be written outside of the
+## output section declaration.
# RUN: echo "SECTIONS { .foo : { ASSERT(1, \"true\") } }" > %t7.script
-# RUN: not ld.lld -shared -o %t7 --script %t7.script %t1.o > %t.log 2>&1
-# RUN: FileCheck %s -check-prefix=CHECK-SEMI < %t.log
-# CHECK-SEMI: error: {{.*}}.script:1: ; expected, but got }
+# RUN: ld.lld -shared -o %t7 --script %t7.script %t1.o
.section .foo, "a"
.quad 0
diff --git a/test/ELF/linkerscript/dot-is-not-abs.s b/test/ELF/linkerscript/dot-is-not-abs.s
index a93d1c8..1fae25e 100644
--- a/test/ELF/linkerscript/dot-is-not-abs.s
+++ b/test/ELF/linkerscript/dot-is-not-abs.s
@@ -26,7 +26,7 @@
# CHECK-NEXT: SHF_ALLOC
# CHECK-NEXT: SHF_EXECINSTR
# CHECK-NEXT: ]
-# CHECK-NEXT: Address: 0x0
+# CHECK-NEXT: Address: 0x1C
# CHECK-NEXT: Offset:
# CHECK-NEXT: Size: 4
# CHECK-NEXT: Link:
@@ -40,7 +40,7 @@
# CHECK: Symbol {
# CHECK: Name: foo
-# CHECK-NEXT: Value: 0x4
+# CHECK-NEXT: Value: 0x20
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Local
# CHECK-NEXT: Type: None
diff --git a/test/ELF/linkerscript/eh-frame-hdr.s b/test/ELF/linkerscript/eh-frame-hdr.s
index 02bc3ea..a7892b2 100644
--- a/test/ELF/linkerscript/eh-frame-hdr.s
+++ b/test/ELF/linkerscript/eh-frame-hdr.s
@@ -4,7 +4,7 @@
# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t
# RUN: llvm-objdump -s -section=".eh_frame_hdr" %t1 | FileCheck %s
-# CHECK: 011b033b 14000000 01000000 49000000
+# CHECK: 011b033b 14000000 01000000 4d000000
# CHECK-NEXT: 30000000
.global _start
diff --git a/test/ELF/linkerscript/emit-reloc.s b/test/ELF/linkerscript/emit-reloc.s
index 2fe127a..43ab4e8 100644
--- a/test/ELF/linkerscript/emit-reloc.s
+++ b/test/ELF/linkerscript/emit-reloc.s
@@ -9,9 +9,9 @@
# CHECK: Relocations [
# CHECK-NEXT: Section ({{.*}}) .rela.dyn {
-# CHECK-NEXT: 0x66 R_X86_64_64 .foo 0x0
+# CHECK-NEXT: 0x68 R_X86_64_64 .foo 0x0
# CHECK-NEXT: }
# CHECK-NEXT: Section ({{.*}}) .rela.data {
-# CHECK-NEXT: 0x66 R_X86_64_64 .foo 0x0
+# CHECK-NEXT: 0x68 R_X86_64_64 .foo 0x0
# CHECK-NEXT: }
# CHECK-NEXT: ]
diff --git a/test/ELF/linkerscript/empty-section-size.test b/test/ELF/linkerscript/empty-section-size.test
new file mode 100644
index 0000000..665ddf1
--- /dev/null
+++ b/test/ELF/linkerscript/empty-section-size.test
@@ -0,0 +1,17 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o
+# RUN: ld.lld %t.o --script %s -o %t1
+# RUN: llvm-readobj -symbols %t1 | FileCheck %s
+
+## We had a bug when LLD increased the size of the output section even
+## if it was empty. That happened because of empty synthetic sections included.
+## Here we check that size of empty output section is zero.
+
+# CHECK: Name: foo
+# CHECK-NEXT: Value: 0x0
+
+SECTIONS {
+ . = 0x1000;
+ .bss : { *(.bss*) *(COMMON) }
+ foo = SIZEOF(.bss);
+}
diff --git a/test/ELF/linkerscript/expr-sections.test b/test/ELF/linkerscript/expr-sections.test
index a9219e6..f7d541d 100644
--- a/test/ELF/linkerscript/expr-sections.test
+++ b/test/ELF/linkerscript/expr-sections.test
@@ -13,11 +13,11 @@
}
};
-# CHECK: 1 .text 00000000 0000000000000004 TEXT DATA
+# CHECK: 3 .text 00000000 00000000000000d0 TEXT DATA
-# CHECK: 0000000000000005 .text 00000000 foo1
-# CHECK: 0000000000000005 .text 00000000 bar1
+# CHECK: 00000000000000d1 .text 00000000 foo1
+# CHECK: 00000000000000d1 .text 00000000 bar1
# CHECK: 0000000000000000 .text 00000000 foo2
# CHECK: 0000000000000000 .text 00000000 bar2
-# CHECK: 0000000000000005 .text 00000000 foo3
-# CHECK: 0000000000000005 .text 00000000 bar3
+# CHECK: 00000000000000d1 .text 00000000 foo3
+# CHECK: 00000000000000d1 .text 00000000 bar3
diff --git a/test/ELF/linkerscript/i386-sections-max-va-overflow.s b/test/ELF/linkerscript/i386-sections-max-va-overflow.s
new file mode 100644
index 0000000..80c4fb5
--- /dev/null
+++ b/test/ELF/linkerscript/i386-sections-max-va-overflow.s
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t.o
+
+# RUN: echo "SECTIONS { . = 0xfffffff1;" > %t.script
+# RUN: echo " .bar : { *(.bar*) } }" >> %t.script
+# RUN: not ld.lld -o %t.so --script %t.script %t.o 2>&1 | FileCheck %s -check-prefix=ERR
+
+## .bar section has data in [0xfffffff1, 0xfffffff1 + 0x10] == [0xffffff1, 0x1].
+## Check we can catch this overflow.
+# ERR: error: section .bar at 0xFFFFFFF1 of size 0x10 exceeds available address space
+
+.section .bar,"ax",@progbits
+.zero 0x10
diff --git a/test/ELF/linkerscript/implicit-program-header.test b/test/ELF/linkerscript/implicit-program-header.test
index ea5c873..06b6161 100644
--- a/test/ELF/linkerscript/implicit-program-header.test
+++ b/test/ELF/linkerscript/implicit-program-header.test
@@ -8,8 +8,8 @@
# RUN: llvm-readobj -elf-output-style=GNU -l %t1 | FileCheck %s
# CHECK: Segment Sections...
-# CHECK-NEXT: 00 .text .dynsym .hash .dynstr .dynamic
-# CHECK-NEXT: 01 .bar .foo
+# CHECK-NEXT: 00 .text .hash .dynamic
+# CHECK-NEXT: 01 .bar .dynsym .dynstr .foo
PHDRS {
ph_write PT_LOAD FLAGS(2);
diff --git a/test/ELF/linkerscript/locationcountererr2.s b/test/ELF/linkerscript/locationcountererr2.s
index 8968f67..7e7bd72 100644
--- a/test/ELF/linkerscript/locationcountererr2.s
+++ b/test/ELF/linkerscript/locationcountererr2.s
@@ -1,11 +1,11 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
# RUN: echo "SECTIONS {" > %t.script
-# RUN: echo ". = 0x20; . = 0x10; .text : {} }" >> %t.script
+# RUN: echo ". = 0x150; . = 0x10; .text : {} }" >> %t.script
# RUN: ld.lld %t.o --script %t.script -o %t -shared
# RUN: llvm-objdump -section-headers %t | FileCheck %s
# CHECK: Idx Name Size Address
-# CHECK: 1 .text 00000000 0000000000000010
+# CHECK: 3 .text 00000000 0000000000000010
# RUN: echo "SECTIONS { . = 0x20; . = ASSERT(0x1, "foo"); }" > %t2.script
# RUN: ld.lld %t.o --script %t2.script -o %t -shared
diff --git a/test/ELF/linkerscript/map-file.test b/test/ELF/linkerscript/map-file.test
index 5ab3d01..540b8d4 100644
--- a/test/ELF/linkerscript/map-file.test
+++ b/test/ELF/linkerscript/map-file.test
@@ -1,6 +1,6 @@
# REQUIRES: x86
-# RUN: echo '.section .foo.1, "a"; .quad 1' > %t.s
+# RUN: echo '.quad sym3; .quad sym4; .section .foo.1, "a"; .quad 1' > %t.s
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t.s -o %t.o
# RUN: ld.lld -o %t %t.o -Map=%t.map --script %s
@@ -13,25 +13,48 @@
SHORT(0x1122)
LONG(0x11223344)
QUAD(0x1122334455667788)
+ PROVIDE_HIDDEN(sym4 = .);
. += 0x1000;
*(.foo.1)
+ PROVIDE(unused1 = 0xff);
+ HIDDEN(sym6 = .);
. += 0x123 *
(1 + 1);
foo = .;
bar = 0x42 - 0x26;
}
+ sym1 = .;
+ . += 0x500;
+ sym2 = .;
+ PROVIDE(unused2 = 0xff);
+ PROVIDE(sym3 = 42);
}
-# CHECK: Address Size Align Out In Symbol
-# CHECK-NEXT: 0000000000001000 000000000000125d 1 .foo
-# CHECK-NEXT: 0000000000001000 0000000000000001 1 BYTE ( 0x11 )
-# CHECK-NEXT: 0000000000001001 0000000000000002 1 SHORT ( 0x1122 )
-# CHECK-NEXT: 0000000000001003 0000000000000004 1 LONG ( 0x11223344 )
-# CHECK-NEXT: 0000000000001007 0000000000000008 1 QUAD ( 0x1122334455667788 )
-# CHECK-NEXT: 000000000000100f 0000000000001000 1 . += 0x1000
-# CHECK-NEXT: 000000000000200f 0000000000000008 1 {{.*}}{{/|\\}}map-file.test.tmp.o:(.foo.1)
-# CHECK-NEXT: 0000000000002017 0000000000000246 1 . += 0x123 * ( 1 + 1 )
-# CHECK-NEXT: 000000000000225d 0000000000000000 1 foo = .
-# CHECK-NEXT: 000000000000225d 0000000000000000 1 bar = 0x42 - 0x26
-# CHECK-NEXT: 0000000000002260 0000000000000000 4 .text
-# CHECK-NEXT: 0000000000002260 0000000000000000 4 {{.*}}{{/|\\}}map-file.test.tmp.o:(.text)
+# CHECK: VMA LMA Size Align Out In Symbol
+# CHECK-NEXT: 0 0 1000 1 . = 0x1000
+# CHECK-NEXT: 1000 1000 125d 1 .foo
+# CHECK-NEXT: 1000 1000 1 1 BYTE ( 0x11 )
+# CHECK-NEXT: 1001 1001 2 1 SHORT ( 0x1122 )
+# CHECK-NEXT: 1003 1003 4 1 LONG ( 0x11223344 )
+# CHECK-NEXT: 1007 1007 8 1 QUAD ( 0x1122334455667788 )
+# CHECK-NEXT: 100f 100f 0 1 PROVIDE_HIDDEN ( sym4 = . )
+# CHECK-NEXT: 100f 100f 1000 1 . += 0x1000
+# CHECK-NEXT: 200f 200f 8 1 {{.*}}{{/|\\}}map-file.test.tmp.o:(.foo.1)
+# CHECK-NEXT: 2017 2017 0 1 HIDDEN ( sym6 = . )
+# CHECK-NEXT: 2017 2017 246 1 . += 0x123 * ( 1 + 1 )
+# CHECK-NEXT: 225d 225d 0 1 foo = .
+# CHECK-NEXT: 225d 225d 0 1 bar = 0x42 - 0x26
+# CHECK-NEXT: 225d 0 0 1 sym1 = .
+# CHECK-NEXT: 225d 0 500 1 . += 0x500
+# CHECK-NEXT: 275d 0 0 1 sym2 = .
+# CHECK-NEXT: 275d 0 0 1 PROVIDE ( sym3 = 42 )
+# CHECK-NEXT: 2760 2760 10 4 .text
+# CHECK-NEXT: 2760 2760 10 4 {{.*}}{{/|\\}}map-file.test.tmp.o:(.text)
+# CHECK-NEXT: 0 0 8 1 .comment
+# CHECK-NEXT: 0 0 8 1 <internal>:(.comment)
+# CHECK-NEXT: 0 0 c0 8 .symtab
+# CHECK-NEXT: 0 0 c0 8 <internal>:(.symtab)
+# CHECK-NEXT: 0 0 2f 1 .shstrtab
+# CHECK-NEXT: 0 0 2f 1 <internal>:(.shstrtab)
+# CHECK-NEXT: 0 0 22 1 .strtab
+# CHECK-NEXT: 0 0 22 1 <internal>:(.strtab)
diff --git a/test/ELF/linkerscript/map-file2.test b/test/ELF/linkerscript/map-file2.test
new file mode 100644
index 0000000..7c4689c
--- /dev/null
+++ b/test/ELF/linkerscript/map-file2.test
@@ -0,0 +1,44 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/map-file2.s -o %t.o
+# RUN: ld.lld -o %t %t.o -Map=%t.map --script %s
+# RUN: FileCheck -strict-whitespace %s < %t.map
+
+SECTIONS {
+ . = 0x1000;
+ .aaa : { *(.aaa.*) }
+ .bbb : AT(0x2000) { *(.bbb.*) }
+ .ccc : AT(0x3000) { *(.ccc.*) }
+ .ddd : {
+ BYTE(0x11)
+ . += 0x100;
+ *(.ddd.*)
+ }
+ .text : { *(.text.*) }
+}
+
+# CHECK: VMA LMA Size Align Out In Symbol
+# CHECK-NEXT: 0 0 1000 1 . = 0x1000
+# CHECK-NEXT: 1000 1000 8 1 .aaa
+# CHECK-NEXT: 1000 1000 8 1 {{.*}}{{/|\\}}map-file2.test.tmp.o:(.aaa)
+# CHECK-NEXT: 1008 2000 8 1 .bbb
+# CHECK-NEXT: 1008 2000 8 1 {{.*}}{{/|\\}}map-file2.test.tmp.o:(.bbb)
+# CHECK-NEXT: 1010 3000 8 1 .ccc
+# CHECK-NEXT: 1010 3000 8 1 {{.*}}{{/|\\}}map-file2.test.tmp.o:(.ccc)
+# CHECK-NEXT: 1018 3008 109 1 .ddd
+# CHECK-NEXT: 1018 3008 1 1 BYTE ( 0x11 )
+# CHECK-NEXT: 1019 3009 100 1 . += 0x100
+# CHECK-NEXT: 1119 3109 8 1 {{.*}}{{/|\\}}map-file2.test.tmp.o:(.ddd)
+# CHECK-NEXT: 1124 3114 1 4 .text
+# CHECK-NEXT: 1124 3114 1 4 {{.*}}{{/|\\}}map-file2.test.tmp.o:(.text)
+# CHECK-NEXT: 1124 3114 0 1 f(int)
+# CHECK-NEXT: 1124 3114 0 1 _start
+# CHECK-NEXT: 1128 3118 34 8 .eh_frame
+# CHECK-NEXT: 1128 3118 30 1 {{.*}}{{/|\\}}map-file2.test.tmp.o:(.eh_frame+0x0)
+# CHECK-NEXT: 0 0 8 1 .comment
+# CHECK-NEXT: 0 0 8 1 <internal>:(.comment)
+# CHECK-NEXT: 0 0 48 8 .symtab
+# CHECK-NEXT: 0 0 48 8 <internal>:(.symtab)
+# CHECK-NEXT: 0 0 48 1 .shstrtab
+# CHECK-NEXT: 0 0 48 1 <internal>:(.shstrtab)
+# CHECK-NEXT: 0 0 e 1 .strtab
+# CHECK-NEXT: 0 0 e 1 <internal>:(.strtab)
diff --git a/test/ELF/linkerscript/merge-sections-syms.s b/test/ELF/linkerscript/merge-sections-syms.s
index 713d334..37b25c3 100644
--- a/test/ELF/linkerscript/merge-sections-syms.s
+++ b/test/ELF/linkerscript/merge-sections-syms.s
@@ -20,7 +20,7 @@
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: A
-# CHECK-NEXT: Value: 0x195
+# CHECK-NEXT: Value: 0x1E2
# CHECK-NEXT: Size:
# CHECK-NEXT: Binding:
# CHECK-NEXT: Type:
@@ -29,7 +29,7 @@
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: B
-# CHECK-NEXT: Value: 0x196
+# CHECK-NEXT: Value: 0x1E3
# CHECK-NEXT: Size:
# CHECK-NEXT: Binding:
# CHECK-NEXT: Type:
diff --git a/test/ELF/linkerscript/merge-sections.s b/test/ELF/linkerscript/merge-sections.s
index 2709bda..e76e2cd 100644
--- a/test/ELF/linkerscript/merge-sections.s
+++ b/test/ELF/linkerscript/merge-sections.s
@@ -29,7 +29,7 @@
# CHECK: Name: end
# 0x19E = begin + sizeof(.foo) = 0x190 + 0xE
-# CHECK-NEXT: Value: 0x19E
+# CHECK-NEXT: Value: 0x1F2
# Check that we don't crash with --gc-sections
# RUN: ld.lld --gc-sections -o %t2 --script %t.script %t -shared
diff --git a/test/ELF/linkerscript/no-space.s b/test/ELF/linkerscript/no-space.s
index 21a38e4..a423a5e 100644
--- a/test/ELF/linkerscript/no-space.s
+++ b/test/ELF/linkerscript/no-space.s
@@ -1,11 +1,11 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: echo "SECTIONS {foo 0 : {*(foo*)} }" > %t.script
+# RUN: echo "SECTIONS {foo 0 : {*(foo*)} .dynsym : {*(.dynsym)} .dynstr : {*(.dynstr)} }" > %t.script
# RUN: ld.lld --hash-style=sysv -o %t --script %t.script %t.o -shared
# RUN: llvm-readobj -elf-output-style=GNU -l %t | FileCheck %s
-# RUN: echo "SECTIONS {foo : {*(foo*)} }" > %t.script
+# RUN: echo "SECTIONS {foo : {*(foo*)} .dynsym : { *(.dynsym) } .dynstr : { *(.dynstr) } }" > %t.script
# RUN: ld.lld --hash-style=sysv -o %t --script %t.script %t.o -shared
# RUN: llvm-readobj -elf-output-style=GNU -l %t | FileCheck %s
@@ -18,7 +18,7 @@
# CHECK: Section to Segment mapping:
# CHECK-NEXT: Segment Sections...
-# CHECK-NEXT: 00 foo .text .dynsym .hash .dynstr
+# CHECK-NEXT: 00 foo .text .hash .dynsym .dynstr
.section foo, "a"
.quad 0
diff --git a/test/ELF/linkerscript/noload.s b/test/ELF/linkerscript/noload.s
index 28be55d..bd49160 100644
--- a/test/ELF/linkerscript/noload.s
+++ b/test/ELF/linkerscript/noload.s
@@ -2,12 +2,13 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
# RUN: echo "SECTIONS { \
# RUN: .data_noload_a (NOLOAD) : { *(.data_noload_a) } \
-# RUN: .data_noload_b (0x10000) (NOLOAD) : { *(.data_noload_b) } };" > %t.script
+# RUN: .data_noload_b (0x10000) (NOLOAD) : { *(.data_noload_b) } \
+# RUN: .text (0x20000) : { *(.text) } };" > %t.script
# RUN: ld.lld -o %t --script %t.script %t.o
-# RUN: llvm-readobj --symbols -sections %t | FileCheck %s
+# RUN: llvm-readobj -sections -program-headers %t | FileCheck %s
# CHECK: Section {
-# CHECK: Index: 2
+# CHECK: Index: 1
# CHECK-NEXT: Name: .data_noload_a
# CHECK-NEXT: Type: SHT_NOBITS
# CHECK-NEXT: Flags [
@@ -15,7 +16,7 @@
# CHECK-NEXT: SHF_WRITE
# CHECK-NEXT: ]
# CHECK-NEXT: Address: 0x0
-# CHECK-NEXT: Offset: 0x1000
+# CHECK-NEXT: Offset: 0xE8
# CHECK-NEXT: Size: 4096
# CHECK-NEXT: Link: 0
# CHECK-NEXT: Info: 0
@@ -23,7 +24,7 @@
# CHECK-NEXT: EntrySize: 0
# CHECK-NEXT: }
# CHECK-NEXT: Section {
-# CHECK-NEXT: Index: 3
+# CHECK-NEXT: Index: 2
# CHECK-NEXT: Name: .data_noload_b
# CHECK-NEXT: Type: SHT_NOBITS
# CHECK-NEXT: Flags [
@@ -31,13 +32,29 @@
# CHECK-NEXT: SHF_WRITE
# CHECK-NEXT: ]
# CHECK-NEXT: Address: 0x10000
-# CHECK-NEXT: Offset: 0x1000
+# CHECK-NEXT: Offset: 0xE8
# CHECK-NEXT: Size: 4096
# CHECK-NEXT: Link: 0
# CHECK-NEXT: Info: 0
# CHECK-NEXT: AddressAlignment: 1
# CHECK-NEXT: EntrySize: 0
# CHECK-NEXT: }
+# CHECK: ProgramHeader {
+# CHECK-NEXT: Type: PT_LOAD (0x1)
+# CHECK-NEXT: Offset: 0x1000
+# CHECK-NEXT: VirtualAddress: 0x20000
+# CHECK-NEXT: PhysicalAddress: 0x20000
+# CHECK-NEXT: FileSize: 1
+# CHECK-NEXT: MemSize: 1
+# CHECK-NEXT: Flags [ (0x5)
+# CHECK-NEXT: PF_R (0x4)
+# CHECK-NEXT: PF_X (0x1)
+# CHECK-NEXT: ]
+# CHECK-NEXT: Alignment: 4096
+# CHECK-NEXT: }
+
+.section .text,"ax",@progbits
+ nop
.section .data_noload_a,"aw",@progbits
.zero 4096
diff --git a/test/ELF/linkerscript/non-absolute.s b/test/ELF/linkerscript/non-absolute.s
index a0e9e7d..6e8d3e6 100644
--- a/test/ELF/linkerscript/non-absolute.s
+++ b/test/ELF/linkerscript/non-absolute.s
@@ -7,7 +7,7 @@
# DUMP: Disassembly of section .text:
# DUMP-NEXT: foo:
-# DUMP-NEXT: 0: {{.*}} -21(%rip), %eax
+# DUMP-NEXT: 50: {{.*}} -101(%rip), %eax
# SYMBOL: Symbol {
# SYMBOL: Name: B
@@ -18,7 +18,7 @@
# SYMBOL-NEXT: Other [
# SYMBOL-NEXT: STV_HIDDEN
# SYMBOL-NEXT: ]
-# SYMBOL-NEXT: Section: .text
+# SYMBOL-NEXT: Section: .dynsym
# SYMBOL-NEXT: }
.text
diff --git a/test/ELF/linkerscript/non-absolute2.test b/test/ELF/linkerscript/non-absolute2.test
index fa9e0e4..8935602 100644
--- a/test/ELF/linkerscript/non-absolute2.test
+++ b/test/ELF/linkerscript/non-absolute2.test
@@ -9,8 +9,10 @@
}
# CHECK: Sections:
-# CHECK-NEXT: Idx Name Size Address
-# CHECK-NEXT: 0 00000000 0000000000000000
-# CHECK-NEXT: 1 .text 00000000 0000000000001000
+# CHECK-NEXT: Idx Name Size Address Type
+# CHECK-NEXT: 0 00000000 0000000000000000
+# CHECK-NEXT: 1 .dynsym 00000030 0000000000001000
+# CHECK-NEXT: 2 .dynstr 00000003 0000000000001030
+# CHECK-NEXT: 3 .text 00000000 0000000000001034
-# CHECK: 0000000000000001 .text 00000000 A
+# CHECK: 0000000000000001 .dynsym 00000000 A
diff --git a/test/ELF/linkerscript/non-alloc.s b/test/ELF/linkerscript/non-alloc.s
index 3257cb9..a40d29d 100644
--- a/test/ELF/linkerscript/non-alloc.s
+++ b/test/ELF/linkerscript/non-alloc.s
@@ -15,7 +15,7 @@
# CHECK: Section to Segment mapping:
# CHECK-NEXT: Segment Sections...
-# CHECK-NEXT: 00 .text .dynsym .hash .dynstr
+# CHECK-NEXT: 00 .dynsym .dynstr .text .hash
# CHECK-NEXT: 01 .dynamic
nop
diff --git a/test/ELF/linkerscript/orphan-first-cmd.test b/test/ELF/linkerscript/orphan-first-cmd.test
index 6ef473b..31bff59 100644
--- a/test/ELF/linkerscript/orphan-first-cmd.test
+++ b/test/ELF/linkerscript/orphan-first-cmd.test
@@ -17,4 +17,4 @@
# CHECK-NEXT: SHF_ALLOC
# CHECK-NEXT: SHF_EXECINSTR
# CHECK-NEXT: ]
-# CHECK-NEXT: Address: 0x1000
+# CHECK-NEXT: Address: 0x1038
diff --git a/test/ELF/linkerscript/out-of-order.s b/test/ELF/linkerscript/out-of-order.s
index c43df43..c76604a 100644
--- a/test/ELF/linkerscript/out-of-order.s
+++ b/test/ELF/linkerscript/out-of-order.s
@@ -1,19 +1,37 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-linux %s -o %t.o
-# RUN: echo "SECTIONS { .data 0x4000 : { *(.data) } .text 0x2000 : { *(.text) } }" > %t.script
+# RUN: echo "SECTIONS { .data 0x4000 : {*(.data)} .dynsym 0x2000 : {*(.dynsym)} .dynstr : {*(.dynstr)} }" > %t.script
# RUN: ld.lld --hash-style=sysv -o %t.so --script %t.script %t.o -shared
# RUN: llvm-objdump -section-headers %t.so | FileCheck %s
+# Note: how the layout is done:
+# we need to layout 2 segments, each contains sections:
+# seg1: .data .dynamic
+# seg2: .dynsym .dynstr .text .hash
+# for each segment, we start from the first section, regardless
+# whether it is an orphan or not (sections that are not listed in the
+# linkerscript are orphans):
+# for seg1, we assign address: .data(0x4000), .dynamic(0x4008)
+# for seg2, we assign address: .dynsym(0x2000), .dynstr(0x2018) ...
+# .dynsym is not an orphan, so we take address from script, we assign
+# .dynstr current address cursor, which is the end # of .dynsym and so
+# on for later sections.
+
+# Also note, it is absolutely *illegal* to have section addresses of
+# the same segment in none-increasing order, authors of linker scripts
+# must take responsibility to make sure this does not happen.
+
# CHECK: Sections:
# CHECK-NEXT: Idx Name Size Address Type
# CHECK-NEXT: 0 00000000 0000000000000000
-# CHECK-NEXT: 1 .data 00000008 0000000000004000 DATA
+# CHECK-NEXT: 1 .data 00000008 0000000000004000
# CHECK-NEXT: 2 .dynamic 00000060 0000000000004008
-# CHECK-NEXT: 3 .text 00000008 0000000000002000 TEXT DATA
-# CHECK-NEXT: 4 .dynsym 00000018 0000000000002008
-# CHECK-NEXT: 5 .hash 00000010 0000000000002020
-# CHECK-NEXT: 6 .dynstr 00000001 0000000000002030
+# CHECK-NEXT: 3 .dynsym 00000018 0000000000002000
+# CHECK-NEXT: 4 .dynstr 00000001 0000000000002018
+# CHECK-NEXT: 5 .text 00000008 000000000000201c
+# CHECK-NEXT: 6 .hash 00000010 0000000000002024
.quad 0
.data
.quad 0
+
diff --git a/test/ELF/linkerscript/output-too-large.s b/test/ELF/linkerscript/output-too-large.s
index c892a88..5b9c04a 100644
--- a/test/ELF/linkerscript/output-too-large.s
+++ b/test/ELF/linkerscript/output-too-large.s
@@ -1,7 +1,7 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
# RUN: echo "SECTIONS { .text : { . = 0xffffffff; *(.text*); } }" > %t.script
-# RUN: not ld.lld --script %t.script %t.o -o %t 2>&1 | FileCheck %s
+# RUN: not ld.lld --no-check-sections --script %t.script %t.o -o %t 2>&1 | FileCheck %s
# CHECK: error: output file too large
.global _start
diff --git a/test/ELF/linkerscript/overlapping-sections.s b/test/ELF/linkerscript/overlapping-sections.s
index 0b7b741..98fa374 100644
--- a/test/ELF/linkerscript/overlapping-sections.s
+++ b/test/ELF/linkerscript/overlapping-sections.s
@@ -23,7 +23,7 @@
# BAD-LMA: .sec2 PROGBITS 0000000000008800 002800 000100 00 WA 0 0 1
# BAD-LMA-LABEL: Program Headers:
# BAD-LMA-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
-# BAD-LMA-NEXT: LOAD 0x001000 0x0000000000000000 0x0000000000000000 0x0000fd 0x0000fd R E 0x1000
+# BAD-LMA-NEXT: LOAD 0x001000 0x0000000000000000 0x0000000000000000 0x000104 0x000104 R E 0x1000
# BAD-LMA-NEXT: LOAD 0x002000 0x0000000000008000 0x0000000000008000 0x000100 0x000100 RW 0x1000
# BAD-LMA-NEXT: LOAD 0x002800 0x0000000000008800 0x0000000000008080 0x000170 0x000170 RW 0x1000
# BAD-LMA-LABEL: Section to Segment mapping:
@@ -49,7 +49,7 @@
# BAD-VADDR: .sec2 PROGBITS 0000000000008020 003020 000100 00 WA 0 0 1
# BAD-VADDR-LABEL: Program Headers:
# BAD-VADDR-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
-# BAD-VADDR-NEXT: LOAD 0x001000 0x0000000000000000 0x0000000000000000 0x0000fd 0x0000fd R E 0x1000
+# BAD-VADDR-NEXT: LOAD 0x001000 0x0000000000000000 0x0000000000000000 0x000104 0x000104 R E 0x1000
# BAD-VADDR-NEXT: LOAD 0x002000 0x0000000000008000 0x0000000000008000 0x000100 0x000100 RW 0x1000
# BAD-VADDR-NEXT: LOAD 0x003020 0x0000000000008020 0x0000000000008800 0x000170 0x000170 RW 0x1000
# BAD-VADDR-LABEL: Section to Segment mapping:
@@ -97,7 +97,7 @@
# BAD-BOTH: .sec2 PROGBITS 0000000000008040 002040 000100 00 WA 0 0 1
# BAD-BOTH-LABEL: Program Headers:
# BAD-BOTH-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
-# BAD-BOTH-NEXT: LOAD 0x001000 0x0000000000000000 0x0000000000000000 0x0000fd 0x0000fd R E 0x1000
+# BAD-BOTH-NEXT: LOAD 0x001000 0x0000000000000000 0x0000000000000000 0x000104 0x000104 R E 0x1000
# BAD-BOTH-NEXT: LOAD 0x002000 0x0000000000008000 0x0000000000008000 0x0001b0 0x0001b0 RW 0x1000
# BAD-BOTH-LABEL: Section to Segment mapping:
# BAD-BOTH: 01 .sec1 .sec2 .dynamic
diff --git a/test/ELF/linkerscript/section-metadata2.s b/test/ELF/linkerscript/section-metadata2.s
new file mode 100644
index 0000000..6302492
--- /dev/null
+++ b/test/ELF/linkerscript/section-metadata2.s
@@ -0,0 +1,37 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { .text : { *(.text.*) } }" > %t.script
+
+# RUN: echo "_bar" > %t.ord
+# RUN: echo "_foo" >> %t.ord
+# RUN: ld.lld --symbol-ordering-file %t.ord -o %t --script %t.script %t.o
+# RUN: llvm-objdump -s %t | FileCheck %s
+
+# CHECK: Contents of section .text:
+# CHECK-NEXT: 02000000 00000000 01000000 00000000
+# CHECK: Contents of section .rodata:
+# CHECK-NEXT: 02000000 00000000 01000000 00000000
+
+# RUN: echo "_foo" > %t.ord
+# RUN: echo "_bar" >> %t.ord
+# RUN: ld.lld --symbol-ordering-file %t.ord -o %t --script %t.script %t.o
+# RUN: llvm-objdump -s %t | FileCheck %s --check-prefix=INV
+
+# INV: Contents of section .text:
+# INV-NEXT: 01000000 00000000 02000000 00000000
+# INV: Contents of section .rodata:
+# INV-NEXT: 01000000 00000000 02000000 00000000
+
+.section .text.foo,"a",@progbits
+_foo:
+.quad 1
+
+.section .text.bar,"a",@progbits
+_bar:
+.quad 2
+
+.section .rodata.foo,"ao",@progbits,.text.foo
+.quad 1
+
+.section .rodata.bar,"ao",@progbits,.text.bar
+.quad 2
diff --git a/test/ELF/linkerscript/sections-max-va-overflow.s b/test/ELF/linkerscript/sections-max-va-overflow.s
new file mode 100644
index 0000000..e8fcd8d
--- /dev/null
+++ b/test/ELF/linkerscript/sections-max-va-overflow.s
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+
+# RUN: echo "SECTIONS { . = 0xfffffffffffffff1;" > %t.script
+# RUN: echo " .bar : { *(.bar*) } }" >> %t.script
+# RUN: not ld.lld -o %t.so --script %t.script %t.o 2>&1 | FileCheck %s -check-prefix=ERR
+
+## .bar section has data in [0xfffffffffffffff1, 0xfffffffffffffff1 + 0x10] ==
+## [0xfffffffffffffff1, 0x1]. Check we can catch this overflow.
+# ERR: error: section .bar at 0xFFFFFFFFFFFFFFF1 of size 0x10 exceeds available address space
+
+.section .bar,"ax",@progbits
+.zero 0x10
diff --git a/test/ELF/linkerscript/sections-sort.s b/test/ELF/linkerscript/sections-sort.s
index 99bbbea..dd93f5a 100644
--- a/test/ELF/linkerscript/sections-sort.s
+++ b/test/ELF/linkerscript/sections-sort.s
@@ -15,11 +15,11 @@
# CHECK: Id
# CHECK-NEXT: 0
-# CHECK-NEXT: 1 .text
-# CHECK-NEXT: 2 foo
-# CHECK-NEXT: 3 .dynsym
-# CHECK-NEXT: 4 .hash
-# CHECK-NEXT: 5 .dynstr
+# CHECK-NEXT: 1 .dynsym
+# CHECK-NEXT: 2 .dynstr
+# CHECK-NEXT: 3 .text
+# CHECK-NEXT: 4 foo
+# CHECK-NEXT: 5 .hash
# CHECK-NEXT: 6 .dynamic
# CHECK-NEXT: 7 .comment
# CHECK-NEXT: 8 .symtab
diff --git a/test/ELF/linkerscript/sort-non-script.s b/test/ELF/linkerscript/sort-non-script.s
index 4611b18..563843c 100644
--- a/test/ELF/linkerscript/sort-non-script.s
+++ b/test/ELF/linkerscript/sort-non-script.s
@@ -5,10 +5,10 @@
# RUN: ld.lld --hash-style=sysv -o %t1 --script %t.script %t -shared
# RUN: llvm-readobj -elf-output-style=GNU -s %t1 | FileCheck %s
-# CHECK: .text {{.*}} AX
-# CHECK-NEXT: .dynsym {{.*}} A
-# CHECK-NEXT: .hash {{.*}} A
+# CHECK: .dynsym {{.*}} A
# CHECK-NEXT: .dynstr {{.*}} A
+# CHECK-NEXT: .text {{.*}} AX
+# CHECK-NEXT: .hash {{.*}} A
# CHECK-NEXT: foo {{.*}} WA
# CHECK-NEXT: .dynamic {{.*}} WA
diff --git a/test/ELF/linkerscript/symbol-only.test b/test/ELF/linkerscript/symbol-only.test
index e2123fb..6763423 100644
--- a/test/ELF/linkerscript/symbol-only.test
+++ b/test/ELF/linkerscript/symbol-only.test
@@ -15,6 +15,8 @@
# CHECK-NEXT: Idx Name Size Address
# CHECK-NEXT: 0 00000000 0000000000000000
# CHECK: abc 00000000 [[ADDR:[0-9a-f]*]] BSS
+# CHECK-NEXT: .dynsym 00000030 0000000000000190
+# CHECK-NEXT: .dynstr 00000005 00000000000001c0
# CHECK-NEXT: bar 00000000 0000000000001000 DATA
# CHECK: SYMBOL TABLE:
diff --git a/test/ELF/linkerscript/symbol-ordering-file2.s b/test/ELF/linkerscript/symbol-ordering-file2.s
new file mode 100644
index 0000000..31746ae
--- /dev/null
+++ b/test/ELF/linkerscript/symbol-ordering-file2.s
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+## Check we do not crash when trying to order linker script symbol.
+
+# RUN: echo "bar" > %t.ord
+# RUN: echo "SECTIONS { bar = 1; }" > %t.script
+# RUN: ld.lld --symbol-ordering-file %t.ord %t.o --script %t.script \
+# RUN: -o %t.out 2>&1 | FileCheck %s
+# CHECK: warning: <internal>: unable to order absolute symbol: bar
+
+## Check we do not crash when trying to order --defsym symbol.
+
+# RUN: echo "bar" > %t.ord
+# RUN: ld.lld --symbol-ordering-file %t.ord %t.o -defsym=bar=1 \
+# RUN: -o %t.out 2>&1 | FileCheck %s
diff --git a/test/ELF/linkerscript/synthetic-symbols1.test b/test/ELF/linkerscript/synthetic-symbols1.test
index eb09d2d..908a05f 100644
--- a/test/ELF/linkerscript/synthetic-symbols1.test
+++ b/test/ELF/linkerscript/synthetic-symbols1.test
@@ -41,7 +41,7 @@
# CHECK: 0000000000000128 .foo 00000000 .hidden _end_sec
# CHECK-NEXT: 0000000000000120 .foo 00000000 _begin_sec
# CHECK-NEXT: 0000000000000128 *ABS* 00000000 _end_sec_abs
-# CHECK-NEXT: 0000000000001048 .text 00000000 _start
+# CHECK-NEXT: 000000000000104c .text 00000000 _start
# CHECK-NEXT: 0000000000000120 .foo 00000000 begin_foo
# CHECK-NEXT: 0000000000000128 .foo 00000000 end_foo
# CHECK-NEXT: 0000000000000008 *ABS* 00000000 size_foo_1
diff --git a/test/ELF/linkerscript/unused-synthetic.s b/test/ELF/linkerscript/unused-synthetic.s
index fb33421..80f0627 100644
--- a/test/ELF/linkerscript/unused-synthetic.s
+++ b/test/ELF/linkerscript/unused-synthetic.s
@@ -10,8 +10,10 @@
# RUN: llvm-objdump -section-headers %t.so | FileCheck %s
# CHECK-NOT: .got
# CHECK-NOT: .plt
-# CHECK: .text
-# CHECK-NEXT: .dynsym
+# CHECK: .dynsym
+# CHECK-NEXT: .dynstr
+# CHECK-NEXT: .text
+# CHECK-NEXT: .gnu.hash
# Test that the size of a removed unused synthetic input section is not added
# to the output section size. Adding a symbol assignment prevents removal of
diff --git a/test/ELF/local-symbols-order.s b/test/ELF/local-symbols-order.s
new file mode 100644
index 0000000..dfd964f
--- /dev/null
+++ b/test/ELF/local-symbols-order.s
@@ -0,0 +1,37 @@
+# REQUIRES: x86
+
+# RUN: echo '.data; .file "file2"; foo2:; .global bar2; .hidden bar2; bar2:' > %t2.s
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t2.s -o %t2.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+
+# RUN: ld.lld -o %t %t1.o %t2.o --emit-relocs
+# RUN: llvm-readobj -symbols -sections -elf-output-style=GNU %t | FileCheck %s
+
+## Check we sort local symbols to match the following order:
+## file1, local1, section1, hidden1, file2, local2, section2, hidden2 ...
+
+# CHECK: Section Headers:
+# CHECK: [Nr] Name
+# CHECK: [ [[ST:.*]]] .text
+# CHECK: [ [[SD:.*]]] .data
+# CHECK: [ [[SC:.*]]] .comment
+
+# CHECK: Num: Value Size Type Bind Vis Ndx Name
+# CHECK-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
+# CHECK-NEXT: 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS file1
+# CHECK-NEXT: 2: 0000000000201000 0 NOTYPE LOCAL DEFAULT 1 foo1
+# CHECK-NEXT: 3: 0000000000201000 0 SECTION LOCAL DEFAULT [[ST]]
+# CHECK-NEXT: 4: 0000000000201000 0 NOTYPE LOCAL HIDDEN 1 bar1
+# CHECK-NEXT: 5: 0000000000000000 0 FILE LOCAL DEFAULT ABS file2
+# CHECK-NEXT: 6: 0000000000201000 0 NOTYPE LOCAL DEFAULT 2 foo2
+# CHECK-NEXT: 7: 0000000000201000 0 SECTION LOCAL DEFAULT [[SD]]
+# CHECK-NEXT: 8: 0000000000201000 0 NOTYPE LOCAL HIDDEN 2 bar2
+# CHECK-NEXT: 9: 0000000000000000 0 SECTION LOCAL DEFAULT [[SC]]
+
+foo1:
+
+.global bar1
+.hidden bar1
+bar1:
+
+.file "file1"
diff --git a/test/ELF/lto/Inputs/archive-3.ll b/test/ELF/lto/Inputs/archive-3.ll
index ad8fb1e..3744246 100644
--- a/test/ELF/lto/Inputs/archive-3.ll
+++ b/test/ELF/lto/Inputs/archive-3.ll
@@ -1,5 +1,6 @@
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
+
define void @foo() {
ret void
}
diff --git a/test/ELF/lto/Inputs/common3.ll b/test/ELF/lto/Inputs/common3.ll
index a4efc65..8f20a1e 100644
--- a/test/ELF/lto/Inputs/common3.ll
+++ b/test/ELF/lto/Inputs/common3.ll
@@ -1,3 +1,4 @@
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
+
@a = common hidden global i64 0, align 4
diff --git a/test/ELF/lto/Inputs/lazy-internal.ll b/test/ELF/lto/Inputs/lazy-internal.ll
new file mode 100644
index 0000000..918791c
--- /dev/null
+++ b/test/ELF/lto/Inputs/lazy-internal.ll
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define hidden void @bar() {
+ ret void
+}
diff --git a/test/ELF/lto/Inputs/thinlto_empty.ll b/test/ELF/lto/Inputs/thinlto_empty.ll
new file mode 100644
index 0000000..a3c99cd
--- /dev/null
+++ b/test/ELF/lto/Inputs/thinlto_empty.ll
@@ -0,0 +1,2 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/archive-2.ll b/test/ELF/lto/archive-2.ll
index 6712d60..28e349e 100644
--- a/test/ELF/lto/archive-2.ll
+++ b/test/ELF/lto/archive-2.ll
@@ -3,9 +3,9 @@
; RUN: rm -f %t.a
; RUN: llvm-ar rcs %t.a %t1.o
; RUN: llvm-as %s -o %t2.o
-; RUN: ld.lld -m elf_x86_64 %t2.o %t.a -o %t3
+; RUN: ld.lld %t2.o %t.a -o %t3
; RUN: llvm-readobj -t %t3 | FileCheck %s
-; RUN: ld.lld -m elf_x86_64 %t2.o --whole-archive %t.a -o %t3 -shared
+; RUN: ld.lld %t2.o --whole-archive %t.a -o %t3 -shared
; RUN: llvm-readobj -t %t3 | FileCheck %s
; CHECK: Name: _start (
diff --git a/test/ELF/lto/archive-3.ll b/test/ELF/lto/archive-3.ll
index 0322e41..fec1b61 100644
--- a/test/ELF/lto/archive-3.ll
+++ b/test/ELF/lto/archive-3.ll
@@ -2,12 +2,12 @@
; RUN: llvm-as %S/Inputs/archive-3.ll -o %t1.o
; RUN: llvm-as %s -o %t2.o
-; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o -o %t3 -save-temps
+; RUN: ld.lld %t1.o %t2.o -o %t3 -save-temps
; RUN: llvm-dis %t3.0.2.internalize.bc -o - | FileCheck %s
; RUN: rm -f %t.a
; RUN: llvm-ar rcs %t.a %t1.o
-; RUN: ld.lld -m elf_x86_64 %t.a %t1.o %t2.o -o %t3 -save-temps
+; RUN: ld.lld %t.a %t1.o %t2.o -o %t3 -save-temps
; RUN: llvm-dis %t3.0.2.internalize.bc -o - | FileCheck %s
; CHECK: define internal void @foo() {
diff --git a/test/ELF/lto/archive-no-index.ll b/test/ELF/lto/archive-no-index.ll
index 48cca0a..5ac2628 100644
--- a/test/ELF/lto/archive-no-index.ll
+++ b/test/ELF/lto/archive-no-index.ll
@@ -11,8 +11,8 @@
; RUN: llvm-ar crS %t1.a %t2.o
; RUN: llvm-ar crs %t2.a %t2.o
-; RUN: ld.lld -o %t -emain -m elf_x86_64 %t1.o %t1.a
-; RUN: ld.lld -o %t -emain -m elf_x86_64 %t1.o %t2.a
+; RUN: ld.lld -o %t -emain %t1.o %t1.a
+; RUN: ld.lld -o %t -emain %t1.o %t2.a
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/archive.ll b/test/ELF/lto/archive.ll
index b4d011f..6c4ca5e 100644
--- a/test/ELF/lto/archive.ll
+++ b/test/ELF/lto/archive.ll
@@ -3,9 +3,9 @@
; RUN: rm -f %t.a
; RUN: llvm-ar rcs %t.a %t1.o
; RUN: llvm-as %s -o %t2.o
-; RUN: ld.lld -m elf_x86_64 %t2.o %t.a -o %t3 -shared
+; RUN: ld.lld %t2.o %t.a -o %t3 -shared
; RUN: llvm-readobj -t %t3 | FileCheck %s
-; RUN: ld.lld -m elf_x86_64 %t2.o --whole-archive %t.a -o %t3 -shared
+; RUN: ld.lld %t2.o --whole-archive %t.a -o %t3 -shared
; RUN: llvm-readobj -t %t3 | FileCheck %s
; CHECK: Name: g (
diff --git a/test/ELF/lto/asmundef.ll b/test/ELF/lto/asmundef.ll
index 677bee6..604af8f 100644
--- a/test/ELF/lto/asmundef.ll
+++ b/test/ELF/lto/asmundef.ll
@@ -1,7 +1,7 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
; RUN: llvm-as %S/Inputs/asmundef.ll -o %t2.o
-; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t -save-temps
+; RUN: ld.lld %t.o %t2.o -o %t -save-temps
; RUN: llvm-dis %t.0.4.opt.bc -o - | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/test/ELF/lto/available-externally.ll b/test/ELF/lto/available-externally.ll
index 315e710..516bec8 100644
--- a/test/ELF/lto/available-externally.ll
+++ b/test/ELF/lto/available-externally.ll
@@ -1,7 +1,7 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t1.o
; RUN: llvm-as %p/Inputs/available-externally.ll -o %t2.o
-; RUN: ld.lld %t1.o %t2.o -m elf_x86_64 -o %t.so -shared -save-temps
+; RUN: ld.lld %t1.o %t2.o -o %t.so -shared -save-temps
; RUN: llvm-dis < %t.so.0.2.internalize.bc | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/test/ELF/lto/bitcode-nodatalayout.ll b/test/ELF/lto/bitcode-nodatalayout.ll
index 5c4883a..c99cbb8 100644
--- a/test/ELF/lto/bitcode-nodatalayout.ll
+++ b/test/ELF/lto/bitcode-nodatalayout.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: not ld.lld -m elf_x86_64 %t.o -o %t 2>&1 | FileCheck %s
+; RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
; CHECK: input module has no datalayout
diff --git a/test/ELF/lto/codemodel.ll b/test/ELF/lto/codemodel.ll
index cc12620..995575a 100644
--- a/test/ELF/lto/codemodel.ll
+++ b/test/ELF/lto/codemodel.ll
@@ -1,7 +1,7 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o -o %ts -mllvm -code-model=small
-; RUN: ld.lld -m elf_x86_64 %t.o -o %tl -mllvm -code-model=large
+; RUN: ld.lld %t.o -o %ts -mllvm -code-model=small
+; RUN: ld.lld %t.o -o %tl -mllvm -code-model=large
; RUN: llvm-objdump -d %ts | FileCheck %s --check-prefix=CHECK-SMALL
; RUN: llvm-objdump -d %tl | FileCheck %s --check-prefix=CHECK-LARGE
diff --git a/test/ELF/lto/combined-lto-object-name.ll b/test/ELF/lto/combined-lto-object-name.ll
index 76564f9..e0b9874 100644
--- a/test/ELF/lto/combined-lto-object-name.ll
+++ b/test/ELF/lto/combined-lto-object-name.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: not ld.lld -m elf_x86_64 %t.o -o %t2 2>&1 | FileCheck %s
+; RUN: not ld.lld %t.o -o %t2 2>&1 | FileCheck %s
target triple = "x86_64-unknown-linux-gnu"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/test/ELF/lto/comdat.ll b/test/ELF/lto/comdat.ll
index e1384d0..1739351 100644
--- a/test/ELF/lto/comdat.ll
+++ b/test/ELF/lto/comdat.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o %t.o -o %t.so -shared
+; RUN: ld.lld %t.o %t.o -o %t.so -shared
; RUN: llvm-readobj -t %t.so | FileCheck %s
; CHECK: Name: foo
diff --git a/test/ELF/lto/comdat2.ll b/test/ELF/lto/comdat2.ll
index 2831821..e7c6ea1 100644
--- a/test/ELF/lto/comdat2.ll
+++ b/test/ELF/lto/comdat2.ll
@@ -1,9 +1,9 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
; RUN: llvm-mc -triple=x86_64-pc-linux %p/Inputs/comdat.s -o %t2.o -filetype=obj
-; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t.so -shared
+; RUN: ld.lld %t.o %t2.o -o %t.so -shared
; RUN: llvm-readobj -t %t.so | FileCheck %s
-; RUN: ld.lld -m elf_x86_64 %t2.o %t.o -o %t2.so -shared
+; RUN: ld.lld %t2.o %t.o -o %t2.so -shared
; RUN: llvm-readobj -t %t2.so | FileCheck %s --check-prefix=OTHER
diff --git a/test/ELF/lto/common2.ll b/test/ELF/lto/common2.ll
index 2345a20..1cb5c32 100644
--- a/test/ELF/lto/common2.ll
+++ b/test/ELF/lto/common2.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t1.o
-; RUN: ld.lld -m elf_x86_64 %t1.o -o %t -shared -save-temps
+; RUN: ld.lld %t1.o -o %t -shared -save-temps
; RUN: llvm-dis < %t.0.2.internalize.bc | FileCheck %s
; RUN: llvm-readobj -t %t | FileCheck %s --check-prefix=SHARED
diff --git a/test/ELF/lto/common3.ll b/test/ELF/lto/common3.ll
index aea33f4..de52615 100644
--- a/test/ELF/lto/common3.ll
+++ b/test/ELF/lto/common3.ll
@@ -1,7 +1,7 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t1.o
; RUN: llvm-as %S/Inputs/common3.ll -o %t2.o
-; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o -o %t -shared -save-temps
+; RUN: ld.lld %t1.o %t2.o -o %t -shared -save-temps
; RUN: llvm-dis < %t.0.2.internalize.bc | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/test/ELF/lto/ctors.ll b/test/ELF/lto/ctors.ll
index 7fce645..f641897 100644
--- a/test/ELF/lto/ctors.ll
+++ b/test/ELF/lto/ctors.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -shared
+; RUN: ld.lld %t.o -o %t.so -shared
; RUN: llvm-readobj -sections %t.so | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/test/ELF/lto/data-ordering-lto.s b/test/ELF/lto/data-ordering-lto.s
index 0364e58..8291ef0 100644
--- a/test/ELF/lto/data-ordering-lto.s
+++ b/test/ELF/lto/data-ordering-lto.s
@@ -12,13 +12,14 @@
# Check that the order is tin -> dipsy -> pat.
-# CHECK: Symbol table '.symtab' contains 5 entries:
+# CHECK: Symbol table '.symtab' contains 6 entries:
# CHECK-NEXT: Num: Value Size Type Bind Vis Ndx Name
# CHECK-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
-# CHECK-NEXT: 1: 0000000000201000 0 NOTYPE GLOBAL DEFAULT 1 _start
-# CHECK-NEXT: 2: 0000000000202004 4 OBJECT GLOBAL DEFAULT 2 dipsy
-# CHECK-NEXT: 3: 0000000000202008 4 OBJECT GLOBAL DEFAULT 2 pat
-# CHECK-NEXT: 4: 0000000000202000 4 OBJECT GLOBAL DEFAULT 2 tin
+# CHECK-NEXT: 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS {{.*}}.o
+# CHECK-NEXT: 2: 0000000000201000 0 NOTYPE GLOBAL DEFAULT 1 _start
+# CHECK-NEXT: 3: 0000000000202004 4 OBJECT GLOBAL DEFAULT 2 dipsy
+# CHECK-NEXT: 4: 0000000000202008 4 OBJECT GLOBAL DEFAULT 2 pat
+# CHECK-NEXT: 5: 0000000000202000 4 OBJECT GLOBAL DEFAULT 2 tin
.globl _start
_start:
diff --git a/test/ELF/lto/discard-value-names.ll b/test/ELF/lto/discard-value-names.ll
index f1e95fe..485014e 100644
--- a/test/ELF/lto/discard-value-names.ll
+++ b/test/ELF/lto/discard-value-names.ll
@@ -1,7 +1,7 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 -shared -save-temps %t.o -o %t2.o
+; RUN: ld.lld -shared -save-temps %t.o -o %t2.o
; RUN: llvm-dis < %t2.o.0.0.preopt.bc | FileCheck %s
; CHECK: @GlobalValueName
diff --git a/test/ELF/lto/drop-debug-info.ll b/test/ELF/lto/drop-debug-info.ll
index dae7b96..f820faf 100644
--- a/test/ELF/lto/drop-debug-info.ll
+++ b/test/ELF/lto/drop-debug-info.ll
@@ -3,7 +3,7 @@
; drop-debug-info.bc was created from "void f(void) {}" with clang 3.5 and
; -gline-tables-only, so it contains old debug info.
;
-; RUN: ld.lld -m elf_x86_64 -shared %p/Inputs/drop-debug-info.bc \
+; RUN: ld.lld -shared %p/Inputs/drop-debug-info.bc \
; RUN: -disable-verify -o %t 2>&1 | FileCheck %s
; CHECK: ignoring debug info with an invalid version (1) in {{.*}}drop-debug-info.bc
diff --git a/test/ELF/lto/drop-linkage.ll b/test/ELF/lto/drop-linkage.ll
index 1ff1796..f02fa02 100644
--- a/test/ELF/lto/drop-linkage.ll
+++ b/test/ELF/lto/drop-linkage.ll
@@ -1,12 +1,12 @@
-target triple = "x86_64-unknown-linux-gnu"
-target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
-
; REQUIRES: x86
; RUN: llc %s -o %t.o -filetype=obj
; RUN: llvm-as %p/Inputs/drop-linkage.ll -o %t2.o
; RUN: ld.lld %t.o %t2.o -o %t.so -save-temps -shared
; RUN: llvm-dis %t.so.0.4.opt.bc -o - | FileCheck %s
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
define void @foo() {
ret void
}
diff --git a/test/ELF/lto/duplicated.ll b/test/ELF/lto/duplicated.ll
index 1567481..fc60fba 100644
--- a/test/ELF/lto/duplicated.ll
+++ b/test/ELF/lto/duplicated.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: not ld.lld -m elf_x86_64 %t.o %t.o -o %t.so -shared 2>&1 | FileCheck %s
+; RUN: not ld.lld %t.o %t.o -o %t.so -shared 2>&1 | FileCheck %s
; CHECK: duplicate symbol: f
; CHECK-NEXT: >>> defined in {{.*}}.o
diff --git a/test/ELF/lto/dynamic-list.ll b/test/ELF/lto/dynamic-list.ll
index 0e950b3..c5473d8 100644
--- a/test/ELF/lto/dynamic-list.ll
+++ b/test/ELF/lto/dynamic-list.ll
@@ -1,7 +1,7 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
; RUN: echo "{ foo; };" > %t.list
-; RUN: ld.lld -m elf_x86_64 -o %t --dynamic-list %t.list -pie %t.o
+; RUN: ld.lld -o %t --dynamic-list %t.list -pie %t.o
; RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
; CHECK: Name: foo@
diff --git a/test/ELF/lto/dynsym.ll b/test/ELF/lto/dynsym.ll
index b2b4157..d056c0b 100644
--- a/test/ELF/lto/dynsym.ll
+++ b/test/ELF/lto/dynsym.ll
@@ -1,12 +1,12 @@
; REQUIRES: x86
; RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux -o %t.o %p/Inputs/dynsym.s
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -shared
+; RUN: ld.lld %t.o -o %t.so -shared
; RUN: llvm-as %s -o %t2.o
-; RUN: ld.lld -m elf_x86_64 %t2.o %t.so -o %t
+; RUN: ld.lld %t2.o %t.so -o %t
; RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
; Check that we don't crash when gc'ing sections and printing the result.
-; RUN: ld.lld -m elf_x86_64 %t2.o %t.so --gc-sections --print-gc-sections \
+; RUN: ld.lld %t2.o %t.so --gc-sections --print-gc-sections \
; RUN: -o %t
; RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
diff --git a/test/ELF/lto/inline-asm.ll b/test/ELF/lto/inline-asm.ll
index b6af6a5..e0732e6 100644
--- a/test/ELF/lto/inline-asm.ll
+++ b/test/ELF/lto/inline-asm.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -shared
+; RUN: ld.lld %t.o -o %t.so -shared
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/internalize-basic.ll b/test/ELF/lto/internalize-basic.ll
index b5691a7..5197654 100644
--- a/test/ELF/lto/internalize-basic.ll
+++ b/test/ELF/lto/internalize-basic.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -save-temps
+; RUN: ld.lld %t.o -o %t2 -save-temps
; RUN: llvm-dis < %t2.0.2.internalize.bc | FileCheck %s
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/internalize-exportdyn.ll b/test/ELF/lto/internalize-exportdyn.ll
index 0ffde69..7c996e1 100644
--- a/test/ELF/lto/internalize-exportdyn.ll
+++ b/test/ELF/lto/internalize-exportdyn.ll
@@ -1,7 +1,7 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
; RUN: llvm-as %p/Inputs/internalize-exportdyn.ll -o %t2.o
-; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t2 --export-dynamic -save-temps
+; RUN: ld.lld %t.o %t2.o -o %t2 --export-dynamic -save-temps
; RUN: llvm-dis < %t2.0.2.internalize.bc | FileCheck %s
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/internalize-llvmused.ll b/test/ELF/lto/internalize-llvmused.ll
index 253dcb2..7e3d867 100644
--- a/test/ELF/lto/internalize-llvmused.ll
+++ b/test/ELF/lto/internalize-llvmused.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -save-temps
+; RUN: ld.lld %t.o -o %t2 -save-temps
; RUN: llvm-dis < %t2.0.2.internalize.bc | FileCheck %s
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/internalize-undef.ll b/test/ELF/lto/internalize-undef.ll
index f76528b..c0860d8 100644
--- a/test/ELF/lto/internalize-undef.ll
+++ b/test/ELF/lto/internalize-undef.ll
@@ -1,7 +1,7 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
; RUN: llvm-as %p/Inputs/internalize-undef.ll -o %t2.o
-; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t -save-temps
+; RUN: ld.lld %t.o %t2.o -o %t -save-temps
; RUN: llvm-dis < %t.0.2.internalize.bc | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/test/ELF/lto/internalize-version-script.ll b/test/ELF/lto/internalize-version-script.ll
index c577e43..7e242e1 100644
--- a/test/ELF/lto/internalize-version-script.ll
+++ b/test/ELF/lto/internalize-version-script.ll
@@ -1,7 +1,7 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
; RUN: echo "{ global: foo; local: *; };" > %t.script
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -shared --version-script %t.script -save-temps
+; RUN: ld.lld %t.o -o %t2 -shared --version-script %t.script -save-temps
; RUN: llvm-dis < %t2.0.2.internalize.bc | FileCheck %s
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/irmover-error.ll b/test/ELF/lto/irmover-error.ll
index 8b9836d..d1c962f 100644
--- a/test/ELF/lto/irmover-error.ll
+++ b/test/ELF/lto/irmover-error.ll
@@ -1,6 +1,6 @@
; RUN: llvm-as -o %t1.bc %s
; RUN: llvm-as -o %t2.bc %S/Inputs/irmover-error.ll
-; RUN: not ld.lld -m elf_x86_64 %t1.bc %t2.bc -o %t 2>&1 | FileCheck %s
+; RUN: not ld.lld %t1.bc %t2.bc -o %t 2>&1 | FileCheck %s
; CHECK: linking module flags 'foo': IDs have conflicting values
diff --git a/test/ELF/lto/keep-undefined.ll b/test/ELF/lto/keep-undefined.ll
index cb0f4ce..55d2a05 100644
--- a/test/ELF/lto/keep-undefined.ll
+++ b/test/ELF/lto/keep-undefined.ll
@@ -2,7 +2,7 @@
; This test checks that symbols which are specified in "-u" switches
; are kept over LTO if we link an executable.
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o -o %tout -u foo
+; RUN: ld.lld %t.o -o %tout -u foo
; RUN: llvm-nm %tout | FileCheck %s
; CHECK: T foo
diff --git a/test/ELF/lto/lazy-internal.ll b/test/ELF/lto/lazy-internal.ll
new file mode 100644
index 0000000..1bb2bac
--- /dev/null
+++ b/test/ELF/lto/lazy-internal.ll
@@ -0,0 +1,19 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t1.o
+; RUN: llvm-as %p/Inputs/lazy-internal.ll -o %t2.o
+; RUN: rm -f %t2.a
+; RUN: llvm-ar rc %t2.a %t2.o
+; RUN: ld.lld %t2.a %t1.o -o %t.so -shared -save-temps
+; RUN: llvm-dis %t.so.0.2.internalize.bc -o - | FileCheck %s
+
+; CHECK: define internal void @foo()
+; CHECK: define internal void @bar()
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define hidden void @foo() {
+ call void @bar()
+ ret void
+}
+declare void @bar()
diff --git a/test/ELF/lto/linkage.ll b/test/ELF/lto/linkage.ll
index 5af9b32..9b93900 100644
--- a/test/ELF/lto/linkage.ll
+++ b/test/ELF/lto/linkage.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t1.o
-; RUN: ld.lld -m elf_x86_64 %t1.o %t1.o -o %t.so -shared
+; RUN: ld.lld %t1.o %t1.o -o %t.so -shared
; RUN: llvm-nm %t.so | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/test/ELF/lto/linker-script-symbols-assign.ll b/test/ELF/lto/linker-script-symbols-assign.ll
index 6ca7824..bd7a374 100644
--- a/test/ELF/lto/linker-script-symbols-assign.ll
+++ b/test/ELF/lto/linker-script-symbols-assign.ll
@@ -2,7 +2,7 @@
; RUN: llvm-as %s -o %t.o
; RUN: echo "foo = 1;" > %t.script
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 --script %t.script -save-temps
+; RUN: ld.lld %t.o -o %t2 --script %t.script -save-temps
; RUN: llvm-readobj -symbols %t2.lto.o | FileCheck %s
; CHECK-NOT: bar
@@ -20,7 +20,7 @@
; VAL-NEXT: }
; RUN: echo "zed = 1;" > %t2.script
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t3 --script %t2.script
+; RUN: ld.lld %t.o -o %t3 --script %t2.script
; RUN: llvm-readobj -symbols %t3 | FileCheck %s --check-prefix=ABS
; ABS: Symbol {
; ABS: Name: zed
diff --git a/test/ELF/lto/linker-script-symbols-ipo.ll b/test/ELF/lto/linker-script-symbols-ipo.ll
index 330ac67..4cc95c6 100644
--- a/test/ELF/lto/linker-script-symbols-ipo.ll
+++ b/test/ELF/lto/linker-script-symbols-ipo.ll
@@ -4,7 +4,7 @@
; RUN: echo "bar = foo;" > %t.script
;; Check that without linkerscript bar is inlined.
-; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o -o %t3 -save-temps
+; RUN: ld.lld %t1.o %t2.o -o %t3 -save-temps
; RUN: llvm-objdump -d %t3 | FileCheck %s --check-prefix=IPO
; IPO: Disassembly of section .text:
; IPO: _start:
@@ -12,7 +12,7 @@
; IPO-NEXT: 201005: {{.*}} retq
;; Check that LTO does not do IPO for symbols assigned by script.
-; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o -o %t4 --script %t.script -save-temps
+; RUN: ld.lld %t1.o %t2.o -o %t4 --script %t.script -save-temps
; RUN: llvm-objdump -d %t4 | FileCheck %s --check-prefix=NOIPO
; NOIPO: Disassembly of section .text:
; NOIPO: foo:
diff --git a/test/ELF/lto/linker-script-symbols.ll b/test/ELF/lto/linker-script-symbols.ll
index c2a58b6..28758c0 100644
--- a/test/ELF/lto/linker-script-symbols.ll
+++ b/test/ELF/lto/linker-script-symbols.ll
@@ -2,7 +2,7 @@
; RUN: llvm-as %s -o %t.o
; RUN: echo "foo = bar;" > %t.script
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 --script %t.script -save-temps
+; RUN: ld.lld %t.o -o %t2 --script %t.script -save-temps
; RUN: llvm-readobj -symbols %t2.lto.o | FileCheck %s
; CHECK-NOT: zed
diff --git a/test/ELF/lto/lto-start.ll b/test/ELF/lto/lto-start.ll
index e93eecf..cc1eb4b 100644
--- a/test/ELF/lto/lto-start.ll
+++ b/test/ELF/lto/lto-start.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t2
+; RUN: ld.lld %t.o -o %t2
; RUN: llvm-readobj -t %t2 | FileCheck %s
; CHECK: Format: ELF64-x86-64
diff --git a/test/ELF/lto/ltopasses-basic.ll b/test/ELF/lto/ltopasses-basic.ll
index 0c4ad8b..6789bdc 100644
--- a/test/ELF/lto/ltopasses-basic.ll
+++ b/test/ELF/lto/ltopasses-basic.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -save-temps -mllvm -debug-pass=Arguments -shared 2>&1 | FileCheck %s --check-prefix=MLLVM
+; RUN: ld.lld %t.o -o %t.so -save-temps -mllvm -debug-pass=Arguments -shared 2>&1 | FileCheck %s --check-prefix=MLLVM
; RUN: llvm-dis %t.so.0.4.opt.bc -o - | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/test/ELF/lto/ltopasses-custom.ll b/test/ELF/lto/ltopasses-custom.ll
index a48959a..a75000d 100644
--- a/test/ELF/lto/ltopasses-custom.ll
+++ b/test/ELF/lto/ltopasses-custom.ll
@@ -1,8 +1,8 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -save-temps --lto-aa-pipeline=basic-aa \
+; RUN: ld.lld %t.o -o %t.so -save-temps --lto-aa-pipeline=basic-aa \
; RUN: --lto-newpm-passes=ipsccp -shared
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t2.so -save-temps --lto-newpm-passes=loweratomic -shared
+; RUN: ld.lld %t.o -o %t2.so -save-temps --lto-newpm-passes=loweratomic -shared
; RUN: llvm-dis %t.so.0.4.opt.bc -o - | FileCheck %s
; RUN: llvm-dis %t2.so.0.4.opt.bc -o - | FileCheck %s --check-prefix=ATOMIC
diff --git a/test/ELF/lto/metadata.ll b/test/ELF/lto/metadata.ll
index 2eaacaa..238b5bd 100644
--- a/test/ELF/lto/metadata.ll
+++ b/test/ELF/lto/metadata.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t1.o
-; RUN: ld.lld -m elf_x86_64 %t1.o %t1.o -o %t.so -shared
+; RUN: ld.lld %t1.o %t1.o -o %t.so -shared
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/module-asm.ll b/test/ELF/lto/module-asm.ll
index 1389b9f..eaf2762 100644
--- a/test/ELF/lto/module-asm.ll
+++ b/test/ELF/lto/module-asm.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t
+; RUN: ld.lld %t.o -o %t
; RUN: llvm-nm %t | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/test/ELF/lto/new-pass-manager.ll b/test/ELF/lto/new-pass-manager.ll
new file mode 100644
index 0000000..918b505
--- /dev/null
+++ b/test/ELF/lto/new-pass-manager.ll
@@ -0,0 +1,14 @@
+; REQUIRES: x86
+; RUN: opt -module-summary %s -o %t.o
+
+; Test new-pass-manager and debug-pass-manager option
+; RUN: ld.lld --plugin-opt=new-pass-manager --plugin-opt=debug-pass-manager -o %t2.o %t.o 2>&1 | FileCheck %s
+; RUN: ld.lld --plugin-opt=new-pass-manager --lto-debug-pass-manager -o %t2.o %t.o 2>&1 | FileCheck %s
+; RUN: ld.lld --lto-new-pass-manager --plugin-opt=debug-pass-manager -o %t2.o %t.o 2>&1 | FileCheck %s
+; RUN: ld.lld --lto-new-pass-manager --lto-debug-pass-manager -o %t2.o %t.o 2>&1 | FileCheck %s
+
+; CHECK: Starting llvm::Module pass manager run
+; CHECK: Finished llvm::Module pass manager run
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/opt-level.ll b/test/ELF/lto/opt-level.ll
index b2b56a4..5c4ec43 100644
--- a/test/ELF/lto/opt-level.ll
+++ b/test/ELF/lto/opt-level.ll
@@ -1,30 +1,30 @@
; REQUIRES: x86
; RUN: llvm-as -o %t.o %s
-; RUN: ld.lld -o %t0 -m elf_x86_64 -e main --lto-O0 %t.o
+; RUN: ld.lld -o %t0 -e main --lto-O0 %t.o
; RUN: llvm-nm %t0 | FileCheck --check-prefix=CHECK-O0 %s
-; RUN: ld.lld -o %t0 -m elf_x86_64 -e main --plugin-opt=O0 %t.o
+; RUN: ld.lld -o %t0 -e main --plugin-opt=O0 %t.o
; RUN: llvm-nm %t0 | FileCheck --check-prefix=CHECK-O0 %s
-; RUN: ld.lld -o %t2 -m elf_x86_64 -e main --lto-O2 %t.o
+; RUN: ld.lld -o %t2 -e main --lto-O2 %t.o
; RUN: llvm-nm %t2 | FileCheck --check-prefix=CHECK-O2 %s
-; RUN: ld.lld -o %t2a -m elf_x86_64 -e main %t.o
+; RUN: ld.lld -o %t2a -e main %t.o
; RUN: llvm-nm %t2a | FileCheck --check-prefix=CHECK-O2 %s
-; RUN: ld.lld -o %t2 -m elf_x86_64 -e main --plugin-opt=O2 %t.o
+; RUN: ld.lld -o %t2 -e main %t.o --plugin-opt O2
; RUN: llvm-nm %t2 | FileCheck --check-prefix=CHECK-O2 %s
; Reject invalid optimization levels.
-; RUN: not ld.lld -o %t3 -m elf_x86_64 -e main --lto-O6 %t.o 2>&1 | \
+; RUN: not ld.lld -o %t3 -e main --lto-O6 %t.o 2>&1 | \
; RUN: FileCheck --check-prefix=INVALID1 %s
; INVALID1: invalid optimization level for LTO: 6
-; RUN: not ld.lld -o %t3 -m elf_x86_64 -e main --plugin-opt=O6 %t.o 2>&1 | \
+; RUN: not ld.lld -o %t3 -e main --plugin-opt=O6 %t.o 2>&1 | \
; RUN: FileCheck --check-prefix=INVALID1 %s
-; RUN: not ld.lld -o %t3 -m elf_x86_64 -e main --plugin-opt=Ofoo %t.o 2>&1 | \
+; RUN: not ld.lld -o %t3 -e main --plugin-opt=Ofoo %t.o 2>&1 | \
; RUN: FileCheck --check-prefix=INVALID2 %s
; INVALID2: --plugin-opt=Ofoo: number expected, but got 'foo'
-; RUN: not ld.lld -o %t3 -m elf_x86_64 -e main --lto-O-1 %t.o 2>&1 | \
+; RUN: not ld.lld -o %t3 -e main --lto-O-1 %t.o 2>&1 | \
; RUN: FileCheck --check-prefix=INVALIDNEGATIVE1 %s
; INVALIDNEGATIVE1: invalid optimization level for LTO: 4294967295
-; RUN: not ld.lld -o %t3 -m elf_x86_64 -e main --plugin-opt=O-1 %t.o 2>&1 | \
+; RUN: not ld.lld -o %t3 -e main --plugin-opt=O-1 %t.o 2>&1 | \
; RUN: FileCheck --check-prefix=INVALIDNEGATIVE2 %s
; INVALIDNEGATIVE2: invalid optimization level for LTO: 4294967295
diff --git a/test/ELF/lto/parallel-internalize.ll b/test/ELF/lto/parallel-internalize.ll
index da5bdc6..f21b3cc 100644
--- a/test/ELF/lto/parallel-internalize.ll
+++ b/test/ELF/lto/parallel-internalize.ll
@@ -1,7 +1,7 @@
; REQUIRES: x86
; RUN: llvm-as -o %t.bc %s
; RUN: rm -f %t.lto.o %t1.lto.o
-; RUN: ld.lld -m elf_x86_64 --lto-partitions=2 -save-temps -o %t %t.bc \
+; RUN: ld.lld --lto-partitions=2 -save-temps -o %t %t.bc \
; RUN: -e foo --lto-O0
; RUN: llvm-readobj -t -dyn-symbols %t | FileCheck %s
; RUN: llvm-nm %t.lto.o | FileCheck --check-prefix=CHECK0 %s
@@ -18,6 +18,24 @@
; CHECK-NEXT: Section: Undefined (0x0)
; CHECK-NEXT: }
; CHECK-NEXT: Symbol {
+; CHECK-NEXT: Name: {{.*}}.o
+; CHECK-NEXT: Value: 0x0
+; CHECK-NEXT: Size: 0
+; CHECK-NEXT: Binding: Local
+; CHECK-NEXT: Type: File
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: Absolute
+; CHECK-NEXT: }
+; CHECK-NEXT: Symbol {
+; CHECK-NEXT: Name: {{.*}}.o
+; CHECK-NEXT: Value: 0x0
+; CHECK-NEXT: Size: 0
+; CHECK-NEXT: Binding: Local
+; CHECK-NEXT: Type: File
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: Absolute
+; CHECK-NEXT: }
+; CHECK-NEXT: Symbol {
; CHECK-NEXT: Name: bar
; CHECK-NEXT: Value: 0x201010
; CHECK-NEXT: Size: 8
diff --git a/test/ELF/lto/parallel.ll b/test/ELF/lto/parallel.ll
index a1c15af..4ba3fd6 100644
--- a/test/ELF/lto/parallel.ll
+++ b/test/ELF/lto/parallel.ll
@@ -1,7 +1,7 @@
; REQUIRES: x86
; RUN: llvm-as -o %t.bc %s
; RUN: rm -f %t.lto.o %t1.lto.o
-; RUN: ld.lld -m elf_x86_64 --lto-partitions=2 -save-temps -o %t %t.bc -shared
+; RUN: ld.lld --lto-partitions=2 -save-temps -o %t %t.bc -shared
; RUN: llvm-nm %t.lto.o | FileCheck --check-prefix=CHECK0 %s
; RUN: llvm-nm %t1.lto.o | FileCheck --check-prefix=CHECK1 %s
diff --git a/test/ELF/lto/relax-relocs.ll b/test/ELF/lto/relax-relocs.ll
index 8e8d9d1..80e5dac 100644
--- a/test/ELF/lto/relax-relocs.ll
+++ b/test/ELF/lto/relax-relocs.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 -save-temps -shared %t.o -o %t.so
+; RUN: ld.lld -save-temps -shared %t.o -o %t.so
; RUN: llvm-readobj -r %t.so.lto.o | FileCheck %s
; Test that we produce R_X86_64_REX_GOTPCRELX instead of R_X86_64_GOTPCREL
diff --git a/test/ELF/lto/relocatable.ll b/test/ELF/lto/relocatable.ll
index ef21f84..2ec9144 100644
--- a/test/ELF/lto/relocatable.ll
+++ b/test/ELF/lto/relocatable.ll
@@ -14,6 +14,15 @@
; CHECK-NEXT: Section: Undefined
; CHECK-NEXT: }
; CHECK-NEXT: Symbol {
+; CHECK-NEXT: Name: {{.*}}.o
+; CHECK-NEXT: Value: 0x0
+; CHECK-NEXT: Size: 0
+; CHECK-NEXT: Binding: Local
+; CHECK-NEXT: Type: File
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: Absolute
+; CHECK-NEXT: }
+; CHECK-NEXT: Symbol {
; CHECK-NEXT: Name:
; CHECK-NEXT: Value: 0x0
; CHECK-NEXT: Size: 0
diff --git a/test/ELF/lto/sample-profile.ll b/test/ELF/lto/sample-profile.ll
new file mode 100644
index 0000000..17eead7
--- /dev/null
+++ b/test/ELF/lto/sample-profile.ll
@@ -0,0 +1,25 @@
+; REQUIRES: x86
+; RUN: opt -module-summary %s -o %t1.o
+; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o
+
+; RUN: rm -f %t1.lto.o %t2.lto.o
+; RUN: ld.lld --lto-sample-profile=/dev/null %t1.o %t2.o -o %t3
+; RUN opt -S %t3.lto.o | FileCheck %s
+
+; RUN: rm -f %t1.lto.o %t2.lto.o
+; RUN: ld.lld --plugin-opt=sample-profile=/dev/null %t1.o %t2.o -o %t3
+; RUN opt -S %t3.lto.o | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; CHECK: ProfileSummary
+declare void @g(...)
+declare void @h(...)
+
+define void @f() {
+entry:
+ call void (...) @g()
+ call void (...) @h()
+ ret void
+}
diff --git a/test/ELF/lto/save-temps.ll b/test/ELF/lto/save-temps.ll
index c8e52ff..b34134c 100644
--- a/test/ELF/lto/save-temps.ll
+++ b/test/ELF/lto/save-temps.ll
@@ -3,7 +3,7 @@
; RUN: rm -f a.out a.out.lto.bc a.out.lto.o
; RUN: llvm-as %s -o %t.o
; RUN: llvm-as %p/Inputs/save-temps.ll -o %t2.o
-; RUN: ld.lld -shared -m elf_x86_64 %t.o %t2.o -save-temps
+; RUN: ld.lld -shared %t.o %t2.o -save-temps
; RUN: llvm-nm a.out | FileCheck %s
; RUN: llvm-nm a.out.0.0.preopt.bc | FileCheck %s
; RUN: llvm-nm a.out.lto.o | FileCheck %s
diff --git a/test/ELF/lto/start-lib.ll b/test/ELF/lto/start-lib.ll
index ec73954..024d887 100644
--- a/test/ELF/lto/start-lib.ll
+++ b/test/ELF/lto/start-lib.ll
@@ -4,17 +4,17 @@
; RUN: llvm-as %p/Inputs/start-lib1.ll -o %t2.o
; RUN: llvm-as %p/Inputs/start-lib2.ll -o %t3.o
;
-; RUN: ld.lld -m elf_x86_64 -shared -o %t3 %t1.o %t2.o %t3.o
+; RUN: ld.lld -shared -o %t3 %t1.o %t2.o %t3.o
; RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=TEST1 %s
; TEST1: Name: bar
; TEST1: Name: foo
;
-; RUN: ld.lld -m elf_x86_64 -shared -o %t3 -u bar %t1.o --start-lib %t2.o %t3.o
+; RUN: ld.lld -shared -o %t3 -u bar %t1.o --start-lib %t2.o %t3.o
; RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=TEST2 %s
; TEST2: Name: bar
; TEST2-NOT: Name: foo
;
-; RUN: ld.lld -m elf_x86_64 -shared -o %t3 %t1.o --start-lib %t2.o %t3.o
+; RUN: ld.lld -shared -o %t3 %t1.o --start-lib %t2.o %t3.o
; RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=TEST3 %s
; TEST3-NOT: Name: bar
; TEST3-NOT: Name: foo
diff --git a/test/ELF/lto/symbol-ordering-lto.s b/test/ELF/lto/symbol-ordering-lto.s
index 4c29e54..232817c 100644
--- a/test/ELF/lto/symbol-ordering-lto.s
+++ b/test/ELF/lto/symbol-ordering-lto.s
@@ -12,12 +12,13 @@
# Check that the order is tin -> _start -> pat.
-# CHECK: Symbol table '.symtab' contains 4 entries:
+# CHECK: Symbol table '.symtab' contains 5 entries:
# CHECK-NEXT: Num: Value Size Type Bind Vis Ndx Name
# CHECK-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
-# CHECK-NEXT: 1: 0000000000201008 0 NOTYPE GLOBAL DEFAULT 1 _start
-# CHECK-NEXT: 2: 0000000000201020 6 FUNC GLOBAL DEFAULT 1 pat
-# CHECK-NEXT: 3: 0000000000201000 6 FUNC GLOBAL DEFAULT 1 tin
+# CHECK-NEXT: 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS {{.*}}.o
+# CHECK-NEXT: 2: 0000000000201008 0 NOTYPE GLOBAL DEFAULT 1 _start
+# CHECK-NEXT: 3: 0000000000201020 6 FUNC GLOBAL DEFAULT 1 pat
+# CHECK-NEXT: 4: 0000000000201000 6 FUNC GLOBAL DEFAULT 1 tin
.globl _start
_start:
diff --git a/test/ELF/lto/thinlto-cant-write-index.ll b/test/ELF/lto/thinlto-cant-write-index.ll
new file mode 100644
index 0000000..94f2a45
--- /dev/null
+++ b/test/ELF/lto/thinlto-cant-write-index.ll
@@ -0,0 +1,23 @@
+; REQUIRES: x86
+
+; Basic ThinLTO tests.
+; RUN: opt -module-summary %s -o %t1.o
+; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o
+
+; Ensure lld generates error if unable to write to index files
+; RUN: rm -f %t2.o.thinlto.bc
+; RUN: touch %t2.o.thinlto.bc
+; RUN: chmod 400 %t2.o.thinlto.bc
+; RUN: not ld.lld --plugin-opt=thinlto-index-only -shared %t1.o %t2.o -o %t3 2>&1 | FileCheck %s
+; CHECK: cannot open {{.*}}2.o.thinlto.bc: {{P|p}}ermission denied
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @g(...)
+
+define void @f() {
+entry:
+ call void (...) @g()
+ ret void
+}
diff --git a/test/ELF/lto/thinlto-emit-imports.ll b/test/ELF/lto/thinlto-emit-imports.ll
new file mode 100644
index 0000000..cae7922
--- /dev/null
+++ b/test/ELF/lto/thinlto-emit-imports.ll
@@ -0,0 +1,55 @@
+; REQUIRES: x86
+
+; Generate summary sections and test lld handling.
+; RUN: opt -module-summary %s -o %t1.o
+; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o
+
+; Include a file with an empty module summary index, to ensure that the expected
+; output files are created regardless, for a distributed build system.
+; RUN: opt -module-summary %p/Inputs/thinlto_empty.ll -o %t3.o
+
+; Ensure lld generates imports files if requested for distributed backends.
+; RUN: rm -f %t3.o.imports %t3.o.thinlto.bc
+; RUN: ld.lld --plugin-opt=thinlto-index-only --plugin-opt=thinlto-emit-imports-files -shared %t1.o %t2.o %t3.o -o %t4
+
+; The imports file for this module contains the bitcode file for
+; Inputs/thinlto.ll
+; RUN: cat %t1.o.imports | count 1
+; RUN: cat %t1.o.imports | FileCheck %s --check-prefix=IMPORTS1
+; IMPORTS1: thinlto-emit-imports.ll.tmp2.o
+
+; The imports file for Input/thinlto.ll is empty as it does not import anything.
+; RUN: cat %t2.o.imports | count 0
+
+; The imports file for Input/thinlto_empty.ll is empty but should exist.
+; RUN: cat %t3.o.imports | count 0
+
+; The index file should be created even for the input with an empty summary.
+; RUN: ls %t3.o.thinlto.bc
+
+; Ensure lld generates error if unable to write to imports file.
+; RUN: rm -f %t3.o.imports
+; RUN: touch %t3.o.imports
+; RUN: chmod 400 %t3.o.imports
+; RUN: not ld.lld --plugin-opt=thinlto-index-only --plugin-opt=thinlto-emit-imports-files -shared %t1.o %t2.o %t3.o -o %t4 2>&1 | FileCheck %s --check-prefix=ERR
+; ERR: cannot open {{.*}}3.o.imports: {{P|p}}ermission denied
+
+; Ensure lld doesn't generate import files when thinlto-index-only is not enabled
+; RUN: rm -f %t1.o.imports
+; RUN: rm -f %t2.o.imports
+; RUN: rm -f %t3.o.imports
+; RUN: ld.lld --plugin-opt=thinlto-emit-imports-files -shared %t1.o %t2.o %t3.o -o %t4
+; RUN: not ls %t1.o.imports
+; RUN: not ls %t2.o.imports
+; RUN: not ls %t3.o.imports
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @g(...)
+
+define void @f() {
+entry:
+ call void (...) @g()
+ ret void
+}
diff --git a/test/ELF/lto/thinlto-index-file.ll b/test/ELF/lto/thinlto-index-file.ll
new file mode 100644
index 0000000..91f0b29
--- /dev/null
+++ b/test/ELF/lto/thinlto-index-file.ll
@@ -0,0 +1,24 @@
+; REQUIRES: x86
+
+; Basic ThinLTO tests.
+; RUN: opt -module-summary %s -o %t1.o
+; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o
+; RUN: opt -module-summary %p/Inputs/thinlto_empty.ll -o %t3.o
+
+; Ensure lld writes linked files to linked objects file
+; RUN: ld.lld --plugin-opt=thinlto-index-only=%t.idx -shared %t1.o %t2.o %t3.o -o %t4
+; RUN: FileCheck %s < %t.idx
+; CHECK: {{.*}}thinlto-index-file.ll.tmp1.o
+; CHECK: {{.*}}thinlto-index-file.ll.tmp2.o
+; CHECK: {{.*}}thinlto-index-file.ll.tmp3.o
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @g(...)
+
+define void @f() {
+entry:
+ call void (...) @g()
+ ret void
+}
diff --git a/test/ELF/lto/thinlto-index-only.ll b/test/ELF/lto/thinlto-index-only.ll
new file mode 100644
index 0000000..dba2fbc
--- /dev/null
+++ b/test/ELF/lto/thinlto-index-only.ll
@@ -0,0 +1,70 @@
+; REQUIRES: x86
+
+; First ensure that the ThinLTO handling in lld handles
+; bitcode without summary sections gracefully and generates index file.
+; RUN: llvm-as %s -o %t1.o
+; RUN: llvm-as %p/Inputs/thinlto.ll -o %t2.o
+; RUN: rm -f %t3
+; RUN: ld.lld --plugin-opt=thinlto-index-only -shared %t1.o %t2.o -o %t3
+; RUN: ls %t2.o.thinlto.bc
+; RUN: not test -e %t3
+; RUN: ld.lld -shared %t1.o %t2.o -o %t3
+; RUN: llvm-nm %t3 | FileCheck %s --check-prefix=NM
+
+; Basic ThinLTO tests.
+; RUN: opt -module-summary %s -o %t1.o
+; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o
+; RUN: opt -module-summary %p/Inputs/thinlto_empty.ll -o %t3.o
+
+; Ensure lld generates an index and not a binary if requested.
+; RUN: rm -f %t4
+; RUN: ld.lld --plugin-opt=thinlto-index-only -shared %t1.o %t2.o -o %t4
+; RUN: llvm-bcanalyzer -dump %t1.o.thinlto.bc | FileCheck %s --check-prefix=BACKEND1
+; RUN: llvm-bcanalyzer -dump %t2.o.thinlto.bc | FileCheck %s --check-prefix=BACKEND2
+; RUN: not test -e %t4
+
+; Ensure lld generates an index even if the file is wrapped in --start-lib/--end-lib
+; RUN: rm -f %t2.o.thinlto.bc %t4
+; RUN: ld.lld --plugin-opt=thinlto-index-only -shared %t1.o %t3.o --start-lib %t2.o --end-lib -o %t4
+; RUN: ls %t2.o.thinlto.bc
+; RUN: not test -e %t4
+
+; NM: T f
+
+; The backend index for this module contains summaries from itself and
+; Inputs/thinlto.ll, as it imports from the latter.
+; BACKEND1: <MODULE_STRTAB_BLOCK
+; BACKEND1-NEXT: <ENTRY {{.*}} record string = '{{.*}}thinlto-index-only.ll.tmp{{.*}}.o'
+; BACKEND1-NEXT: <ENTRY {{.*}} record string = '{{.*}}thinlto-index-only.ll.tmp{{.*}}.o'
+; BACKEND1-NEXT: </MODULE_STRTAB_BLOCK
+; BACKEND1: <GLOBALVAL_SUMMARY_BLOCK
+; BACKEND1: <VERSION
+; BACKEND1: <FLAGS
+; BACKEND1: <VALUE_GUID op0={{1|2}} op1={{-3706093650706652785|-5300342847281564238}}
+; BACKEND1: <VALUE_GUID op0={{1|2}} op1={{-3706093650706652785|-5300342847281564238}}
+; BACKEND1: <COMBINED
+; BACKEND1: <COMBINED
+; BACKEND1: </GLOBALVAL_SUMMARY_BLOCK
+
+; The backend index for Input/thinlto.ll contains summaries from itself only,
+; as it does not import anything.
+; BACKEND2: <MODULE_STRTAB_BLOCK
+; BACKEND2-NEXT: <ENTRY {{.*}} record string = '{{.*}}thinlto-index-only.ll.tmp2.o'
+; BACKEND2-NEXT: </MODULE_STRTAB_BLOCK
+; BACKEND2-NEXT: <GLOBALVAL_SUMMARY_BLOCK
+; BACKEND2-NEXT: <VERSION
+; BACKEND2-NEXT: <FLAGS
+; BACKEND2-NEXT: <VALUE_GUID op0=1 op1=-5300342847281564238
+; BACKEND2-NEXT: <COMBINED
+; BACKEND2-NEXT: </GLOBALVAL_SUMMARY_BLOCK
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @g(...)
+
+define void @f() {
+entry:
+ call void (...) @g()
+ ret void
+}
diff --git a/test/ELF/lto/thinlto-no-index.ll b/test/ELF/lto/thinlto-no-index.ll
new file mode 100644
index 0000000..f80cf0e
--- /dev/null
+++ b/test/ELF/lto/thinlto-no-index.ll
@@ -0,0 +1,24 @@
+; REQUIRES: x86
+
+; Basic ThinLTO tests.
+; RUN: opt -module-summary %s -o %t1.o
+; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o
+; RUN: opt -module-summary %p/Inputs/thinlto_empty.ll -o %t3.o
+
+; Ensure lld doesn't generates index files when thinlto-index-only is not enabled
+; RUN: rm -f %t1.o.thinlto.bc %t2.o.thinlto.bc %t3.o.thinlto.bc
+; RUN: ld.lld -shared %t1.o %t2.o %t3.o -o %t4
+; RUN: not ls %t1.o.thinlto.bc
+; RUN: not ls %t2.o.thinlto.bc
+; RUN: not ls %t3.o.thinlto.bc
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @g(...)
+
+define void @f() {
+entry:
+ call void (...) @g()
+ ret void
+}
diff --git a/test/ELF/lto/thinlto-obj-path.ll b/test/ELF/lto/thinlto-obj-path.ll
new file mode 100644
index 0000000..bb69bb8
--- /dev/null
+++ b/test/ELF/lto/thinlto-obj-path.ll
@@ -0,0 +1,23 @@
+; REQUIRES: x86
+
+; RUN: opt -module-summary %s -o %t1.o
+; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o
+
+; Test to ensure that thinlto-index-only with obj-path creates the file.
+; RUN: rm -f %t4.o
+; RUN: ld.lld --plugin-opt=thinlto-index-only --plugin-opt=obj-path=%t4.o -shared %t1.o %t2.o -o %t3
+; RUN: llvm-readobj -h %t4.o | FileCheck %s
+; RUN: llvm-nm %t4.o | count 0
+
+; CHECK: Format: ELF64-x86-64
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @g(...)
+
+define void @f() {
+entry:
+ call void (...) @g()
+ ret void
+}
diff --git a/test/ELF/lto/thinlto-object-suffix-replace.ll b/test/ELF/lto/thinlto-object-suffix-replace.ll
new file mode 100644
index 0000000..05ce942
--- /dev/null
+++ b/test/ELF/lto/thinlto-object-suffix-replace.ll
@@ -0,0 +1,50 @@
+; REQUIRES: x86
+
+; Test to make sure the thinlto-object-suffix-replace option is handled
+; correctly.
+
+; Generate bitcode file with summary, as well as a minimized bitcode without
+; the debug metadata for the thin link.
+; RUN: opt -thinlto-bc %s -thin-link-bitcode-file=%t1.thinlink.bc -o %t1.o
+
+; First perform the thin link on the normal bitcode file, and save the
+; resulting index.
+; RUN: ld.lld --plugin-opt=thinlto-index-only -shared %t1.o -o %t3
+; RUN: cp %t1.o.thinlto.bc %t1.o.thinlto.bc.orig
+
+; Next perform the thin link on the minimized bitcode file, and compare dump
+; of the resulting index to the above dump to ensure they are identical.
+; RUN: rm -f %t1.o.thinlto.bc
+; Make sure it isn't inadvertently using the regular bitcode file.
+; RUN: rm -f %t1.o
+; RUN: ld.lld --plugin-opt=thinlto-index-only \
+; RUN: --plugin-opt=thinlto-object-suffix-replace=".thinlink.bc;.o" \
+; RUN: -shared %t1.thinlink.bc -o %t3
+; RUN: diff %t1.o.thinlto.bc.orig %t1.o.thinlto.bc
+
+; Ensure lld generates error if object suffix replace option does not have 'old;new' format
+; RUN: rm -f %t1.o.thinlto.bc
+; RUN: not ld.lld --plugin-opt=thinlto-index-only \
+; RUN: --plugin-opt=thinlto-object-suffix-replace="abc:def" -shared %t1.thinlink.bc \
+; RUN: -o %t3 2>&1 | FileCheck %s --check-prefix=ERR1
+; ERR1: --plugin-opt=thinlto-object-suffix-replace= expects 'old;new' format, but got abc:def
+
+; Ensure lld generates error if old suffix doesn't exist in file name
+; RUN: rm -f %t1.o
+; RUN: not ld.lld --plugin-opt=thinlto-index-only \
+; RUN: --plugin-opt=thinlto-object-suffix-replace=".abc;.o" -shared %t1.thinlink.bc \
+; RUN: -o %t3 2>&1 | FileCheck %s --check-prefix=ERR2
+; ERR2: error: -thinlto-object-suffix-replace=.abc;.o was given, but {{.*}} does not end with the suffix
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @f() {
+entry:
+ ret void
+}
+
+!llvm.dbg.cu = !{}
+
+!1 = !{i32 2, !"Debug Info Version", i32 3}
+!llvm.module.flags = !{!1}
diff --git a/test/ELF/lto/thinlto-prefix-replace.ll b/test/ELF/lto/thinlto-prefix-replace.ll
new file mode 100644
index 0000000..c276dae
--- /dev/null
+++ b/test/ELF/lto/thinlto-prefix-replace.ll
@@ -0,0 +1,23 @@
+; REQUIRES: x86
+; Check that changing the output path via thinlto-prefix-replace works
+; RUN: mkdir -p %t/oldpath
+; RUN: opt -module-summary %s -o %t/oldpath/thinlto_prefix_replace.o
+
+; Ensure that there is no existing file at the new path, so we properly
+; test the creation of the new file there.
+; RUN: rm -f %t/newpath/thinlto_prefix_replace.o.thinlto.bc
+; RUN: ld.lld --plugin-opt=thinlto-index-only --plugin-opt=thinlto-prefix-replace="%t/oldpath/;%t/newpath/" -shared %t/oldpath/thinlto_prefix_replace.o -o %t/thinlto_prefix_replace
+; RUN: ls %t/newpath/thinlto_prefix_replace.o.thinlto.bc
+
+; Ensure that lld generates error if prefix replace option does not have 'old;new' format
+; RUN: rm -f %t/newpath/thinlto_prefix_replace.o.thinlto.bc
+; RUN: not ld.lld --plugin-opt=thinlto-index-only --plugin-opt=thinlto-prefix-replace=abc:def -shared %t/oldpath/thinlto_prefix_replace.o -o %t/thinlto_prefix_replace 2>&1 | FileCheck %s --check-prefix=ERR
+; ERR: --plugin-opt=thinlto-prefix-replace= expects 'old;new' format, but got abc:def
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @f() {
+entry:
+ ret void
+}
diff --git a/test/ELF/lto/thinlto.ll b/test/ELF/lto/thinlto.ll
index 37d2b88..51c82ec 100644
--- a/test/ELF/lto/thinlto.ll
+++ b/test/ELF/lto/thinlto.ll
@@ -1,29 +1,28 @@
; REQUIRES: x86
+
; Basic ThinLTO tests.
-; RUN: opt -module-summary %s -o %t.o
+; RUN: opt -module-summary %s -o %t1.o
; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o
; First force single-threaded mode
-; RUN: rm -f %t.lto.o %t1.lto.o
-; RUN: ld.lld -save-temps --thinlto-jobs=1 -shared %t.o %t2.o -o %t
-; RUN: llvm-nm %t1.lto.o | FileCheck %s --check-prefix=NM1
-; RUN: llvm-nm %t2.lto.o | FileCheck %s --check-prefix=NM2
+; RUN: rm -f %t31.lto.o %t32.lto.o
+; RUN: ld.lld -save-temps --thinlto-jobs=1 -shared %t1.o %t2.o -o %t3
+; RUN: llvm-nm %t31.lto.o | FileCheck %s --check-prefix=NM1
+; RUN: llvm-nm %t32.lto.o | FileCheck %s --check-prefix=NM2
; Next force multi-threaded mode
-; RUN: rm -f %t2.lto.o %t21.lto.o
-; RUN: ld.lld -save-temps --thinlto-jobs=2 -shared %t.o %t2.o -o %t2
-; RUN: llvm-nm %t21.lto.o | FileCheck %s --check-prefix=NM1
-; RUN: llvm-nm %t22.lto.o | FileCheck %s --check-prefix=NM2
-
-; NM1: T f
-; NM1-NOT: U g
-
-; NM2: T g
+; RUN: rm -f %t31.lto.o %t32.lto.o
+; RUN: ld.lld -save-temps --thinlto-jobs=2 -shared %t1.o %t2.o -o %t3
+; RUN: llvm-nm %t31.lto.o | FileCheck %s --check-prefix=NM1
+; RUN: llvm-nm %t32.lto.o | FileCheck %s --check-prefix=NM2
; Then check without --thinlto-jobs (which currently default to hardware_concurrency)
-; We just check that we don't crash or fail (as it's not sure which tests are
-; stable on the final output file itself.
-; RUN: ld.lld -shared %t.o %t2.o -o %t2
+; RUN: ld.lld -shared %t1.o %t2.o -o %t3
+; RUN: llvm-nm %t31.lto.o | FileCheck %s --check-prefix=NM1
+; RUN: llvm-nm %t32.lto.o | FileCheck %s --check-prefix=NM2
+
+; NM1: T f
+; NM2: T g
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/tls-mixed.ll b/test/ELF/lto/tls-mixed.ll
index 524bb4f..9d5a693 100644
--- a/test/ELF/lto/tls-mixed.ll
+++ b/test/ELF/lto/tls-mixed.ll
@@ -1,7 +1,7 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t1.o
; RUN: llvm-mc %p/Inputs/tls-mixed.s -o %t2.o -filetype=obj -triple=x86_64-pc-linux
-; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o -o %t.so -shared
+; RUN: ld.lld %t1.o %t2.o -o %t.so -shared
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/tls-preserve.ll b/test/ELF/lto/tls-preserve.ll
index 8aebcb7..c9b7675 100644
--- a/test/ELF/lto/tls-preserve.ll
+++ b/test/ELF/lto/tls-preserve.ll
@@ -1,7 +1,7 @@
; TLS attribute needs to be preserved.
; REQUIRES: x86
; RUN: llvm-as %s -o %t1.o
-; RUN: ld.lld -shared %t1.o -m elf_x86_64 -o %t1
+; RUN: ld.lld -shared %t1.o -o %t1
; RUN: llvm-readobj -t %t1 | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/test/ELF/lto/type-merge.ll b/test/ELF/lto/type-merge.ll
index d6f196d..985c44b 100644
--- a/test/ELF/lto/type-merge.ll
+++ b/test/ELF/lto/type-merge.ll
@@ -1,7 +1,7 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
; RUN: llvm-as %p/Inputs/type-merge.ll -o %t2.o
-; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t -shared -save-temps
+; RUN: ld.lld %t.o %t2.o -o %t -shared -save-temps
; RUN: llvm-dis < %t.0.0.preopt.bc | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/test/ELF/lto/type-merge2.ll b/test/ELF/lto/type-merge2.ll
index 6ebbf77..5944be7 100644
--- a/test/ELF/lto/type-merge2.ll
+++ b/test/ELF/lto/type-merge2.ll
@@ -1,7 +1,7 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
; RUN: llvm-as %p/Inputs/type-merge2.ll -o %t2.o
-; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t.so -shared -save-temps
+; RUN: ld.lld %t.o %t2.o -o %t.so -shared -save-temps
; RUN: llvm-dis %t.so.0.0.preopt.bc -o - | FileCheck %s
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/undef-weak.ll b/test/ELF/lto/undef-weak.ll
index 215978a..e090f56 100644
--- a/test/ELF/lto/undef-weak.ll
+++ b/test/ELF/lto/undef-weak.ll
@@ -1,13 +1,12 @@
; REQUIRES: x86
-
; RUN: llvm-as %S/Inputs/archive.ll -o %t1.o
; RUN: rm -f %t.a
; RUN: llvm-ar rcs %t.a %t1.o
-
; RUN: llvm-as %s -o %t2.o
-; RUN: ld.lld -m elf_x86_64 %t2.o -o %t2.so %t.a -shared
+; RUN: ld.lld %t2.o -o %t2.so %t.a -shared
; RUN: llvm-readobj -t %t2.so | FileCheck %s
+
target triple = "x86_64-unknown-linux-gnu"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/test/ELF/lto/undef.ll b/test/ELF/lto/undef.ll
index 41da610..4ea7e83 100644
--- a/test/ELF/lto/undef.ll
+++ b/test/ELF/lto/undef.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -shared
+; RUN: ld.lld %t.o -o %t.so -shared
; RUN: llvm-readobj -t %t.so | FileCheck %s
target triple = "x86_64-unknown-linux-gnu"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/test/ELF/lto/undefined-puts.ll b/test/ELF/lto/undefined-puts.ll
index d136303..6c3dc76 100644
--- a/test/ELF/lto/undefined-puts.ll
+++ b/test/ELF/lto/undefined-puts.ll
@@ -2,7 +2,7 @@
; RUN: llvm-mc %p/Inputs/shared.s -o %t1.o -filetype=obj -triple=x86_64-unknown-linux
; RUN: ld.lld %t1.o -o %t1.so -shared
; RUN: llvm-as %s -o %t2.o
-; RUN: ld.lld %t1.so %t2.o -m elf_x86_64 -o %t
+; RUN: ld.lld %t1.so %t2.o -o %t
; RUN: llvm-readobj -dyn-symbols -dyn-relocations %t | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/test/ELF/lto/unnamed-addr-comdat.ll b/test/ELF/lto/unnamed-addr-comdat.ll
index 29a5941..38b08ab 100644
--- a/test/ELF/lto/unnamed-addr-comdat.ll
+++ b/test/ELF/lto/unnamed-addr-comdat.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o %t.o -o %t.so -save-temps -shared
+; RUN: ld.lld %t.o %t.o -o %t.so -save-temps -shared
; RUN: llvm-dis %t.so.0.2.internalize.bc -o - | FileCheck %s
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/unnamed-addr-drop.ll b/test/ELF/lto/unnamed-addr-drop.ll
index e827cbb..ad662b7 100644
--- a/test/ELF/lto/unnamed-addr-drop.ll
+++ b/test/ELF/lto/unnamed-addr-drop.ll
@@ -1,7 +1,7 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t1.o
; RUN: llvm-as %S/Inputs/unnamed-addr-drop.ll -o %t2.o
-; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o -o %t.so -save-temps -shared
+; RUN: ld.lld %t1.o %t2.o -o %t.so -save-temps -shared
; RUN: llvm-dis %t.so.0.2.internalize.bc -o - | FileCheck %s
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/unnamed-addr-lib.ll b/test/ELF/lto/unnamed-addr-lib.ll
index c2bc601..0c47468 100644
--- a/test/ELF/lto/unnamed-addr-lib.ll
+++ b/test/ELF/lto/unnamed-addr-lib.ll
@@ -2,7 +2,7 @@
; RUN: llvm-as %s -o %t.o
; RUN: llvm-mc %p/Inputs/unnamed-addr-lib.s -o %t2.o -filetype=obj -triple=x86_64-pc-linux
; RUN: ld.lld %t2.o -shared -o %t2.so
-; RUN: ld.lld -m elf_x86_64 %t.o %t2.so -o %t.so -save-temps -shared
+; RUN: ld.lld %t.o %t2.so -o %t.so -save-temps -shared
; RUN: llvm-dis %t.so.0.2.internalize.bc -o - | FileCheck %s
; This documents a small limitation of lld's internalization logic. We decide
diff --git a/test/ELF/lto/unnamed-addr.ll b/test/ELF/lto/unnamed-addr.ll
index 56fe148..7504fdf 100644
--- a/test/ELF/lto/unnamed-addr.ll
+++ b/test/ELF/lto/unnamed-addr.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -save-temps -shared
+; RUN: ld.lld %t.o -o %t.so -save-temps -shared
; RUN: llvm-dis %t.so.0.4.opt.bc -o - | FileCheck %s
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/verify-invalid.ll b/test/ELF/lto/verify-invalid.ll
index e6138a3..9fa0f9e 100644
--- a/test/ELF/lto/verify-invalid.ll
+++ b/test/ELF/lto/verify-invalid.ll
@@ -1,10 +1,10 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -mllvm -debug-pass=Arguments \
+; RUN: ld.lld %t.o -o %t2 -mllvm -debug-pass=Arguments \
; RUN: 2>&1 | FileCheck -check-prefix=DEFAULT %s
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -mllvm -debug-pass=Arguments \
+; RUN: ld.lld %t.o -o %t2 -mllvm -debug-pass=Arguments \
; RUN: -disable-verify 2>&1 | FileCheck -check-prefix=DISABLE %s
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -mllvm -debug-pass=Arguments \
+; RUN: ld.lld %t.o -o %t2 -mllvm -debug-pass=Arguments \
; RUN: --plugin-opt=disable-verify 2>&1 | FileCheck -check-prefix=DISABLE %s
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/lto/version-script.ll b/test/ELF/lto/version-script.ll
index c43b443..35a36b5 100644
--- a/test/ELF/lto/version-script.ll
+++ b/test/ELF/lto/version-script.ll
@@ -1,7 +1,7 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
; RUN: echo "VERSION_1.0{ global: foo; local: *; }; VERSION_2.0{ global: bar; local: *; };" > %t.script
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -shared --version-script %t.script -save-temps
+; RUN: ld.lld %t.o -o %t2 -shared --version-script %t.script -save-temps
; RUN: llvm-dis < %t2.0.0.preopt.bc | FileCheck %s
; RUN: llvm-readobj -V -dyn-symbols %t2 | FileCheck --check-prefix=DSO %s
diff --git a/test/ELF/lto/weak.ll b/test/ELF/lto/weak.ll
index 381ef7a..a807c13 100644
--- a/test/ELF/lto/weak.ll
+++ b/test/ELF/lto/weak.ll
@@ -1,6 +1,6 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o %t.o -o %t.so -shared
+; RUN: ld.lld %t.o %t.o -o %t.so -shared
; RUN: llvm-readobj -t %t.so | FileCheck %s
target triple = "x86_64-unknown-linux-gnu"
diff --git a/test/ELF/map-file.s b/test/ELF/map-file.s
index 23b9381..390d880 100644
--- a/test/ELF/map-file.s
+++ b/test/ELF/map-file.s
@@ -40,60 +40,61 @@
abs = 0xAB5
labs = 0x1AB5
-// CHECK: Address Size Align Out In Symbol
-// CHECK-NEXT: 00000000002001c8 0000000000000078 8 .dynsym
-// CHECK-NEXT: 00000000002001c8 0000000000000078 8 <internal>:(.dynsym)
-// CHECK-NEXT: 0000000000200240 000000000000002c 8 .gnu.hash
-// CHECK-NEXT: 0000000000200240 000000000000002c 8 <internal>:(.gnu.hash)
-// CHECK-NEXT: 000000000020026c 0000000000000030 4 .hash
-// CHECK-NEXT: 000000000020026c 0000000000000030 4 <internal>:(.hash)
-// CHECK-NEXT: 000000000020029c 0000000000000031 1 .dynstr
-// CHECK-NEXT: 000000000020029c 0000000000000031 1 <internal>:(.dynstr)
-// CHECK-NEXT: 00000000002002d0 0000000000000030 8 .rela.dyn
-// CHECK-NEXT: 00000000002002d0 0000000000000030 8 <internal>:(.rela.dyn)
-// CHECK-NEXT: 0000000000200300 0000000000000030 8 .rela.plt
-// CHECK-NEXT: 0000000000200300 0000000000000030 8 <internal>:(.rela.plt)
-// CHECK-NEXT: 0000000000200330 0000000000000060 8 .eh_frame
-// CHECK-NEXT: 0000000000200330 000000000000002c 0 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.eh_frame+0x0)
-// CHECK-NEXT: 0000000000200360 0000000000000014 0 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.eh_frame+0x2c)
-// CHECK-NEXT: 0000000000200378 0000000000000018 0 {{.*}}{{/|\\}}map-file.s.tmp2.o:(.eh_frame+0x18)
-// CHECK-NEXT: 0000000000201000 000000000000002d 4 .text
-// CHECK-NEXT: 0000000000201000 0000000000000028 4 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.text)
-// CHECK-NEXT: 0000000000201000 0000000000000000 0 _start
-// CHECK-NEXT: 000000000020101f 0000000000000000 0 f(int)
-// CHECK-NEXT: 0000000000201028 0000000000000000 0 local
-// CHECK-NEXT: 0000000000201028 0000000000000002 4 {{.*}}{{/|\\}}map-file.s.tmp2.o:(.text)
-// CHECK-NEXT: 0000000000201028 0000000000000000 0 foo
-// CHECK-NEXT: 0000000000201029 0000000000000000 0 bar
-// CHECK-NEXT: 000000000020102a 0000000000000000 1 {{.*}}{{/|\\}}map-file.s.tmp2.o:(.text.zed)
-// CHECK-NEXT: 000000000020102a 0000000000000000 0 zed
-// CHECK-NEXT: 000000000020102c 0000000000000000 4 {{.*}}{{/|\\}}map-file.s.tmp3.o:(.text)
-// CHECK-NEXT: 000000000020102c 0000000000000000 0 bah
-// CHECK-NEXT: 000000000020102c 0000000000000001 4 {{.*}}{{/|\\}}map-file.s.tmp4.a(map-file.s.tmp4.o):(.text)
-// CHECK-NEXT: 000000000020102c 0000000000000000 0 baz
-// CHECK-NEXT: 0000000000201030 0000000000000030 16 .plt
-// CHECK-NEXT: 0000000000201030 0000000000000030 16 <internal>:(.plt)
-// CHECK-NEXT: 0000000000201040 0000000000000000 0 sharedFunc1
-// CHECK-NEXT: 0000000000201050 0000000000000000 0 sharedFunc2
-// CHECK-NEXT: 0000000000202000 0000000000000028 8 .got.plt
-// CHECK-NEXT: 0000000000202000 0000000000000028 8 <internal>:(.got.plt)
-// CHECK-NEXT: 0000000000203000 0000000000000100 8 .dynamic
-// CHECK-NEXT: 0000000000203000 0000000000000100 8 <internal>:(.dynamic)
-// CHECK-NEXT: 0000000000204000 0000000000000010 16 .bss
-// CHECK-NEXT: 0000000000204000 0000000000000004 16 {{.*}}{{/|\\}}map-file.s.tmp1.o:(COMMON)
-// CHECK-NEXT: 0000000000204000 0000000000000004 0 common
-// CHECK-NEXT: 0000000000204004 0000000000000004 1 <internal>:(.bss)
-// CHECK-NEXT: 0000000000204004 0000000000000004 0 sharedFoo
-// CHECK-NEXT: 0000000000204008 0000000000000008 1 <internal>:(.bss)
-// CHECK-NEXT: 0000000000204008 0000000000000008 0 sharedBar
-// CHECK-NEXT: 0000000000000000 0000000000000008 1 .comment
-// CHECK-NEXT: 0000000000000000 0000000000000008 1 <internal>:(.comment)
-// CHECK-NEXT: 0000000000000000 0000000000000198 8 .symtab
-// CHECK-NEXT: 0000000000000000 0000000000000198 8 <internal>:(.symtab)
-// CHECK-NEXT: 0000000000000000 0000000000000084 1 .shstrtab
-// CHECK-NEXT: 0000000000000000 0000000000000084 1 <internal>:(.shstrtab)
-// CHECK-NEXT: 0000000000000000 000000000000006d 1 .strtab
-// CHECK-NEXT: 0000000000000000 000000000000006d 1 <internal>:(.strtab)
+// CHECK: VMA LMA Size Align Out In Symbol
+// CHECK-NEXT: 2001c8 2001c8 78 8 .dynsym
+// CHECK-NEXT: 2001c8 2001c8 78 8 <internal>:(.dynsym)
+// CHECK-NEXT: 200240 200240 31 1 .dynstr
+// CHECK-NEXT: 200240 200240 31 1 <internal>:(.dynstr)
+// CHECK-NEXT: 200278 200278 2c 8 .gnu.hash
+// CHECK-NEXT: 200278 200278 2c 8 <internal>:(.gnu.hash)
+// CHECK-NEXT: 2002a4 2002a4 30 4 .hash
+// CHECK-NEXT: 2002a4 2002a4 30 4 <internal>:(.hash)
+// CHECK-NEXT: 2002d8 2002d8 30 8 .rela.dyn
+// CHECK-NEXT: 2002d8 2002d8 30 8 <internal>:(.rela.dyn)
+// CHECK-NEXT: 200308 200308 30 8 .rela.plt
+// CHECK-NEXT: 200308 200308 30 8 <internal>:(.rela.plt)
+// CHECK-NEXT: 200338 200338 64 8 .eh_frame
+// CHECK-NEXT: 200338 200338 2c 1 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.eh_frame+0x0)
+// CHECK-NEXT: 200368 200368 14 1 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.eh_frame+0x2c)
+// CHECK-NEXT: 200380 200380 18 1 {{.*}}{{/|\\}}map-file.s.tmp2.o:(.eh_frame+0x18)
+// CHECK-NEXT: 201000 201000 2d 4 .text
+// CHECK-NEXT: 201000 201000 28 4 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.text)
+// CHECK-NEXT: 201000 201000 0 1 _start
+// CHECK-NEXT: 20101f 20101f 0 1 f(int)
+// CHECK-NEXT: 201028 201028 0 1 local
+// CHECK-NEXT: 201028 201028 2 4 {{.*}}{{/|\\}}map-file.s.tmp2.o:(.text)
+// CHECK-NEXT: 201028 201028 0 1 foo
+// CHECK-NEXT: 201029 201029 0 1 bar
+// CHECK-NEXT: 20102a 20102a 0 1 {{.*}}{{/|\\}}map-file.s.tmp2.o:(.text.zed)
+// CHECK-NEXT: 20102a 20102a 0 1 zed
+// CHECK-NEXT: 20102c 20102c 0 4 {{.*}}{{/|\\}}map-file.s.tmp3.o:(.text)
+// CHECK-NEXT: 20102c 20102c 0 1 bah
+// CHECK-NEXT: 20102c 20102c 1 4 {{.*}}{{/|\\}}map-file.s.tmp4.a(map-file.s.tmp4.o):(.text)
+// CHECK-NEXT: 20102c 20102c 0 1 baz
+// CHECK-NEXT: 201030 201030 30 16 .plt
+// CHECK-NEXT: 201030 201030 30 16 <internal>:(.plt)
+// CHECK-NEXT: 201040 201040 0 1 sharedFunc1
+// CHECK-NEXT: 201050 201050 0 1 sharedFunc2
+// CHECK-NEXT: 202000 202000 28 8 .got.plt
+// CHECK-NEXT: 202000 202000 28 8 <internal>:(.got.plt)
+// CHECK-NEXT: 203000 203000 100 8 .dynamic
+// CHECK-NEXT: 203000 203000 100 8 <internal>:(.dynamic)
+// CHECK-NEXT: 204000 204000 10 16 .bss
+// CHECK-NEXT: 204000 204000 4 16 {{.*}}{{/|\\}}map-file.s.tmp1.o:(COMMON)
+// CHECK-NEXT: 204000 204000 4 1 common
+// CHECK-NEXT: 204004 204004 4 1 <internal>:(.bss)
+// CHECK-NEXT: 204004 204004 4 1 sharedFoo
+// CHECK-NEXT: 204008 204008 8 1 <internal>:(.bss)
+// CHECK-NEXT: 204008 204008 8 1 sharedBar
+// CHECK-NEXT: 0 0 8 1 .comment
+// CHECK-NEXT: 0 0 8 1 <internal>:(.comment)
+// CHECK-NEXT: 0 0 198 8 .symtab
+// CHECK-NEXT: 0 0 198 8 <internal>:(.symtab)
+// CHECK-NEXT: 0 0 84 1 .shstrtab
+// CHECK-NEXT: 0 0 84 1 <internal>:(.shstrtab)
+// CHECK-NEXT: 0 0 6d 1 .strtab
+// CHECK-NEXT: 0 0 6d 1 <internal>:(.strtab)
+
// RUN: not ld.lld %t1.o %t2.o %t3.o %t4.a -o %t -Map=/ 2>&1 \
// RUN: | FileCheck -check-prefix=FAIL %s
diff --git a/test/ELF/merge-gc-piece.s b/test/ELF/merge-gc-piece.s
new file mode 100644
index 0000000..95ea17c
--- /dev/null
+++ b/test/ELF/merge-gc-piece.s
@@ -0,0 +1,38 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.so -shared --gc-sections
+# RUN: llvm-readobj -s -section-data %t.so | FileCheck %s
+
+
+# CHECK: Name: .foo
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: SHF_MERGE
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x1C8
+
+# CHECK: Name: .bar
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Size: 16
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info:
+# CHECK-NEXT: AddressAlignment:
+# CHECK-NEXT: EntrySize:
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT: 0000: C9010000 00000000 CA010000 00000000
+# CHECK-NEXT: )
+
+ .section .foo,"aM",@progbits,8
+ .quad 42
+ .global sym
+sym:
+ .quad 43
+
+ .section .bar
+ .quad .foo + 1
+ .quad .foo + 2
diff --git a/test/ELF/merge-gc-piece2.s b/test/ELF/merge-gc-piece2.s
new file mode 100644
index 0000000..88e0904
--- /dev/null
+++ b/test/ELF/merge-gc-piece2.s
@@ -0,0 +1,27 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.so -shared --gc-sections
+# RUN: llvm-readobj -s -section-data %t.so | FileCheck %s
+
+# CHECK: Name: .bar
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Size: 16
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info:
+# CHECK-NEXT: AddressAlignment:
+# CHECK-NEXT: EntrySize:
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT: 0000: 01000000 00000000 02000000 00000000
+# CHECK-NEXT: )
+
+ .section .foo,"aM",@progbits,8
+ .quad 42
+ .quad 43
+
+ .section .bar
+ .quad .foo + 1
+ .quad .foo + 2
diff --git a/test/ELF/merge-shared-str.s b/test/ELF/merge-shared-str.s
index 2ab03a4..e06d00d 100644
--- a/test/ELF/merge-shared-str.s
+++ b/test/ELF/merge-shared-str.s
@@ -19,10 +19,10 @@
// CHECK-NEXT: SHF_MERGE
// CHECK-NEXT: SHF_STRINGS
// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x1C8
+// CHECK-NEXT: Address: 0x1E1
// CHECK: Relocations [
// CHECK-NEXT: Section ({{.*}}) .rela.dyn {
-// CHECK-NEXT: 0x{{.*}} R_X86_64_RELATIVE - 0x1C9
+// CHECK-NEXT: 0x{{.*}} R_X86_64_RELATIVE - 0x1E2
// CHECK-NEXT: }
// CHECK-NEXT: ]
diff --git a/test/ELF/merge-shared.s b/test/ELF/merge-shared.s
index 4c1d7c0..3894e53 100644
--- a/test/ELF/merge-shared.s
+++ b/test/ELF/merge-shared.s
@@ -17,10 +17,10 @@
// CHECK-NEXT: SHF_ALLOC
// CHECK-NEXT: SHF_MERGE
// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x1C8
+// CHECK-NEXT: Address: 0x1E4
// CHECK: Relocations [
// CHECK-NEXT: Section ({{.*}}) .rela.dyn {
-// CHECK-NEXT: 0x{{.*}} R_X86_64_RELATIVE - 0x1CA
+// CHECK-NEXT: 0x{{.*}} R_X86_64_RELATIVE - 0x1E6
// CHECK-NEXT: }
// CHECK-NEXT: ]
diff --git a/test/ELF/merge-string.s b/test/ELF/merge-string.s
index d284d0a..2496205 100644
--- a/test/ELF/merge-string.s
+++ b/test/ELF/merge-string.s
@@ -28,8 +28,8 @@
// CHECK-NEXT: SHF_MERGE
// CHECK-NEXT: SHF_STRINGS
// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x1C8
-// CHECK-NEXT: Offset: 0x1C8
+// CHECK-NEXT: Address: 0x1E1
+// CHECK-NEXT: Offset: 0x1E1
// CHECK-NEXT: Size: 4
// CHECK-NEXT: Link: 0
// CHECK-NEXT: Info: 0
@@ -46,8 +46,8 @@
// NOTAIL-NEXT: SHF_MERGE
// NOTAIL-NEXT: SHF_STRINGS
// NOTAIL-NEXT: ]
-// NOTAIL-NEXT: Address: 0x1C8
-// NOTAIL-NEXT: Offset: 0x1C8
+// NOTAIL-NEXT: Address: 0x1E1
+// NOTAIL-NEXT: Offset: 0x1E1
// NOTAIL-NEXT: Size: 7
// NOTAIL-NEXT: Link: 0
// NOTAIL-NEXT: Info: 0
@@ -64,8 +64,8 @@
// NOMERGE-NEXT: SHF_MERGE
// NOMERGE-NEXT: SHF_STRINGS
// NOMERGE-NEXT: ]
-// NOMERGE-NEXT: Address: 0x1C8
-// NOMERGE-NEXT: Offset: 0x1C8
+// NOMERGE-NEXT: Address: 0x1E1
+// NOMERGE-NEXT: Offset: 0x1E1
// NOMERGE-NEXT: Size: 11
// NOMERGE-NEXT: Link: 0
// NOMERGE-NEXT: Info: 0
@@ -82,8 +82,8 @@
// CHECK-NEXT: SHF_MERGE
// CHECK-NEXT: SHF_STRINGS
// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x1CC
-// CHECK-NEXT: Offset: 0x1CC
+// CHECK-NEXT: Address: 0x1E6
+// CHECK-NEXT: Offset: 0x1E6
// CHECK-NEXT: Size: 4
// CHECK-NEXT: Link: 0
// CHECK-NEXT: Info: 0
@@ -95,11 +95,11 @@
// CHECK: Name: bar
-// CHECK-NEXT: Value: 0x1C9
+// CHECK-NEXT: Value: 0x1E2
// CHECK: Name: foo
-// CHECK-NEXT: Value: 0x1C8
+// CHECK-NEXT: Value: 0x1E1
// CHECK: Name: zed
-// CHECK-NEXT: Value: 0x1CC
+// CHECK-NEXT: Value: 0x1E6
// CHECK-NEXT: Size: 0
diff --git a/test/ELF/merge-sym.s b/test/ELF/merge-sym.s
index 4a4e982..7329bd4 100644
--- a/test/ELF/merge-sym.s
+++ b/test/ELF/merge-sym.s
@@ -15,7 +15,7 @@
// CHECK-NEXT: SHF_ALLOC
// CHECK-NEXT: SHF_MERGE
// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x1C8
+// CHECK-NEXT: Address: 0x1E4
// CHECK: Name: foo
-// CHECK-NEXT: Value: 0x1CA
+// CHECK-NEXT: Value: 0x1E6
diff --git a/test/ELF/merge-to-non-alloc.s b/test/ELF/merge-to-non-alloc.s
new file mode 100644
index 0000000..e2894ed
--- /dev/null
+++ b/test/ELF/merge-to-non-alloc.s
@@ -0,0 +1,33 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -s -section-data -t %t.so | FileCheck %s
+
+// CHECK: Name: .bar
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 16
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment:
+// CHECK-NEXT: EntrySize:
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT: 0000: E4010000 00000000 EC010000 00000000 |
+// CHECK-NEXT: )
+
+// CHECK: Name: foo
+// CHECK-NEXT: Value: 0x1E4
+
+ .section .foo,"aM",@progbits,4
+ .align 4
+ .global foo
+ .hidden foo
+foo:
+ .long 0x42
+
+ .section .bar
+ .quad foo
+ .quad foo + 8
diff --git a/test/ELF/mips-dynamic.s b/test/ELF/mips-dynamic.s
index 15afb02..820776b 100644
--- a/test/ELF/mips-dynamic.s
+++ b/test/ELF/mips-dynamic.s
@@ -6,7 +6,11 @@
# RUN: ld.lld %t.o %td.so -o %t.exe
# RUN: llvm-readobj -sections -dynamic-table %t.exe \
-# RUN: | FileCheck -check-prefix=EXE %s
+# RUN: | FileCheck -check-prefixes=EXE,NOPIE %s
+
+# RUN: ld.lld -pie %t.o %td.so -o %t.so
+# RUN: llvm-readobj -sections -dyn-symbols -dynamic-table %t.so \
+# RUN: | FileCheck -check-prefixes=EXE,PIE %s
# RUN: ld.lld %t.o --image-base=0x123000 %td.so -o %t.exe
# RUN: llvm-readobj -sections -dynamic-table %t.exe \
@@ -44,17 +48,35 @@
# EXE-NEXT: Offset:
# EXE-NEXT: Size: 8
# EXE: ]
-# EXE: DynamicSection [
-# EXE-NEXT: Tag Type Name/Value
-# EXE-DAG: 0x00000003 PLTGOT [[GOTADDR]]
-# EXE-DAG: 0x70000001 MIPS_RLD_VERSION 1
-# EXE-DAG: 0x70000005 MIPS_FLAGS NOTPOT
-# EXE-DAG: 0x70000006 MIPS_BASE_ADDRESS 0x10000
-# EXE-DAG: 0x7000000A MIPS_LOCAL_GOTNO 2
-# EXE-DAG: 0x70000011 MIPS_SYMTABNO 2
-# EXE-DAG: 0x70000013 MIPS_GOTSYM 0x2
-# EXE-DAG: 0x70000016 MIPS_RLD_MAP [[RLDMAPADDR]]
-# EXE: ]
+
+# PIE: DynamicSection [
+# PIE-NEXT: Tag Type Name/Value
+# PIE: 0x00000004 HASH 0x{{[0-9A-F]+}}
+# PIE-NEXT: 0x70000001 MIPS_RLD_VERSION 1
+# PIE-NEXT: 0x70000005 MIPS_FLAGS NOTPOT
+# PIE-NEXT: 0x70000006 MIPS_BASE_ADDRESS 0x0
+# PIE-NEXT: 0x70000011 MIPS_SYMTABNO 2
+# PIE-NEXT: 0x7000000A MIPS_LOCAL_GOTNO 2
+# PIE-NEXT: 0x70000013 MIPS_GOTSYM 0x2
+# PIE-NEXT: 0x00000003 PLTGOT [[GOTADDR]]
+# PIE-NEXT: 0x70000035 MIPS_RLD_MAP_REL 0x{{[0-9A-F]+}}
+# PIE-NEXT: 0x00000000 NULL 0x0
+# PIE-NEXT: ]
+
+# NOPIE: DynamicSection [
+# NOPIE-NEXT: Tag Type Name/Value
+# NOPIE: 0x00000004 HASH 0x{{[0-9A-F]+}}
+# NOPIE-NEXT: 0x70000001 MIPS_RLD_VERSION 1
+# NOPIE-NEXT: 0x70000005 MIPS_FLAGS NOTPOT
+# NOPIE-NEXT: 0x70000006 MIPS_BASE_ADDRESS 0x10000
+# NOPIE-NEXT: 0x70000011 MIPS_SYMTABNO 2
+# NOPIE-NEXT: 0x7000000A MIPS_LOCAL_GOTNO 2
+# NOPIE-NEXT: 0x70000013 MIPS_GOTSYM 0x2
+# NOPIE-NEXT: 0x00000003 PLTGOT [[GOTADDR]]
+# NOPIE-NEXT: 0x70000016 MIPS_RLD_MAP [[RLDMAPADDR]]
+# NOPIE-NEXT: 0x70000035 MIPS_RLD_MAP_REL 0x{{[0-9A-F]+}}
+# NOPIE-NEXT: 0x00000000 NULL 0x0
+# NOPIE-NEXT: ]
# IMAGE_BASE: 0x70000006 MIPS_BASE_ADDRESS 0x123000
diff --git a/test/ELF/mips-got-string.s b/test/ELF/mips-got-string.s
index 598865c..aec80dd 100644
--- a/test/ELF/mips-got-string.s
+++ b/test/ELF/mips-got-string.s
@@ -8,7 +8,7 @@
# CHECK: Symbol {
# CHECK: Name: $.str
-# CHECK-NEXT: Value: 0xF4
+# CHECK-NEXT: Value: 0x105
# CHECK: }
# CHECK: Local entries [
diff --git a/test/ELF/mips-gp-ext.s b/test/ELF/mips-gp-ext.s
index 2fd21b7..eb9788c 100644
--- a/test/ELF/mips-gp-ext.s
+++ b/test/ELF/mips-gp-ext.s
@@ -27,42 +27,44 @@
# REQUIRES: mips
# REL: Contents of section .text:
-# REL-NEXT: 0000 3c080000 2108010c 8f82fffc
+# REL-NEXT: 0030 3c080000 2108010c 8f82ffcc
# ^-- %hi(_gp_disp)
# ^-- %lo(_gp_disp)
-# ^-- 8 - (0x10c - 0x100)
+# ^-- 8 - (0x13c - 0x100)
# G - (GP - .got)
# REL: Contents of section .reginfo:
-# REL-NEXT: 0028 10000104 00000000 00000000 00000000
-# REL-NEXT: 0038 00000000 0000010c
+# REL-NEXT: 0058 10000104 00000000 00000000 00000000
+# REL-NEXT: 0068 00000000 0000013c
# ^-- _gp
# REL: Contents of section .data:
# REL-NEXT: 00f0 fffffef4
-# ^-- 0-0x10c
+# ^-- 0x30-0x13c
+# foo - GP
-# REL: 00000000 .text 00000000 foo
+# REL: 00000030 .text 00000000 foo
# REL: 00000000 *ABS* 00000000 .hidden _gp_disp
-# REL: 0000010c *ABS* 00000000 .hidden _gp
+# REL: 0000013c *ABS* 00000000 .hidden _gp
# ABS: Contents of section .text:
-# ABS-NEXT: 0000 3c080000 21080200 8f82ff08
+# ABS-NEXT: 0030 3c080000 210801d0 8f82ff08
# ^-- %hi(_gp_disp)
# ^-- %lo(_gp_disp)
# ^-- 8 - (0x200 - 0x100)
# G - (GP - .got)
# ABS: Contents of section .reginfo:
-# ABS-NEXT: 0028 10000104 00000000 00000000 00000000
-# ABS-NEXT: 0038 00000000 00000200
+# ABS-NEXT: 0058 10000104 00000000 00000000 00000000
+# ABS-NEXT: 0068 00000000 00000200
# ^-- _gp
# ABS: Contents of section .data:
-# ABS-NEXT: 00f0 fffffe00
-# ^-- 0-0x200
+# ABS-NEXT: 00f0 fffffe30
+# ^-- 0x30-0x200
+# foo - GP
-# ABS: 00000000 .text 00000000 foo
+# ABS: 00000030 .text 00000000 foo
# ABS: 00000000 *ABS* 00000000 .hidden _gp_disp
# ABS: 00000200 *ABS* 00000000 .hidden _gp
diff --git a/test/ELF/mips-gp-lowest.s b/test/ELF/mips-gp-lowest.s
index 32a3e85..ecc5f7b 100644
--- a/test/ELF/mips-gp-lowest.s
+++ b/test/ELF/mips-gp-lowest.s
@@ -26,7 +26,7 @@
# CHECK-NEXT: SHF_MIPS_GPREL
# CHECK-NEXT: SHF_WRITE
# CHECK-NEXT: ]
-# CHECK-NEXT: Address: 0xE0
+# CHECK-NEXT: Address: 0xF0
# CHECK: }
# CHECK: Section {
# CHECK: Name: .got
@@ -36,9 +36,9 @@
# CHECK-NEXT: SHF_MIPS_GPREL
# CHECK-NEXT: SHF_WRITE
# CHECK-NEXT: ]
-# CHECK-NEXT: Address: 0xF0
+# CHECK-NEXT: Address: 0x100
# CHECK: }
# CHECK: Name: _gp (5)
-# CHECK-NEXT: Value: 0x80D0
-# ^-- 0xE0 + 0x7ff0
+# CHECK-NEXT: Value: 0x80E0
+# ^-- 0xF0 + 0x7ff0
diff --git a/test/ELF/mips-gprel32-relocs-gp0.s b/test/ELF/mips-gprel32-relocs-gp0.s
index 507224e..f27caa3 100644
--- a/test/ELF/mips-gprel32-relocs-gp0.s
+++ b/test/ELF/mips-gprel32-relocs-gp0.s
@@ -1,8 +1,4 @@
# Check that relocatable object produced by LLD has zero gp0 value.
-# Also check an error message if input object file has non-zero gp0 value
-# and the linker generates a relocatable object.
-# mips-gp0-non-zero.o is a relocatable object produced from the asm code
-# below and linked by GNU bfd linker.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
# RUN: ld.lld -r -o %t-rel.o %t.o
@@ -12,9 +8,6 @@
# RUN: llvm-readobj -mips-reginfo %t.so | FileCheck --check-prefix=DSO %s
# RUN: llvm-objdump -s -t %t.so | FileCheck --check-prefix=DUMP %s
-# RUN: not ld.lld -r -o %t-rel.o %S/Inputs/mips-gp0-non-zero.o 2>&1 \
-# RUN: | FileCheck --check-prefix=ERR %s
-
# REQUIRES: mips
# REL: GP: 0x0
@@ -31,8 +24,6 @@
# DUMP: 00010004 .text 00000000 foo
# DUMP: 00027ff0 .got 00000000 .hidden _gp
-# ERR: error: {{.*}}mips-gp0-non-zero.o: unsupported non-zero ri_gp_value
-
.text
.global __start
__start:
diff --git a/test/ELF/mips-micro-plt.s b/test/ELF/mips-micro-plt.s
index 5671dc4..16f3bd4 100644
--- a/test/ELF/mips-micro-plt.s
+++ b/test/ELF/mips-micro-plt.s
@@ -7,13 +7,14 @@
# RUN: -mattr=micromips %s -o %t-exe.o
# RUN: ld.lld %t-exe.o %t.so -o %t.exe
# RUN: llvm-readobj -t -dt -mips-plt-got %t.exe | FileCheck %s
+# RUN: llvm-objdump -d -mattr=micromips %t.exe | FileCheck --check-prefix=ASM %s
# REQUIRES: mips
# CHECK: Symbols [
# CHECK: Symbol {
# CHECK: Name: foo
-# CHECK-NEXT: Value: 0x20008
+# CHECK-NEXT: Value: 0x20010
# CHECK-NEXT: Size:
# CHECK-NEXT: Binding: Local
# CHECK-NEXT: Type: None
@@ -36,22 +37,28 @@
# CHECK-NEXT: }
# CHECK: Symbol {
# CHECK: Name: foo0
-# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Value: 0x20040
# CHECK-NEXT: Size:
# CHECK-NEXT: Binding: Global
# CHECK-NEXT: Type: Function
-# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Other [
+# CHECK-NEXT: STO_MIPS_MICROMIPS
+# CHECK-NEXT: STO_MIPS_PLT
+# CHECK-NEXT: ]
# CHECK-NEXT: Section: Undefined
# CHECK-NEXT: }
# CHECK-NEXT: ]
# CHECK: DynamicSymbols [
# CHECK: Symbol {
# CHECK: Name: foo0
-# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Value: 0x20041
# CHECK-NEXT: Size:
# CHECK-NEXT: Binding: Global
# CHECK-NEXT: Type: Function
-# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Other [
+# CHECK-NEXT: STO_MIPS_MICROMIPS
+# CHECK-NEXT: STO_MIPS_PLT
+# CHECK-NEXT: ]
# CHECK-NEXT: Section: Undefined
# CHECK-NEXT: }
# CHECK-NEXT: ]
@@ -61,7 +68,7 @@
# CHECK-NEXT: Entry {
# CHECK-NEXT: Address:
# CHECK-NEXT: Access:
-# CHECK-NEXT: Initial: 0x20009
+# CHECK-NEXT: Initial: 0x20011
# CHECK-NEXT: }
# CHECK: ]
# CHECK: }
@@ -70,8 +77,8 @@
# CHECK: Entries [
# CHECK-NEXT: Entry {
# CHECK-NEXT: Address:
-# CHECK-NEXT: Initial: 0x20011
-# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Initial: 0x20021
+# CHECK-NEXT: Value: 0x20041
# CHECK-NEXT: Type: Function
# CHECK-NEXT: Section: Undefined
# CHECK-NEXT: Name: foo0@
@@ -79,6 +86,15 @@
# CHECK-NEXT: ]
# CHECK-NEXT: }
+# ASM: __start:
+# ASM-NEXT: 20000: fd 1c 80 18 lw $8, -32744($gp)
+# ASM-NEXT: 20004: 11 08 00 10 addi $8, $8, 16
+# ASM-NEXT: 20008: 41 a8 00 02 lui $8, 2
+# ASM-NEXT: 2000c: 11 08 00 40 addi $8, $8, 64
+#
+# ASM: foo:
+# ASM-NEXT: 20010: f4 01 00 20 jal 131136
+
.text
.set micromips
.global foo
@@ -87,5 +103,7 @@
__start:
lw $t0,%got(foo)($gp)
addi $t0,$t0,%lo(foo)
+ lui $t0,%hi(foo0)
+ addi $t0,$t0,%lo(foo0)
foo:
jal foo0
diff --git a/test/ELF/mips-micro-thunks.s b/test/ELF/mips-micro-thunks.s
index 18a8fc3..c8695cc 100644
--- a/test/ELF/mips-micro-thunks.s
+++ b/test/ELF/mips-micro-thunks.s
@@ -1,44 +1,78 @@
# Check microMIPS thunk generation.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
-# RUN: -mattr=micromips %s -o %t-eb.o
+# RUN: -mcpu=mips32r2 -mattr=micromips %s -o %t-eb.o
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
-# RUN: -position-independent -mattr=micromips \
+# RUN: -position-independent -mcpu=mips32r2 -mattr=micromips \
# RUN: %S/Inputs/mips-micro.s -o %t-eb-pic.o
# RUN: ld.lld -o %t-eb.exe %t-eb.o %t-eb-pic.o
# RUN: llvm-objdump -d -mattr=+micromips %t-eb.exe \
-# RUN: | FileCheck --check-prefix=EB %s
+# RUN: | FileCheck --check-prefix=EB-R2 %s
# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
-# RUN: -mattr=micromips %s -o %t-el.o
+# RUN: -mcpu=mips32r2 -mattr=micromips %s -o %t-el.o
# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
-# RUN: -position-independent -mattr=micromips \
+# RUN: -position-independent -mcpu=mips32r2 -mattr=micromips \
# RUN: %S/Inputs/mips-micro.s -o %t-el-pic.o
# RUN: ld.lld -o %t-el.exe %t-el.o %t-el-pic.o
# RUN: llvm-objdump -d -mattr=+micromips %t-el.exe \
-# RUN: | FileCheck --check-prefix=EL %s
+# RUN: | FileCheck --check-prefix=EL-R2 %s
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN: -mcpu=mips32r6 -mattr=micromips %s -o %t-eb-r6.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN: -position-independent -mcpu=mips32r6 -mattr=micromips \
+# RUN: %S/Inputs/mips-micro.s -o %t-eb-pic-r6.o
+# RUN: ld.lld -o %t-eb-r6.exe %t-eb-r6.o %t-eb-pic-r6.o
+# RUN: llvm-objdump -d -mattr=+micromips %t-eb-r6.exe \
+# RUN: | FileCheck --check-prefix=EB-R6 %s
+
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
+# RUN: -mcpu=mips32r6 -mattr=micromips %s -o %t-el-r6.o
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
+# RUN: -position-independent -mcpu=mips32r6 -mattr=micromips \
+# RUN: %S/Inputs/mips-micro.s -o %t-el-pic-r6.o
+# RUN: ld.lld -o %t-el-r6.exe %t-el-r6.o %t-el-pic-r6.o
+# RUN: llvm-objdump -d -mattr=+micromips %t-el-r6.exe \
+# RUN: | FileCheck --check-prefix=EL-R6 %s
# REQUIRES: mips
-# EB: __start:
-# EB-NEXT: 20000: f4 01 00 04 jal 131080 <__microLA25Thunk_foo>
-# EB-NEXT: 20004: 00 00 00 00 nop
+# EB-R2: __start:
+# EB-R2-NEXT: 20000: f4 01 00 04 jal 131080 <__microLA25Thunk_foo>
+# EB-R2-NEXT: 20004: 00 00 00 00 nop
-# EB: __microLA25Thunk_foo:
-# EB-NEXT: 20008: 41 b9 00 02 lui $25, 2
-# EB-NEXT: 2000c: d4 01 00 10 j 131104
-# EB-NEXT: 20010: 33 39 00 21 addiu $25, $25, 33
-# EB-NEXT: 20014: 0c 00 nop
+# EB-R2: __microLA25Thunk_foo:
+# EB-R2-NEXT: 20008: 41 b9 00 02 lui $25, 2
+# EB-R2-NEXT: 2000c: d4 01 00 10 j 131104
+# EB-R2-NEXT: 20010: 33 39 00 21 addiu $25, $25, 33
+# EB-R2-NEXT: 20014: 0c 00 nop
-# EL: __start:
-# EL-NEXT: 20000: 01 f4 04 00 jal 131080 <__microLA25Thunk_foo>
-# EL-NEXT: 20004: 00 00 00 00 nop
+# EL-R2: __start:
+# EL-R2-NEXT: 20000: 01 f4 04 00 jal 131080 <__microLA25Thunk_foo>
+# EL-R2-NEXT: 20004: 00 00 00 00 nop
-# EL: __microLA25Thunk_foo:
-# EL-NEXT: 20008: b9 41 02 00 lui $25, 2
-# EL-NEXT: 2000c: 01 d4 10 00 j 131104
-# EL-NEXT: 20010: 39 33 21 00 addiu $25, $25, 33
-# EL-NEXT: 20014: 00 0c nop
+# EL-R2: __microLA25Thunk_foo:
+# EL-R2-NEXT: 20008: b9 41 02 00 lui $25, 2
+# EL-R2-NEXT: 2000c: 01 d4 10 00 j 131104
+# EL-R2-NEXT: 20010: 39 33 21 00 addiu $25, $25, 33
+# EL-R2-NEXT: 20014: 00 0c nop
+
+# EB-R6: __start:
+# EB-R6-NEXT: 20000: b4 00 00 00 balc 0 <__start>
+
+# EB-R6: __microLA25Thunk_foo:
+# EB-R6-NEXT: 20004: 13 20 00 02 lui $25, 2
+# EB-R6-NEXT: 20008: 33 39 00 11 addiu $25, $25, 17
+# EB-R6-NEXT: 2000c: 94 00 00 00 bc 0 <__microLA25Thunk_foo+0x8>
+
+# EL-R6: __start:
+# EL-R6-NEXT: 20000: 00 b4 00 00 balc 0 <__start>
+
+# EL-R6: __microLA25Thunk_foo:
+# EL-R6-NEXT: 20004: 20 13 02 00 lui $25, 2
+# EL-R6-NEXT: 20008: 39 33 11 00 addiu $25, $25, 17
+# EL-R6-NEXT: 2000c: 00 94 00 00 bc 0 <__microLA25Thunk_foo+0x8>
.text
.set micromips
diff --git a/test/ELF/mips-micro64-relocs.s b/test/ELF/mips-micro64-relocs.s
new file mode 100644
index 0000000..b440c7a
--- /dev/null
+++ b/test/ELF/mips-micro64-relocs.s
@@ -0,0 +1,22 @@
+# REQUIRES: mips
+
+# Check handling of some microMIPS relocations in 64-bit mode.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64el-unknown-linux \
+# RUN: -mattr=micromips %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips64el-unknown-linux \
+# RUN: -mattr=micromips %S/Inputs/mips-dynamic.s -o %t2.o
+# RUN: ld.lld %t1.o %t2.o -o %t.exe
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+ .global __start
+__start:
+ lui $7, %highest(_foo+0x300047FFF7FF8)
+ lui $7, %higher (_foo+0x300047FFF7FF8)
+ lui $gp, %hi(%neg(%gp_rel(__start)))
+ lui $gp, %lo(%neg(%gp_rel(__start)))
+
+# CHECK: 20000: a7 41 03 00 lui $7, 3
+# CHECK-NEXT: 20004: a7 41 05 00 lui $7, 5
+# CHECK-NEXT: 20008: bc 41 02 00 lui $gp, 2
+# CHECK-NEXT: 2000c: bc 41 00 80 lui $gp, 32768
diff --git a/test/ELF/mips-micror6-relocs.s b/test/ELF/mips-micror6-relocs.s
new file mode 100644
index 0000000..ca2c1c0
--- /dev/null
+++ b/test/ELF/mips-micror6-relocs.s
@@ -0,0 +1,38 @@
+# REQUIRES: mips
+
+# Check handling of microMIPS R6 relocations.
+
+# RUN: llvm-mc -filetype=obj -triple=mips -mcpu=mips32r6 \
+# RUN: %S/Inputs/mips-micro.s -o %t1eb.o
+# RUN: llvm-mc -filetype=obj -triple=mips -mcpu=mips32r6 %s -o %t2eb.o
+# RUN: ld.lld -o %teb.exe %t1eb.o %t2eb.o
+# RUN: llvm-objdump -d -t -mattr=micromips %teb.exe \
+# RUN: | FileCheck --check-prefixes=EB,SYM %s
+
+# RUN: llvm-mc -filetype=obj -triple=mipsel -mcpu=mips32r6 \
+# RUN: %S/Inputs/mips-micro.s -o %t1el.o
+# RUN: llvm-mc -filetype=obj -triple=mipsel -mcpu=mips32r6 %s -o %t2el.o
+# RUN: ld.lld -o %tel.exe %t1el.o %t2el.o
+# RUN: llvm-objdump -d -t -mattr=micromips %tel.exe \
+# RUN: | FileCheck --check-prefixes=EL,SYM %s
+
+# EB: __start:
+# EB-NEXT: 20010: 78 47 ff fd lapc $2, -12
+# EB-NEXT: 20014: 80 7f ff f6 beqzc $3, -36
+# EB-NEXT: 20018: b7 ff ff f4 balc -24 <foo>
+
+# EL: __start:
+# EL-NEXT: 20010: 47 78 fd ff lapc $2, -12
+# EL-NEXT: 20014: 7f 80 f6 ff beqzc $3, -36
+# EL-NEXT: 20018: ff b7 f4 ff balc -24 <foo>
+
+# SYM: 00020000 g F .text 00000000 foo
+# SYM: 00020010 .text 00000000 __start
+
+ .text
+ .set micromips
+ .global __start
+__start:
+ addiupc $2, foo+4 # R_MICROMIPS_PC19_S2
+ beqzc $3, foo+4 # R_MICROMIPS_PC21_S1
+ balc foo+4 # R_MICROMIPS_PC26_S1
diff --git a/test/ELF/mips-non-zero-gp0.s b/test/ELF/mips-non-zero-gp0.s
new file mode 100644
index 0000000..babfde9
--- /dev/null
+++ b/test/ELF/mips-non-zero-gp0.s
@@ -0,0 +1,66 @@
+# REQUIRES: mips
+
+# Check addend adjustment in case of generating a relocatable object
+# if some input files have non-zero GP0 value.
+
+# We have to use GNU as and ld.bfd 2.28 to generate relocatable object
+# files with non-zero GP0 value using the following command lines:
+#
+# as -mips32 -o test.o \
+# && ld.bfd -m elf32btsmip -r test.o -o mips-gp0-non-zero.o
+# as -mips64 -mmicromips -o test.o \
+# && ld.bfd -m elf64btsmip -r test.o -o mips-micro-gp0-non-zero.o
+# as -mips64 -o test.o \
+# && ld.bfd -m elf64btsmip -r test.o -o mips-n64-gp0-non-zero.o
+
+# Source code for mips-gp0-non-zero.o:
+# .text
+# .global __start
+# __start:
+# lw $t0,%call16(__start)($gp)
+# foo:
+# nop
+# bar:
+# nop
+#
+# .section .rodata, "a"
+# v:
+# .gpword foo
+# .gpword bar
+
+# Source code for mips-n64-gp0-non-zero.o and mips-micro-gp0-non-zero.o:
+# .text
+# .global __start
+# __start:
+# foo:
+# lui $gp,%hi(%neg(%gp_rel(foo)))
+
+# RUN: ld.lld -r -o %t-32.r %S/Inputs/mips-gp0-non-zero.o
+# RUN: llvm-readobj -mips-reginfo %t-32.r | FileCheck --check-prefix=GPVAL %s
+# RUN: llvm-objdump -s %t-32.r | FileCheck --check-prefix=ADDEND32 %s
+
+# RUN: ld.lld -r -o %t-64.r %S/Inputs/mips-n64-gp0-non-zero.o
+# RUN: llvm-readobj -mips-options %t-64.r | FileCheck --check-prefix=GPVAL %s
+# RUN: llvm-readobj -r %S/Inputs/mips-n64-gp0-non-zero.o %t-64.r \
+# RUN: | FileCheck --check-prefix=ADDEND64 %s
+
+# RUN: ld.lld -r -o %t-micro.r %S/Inputs/mips-micro-gp0-non-zero.o
+# RUN: llvm-readobj -mips-options %t-micro.r | FileCheck --check-prefix=GPVAL %s
+# RUN: llvm-readobj -r %S/Inputs/mips-micro-gp0-non-zero.o %t-micro.r \
+# RUN: | FileCheck --check-prefix=ADDENDMM %s
+
+# GPVAL: GP: 0x0
+
+# ADDEND32: Contents of section .rodata:
+# ADDEND32-NEXT: 0000 00007ff4 00007ff8
+# ^ 4+GP0 ^ 8+GP0
+
+# ADDEND64: File: {{.*}}{{/|\\}}mips-n64-gp0-non-zero.o
+# ADDEND64: .text 0xFFFFFFFFFFFF8011
+# ADDEND64: File: {{.*}}{{/|\\}}mips-non-zero-gp0.s.tmp-64.r
+# ADDEND64: .text 0x0
+
+# ADDENDMM: File: {{.*}}{{/|\\}}mips-micro-gp0-non-zero.o
+# ADDENDMM: .text 0xFFFFFFFFFFFF8012
+# ADDENDMM: File: {{.*}}{{/|\\}}mips-non-zero-gp0.s.tmp-micro.r
+# ADDENDMM: .text 0x1
diff --git a/test/ELF/mips-plt-n32.s b/test/ELF/mips-plt-n32.s
new file mode 100644
index 0000000..06699fc
--- /dev/null
+++ b/test/ELF/mips-plt-n32.s
@@ -0,0 +1,43 @@
+# REQUIRES: mips
+
+# Check PLT entries generation in case of using N32 ABI.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# RUN: -target-abi n32 %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# RUN: -target-abi n32 %S/Inputs/mips-dynamic.s -o %t2.o
+# RUN: ld.lld %t2.o -shared -o %t.so
+# RUN: ld.lld %t1.o %t.so -o %t.exe
+# RUN: llvm-objdump -d %t.exe | FileCheck %s --check-prefixes=DEFAULT,CHECK
+# RUN: ld.lld %t2.o -shared -o %t.so -z hazardplt
+# RUN: ld.lld %t1.o %t.so -o %t.exe -z hazardplt
+# RUN: llvm-objdump -d %t.exe | FileCheck %s --check-prefixes=HAZARDPLT,CHECK
+
+# CHECK: Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT: 20000: 0c 00 80 0c jal 131120
+# ^-- 0x20030 gotplt[foo0]
+# CHECK-NEXT: 20004: 00 00 00 00 nop
+#
+# CHECK-NEXT: Disassembly of section .plt:
+# CHECK-NEXT: .plt:
+# CHECK-NEXT: 20010: 3c 0e 00 03 lui $14, 3
+# CHECK-NEXT: 20014: 8d d9 00 04 lw $25, 4($14)
+# CHECK-NEXT: 20018: 25 ce 00 04 addiu $14, $14, 4
+# CHECK-NEXT: 2001c: 03 0e c0 23 subu $24, $24, $14
+# CHECK-NEXT: 20020: 03 e0 78 25 move $15, $ra
+# CHECK-NEXT: 20024: 00 18 c0 82 srl $24, $24, 2
+# DEFAULT: 20028: 03 20 f8 09 jalr $25
+# HAZARDPLT: 20028: 03 20 fc 09 jalr.hb $25
+# CHECK-NEXT: 2002c: 27 18 ff fe addiu $24, $24, -2
+
+# CHECK-NEXT: 20030: 3c 0f 00 03 lui $15, 3
+# CHECK-NEXT: 20034: 8d f9 00 0c lw $25, 12($15)
+# DEFAULT: 20038: 03 20 00 08 jr $25
+# HAZARDPLT: 20038: 03 20 04 08 jr.hb $25
+# CHECK-NEXT: 2003c: 25 f8 00 0c addiu $24, $15, 12
+
+ .text
+ .global __start
+__start:
+ jal foo0 # R_MIPS_26 against 'foo0' from DSO
diff --git a/test/ELF/no-line-parser-errors-if-empty-section.s b/test/ELF/no-line-parser-errors-if-empty-section.s
new file mode 100644
index 0000000..56b255e
--- /dev/null
+++ b/test/ELF/no-line-parser-errors-if-empty-section.s
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+
+# LLD uses the debug data to get information for error messages, if possible.
+# However, if the debug line section is empty, we should not attempt to parse
+# it, as that would result in errors from the parser.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: not ld.lld %t.o -o %t.elf 2>&1 | FileCheck %s
+
+# CHECK-NOT: warning:
+# CHECK-NOT: error:
+# CHECK: error: undefined symbol: undefined
+# CHECK-NEXT: {{.*}}.o:(.text+0x1)
+# CHECK-NOT: warning:
+# CHECK-NOT: error:
+
+.globl _start
+_start:
+ callq undefined
+
+.section .debug_line,"",@progbits
diff --git a/test/ELF/no-line-parser-errors-if-no-section.s b/test/ELF/no-line-parser-errors-if-no-section.s
new file mode 100644
index 0000000..9210d85
--- /dev/null
+++ b/test/ELF/no-line-parser-errors-if-no-section.s
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+
+# LLD uses the debug data to get information for error messages, if possible.
+# However, if there is no debug line section, we should not attempt to parse
+# it, as that would result in errors from the parser.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: not ld.lld %t.o -o %t.elf 2>&1 | FileCheck %s
+
+# CHECK-NOT: warning:
+# CHECK-NOT: error:
+# CHECK: error: undefined symbol: undefined
+# CHECK-NEXT: {{.*}}.o:(.text+0x1)
+# CHECK-NOT: warning:
+# CHECK-NOT: error:
+
+.globl _start
+_start:
+ callq undefined
diff --git a/test/ELF/non-alloc-link-order-gc.s b/test/ELF/non-alloc-link-order-gc.s
new file mode 100644
index 0000000..8147c45
--- /dev/null
+++ b/test/ELF/non-alloc-link-order-gc.s
@@ -0,0 +1,34 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t1 --gc-sections
+# RUN: llvm-objdump -section-headers -D %t1 | FileCheck %s
+
+## Check that we are able to GC non-allocatable metadata sections without crash.
+
+# CHECK: Disassembly of section .stack_sizes:
+# CHECK-NEXT: .stack_sizes:
+# CHECK-NEXT: 01
+
+# CHECK: Name Size
+# CHECK: .stack_sizes 00000001
+
+.section .text.live,"ax",@progbits
+.globl live
+live:
+ nop
+
+.section .stack_sizes,"o",@progbits,.text.live,unique,0
+.byte 1
+
+.section .text.dead,"ax",@progbits
+.globl dead
+dead:
+ nop
+
+.section .stack_sizes,"o",@progbits,.text.dead,unique,1
+.byte 2
+
+.section .text.main,"ax",@progbits
+.globl _start
+_start:
+ callq live@PLT
diff --git a/test/ELF/note-noalloc.s b/test/ELF/note-noalloc.s
new file mode 100644
index 0000000..ddbde3e
--- /dev/null
+++ b/test/ELF/note-noalloc.s
@@ -0,0 +1,38 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t -shared
+// RUN: llvm-readobj -program-headers -sections %t | FileCheck %s
+
+// PR37361: A note without SHF_ALLOC should not be included into a PT_NOTE program header.
+
+// CHECK: Section {
+// CHECK: Index:
+// CHECK: Name: .note.a
+// CHECK-NEXT: Type: SHT_NOTE
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x[[ADDR:.*]]
+
+// Check we still emit the non-alloc SHT_NOTE section and keep its type.
+
+// CHECK: Name: .note.b
+// CHECK-NEXT: Type: SHT_NOTE
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: ]
+
+// CHECK: ProgramHeader {
+// CHECK: Type: PT_NOTE
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: VirtualAddress: 0x[[ADDR]]
+// CHECK-NEXT: PhysicalAddress: 0x24C
+// CHECK-NEXT: FileSize: 16
+// CHECK-NEXT: MemSize: 16
+// CHECK-NOT: PT_NOTE
+
+.section .note.a,"a",@note
+.quad 1
+.quad 2
+
+.section .note.b,"",@note
+.quad 3
diff --git a/test/ELF/note-noalloc2.s b/test/ELF/note-noalloc2.s
new file mode 100644
index 0000000..3705799
--- /dev/null
+++ b/test/ELF/note-noalloc2.s
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-readobj -program-headers %t | FileCheck %s
+
+## Check we do not create a PT_NOTE segment for non-allocatable note section.
+
+# CHECK-NOT: PT_NOTE
+
+.section .note,"",@note
+.quad 0
diff --git a/test/ELF/ppc64-addr16-error.s b/test/ELF/ppc64-addr16-error.s
index f16ca69..d258089 100644
--- a/test/ELF/ppc64-addr16-error.s
+++ b/test/ELF/ppc64-addr16-error.s
@@ -1,7 +1,12 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-addr16-error.s -o %t2
+// RUN: not ld.lld -shared %t %t2 -o %t3 2>&1 | FileCheck %s
+
// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t
// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-addr16-error.s -o %t2
// RUN: not ld.lld -shared %t %t2 -o %t3 2>&1 | FileCheck %s
-// REQUIRES: ppc
.short sym+65539
diff --git a/test/ELF/ppc64-dynamic-relocations.s b/test/ELF/ppc64-dynamic-relocations.s
new file mode 100644
index 0000000..2d9dfc6
--- /dev/null
+++ b/test/ELF/ppc64-dynamic-relocations.s
@@ -0,0 +1,50 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: llvm-readobj -dyn-relocations %t | FileCheck %s
+// RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=DIS %s
+// RUN: llvm-readelf -dynamic-table %t | FileCheck --check-prefix=DT %s
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: llvm-readobj -dyn-relocations %t | FileCheck %s
+// RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=DIS %s
+// RUN: llvm-readelf -dynamic-table %t | FileCheck --check-prefix=DT %s
+
+
+// The dynamic relocation for foo should point to 16 bytes past the start of
+// the .plt section.
+// CHECK: Dynamic Relocations {
+// CHECK-NEXT: 0x10030010 R_PPC64_JMP_SLOT foo 0x0
+
+// There should be 2 reserved doublewords before the first entry. The dynamic
+// linker will fill those in with the address of the resolver entry point and
+// the dynamic object identifier.
+// DIS: Idx Name Size Address Type
+// DIS: .plt 00000018 0000000010030000 BSS
+
+// DT_PLTGOT should point to the start of the .plt section.
+// DT: 0x0000000000000003 PLTGOT 0x10030000
+
+ .text
+ .abiversion 2
+ .globl _start
+ .p2align 4
+ .type _start,@function
+_start:
+.Lfunc_begin0:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry _start, .Lfunc_lep0-.Lfunc_gep0
+ bl foo
+ nop
+ li 0, 1
+ sc
+ .size _start, .-.Lfunc_begin0
diff --git a/test/ELF/ppc64-error-toc-restore.s b/test/ELF/ppc64-error-toc-restore.s
new file mode 100644
index 0000000..19153b7
--- /dev/null
+++ b/test/ELF/ppc64-error-toc-restore.s
@@ -0,0 +1,20 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s
+
+# Calling external function bar needs a nop
+// CHECK: call lacks nop, can't restore toc
+ .text
+ .abiversion 2
+
+.global _start
+_start:
+ bl foo
diff --git a/test/ELF/ppc64-error-toc-tail-call.s b/test/ELF/ppc64-error-toc-tail-call.s
new file mode 100644
index 0000000..da8fea2
--- /dev/null
+++ b/test/ELF/ppc64-error-toc-tail-call.s
@@ -0,0 +1,20 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s
+
+# A tail call to an external function without a nop should issue an error.
+// CHECK: call lacks nop, can't restore toc
+ .text
+ .abiversion 2
+
+.global _start
+_start:
+ b foo
diff --git a/test/ELF/ppc64-func-entry-points.s b/test/ELF/ppc64-func-entry-points.s
new file mode 100644
index 0000000..640c94f
--- /dev/null
+++ b/test/ELF/ppc64-func-entry-points.s
@@ -0,0 +1,80 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-func-global-entry.s -o %t2.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-func-local-entry.s -o %t3.o
+// RUN: ld.lld -dynamic-linker /lib64/ld64.so.2 %t.o %t2.o %t3.o -o %t
+// RUN: llvm-objdump -d %t | FileCheck %s
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-func-global-entry.s -o %t2.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-func-local-entry.s -o %t3.o
+// RUN: ld.lld -dynamic-linker /lib64/ld64.so.2 %t.o %t2.o %t3.o -o %t
+// RUN: llvm-objdump -d %t | FileCheck %s
+
+ .text
+ .abiversion 2
+ .globl _start # -- Begin function _start
+ .p2align 4
+ .type _start,@function
+_start: # @_start
+.Lfunc_begin0:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry _start, .Lfunc_lep0-.Lfunc_gep0
+# %bb.0: # %entry
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -48(1)
+ li 3, 1
+ li 4, 1
+ std 30, 32(1) # 8-byte Folded Spill
+ bl foo_external_same
+ nop
+ mr 30, 3
+ li 3, 2
+ li 4, 2
+ bl foo_external_diff
+ nop
+ addis 4, 2, .LC0@toc@ha
+ add 3, 3, 30
+ ld 30, 32(1) # 8-byte Folded Reload
+ ld 4, .LC0@toc@l(4)
+ lwz 4, 0(4)
+ add 3, 3, 4
+ extsw 3, 3
+ addi 1, 1, 48
+ ld 0, 16(1)
+ li 0, 1
+ sc
+ .long 0
+ .quad 0
+.Lfunc_end0:
+ .size _start, .Lfunc_end0-.Lfunc_begin0
+ # -- End function
+ .section .toc,"aw",@progbits
+.LC0:
+ .tc glob[TC],glob
+ .type glob,@object # @glob
+ .data
+ .globl glob
+ .p2align 2
+glob:
+ .long 10 # 0xa
+ .size glob, 4
+
+# Check that foo_external_diff has a global entry point and we branch to
+# foo_external_diff+8. Also check that foo_external_same has no global entry
+# point and we branch to start of foo_external_same.
+
+// CHECK: _start:
+// CHECK: 10010020: {{.*}} bl .+144
+// CHECK: 10010034: {{.*}} bl .+84
+// CHECK: foo_external_diff:
+// CHECK-NEXT: 10010080: {{.*}} addis 2, 12, 2
+// CHECK-NEXT: 10010084: {{.*}} addi 2, 2, 32640
+// CHECK-NEXT: 10010088: {{.*}} addis 5, 2, 0
+// CHECK: foo_external_same:
+// CHECK-NEXT: 100100b0: {{.*}} add 3, 4, 3
diff --git a/test/ELF/ppc64-general-dynamic-tls.s b/test/ELF/ppc64-general-dynamic-tls.s
new file mode 100644
index 0000000..66dab93
--- /dev/null
+++ b/test/ELF/ppc64-general-dynamic-tls.s
@@ -0,0 +1,112 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-readelf -relocations --wide %t.so | FileCheck --check-prefix=OutputRelocs %s
+// RUN: llvm-objdump --section-headers %t.so | FileCheck --check-prefix=CheckGot %s
+// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=Dis %s
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-readelf -relocations --wide %t.so | FileCheck --check-prefix=OutputRelocs %s
+// RUN: llvm-objdump --section-headers %t.so | FileCheck --check-prefix=CheckGot %s
+// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=Dis %s
+
+ .text
+ .abiversion 2
+ .globl test
+ .p2align 4
+ .type test,@function
+test:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry test, .Lfunc_lep0-.Lfunc_gep0
+ mflr 0
+ std 31, -8(1)
+ std 0, 16(1)
+ stdu 1, -48(1)
+ mr 31, 1
+ std 30, 32(31)
+ addis 3, 2, i@got@tlsgd@ha
+ addi 3, 3, i@got@tlsgd@l
+ bl __tls_get_addr(i@tlsgd)
+ nop
+ lwz 30, 0(3)
+ extsw 3, 30
+ ld 30, 32(31)
+ addi 1, 1, 48
+ ld 0, 16(1)
+ ld 31, -8(1)
+ mtlr 0
+ blr
+
+
+test_hi:
+.Lfunc_gep1:
+ addis 2, 12, .TOC.-.Lfunc_gep1@ha
+ addi 2, 2, .TOC.-.Lfunc_gep1@l
+.Lfunc_lep1:
+ .localentry test2, .Lfunc_lep1-.Lfunc_gep1
+ addis 3, 0, j@got@tlsgd@h
+ blr
+
+test_16:
+.Lfunc_gep2:
+ addis 2, 12, .TOC.-.Lfunc_gep2@ha
+ addi 2, 2, .TOC.-.Lfunc_gep2@l
+.Lfunc_lep2:
+ .localentry test16, .Lfunc_lep2-.Lfunc_gep2
+ addi 3, 0, k@got@tlsgd
+ blr
+
+// Verify that the input has every general-dynamic tls relocation type.
+// InputRelocs: Relocation section '.rela.text'
+// InputRelocs: R_PPC64_GOT_TLSGD16_HA {{0+}} i + 0
+// InputRelocs: R_PPC64_GOT_TLSGD16_LO {{0+}} i + 0
+// InputRelocs: R_PPC64_TLSGD {{0+}} i + 0
+// InputRelocs: R_PPC64_GOT_TLSGD16_HI {{0+}} j + 0
+// InputRelocs: R_PPC64_GOT_TLSGD16 {{0+}} k + 0
+
+// There is 2 got entries for each tls variable that is accessed with the
+// general-dynamic model. The entries can be though of as a structure to be
+// filled in by the dynamic linker:
+// typedef struct {
+// unsigned long int ti_module; --> R_PPC64_DTPMOD64
+// unsigned long int ti_offset; --> R_PPC64_DTPREL64
+//} tls_index;
+// OutputRelocs: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 6 entries:
+// OutputRelocs: R_PPC64_DTPMOD64 {{0+}} i + 0
+// OutputRelocs: R_PPC64_DTPREL64 {{0+}} i + 0
+// OutputRelocs: R_PPC64_DTPMOD64 {{0+}} j + 0
+// OutputRelocs: R_PPC64_DTPREL64 {{0+}} j + 0
+// OutputRelocs: R_PPC64_DTPMOD64 {{0+}} k + 0
+// OutputRelocs: R_PPC64_DTPREL64 {{0+}} k + 0
+
+// Check that the got has 7 entires. (1 for the TOC and 3 structures of
+// 2 entries for the tls variables). Also verify the address so we can check
+// the offsets we calculated for each relocation type.
+// CheckGot: got 00000038 00000000000200f0
+
+// got starts at 0x200f0, so .TOC. will be 0x280f0.
+
+// We are building the address of the first tls_index in the got which starts at
+// 0x200f8 (got[1]).
+// #ha(i@got@tlsgd) --> (0x200f8 - 0x280f0 + 0x8000) >> 16 = 0
+// #lo(i@got@tlsgd) --> (0x200f8 - 0x280f0) & 0xFFFF = -7ff8 = -32760
+// Dis: test:
+// Dis: addis 3, 2, 0
+// Dis: addi 3, 3, -32760
+
+// Second tls_index starts at got[3].
+// #hi(j@got@tlsgd) --> (0x20108 - 0x280f0) >> 16 = -1
+// Dis: test_hi:
+// Dis: lis 3, -1
+
+// Third tls index is at got[5].
+// k@got@tlsgd --> (0x20118 - 0x280f0) = -0x7fd8 = -32728
+// Dis: test_16:
+// Dis: li 3, -32728
diff --git a/test/ELF/ppc64-got-indirect.s b/test/ELF/ppc64-got-indirect.s
new file mode 100644
index 0000000..2837582
--- /dev/null
+++ b/test/ELF/ppc64-got-indirect.s
@@ -0,0 +1,115 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+# RUN: llvm-readobj -relocations %t.o | FileCheck -check-prefix=RELOCS-LE %s
+# RUN: ld.lld %t.o -o %t2
+# RUN: llvm-objdump -D %t2 | FileCheck %s --check-prefix=CHECK-LE
+# RUN: llvm-objdump -D %t2 | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+# RUN: llvm-readobj -relocations %t.o | FileCheck -check-prefix=RELOCS-BE %s
+# RUN: ld.lld %t.o -o %t2
+# RUN: llvm-objdump -D %t2 | FileCheck %s --check-prefix=CHECK-BE
+# RUN: llvm-objdump -D %t2 | FileCheck %s
+
+# Make sure we calculate the offset correctly for a got-indirect access to a
+# global variable as described by the PPC64 ELF V2 abi.
+ .text
+ .abiversion 2
+ .globl _start # -- Begin function _start
+ .p2align 4
+ .type _start,@function
+_start: # @_start
+.Lfunc_begin0:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry _start, .Lfunc_lep0-.Lfunc_gep0
+# %bb.0: # %entry
+ addis 3, 2, .LC0@toc@ha
+ ld 3, .LC0@toc@l(3)
+ li 4, 0
+ stw 4, -12(1)
+ li 0,1
+ lwa 3, 0(3)
+ sc
+ .long 0
+ .quad 0
+.Lfunc_end0:
+ .size _start, .Lfunc_end0-.Lfunc_begin0
+ # -- End function
+ .section .toc,"aw",@progbits
+.LC0:
+ .tc glob[TC],glob
+ .type glob,@object # @glob
+ .data
+ .globl glob
+ .p2align 2
+glob:
+ .long 55 # 0x37
+ .size glob, 4
+
+# Verify the relocations emitted for glob are through the .toc
+
+# RELOCS-LE: Relocations [
+# RELOCS-LE: .rela.text {
+# RELOCS-LE: 0x0 R_PPC64_REL16_HA .TOC. 0x0
+# RELOCS-LE: 0x4 R_PPC64_REL16_LO .TOC. 0x4
+# RELOCS-LE: 0x8 R_PPC64_TOC16_HA .toc 0x0
+# RELOCS-LE: 0xC R_PPC64_TOC16_LO_DS .toc 0x0
+# RELOCS-LE: }
+# RELOCS-LE: .rela.toc {
+# RELOCS-LE: 0x0 R_PPC64_ADDR64 glob 0x0
+# RELOCS-LE: }
+
+# RELOCS-BE: Relocations [
+# RELOCS-BE: .rela.text {
+# RELOCS-BE: 0x2 R_PPC64_REL16_HA .TOC. 0x2
+# RELOCS-BE: 0x6 R_PPC64_REL16_LO .TOC. 0x6
+# RELOCS-BE: 0xA R_PPC64_TOC16_HA .toc 0x0
+# RELOCS-BE: 0xE R_PPC64_TOC16_LO_DS .toc 0x0
+# RELOCS-BE: }
+# RELOCS-BE: .rela.toc {
+# RELOCS-BE: 0x0 R_PPC64_ADDR64 glob 0x0
+# RELOCS-BE: }
+# RELOCS-BE:]
+
+# Verify that the global variable access is done through the correct
+# toc entry:
+# r2 = .TOC. = 0x10038000.
+# r3 = r2 - 32760 = 0x10030008 -> .toc entry for glob.
+
+# CHECK: _start:
+# CHECK-NEXT: 10010000: {{.*}} addis 2, 12, 3
+# CHECK-NEXT: 10010004: {{.*}} addi 2, 2, -32768
+# CHECK-NEXT: 10010008: {{.*}} addis 3, 2, 0
+# CHECK-NEXT: 1001000c: {{.*}} ld 3, -32760(3)
+# CHECK: 1001001c: {{.*}} lwa 3, 0(3)
+
+# CHECK-LE: Disassembly of section .data:
+# CHECK-LE-NEXT: glob:
+# CHECK-LE-NEXT: 10020000: 37 00 00 00
+
+# CHECK-LE: Disassembly of section .got:
+# CHECK-LE-NEXT: .got:
+# CHECK-LE-NEXT: 10030000: 00 80 03 10
+# CHECK-LE-NEXT: 10030004: 00 00 00 00
+
+# Verify that .toc comes right after .got
+# CHECK-LE: Disassembly of section .toc:
+# CHECK-LE: 10030008: 00 00 02 10
+
+# CHECK-BE: Disassembly of section .data:
+# CHECK-BE-NEXT: glob:
+# CHECK-BE-NEXT: 10020000: 00 00 00 37
+
+# CHECK-BE: Disassembly of section .got:
+# CHECK-BE-NEXT: .got:
+# CHECK-BE-NEXT: 10030000: 00 00 00 00
+# CHECK-BE-NEXT: 10030004: 10 03 80 00
+
+# Verify that .toc comes right after .got
+# CHECK-BE: Disassembly of section .toc:
+# CHECK-BE: 10030008: 00 00 00 00
+# CHECK-BE: 1003000c: 10 02 00 00
diff --git a/test/ELF/ppc64-ifunc.s b/test/ELF/ppc64-ifunc.s
index b993206..6f2d331 100644
--- a/test/ELF/ppc64-ifunc.s
+++ b/test/ELF/ppc64-ifunc.s
@@ -1,41 +1,87 @@
# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -o %t2.so
+# RUN: ld.lld %t.o %t2.so -o %t
+# RUN: llvm-objdump -D %t | FileCheck %s
+# RUN: llvm-readelf -dynamic-table %t | FileCheck --check-prefix=DT %s
+# RUN: llvm-readelf -dyn-relocations %t | FileCheck --check-prefix=DYNREL %s
+
# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o
# RUN: ld.lld -shared %t2.o -o %t2.so
# RUN: ld.lld %t.o %t2.so -o %t
-# RUN: llvm-objdump -d %t | FileCheck %s
+# RUN: llvm-objdump -D %t | FileCheck %s
+# RUN: llvm-readelf -dynamic-table %t | FileCheck --check-prefix=DT %s
+# RUN: llvm-readelf -dyn-relocations %t | FileCheck --check-prefix=DYNREL %s
-# CHECK: _start:
-# CHECK-NEXT: 10010004: {{.*}} bl .+12
-# CHECK-NEXT: 10010008: {{.*}} bl .+40
+# CHECK: Disassembly of section .text:
-# 0x10010004 + 12 = 0x10010010 (PLT entry 0)
-# 0x10010008 + 40 = 0x10010030 (PLT entry 1)
+# Tocbase + (0 << 16) + 32560
+# 0x100280e0 + 0 + 32560 = 0x10030010 (.plt[2])
+# CHECK: __plt_foo:
+# CHECK-NEXT: std 2, 24(1)
+# CHECK-NEXT: addis 12, 2, 0
+# CHECK-NEXT: ld 12, 32560(12)
+# CHECK-NEXT: mtctr 12
+# CHECK-NEXT: bctr
-# CHECK: Disassembly of section .plt:
-# CHECK: 10010010: {{.*}} std 2, 40(1)
-# CHECK-NEXT: 10010014: {{.*}} addis 11, 2, 4098
-# CHECK-NEXT: 10010018: {{.*}} ld 12, -32744(11)
-# CHECK-NEXT: 1001001c: {{.*}} ld 11, 0(12)
-# CHECK-NEXT: 10010020: {{.*}} mtctr 11
-# CHECK-NEXT: 10010024: {{.*}} ld 2, 8(12)
-# CHECK-NEXT: 10010028: {{.*}} ld 11, 16(12)
-# CHECK-NEXT: 1001002c: {{.*}} bctr
-# CHECK-NEXT: 10010030: {{.*}} std 2, 40(1)
-# CHECK-NEXT: 10010034: {{.*}} addis 11, 2, 4098
-# CHECK-NEXT: 10010038: {{.*}} ld 12, -32736(11)
-# CHECK-NEXT: 1001003c: {{.*}} ld 11, 0(12)
-# CHECK-NEXT: 10010040: {{.*}} mtctr 11
-# CHECK-NEXT: 10010044: {{.*}} ld 2, 8(12)
-# CHECK-NEXT: 10010048: {{.*}} ld 11, 16(12)
-# CHECK-NEXT: 1001004c: {{.*}} bctr
+# Tocbase + (0 << 16) + 32568
+# 0x100280e0 + 0 + 32568 = 0x1003018 (.plt[3])
+# CHECK: __plt_ifunc:
+# CHECK-NEXT: std 2, 24(1)
+# CHECK-NEXT: addis 12, 2, 0
+# CHECK-NEXT: ld 12, 32568(12)
+# CHECK-NEXT: mtctr 12
+# CHECK-NEXT: bctr
+
+# CHECK: ifunc:
+# CHECK-NEXT: 10010028: {{.*}} nop
+
+# CHECK: _start:
+# CHECK-NEXT: addis 2, 12, 2
+# CHECK-NEXT: addi 2, 2, -32588
+# CHECK-NEXT: bl .+67108812
+# CHECK-NEXT: ld 2, 24(1)
+# CHECK-NEXT: bl .+67108824
+# CHECK-NEXT: ld 2, 24(1)
+
+# Check tocbase
+# CHECK: Disassembly of section .got:
+# CHECK-NEXT: .got:
+# CHECK-NEXT: 100200e0
+
+# Check .plt address
+# DT_PLTGOT should point to the start of the .plt section.
+# DT: 0x0000000000000003 PLTGOT 0x10030000
+
+# Check that we emit the correct dynamic relocation type for an ifunc
+# DYNREL: 'PLT' relocation section at offset 0x{{[0-9a-f]+}} contains 48 bytes:
+# 48 bytes --> 2 Elf64_Rela relocations
+# DYNREL-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend
+# DYNREL-NEXT: {{[0-9a-f]+}} {{[0-9a-f]+}} R_PPC64_JMP_SLOT {{0+}} foo + 0
+# DYNREL-NEXT: {{[0-9a-f]+}} {{[0-9a-f]+}} R_PPC64_IRELATIVE 10010028
+
+
+ .text
+ .abiversion 2
.type ifunc STT_GNU_IFUNC
.globl ifunc
ifunc:
nop
-.global _start
+ .global _start
+ .type _start,@function
+
_start:
- bl bar
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry _start, .Lfunc_lep0-.Lfunc_gep0
+ bl foo
+ nop
bl ifunc
+ nop
diff --git a/test/ELF/ppc64-initial-exec-tls.s b/test/ELF/ppc64-initial-exec-tls.s
new file mode 100644
index 0000000..5218b68
--- /dev/null
+++ b/test/ELF/ppc64-initial-exec-tls.s
@@ -0,0 +1,102 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-tls.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld -dynamic-linker /lib64/ld64.so.2 %t.o %t2.so -o %t
+// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-readelf -relocations --wide %t | FileCheck --check-prefix=OutputRelocs %s
+// RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=CheckGot %s
+// RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-tls.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld -dynamic-linker /lib64/ld64.so.2 %t.o %t2.so -o %t
+// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-readelf -relocations --wide %t | FileCheck --check-prefix=OutputRelocs %s
+// RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=CheckGot %s
+// RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s
+
+ .text
+ .abiversion 2
+ .file "intial_exec.c"
+ .globl test_initial_exec # -- Begin function test_initial_exec
+ .p2align 4
+ .type test_initial_exec,@function
+test_initial_exec: # @test_initial_exec
+.Lfunc_begin0:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry test_initial_exec, .Lfunc_lep0-.Lfunc_gep0
+# %bb.0: # %entry
+ li 3, 0
+ stw 3, -12(1)
+ addis 3, 2, a@got@tprel@ha
+ ld 3, a@got@tprel@l(3)
+ lwzx 4, 3, a@tls
+ extsw 3, 4
+ blr
+
+
+test_hi:
+.Lfunc_gep1:
+ addis 2, 12, .TOC.-.Lfunc_gep1@ha
+ addi 2, 2, .TOC.-.Lfunc_gep1@l
+.Lfunc_lep1:
+ .localentry test2, .Lfunc_lep1-.Lfunc_gep1
+ addis 3, 0, b@got@tprel@h
+ blr
+
+test_ds:
+.Lfunc_gep2:
+ addis 2, 12, .TOC.-.Lfunc_gep2@ha
+ addi 2, 2, .TOC.-.Lfunc_gep2@l
+.Lfunc_lep2:
+ .localentry test16, .Lfunc_lep2-.Lfunc_gep2
+ addi 3, 0, c@got@tprel
+ blr
+
+// Verify that the input has every initial-exec tls relocation type.
+// InputRelocs: Relocation section '.rela.text'
+// InputRelocs: R_PPC64_GOT_TPREL16_HA {{0+}} a + 0
+// InputRelocs: R_PPC64_GOT_TPREL16_LO_DS {{0+}} a + 0
+// InputRelocs: R_PPC64_TLS {{0+}} a + 0
+// InputRelocs: R_PPC64_GOT_TPREL16_HI {{0+}} b + 0
+// InputRelocs: R_PPC64_GOT_TPREL16_DS {{0+}} c + 0
+
+// There is a got entry for each tls variable that is accessed with the
+// initial-exec model to be filled in by the dynamic linker.
+// OutputRelocs: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 3 entries:
+// OutputRelocs: R_PPC64_TPREL64 {{0+}} a + 0
+// OutputRelocs: R_PPC64_TPREL64 {{0+}} b + 0
+// OutputRelocs: R_PPC64_TPREL64 {{0+}} c + 0
+
+// Check that the got has 4 entires. (1 for the TOC and 3 entries for TLS
+// variables). Also verify the address so we can check
+// the offsets we calculated for each relocation type.
+// CheckGot: got 00000020 00000000100200c0
+
+// GOT stats at 0x100200c0, so TOC will be 0x100280c0
+
+// We are building the address of the first TLS got entry which contains the
+// offset of the tls variable relative to the thread pointer.
+// 0x100200c8 (got[1]).
+// #ha(a@got@tprel) --> (0x100200c8 - 0x100280c0 + 0x8000) >> 16 = 0
+// #lo(a@got@tprel)) --> (0x100200c8 - 0x100280c0) & 0xFFFF = -7ff8 = -32760
+// Dis: test_initial_exec:
+// Dis: addis 3, 2, 0
+// Dis: ld 3, -32760(3)
+// Dis: lwzx 4, 3, 13
+
+// Second TLS got entry starts at got[2] 0x100200d0
+// #hi(b@got@tprel) --> (0x100200d0 - 0x100280c0) >> 16 = -1
+// Dis: test_hi:
+// Dis: lis 3, -1
+
+// Third TLS got entry starts at got[3] 0x100200d8.
+// c@got@tprel--> (0x100200d8. - 0x100280c0) = -0x7fe8 = 32744
+// Dis: test_ds:
+// Dis: li 3, -32744
diff --git a/test/ELF/ppc64-local-dynamic.s b/test/ELF/ppc64-local-dynamic.s
new file mode 100644
index 0000000..a051eae
--- /dev/null
+++ b/test/ELF/ppc64-local-dynamic.s
@@ -0,0 +1,112 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-readelf -relocations --wide %t.so | FileCheck --check-prefix=OutputRelocs %s
+// RUN: llvm-objdump --section-headers %t.so | FileCheck --check-prefix=CheckGot %s
+// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=Dis %s
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-readelf -relocations --wide %t.so | FileCheck --check-prefix=OutputRelocs %s
+// RUN: llvm-objdump --section-headers %t.so | FileCheck --check-prefix=CheckGot %s
+// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=Dis %s
+
+ .text
+ .abiversion 2
+ .globl test
+ .p2align 4
+ .type test,@function
+test:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry test, .Lfunc_lep0-.Lfunc_gep0
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -32(1)
+ addis 3, 2, i@got@tlsld@ha
+ addi 3, 3, i@got@tlsld@l
+ bl __tls_get_addr(i@tlsld)
+ nop
+ ld 0, 16(1)
+ mtlr 0
+ blr
+
+ .globl test_hi
+ .p2align 4
+ .type test_hi,@function
+test_hi:
+ lis 3, j@got@tlsld@h
+ blr
+
+ .globl test_16
+ .p2align 4
+ .type test_16,@function
+test_16:
+ li 3, k@got@tlsld
+ blr
+
+ .type i,@object
+ .section .tdata,"awT",@progbits
+ .p2align 2
+i:
+ .long 55
+ .size i, 4
+
+ .type j,@object
+ .section .tbss,"awT",@nobits
+ .p2align 2
+j:
+ .long 0
+ .size j, 4
+
+ .type k,@object
+ .section .tdata,"awT",@progbits
+ .p2align 3
+k:
+ .quad 66
+ .size k, 8
+
+// Verify that the input contains all the R_PPC64_GOT_TLSLD16* relocations.
+// InputRelocs: Relocation section '.rela.text'
+// InputRelocs: R_PPC64_GOT_TLSLD16_HA 0000000000000000 i + 0
+// InputRelocs: R_PPC64_GOT_TLSLD16_LO 0000000000000000 i + 0
+// InputRelocs: R_PPC64_TLSLD 0000000000000000 i + 0
+// InputRelocs: R_PPC64_GOT_TLSLD16_HI 0000000000000000 j + 0
+// InputRelocs: R_PPC64_GOT_TLSLD16 0000000000000008 k + 0
+
+// The local dynamic version of tls needs to use the same mechanism to look up
+// a variables address as general-dynamic. ie a call to __tls_get_addr with the
+// address of a tls_index struct as the argument. However for local-dynamic
+// variables all will have the same ti_module, and the offset field is left as
+// as 0, so the same struct can be used for every local-dynamic variable
+// used in the shared-object.
+// OutputRelocs: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 1 entries:
+// OutputRelocs-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend
+// OutputRelocs-NEXT: R_PPC64_DTPMOD64
+
+// Check that the got has 3 entries, 1 for the TOC and 1 stucture of 2 entries
+// for the tls variables. Also verify the address so we can check the offsets
+// we calculate for each relocation type.
+// CheckGot: got 00000018 0000000000020100
+
+// got starts at 0x20100 so .TOC. will be 0x28100, and the tls_index struct is
+// at 0x20108.
+
+// #ha(i@got@tlsld) --> (0x20108 - 0x28100 + 0x8000) >> 16 = 0
+// #lo(i@got@tlsld) --> (0x20108 - 0x28100) = -7ff8 = -32760
+// Dis: test:
+// Dis: addis 3, 2, 0
+// Dis-NEXT: addi 3, 3, -32760
+
+// #hi(j@got@tlsld) --> (0x20108 - 0x28100 ) > 16 = -1
+// Dis: test_hi:
+// Dis: lis 3, -1
+
+// k@got@tlsld --> (0x20108 - 0x28100) = -7ff8 = -32760
+// Dis: test_16:
+// Dis: li 3, -32760
diff --git a/test/ELF/ppc64-plt-stub.s b/test/ELF/ppc64-plt-stub.s
new file mode 100644
index 0000000..a644f48
--- /dev/null
+++ b/test/ELF/ppc64-plt-stub.s
@@ -0,0 +1,42 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: llvm-objdump -d %t | FileCheck %s
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: llvm-objdump -d %t | FileCheck %s
+
+// CHECK: Disassembly of section .text:
+// CHECK-NEXT: __plt_foo:
+// CHECK-NEXT: std 2, 24(1)
+// CHECK-NEXT: addis 12, 2, 0
+// CHECK-NEXT: ld 12, 32560(12)
+// CHECK-NEXT: mtctr 12
+// CHECK-NEXT: bctr
+
+
+// CHECK: _start:
+// CHECK: bl .+67108824
+ .text
+ .abiversion 2
+ .globl _start
+ .p2align 4
+ .type _start,@function
+_start:
+.Lfunc_begin0:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry _start, .Lfunc_lep0-.Lfunc_gep0
+ bl foo
+ nop
+ li 0, 1
+ sc
+ .size _start, .-.Lfunc_begin0
diff --git a/test/ELF/ppc64-rel-calls.s b/test/ELF/ppc64-rel-calls.s
index f3b309f..4c79498 100644
--- a/test/ELF/ppc64-rel-calls.s
+++ b/test/ELF/ppc64-rel-calls.s
@@ -1,32 +1,29 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-objdump -d %t2 | FileCheck %s
+
# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t
# RUN: ld.lld %t -o %t2
# RUN: llvm-objdump -d %t2 | FileCheck %s
-# REQUIRES: ppc
# CHECK: Disassembly of section .text:
-.section ".opd","aw"
+.text
.global _start
_start:
-.quad .Lfoo,.TOC.@tocbase,0
-
-.text
.Lfoo:
li 0,1
li 3,42
sc
-# CHECK: 10010000: 38 00 00 01 li 0, 1
-# CHECK: 10010004: 38 60 00 2a li 3, 42
-# CHECK: 10010008: 44 00 00 02 sc
+# CHECK: 10010000: {{.*}} li 0, 1
+# CHECK: 10010004: {{.*}} li 3, 42
+# CHECK: 10010008: {{.*}} sc
-.section ".opd","aw"
.global bar
bar:
-.quad .Lbar,.TOC.@tocbase,0
-
-.text
-.Lbar:
bl _start
nop
bl .Lfoo
@@ -34,9 +31,8 @@
blr
# FIXME: The printing here is misleading, the branch offset here is negative.
-# CHECK: 1001000c: 4b ff ff f5 bl .+67108852
-# CHECK: 10010010: 60 00 00 00 nop
-# CHECK: 10010014: 4b ff ff ed bl .+67108844
-# CHECK: 10010018: 60 00 00 00 nop
-# CHECK: 1001001c: 4e 80 00 20 blr
-
+# CHECK: 1001000c: {{.*}} bl .+67108852
+# CHECK: 10010010: {{.*}} nop
+# CHECK: 10010014: {{.*}} bl .+67108844
+# CHECK: 10010018: {{.*}} nop
+# CHECK: 1001001c: {{.*}} blr
diff --git a/test/ELF/ppc64-rel-so-local-calls.s b/test/ELF/ppc64-rel-so-local-calls.s
new file mode 100644
index 0000000..834dbd5
--- /dev/null
+++ b/test/ELF/ppc64-rel-so-local-calls.s
@@ -0,0 +1,87 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared -z notext %t.o -o %t.so
+// RUN: llvm-readelf -dyn-relocations %t.so | FileCheck %s
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared -z notext %t.o -o %t.so
+// RUN: llvm-readelf -dyn-relocations %t.so | FileCheck %s
+
+
+// CHECK-NOT: foo
+// CHECK-NOT: bar
+
+ .text
+ .abiversion 2
+ .globl baz
+ .p2align 4
+ .type baz,@function
+baz:
+.Lfunc_begin0:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry baz, .Lfunc_lep0-.Lfunc_gep0
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -64(1)
+ std 30, 48(1)
+ std 29, 40(1)
+ mr 30, 3
+ bl foo
+ mr 29, 3
+ mr 3, 30
+ bl bar
+ mullw 3, 3, 29
+ ld 30, 48(1)
+ ld 29, 40(1)
+ extsw 3, 3
+ addi 1, 1, 64
+ ld 0, 16(1)
+ mtlr 0
+ blr
+ .long 0
+ .quad 0
+.Lfunc_end0:
+ .size baz, .Lfunc_end0-.Lfunc_begin0
+
+ .p2align 4
+ .type foo,@function
+foo:
+.Lfunc_begin1:
+ mullw 3, 3, 3
+ extsw 3, 3
+ blr
+ .long 0
+ .quad 0
+.Lfunc_end1:
+ .size foo, .Lfunc_end1-.Lfunc_begin1
+
+ .p2align 4
+ .type bar,@function
+bar:
+.Lfunc_begin2:
+.Lfunc_gep2:
+ addis 2, 12, .TOC.-.Lfunc_gep2@ha
+ addi 2, 2, .TOC.-.Lfunc_gep2@l
+.Lfunc_lep2:
+ .localentry bar, .Lfunc_lep2-.Lfunc_gep2
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -48(1)
+ std 30, 32(1)
+ mr 30, 3
+ bl foo
+ mullw 3, 3, 30
+ ld 30, 32(1)
+ extsw 3, 3
+ addi 1, 1, 48
+ ld 0, 16(1)
+ mtlr 0
+ blr
+ .long 0
+ .quad 0
+.Lfunc_end2:
+ .size bar, .Lfunc_end2-.Lfunc_begin2
diff --git a/test/ELF/ppc64-relocs.s b/test/ELF/ppc64-relocs.s
index cb6177d..88e3d4b 100644
--- a/test/ELF/ppc64-relocs.s
+++ b/test/ELF/ppc64-relocs.s
@@ -1,22 +1,33 @@
-# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t
-# RUN: ld.lld %t -o %t2
-# RUN: llvm-objdump -d %t2 | FileCheck %s
# REQUIRES: ppc
-.section ".opd","aw"
-.global _start
-_start:
-.quad .Lfoo,.TOC.@tocbase,0
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-objdump -D %t2 | FileCheck %s --check-prefix=DATALE
+# RUN: llvm-objdump -D %t2 | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-objdump -D %t2 | FileCheck %s --check-prefix=DATABE
+# RUN: llvm-objdump -D %t2 | FileCheck %s
.text
+.global _start
+_start:
.Lfoo:
li 0,1
li 3,42
sc
-.section ".toc","aw"
+.section .rodata,"a",@progbits
+ .p2align 2
+.LJTI0_0:
+ .long .LBB0_2-.LJTI0_0
+
+.section .toc,"aw",@progbits
.L1:
.quad 22, 37, 89, 47
+.LC0:
+ .tc .LJTI0_0[TC],.LJTI0_0
.section .R_PPC64_TOC16_LO_DS,"ax",@progbits
.globl .FR_PPC64_TOC16_LO_DS
@@ -25,7 +36,7 @@
# CHECK: Disassembly of section .R_PPC64_TOC16_LO_DS:
# CHECK: .FR_PPC64_TOC16_LO_DS:
-# CHECK: 1001000c: e8 22 80 00 ld 1, -32768(2)
+# CHECK: 1001000c: {{.*}} ld 1, -32768(2)
.section .R_PPC64_TOC16_LO,"ax",@progbits
.globl .FR_PPC64_TOC16_LO
@@ -34,7 +45,7 @@
# CHECK: Disassembly of section .R_PPC64_TOC16_LO:
# CHECK: .FR_PPC64_TOC16_LO:
-# CHECK: 10010010: 38 22 80 00 addi 1, 2, -32768
+# CHECK: 10010010: {{.*}} addi 1, 2, -32768
.section .R_PPC64_TOC16_HI,"ax",@progbits
.globl .FR_PPC64_TOC16_HI
@@ -43,7 +54,7 @@
# CHECK: Disassembly of section .R_PPC64_TOC16_HI:
# CHECK: .FR_PPC64_TOC16_HI:
-# CHECK: 10010014: 3c 22 ff fe addis 1, 2, -2
+# CHECK: 10010014: {{.*}} addis 1, 2, -1
.section .R_PPC64_TOC16_HA,"ax",@progbits
.globl .FR_PPC64_TOC16_HA
@@ -52,7 +63,7 @@
# CHECK: Disassembly of section .R_PPC64_TOC16_HA:
# CHECK: .FR_PPC64_TOC16_HA:
-# CHECK: 10010018: 3c 22 ff ff addis 1, 2, -1
+# CHECK: 10010018: {{.*}} addis 1, 2, 0
.section .R_PPC64_REL24,"ax",@progbits
.globl .FR_PPC64_REL24
@@ -63,7 +74,7 @@
# CHECK: Disassembly of section .R_PPC64_REL24:
# CHECK: .FR_PPC64_REL24:
-# CHECK: 1001001c: 48 00 00 04 b .+4
+# CHECK: 1001001c: {{.*}} b .+4
.section .R_PPC64_ADDR16_LO,"ax",@progbits
.globl .FR_PPC64_ADDR16_LO
@@ -72,7 +83,7 @@
# CHECK: Disassembly of section .R_PPC64_ADDR16_LO:
# CHECK: .FR_PPC64_ADDR16_LO:
-# CHECK: 10010020: 38 20 00 00 li 1, 0
+# CHECK: 10010020: {{.*}} li 1, 0
.section .R_PPC64_ADDR16_HI,"ax",@progbits
.globl .FR_PPC64_ADDR16_HI
@@ -81,7 +92,7 @@
# CHECK: Disassembly of section .R_PPC64_ADDR16_HI:
# CHECK: .FR_PPC64_ADDR16_HI:
-# CHECK: 10010024: 38 20 10 01 li 1, 4097
+# CHECK: 10010024: {{.*}} li 1, 4097
.section .R_PPC64_ADDR16_HA,"ax",@progbits
.globl .FR_PPC64_ADDR16_HA
@@ -90,7 +101,7 @@
# CHECK: Disassembly of section .R_PPC64_ADDR16_HA:
# CHECK: .FR_PPC64_ADDR16_HA:
-# CHECK: 10010028: 38 20 10 01 li 1, 4097
+# CHECK: 10010028: {{.*}} li 1, 4097
.section .R_PPC64_ADDR16_HIGHER,"ax",@progbits
.globl .FR_PPC64_ADDR16_HIGHER
@@ -99,7 +110,7 @@
# CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHER:
# CHECK: .FR_PPC64_ADDR16_HIGHER:
-# CHECK: 1001002c: 38 20 00 00 li 1, 0
+# CHECK: 1001002c: {{.*}} li 1, 0
.section .R_PPC64_ADDR16_HIGHERA,"ax",@progbits
.globl .FR_PPC64_ADDR16_HIGHERA
@@ -108,7 +119,7 @@
# CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHERA:
# CHECK: .FR_PPC64_ADDR16_HIGHERA:
-# CHECK: 10010030: 38 20 00 00 li 1, 0
+# CHECK: 10010030: {{.*}} li 1, 0
.section .R_PPC64_ADDR16_HIGHEST,"ax",@progbits
.globl .FR_PPC64_ADDR16_HIGHEST
@@ -117,7 +128,7 @@
# CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHEST:
# CHECK: .FR_PPC64_ADDR16_HIGHEST:
-# CHECK: 10010034: 38 20 00 00 li 1, 0
+# CHECK: 10010034: {{.*}} li 1, 0
.section .R_PPC64_ADDR16_HIGHESTA,"ax",@progbits
.globl .FR_PPC64_ADDR16_HIGHESTA
@@ -126,5 +137,57 @@
# CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHESTA:
# CHECK: .FR_PPC64_ADDR16_HIGHESTA:
-# CHECK: 10010038: 38 20 00 00 li 1, 0
+# CHECK: 10010038: {{.*}} li 1, 0
+.section .R_PPC64_REL32, "ax",@progbits
+.globl .FR_PPC64_REL32
+.FR_PPC64_REL32:
+ addis 5, 2, .LC0@toc@ha
+ ld 5, .LC0@toc@l(5)
+.LBB0_2:
+ add 3, 3, 4
+
+# DATALE: Disassembly of section .rodata:
+# DATALE: .rodata:
+# DATALE: 10000190: b4 fe 00 00
+
+# DATABE: Disassembly of section .rodata:
+# DATABE: .rodata:
+# DATABE: 10000190: 00 00 fe b4
+
+# Address of rodata + value stored at rodata entry
+# should equal address of LBB0_2.
+# 0x10000190 + 0xfeb4 = 0x10010044
+# CHECK: Disassembly of section .R_PPC64_REL32:
+# CHECK: .FR_PPC64_REL32:
+# CHECK: 1001003c: {{.*}} addis 5, 2, 0
+# CHECK: 10010040: {{.*}} ld 5, -32736(5)
+# CHECK: 10010044: {{.*}} add 3, 3, 4
+
+.section .R_PPC64_REL64, "ax",@progbits
+.globl .FR_PPC64_REL64
+.FR_PPC64_REL64:
+ .cfi_startproc
+ .cfi_personality 148, __foo
+ li 0, 1
+ li 3, 55
+ sc
+ .cfi_endproc
+__foo:
+ li 3,0
+
+# Check that address of eh_frame entry + value stored
+# should equal the address of foo. Since it is not aligned,
+# the entry is not stored exactly at 100001a8. It starts at
+# address 0x100001aa and has the value 0xfeaa.
+# 0x100001aa + 0xfeaa = 0x10010054
+# DATALE: Disassembly of section .eh_frame:
+# DATALE: .eh_frame:
+# DATALE: 100001a8: {{.*}} aa fe
+
+# DATABE: Disassembly of section .eh_frame:
+# DATABE: .eh_frame:
+# DATABE: 100001b0: fe aa {{.*}}
+
+# CHECK: __foo
+# CHECK-NEXT: 10010054: {{.*}} li 3, 0
diff --git a/test/ELF/ppc64-shared-rel-toc.s b/test/ELF/ppc64-shared-rel-toc.s
deleted file mode 100644
index 445011b..0000000
--- a/test/ELF/ppc64-shared-rel-toc.s
+++ /dev/null
@@ -1,27 +0,0 @@
-// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
-// RUN: ld.lld -shared %t.o -o %t.so
-// RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s
-// REQUIRES: ppc
-
-// When we create the TOC reference in the shared library, make sure that the
-// R_PPC64_RELATIVE relocation uses the correct (non-zero) offset.
-
- .globl foo
- .align 2
- .type foo,@function
- .section .opd,"aw",@progbits
-foo: # @foo
- .align 3
- .quad .Lfunc_begin0
- .quad .TOC.@tocbase
- .quad 0
- .text
-.Lfunc_begin0:
- blr
-
-// CHECK: 0x20000 R_PPC64_RELATIVE - 0x10000
-// CHECK: 0x20008 R_PPC64_RELATIVE - 0x8000
-
-// CHECK: Name: foo
-// CHECK-NEXT: Value: 0x20000
-
diff --git a/test/ELF/ppc64-toc-rel.s b/test/ELF/ppc64-toc-rel.s
new file mode 100644
index 0000000..ac156c7
--- /dev/null
+++ b/test/ELF/ppc64-toc-rel.s
@@ -0,0 +1,90 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+# RUN: llvm-readobj -relocations %t.o | FileCheck -check-prefix=RELOCS %s
+# RUN: ld.lld %t.o -o %t2
+# RUN: llvm-objdump -D %t2 | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+# RUN: llvm-readobj -relocations %t.o | FileCheck -check-prefix=RELOCS-BE %s
+# RUN: ld.lld %t.o -o %t2
+# RUN: llvm-objdump -D %t2 | FileCheck -check-prefix=CHECK-BE %s
+
+# Make sure we calculate the offset correctly for a toc-relative access to a
+# global variable as described by the PPC64 Elf V2 abi.
+.abiversion 2
+
+# int global_a = 55
+ .globl global_a
+ .section ".data"
+ .align 2
+ .type global_a, @object
+ .size global_a, 4
+ .p2align 2
+global_a:
+ .long 41
+
+
+ .section ".text"
+ .align 2
+ .global _start
+ .type _start, @function
+_start:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry _start, .Lfunc_lep0-.Lfunc_gep0
+
+ addis 3, 2, global_a@toc@ha
+ addi 3, 3, global_a@toc@l
+ li 0,1
+ lwa 3, 0(3)
+ sc
+.size _start,.-_start
+
+# Verify the relocations that get emitted for the global variable are the
+# expected ones.
+# RELOCS: Relocations [
+# RELOCS-NEXT: .rela.text {
+# RELOCS: 0x8 R_PPC64_TOC16_HA global_a 0x0
+# RELOCS: 0xC R_PPC64_TOC16_LO global_a 0x0
+
+# RELOCS-BE: Relocations [
+# RELOCS-BE-NEXT: .rela.text {
+# RELOCS-BE: 0xA R_PPC64_TOC16_HA global_a 0x0
+# RELOCS-NE: 0xE R_PPC64_TOC16_LO global_a 0x0
+
+# Want to check _start for the values used to build the offset from the TOC base
+# to global_a. The .TOC. symbol is expected at address 0x10030000, and the
+# TOC base is address-of(.TOC.) + 0x8000. The expected offset is:
+# 0x10020000(global_a) - 0x10038000(Toc base) = -0x18000(Offset)
+# which gets materialized into r3 as ((-1 << 16) - 32768).
+
+# CHECK: Disassembly of section .text:
+# CHECK-NEXT: _start:
+# CHECK: 10010008: {{.*}} addis 3, 2, -1
+# CHECK-NEXT: 1001000c: {{.*}} addi 3, 3, -32768
+
+# CHECK: Disassembly of section .data:
+# CHECK-NEXT: global_a:
+# CHECK-NEXT: 10020000: {{.*}}
+
+# CHECK: Disassembly of section .got:
+# CHECK-NEXT: .got:
+# CHECK-NEXT: 10030000: 00 80 03 10
+
+
+# CHECK-BE: Disassembly of section .text:
+# CHECK-BE-NEXT: _start:
+# CHECK-BE: 10010008: {{.*}} addis 3, 2, -1
+# CHECK-BE-NEXT: 1001000c: {{.*}} addi 3, 3, -32768
+
+# CHECK-BE: Disassembly of section .data:
+# CHECK-BE-NEXT: global_a:
+# CHECK-BE-NEXT: 10020000: {{.*}}
+
+# CHECK-BE: Disassembly of section .got:
+# CHECK-BE-NEXT: .got:
+# CHECK-BE-NEXT: 10030000: 00 00 00 00
+# CHECK-BE-NEXT: 10030004: 10 03 80 00
diff --git a/test/ELF/ppc64-toc-restore.s b/test/ELF/ppc64-toc-restore.s
index 0c3d30b..9efe0e8 100644
--- a/test/ELF/ppc64-toc-restore.s
+++ b/test/ELF/ppc64-toc-restore.s
@@ -1,62 +1,72 @@
-// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
-// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o
-// RUN: ld.lld -shared %t2.o -o %t2.so
-// RUN: ld.lld %t.o %t2.so -o %t
-// RUN: llvm-objdump -d %t | FileCheck %s
// REQUIRES: ppc
-// CHECK: Disassembly of section .text:
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-func.s -o %t3.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so %t3.o -o %t
+// RUN: llvm-objdump -d %t | FileCheck %s
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-func.s -o %t3.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so %t3.o -o %t
+// RUN: llvm-objdump -d %t | FileCheck %s
+
+ .text
+ .abiversion 2
+.global bar_local
+bar_local:
+ li 3, 2
+ blr
+
+# Calling external function foo in a shared object needs a nop.
+# Calling local function bar_local doe snot need a nop.
.global _start
_start:
- bl bar
+ bl foo
+ nop
+ bl bar_local
+
+
+// CHECK: Disassembly of section .text:
+// CHECK: _start:
+// CHECK: 1001001c: {{.*}} bl .+67108836
+// CHECK-NOT: 10010020: {{.*}} nop
+// CHECK: 10010020: {{.*}} ld 2, 24(1)
+// CHECK: 10010024: {{.*}} bl .+67108848
+// CHECK-NOT: 10010028: {{.*}} nop
+// CHECK-NOT: 10010028: {{.*}} ld 2, 24(1)
+
+# Calling a function in another object file which will have same
+# TOC base does not need a nop. If nop present, do not rewrite to
+# a toc restore
+.global diff_object
+_diff_object:
+ bl foo_not_shared
+ bl foo_not_shared
nop
-// CHECK: _start:
-// CHECK: 10010000: 48 00 00 21 bl .+32
-// CHECK-NOT: 10010004: 60 00 00 00 nop
-// CHECK: 10010004: e8 41 00 28 ld 2, 40(1)
+// CHECK: _diff_object:
+// CHECK-NEXT: 10010028: {{.*}} bl .+24
+// CHECK-NEXT: 1001002c: {{.*}} bl .+20
+// CHECK-NEXT: 10010030: {{.*}} nop
-.global noret
-noret:
- bl bar
- li 5, 7
-
-// CHECK: noret:
-// CHECK: 10010008: 48 00 00 19 bl .+24
-// CHECK: 1001000c: 38 a0 00 07 li 5, 7
-
-.global noretend
-noretend:
- bl bar
-
-// CHECK: noretend:
-// CHECK: 10010010: 48 00 00 11 bl .+16
-
-.global noretb
-noretb:
- b bar
-
-// CHECK: noretb:
-// CHECK: 10010014: 48 00 00 0c b .+12
+# Branching to a local function does not need a nop
+.global noretbranch
+noretbranch:
+ b bar_local
+// CHECK: noretbranch:
+// CHECK: 10010034: {{.*}} b .+67108832
+// CHECK-NOT: 10010038: {{.*}} nop
+// CHECK-NOT: 1001003c: {{.*}} ld 2, 24(1)
// This should come last to check the end-of-buffer condition.
.global last
last:
- bl bar
+ bl foo
nop
-
// CHECK: last:
-// CHECK: 10010018: 48 00 00 09 bl .+8
-// CHECK: 1001001c: e8 41 00 28 ld 2, 40(1)
-
-// CHECK: Disassembly of section .plt:
-// CHECK: .plt:
-// CHECK: 10010020: f8 41 00 28 std 2, 40(1)
-// CHECK: 10010024: 3d 62 10 02 addis 11, 2, 4098
-// CHECK: 10010028: e9 8b 80 18 ld 12, -32744(11)
-// CHECK: 1001002c: e9 6c 00 00 ld 11, 0(12)
-// CHECK: 10010030: 7d 69 03 a6 mtctr 11
-// CHECK: 10010034: e8 4c 00 08 ld 2, 8(12)
-// CHECK: 10010038: e9 6c 00 10 ld 11, 16(12)
-// CHECK: 1001003c: 4e 80 04 20 bctr
+// CHECK: 10010038: {{.*}} bl .+67108808
+// CHECK-NEXT: 1001003c: {{.*}} ld 2, 24(1)
diff --git a/test/ELF/ppc64-weak-undef-call-shared.s b/test/ELF/ppc64-weak-undef-call-shared.s
index 2c27a27..db48247 100644
--- a/test/ELF/ppc64-weak-undef-call-shared.s
+++ b/test/ELF/ppc64-weak-undef-call-shared.s
@@ -1,7 +1,12 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s
+
# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
# RUN: ld.lld -shared %t.o -o %t.so
# RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s
-# REQUIRES: ppc
.section ".toc","aw"
.quad weakfunc
@@ -10,7 +15,7 @@
.text
.Lfoo:
bl weakfunc
+ nop
// CHECK-NOT: R_PPC64_REL24
.weak weakfunc
-
diff --git a/test/ELF/ppc64-weak-undef-call.s b/test/ELF/ppc64-weak-undef-call.s
index 55443cb..30c1686 100644
--- a/test/ELF/ppc64-weak-undef-call.s
+++ b/test/ELF/ppc64-weak-undef-call.s
@@ -1,17 +1,18 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-objdump -d %t2 | FileCheck %s
+
# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t
# RUN: ld.lld %t -o %t2
# RUN: llvm-objdump -d %t2 | FileCheck %s
-# REQUIRES: ppc
# CHECK: Disassembly of section .text:
-.section ".opd","aw"
+.text
.global _start
_start:
-.quad .Lfoo,.TOC.@tocbase,0
-
-.text
-.Lfoo:
bl weakfunc
nop
blr
@@ -22,6 +23,6 @@
# be unreachable. But, we should link successfully. We should not, however,
# generate a .plt entry (this would be wasted space). For now, we do nothing
# (leaving the zero relative offset present in the input).
-# CHECK: 10010000: 48 00 00 01 bl .+0
-# CHECK: 10010004: 60 00 00 00 nop
-# CHECK: 10010008: 4e 80 00 20 blr
+# CHECK: 10010000: {{.*}} bl .+0
+# CHECK: 10010004: {{.*}} nop
+# CHECK: 10010008: {{.*}} blr
diff --git a/test/ELF/ppc64_entry_point.s b/test/ELF/ppc64_entry_point.s
index b3bd5ec..a6f426c 100644
--- a/test/ELF/ppc64_entry_point.s
+++ b/test/ELF/ppc64_entry_point.s
@@ -1,8 +1,13 @@
# REQUIRES: ppc
+
# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t
# RUN: ld.lld %t -o %t2
# RUN: llvm-objdump -D %t2 | FileCheck %s
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-objdump -D %t2 | FileCheck -check-prefix=CHECK-BE %s
+
.text
.abiversion 2
.globl _start
@@ -27,10 +32,19 @@
.Lfunc_end0:
.size _start, .Lfunc_end0-.Lfunc_begin0
-// CHECK: 10010000: 01 10 80 3c lis 4, 4097
-// CHECK-NEXT: 10010004: 00 00 84 38 addi 4, 4, 0
-// CHECK-NEXT: 10010008: 02 00 a0 3c lis 5, 2
-// CHECK-NEXT: 1001000c: 00 80 a5 38 addi 5, 5, -32768
+// CHECK: 10010000: {{.*}} lis 4, 4097
+// CHECK-NEXT: 10010004: {{.*}} addi 4, 4, 0
+// CHECK-NEXT: 10010008: {{.*}} lis 5, 2
+// CHECK-NEXT: 1001000c: {{.*}} addi 5, 5, -32768
// CHECK: Disassembly of section .got:
// CHECK-NEXT: .got:
// CHECK-NEXT: 10020000: 00 80 02 10
+
+// CHECK-BE: 10010000: {{.*}} lis 4, 4097
+// CHECK-BE-NEXT: 10010004: {{.*}} addi 4, 4, 0
+// CHECK-BE-NEXT: 10010008: {{.*}} lis 5, 2
+// CHECK-BE-NEXT: 1001000c: {{.*}} addi 5, 5, -32768
+// CHECK-BE: Disassembly of section .got:
+// CHECK-BE-NEXT: .got:
+// CHECK-BE-NEXT: 10020000: 00 00 00 00 {{.*}}
+// CHECK-BE-NEXT: 10020004: 10 02 80 00 {{.*}}
diff --git a/test/ELF/pre_init_fini_array_missing.s b/test/ELF/pre_init_fini_array_missing.s
index 7dabfa7..4a6b612 100644
--- a/test/ELF/pre_init_fini_array_missing.s
+++ b/test/ELF/pre_init_fini_array_missing.s
@@ -14,30 +14,27 @@
call __fini_array_start
call __fini_array_end
-// With no .init_array section the symbols resolve to 0
-// 0 - (0x201000 + 5) = -2101253
-// 0 - (0x201005 + 5) = -2101258
-// 0 - (0x20100a + 5) = -2101263
-// 0 - (0x20100f + 5) = -2101268
-// 0 - (0x201014 + 5) = -2101273
-// 0 - (0x201019 + 5) = -2101278
+// With no .init_array section the symbols resolve to .text.
+// 0x201000 - (0x201000 + 5) = -5
+// 0x201000 - (0x201005 + 5) = -10
+// ...
// CHECK: Disassembly of section .text:
// CHECK-NEXT: _start:
-// CHECK-NEXT: 201000: e8 fb ef df ff callq -2101253
-// CHECK-NEXT: 201005: e8 f6 ef df ff callq -2101258
-// CHECK-NEXT: 20100a: e8 f1 ef df ff callq -2101263
-// CHECK-NEXT: 20100f: e8 ec ef df ff callq -2101268
-// CHECK-NEXT: 201014: e8 e7 ef df ff callq -2101273
-// CHECK-NEXT: 201019: e8 e2 ef df ff callq -2101278
+// CHECK-NEXT: 201000: e8 fb ff ff ff callq -5
+// CHECK-NEXT: 201005: e8 f6 ff ff ff callq -10
+// CHECK-NEXT: 20100a: e8 f1 ff ff ff callq -15
+// CHECK-NEXT: 20100f: e8 ec ff ff ff callq -20
+// CHECK-NEXT: 201014: e8 e7 ff ff ff callq -25
+// CHECK-NEXT: 201019: e8 e2 ff ff ff callq -30
-// In position-independent binaries, they resolve to the image base.
+// In position-independent binaries, they resolve to .text too.
// PIE: Disassembly of section .text:
// PIE-NEXT: _start:
-// PIE-NEXT: 1000: e8 fb ef ff ff callq -4101
-// PIE-NEXT: 1005: e8 f6 ef ff ff callq -4106
-// PIE-NEXT: 100a: e8 f1 ef ff ff callq -4111
-// PIE-NEXT: 100f: e8 ec ef ff ff callq -4116
-// PIE-NEXT: 1014: e8 e7 ef ff ff callq -4121
-// PIE-NEXT: 1019: e8 e2 ef ff ff callq -4126
+// PIE-NEXT: 1000: e8 fb ff ff ff callq -5
+// PIE-NEXT: 1005: e8 f6 ff ff ff callq -10
+// PIE-NEXT: 100a: e8 f1 ff ff ff callq -15
+// PIE-NEXT: 100f: e8 ec ff ff ff callq -20
+// PIE-NEXT: 1014: e8 e7 ff ff ff callq -25
+// PIE-NEXT: 1019: e8 e2 ff ff ff callq -30
diff --git a/test/ELF/push-state.s b/test/ELF/push-state.s
new file mode 100644
index 0000000..5a01cd2
--- /dev/null
+++ b/test/ELF/push-state.s
@@ -0,0 +1,36 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN: %p/Inputs/whole-archive.s -o %t2.o
+// RUN: rm -f %t.a
+// RUN: llvm-ar rcs %t.a %t2.o
+
+// RUN: ld.lld -o %t.exe -push-state -whole-archive %t.a %t1.o -M | \
+// RUN: FileCheck -check-prefix=WHOLE %s
+// WHOLE: _bar
+
+// RUN: ld.lld -o %t.exe -push-state -whole-archive -pop-state %t.a %t1.o -M | \
+// RUN: FileCheck -check-prefix=NO-WHOLE %s
+// NO-WHOLE-NOT: _bar
+
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t3.o
+// RUN: ld.lld -shared %t3.o -soname libfoo -o %t.so
+
+// RUN: ld.lld -o %t.exe -push-state -as-needed %t.so %t1.o
+// RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=AS-NEEDED %s
+// AS-NEEDED-NOT: NEEDED Shared library: [libfoo]
+
+// RUN: ld.lld -o %t.exe -push-state -as-needed -pop-state %t.so %t1.o
+// RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=NO-AS-NEEDED %s
+// NO-AS-NEEDED: NEEDED Shared library: [libfoo]
+
+
+// RUN: mkdir -p %t.dir
+// RUN: cp %t.so %t.dir/libfoo.so
+// RUN: ld.lld -o %t.exe -L%t.dir -push-state -static -pop-state %t1.o -lfoo
+// RUN: not ld.lld -o %t.exe -L%t.dir -push-state -static %t1.o -lfoo
+
+.globl _start
+_start:
diff --git a/test/ELF/relative-dynamic-reloc-ppc64.s b/test/ELF/relative-dynamic-reloc-ppc64.s
index 65d0e8e..99c2457 100644
--- a/test/ELF/relative-dynamic-reloc-ppc64.s
+++ b/test/ELF/relative-dynamic-reloc-ppc64.s
@@ -1,6 +1,11 @@
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s
+
// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
// RUN: ld.lld -shared %t.o -o %t.so
// RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s
+
// REQUIRES: ppc
// Test that we create R_PPC64_RELATIVE relocations but don't put any
diff --git a/test/ELF/relocatable-comdat-multiple.s b/test/ELF/relocatable-comdat-multiple.s
index 935fbdc..bb7a784 100644
--- a/test/ELF/relocatable-comdat-multiple.s
+++ b/test/ELF/relocatable-comdat-multiple.s
@@ -21,7 +21,7 @@
# CHECK-NEXT: Name: .group
# CHECK-NEXT: Index: 5
# CHECK-NEXT: Link: 8
-# CHECK-NEXT: Info: 2
+# CHECK-NEXT: Info: 6
# CHECK-NEXT: Type: COMDAT
# CHECK-NEXT: Signature: bbb
# CHECK-NEXT: Section(s) in group [
diff --git a/test/ELF/relocatable-eh-frame.s b/test/ELF/relocatable-eh-frame.s
index c2e5ec6..dee906a 100644
--- a/test/ELF/relocatable-eh-frame.s
+++ b/test/ELF/relocatable-eh-frame.s
@@ -5,7 +5,7 @@
# RUN: ld.lld %t -o %t.so -shared
# RUN: llvm-objdump -h %t.so | FileCheck --check-prefix=DSO %s
-# DSO: .eh_frame 00000030
+# DSO: .eh_frame 00000034
# CHECK: Relocations [
# CHECK-NEXT: Section ({{.*}}) .rela.eh_frame {
diff --git a/test/ELF/relocation-shared.s b/test/ELF/relocation-shared.s
index 4fba7a5..730395a 100644
--- a/test/ELF/relocation-shared.s
+++ b/test/ELF/relocation-shared.s
@@ -8,7 +8,7 @@
// CHECK-NEXT: Flags [
// CHECK-NEXT: SHF_ALLOC
// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x1C8
+// CHECK-NEXT: Address: 0x1E1
// CHECK-NEXT: Offset:
// CHECK-NEXT: Size: 8
// CHECK-NEXT: Link: 0
@@ -16,8 +16,8 @@
// CHECK-NEXT: AddressAlignment: 1
// CHECK-NEXT: EntrySize: 0
// CHECK-NEXT: SectionData (
-// CHECK-NEXT: 0000: 380E0000 00000000
-// 0x1000 - 0x1C8 = 0xE38
+// CHECK-NEXT: 0000: 1F0E0000 00000000
+// 0x1000 - 0x1E1 = 0xE1F
// CHECK-NEXT: )
// CHECK: Name: .text
diff --git a/test/ELF/relocation.s b/test/ELF/relocation.s
index 3359a8b..8205728 100644
--- a/test/ELF/relocation.s
+++ b/test/ELF/relocation.s
@@ -1,6 +1,6 @@
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %t2
-// RUN: ld.lld %t2 -o %t2.so -shared
+// RUN: ld.lld %t2 -soname fixed-length-string.so -o %t2.so -shared
// RUN: ld.lld --hash-style=sysv %t %t2.so -o %t3
// RUN: llvm-readobj -s %t3 | FileCheck --check-prefix=SEC %s
// RUN: llvm-objdump -s -d %t3 | FileCheck %s
@@ -113,17 +113,16 @@
.quad R_X86_64_64
// CHECK: Contents of section .R_X86_64_64:
-// CHECK-NEXT: 2001c8 c8012000 00000000
+// CHECK-NEXT: 20024d 4d022000 00000000
.section .R_X86_64_GOTPCREL,"a",@progbits
.global R_X86_64_GOTPCREL
R_X86_64_GOTPCREL:
.long zed@gotpcrel
-// 0x2020F8 - 0x2001D8 = 7952
-// 7952 = 0x101f0000 in little endian
+// 0x2020F0(.got) - 0x200255(.R_X86_64_GOTPCREL) = 0x2e9b
// CHECK: Contents of section .R_X86_64_GOTPCREL
-// CHECK-NEXT: 2001d0 202f0000
+// CHECK-NEXT: 200255 9b2e0000
.section .R_X86_64_GOT32,"a",@progbits
.global R_X86_64_GOT32
diff --git a/test/ELF/relro-omagic.s b/test/ELF/relro-omagic.s
index 97c3a81..3eac082 100644
--- a/test/ELF/relro-omagic.s
+++ b/test/ELF/relro-omagic.s
@@ -9,8 +9,8 @@
# NORELRO-NEXT: Idx Name Size Address Type
# NORELRO-NEXT: 0 00000000 0000000000000000
# NORELRO-NEXT: 1 .dynsym 00000048 0000000000200120
-# NORELRO-NEXT: 2 .hash 00000020 0000000000200168
-# NORELRO-NEXT: 3 .dynstr 00000021 0000000000200188
+# NORELRO-NEXT: 2 .dynstr 00000021 0000000000200168
+# NORELRO-NEXT: 3 .hash 00000020 000000000020018c
# NORELRO-NEXT: 4 .rela.dyn 00000018 00000000002001b0
# NORELRO-NEXT: 5 .rela.plt 00000018 00000000002001c8
# NORELRO-NEXT: 6 .text 0000000a 00000000002001e0 TEXT DATA
diff --git a/test/ELF/relro.s b/test/ELF/relro.s
index b21e514..0f72131 100644
--- a/test/ELF/relro.s
+++ b/test/ELF/relro.s
@@ -1,13 +1,17 @@
+// REQUIRES: x86
+
// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
// RUN: ld.lld -shared %t2.o -o %t2.so
-// RUN: ld.lld %t.o %t2.so -z now -z relro -o %t
+
+// RUN: ld.lld %t.o %t2.so -z now -z norelro -z relro -o %t
// RUN: llvm-readobj -l --elf-output-style=GNU %t | FileCheck --check-prefix=CHECK --check-prefix=FULLRELRO %s
-// RUN: ld.lld %t.o %t2.so -z relro -o %t
+
+// RUN: ld.lld %t.o %t2.so -z norelro -z relro -o %t
// RUN: llvm-readobj -l --elf-output-style=GNU %t | FileCheck --check-prefix=CHECK --check-prefix=PARTRELRO %s
+
// RUN: ld.lld %t.o %t2.so -z norelro -o %t
// RUN: llvm-readobj -l --elf-output-style=GNU %t | FileCheck --check-prefix=NORELRO %s
-// REQUIRES: x86
// CHECK: Program Headers:
// CHECK-NEXT: Type
diff --git a/test/ELF/reproduce-backslash.s b/test/ELF/reproduce-backslash.s
index 40b9dd8..7a9964d 100644
--- a/test/ELF/reproduce-backslash.s
+++ b/test/ELF/reproduce-backslash.s
@@ -3,7 +3,7 @@
# Test that we don't erroneously replace \ with / on UNIX, as it's
# legal for a filename to contain backslashes.
# RUN: llvm-mc %s -o %T/foo\\.o -filetype=obj -triple=x86_64-pc-linux
-# RUN: ld.lld %T/foo\\.o --reproduce repro.tar
-# RUN: tar tf repro.tar | FileCheck %s
+# RUN: ld.lld %T/foo\\.o --reproduce %T/repro.tar -o /dev/null
+# RUN: tar tf %T/repro.tar | FileCheck %s
# CHECK: repro/{{.*}}/foo\\.o
diff --git a/test/ELF/shared-be.s b/test/ELF/shared-ppc64.s
similarity index 78%
rename from test/ELF/shared-be.s
rename to test/ELF/shared-ppc64.s
index 0b941d3..f2280a1 100644
--- a/test/ELF/shared-be.s
+++ b/test/ELF/shared-ppc64.s
@@ -1,9 +1,16 @@
+// REQUIRES: ppc
+
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld -dynamic-linker /lib64/ld64.so.1 -rpath foo -rpath bar --export-dynamic %t.o %t2.so -o %t
+// RUN: llvm-readobj --dynamic-table -s %t | FileCheck %s
+
// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared.s -o %t2.o
// RUN: ld.lld -shared %t2.o -o %t2.so
// RUN: ld.lld -dynamic-linker /lib64/ld64.so.1 -rpath foo -rpath bar --export-dynamic %t.o %t2.so -o %t
// RUN: llvm-readobj --dynamic-table -s %t | FileCheck %s
-// REQUIRES: ppc
// CHECK: Name: .rela.dyn
// CHECK-NEXT: Type: SHT_REL
diff --git a/test/ELF/shared.s b/test/ELF/shared.s
index 65ad2c6..6d4bcd1 100644
--- a/test/ELF/shared.s
+++ b/test/ELF/shared.s
@@ -59,21 +59,6 @@
// CHECK-NEXT: 0030:
// CHECK-NEXT: )
// CHECK-NEXT: }
-// CHECK-NEXT: Section {
-// CHECK-NEXT: Index: 3
-// CHECK-NEXT: Name: .hash
-// CHECK-NEXT: Type: SHT_HASH
-// CHECK-NEXT: Flags [
-// CHECK-NEXT: SHF_ALLOC
-// CHECK-NEXT: ]
-// CHECK-NEXT: Address: [[HASHADDR:.*]]
-// CHECK-NEXT: Offset:
-// CHECK-NEXT: Size:
-// CHECK-NEXT: Link: 2
-// CHECK-NEXT: Info: 0
-// CHECK-NEXT: AddressAlignment: 4
-// CHECK-NEXT: EntrySize: 4
-
// CHECK: Index: [[DYNSTR]]
// CHECK-NEXT: Name: .dynstr
// CHECK-NEXT: Type: SHT_STRTAB
@@ -90,6 +75,20 @@
// CHECK-NEXT: SectionData (
// CHECK: )
// CHECK-NEXT: }
+// CHECK-NEXT: Section {
+// CHECK-NEXT: Index: 4
+// CHECK-NEXT: Name: .hash
+// CHECK-NEXT: Type: SHT_HASH
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: [[HASHADDR:.*]]
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Link: 2
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 4
+// CHECK-NEXT: EntrySize: 4
// CHECK: Name: .rel.dyn
// CHECK-NEXT: Type: SHT_REL
diff --git a/test/ELF/sort-norosegment.s b/test/ELF/sort-norosegment.s
index bd74f2e..6d02eee 100644
--- a/test/ELF/sort-norosegment.s
+++ b/test/ELF/sort-norosegment.s
@@ -4,10 +4,10 @@
# RUN: ld.lld --hash-style=sysv -no-rosegment -o %t1 %t -shared
# RUN: llvm-readobj -elf-output-style=GNU -s %t1 | FileCheck %s
-# CHECK: .text {{.*}} AX
-# CHECK-NEXT: .dynsym {{.*}} A
-# CHECK-NEXT: .hash {{.*}} A
+# CHECK: .dynsym {{.*}} A
# CHECK-NEXT: .dynstr {{.*}} A
+# CHECK-NEXT: .text {{.*}} AX
+# CHECK-NEXT: .hash {{.*}} A
# CHECK-NEXT: foo {{.*}} WA
# CHECK-NEXT: .dynamic {{.*}} WA
diff --git a/test/ELF/start-lib.s b/test/ELF/start-lib.s
index 013a2b2..b79d9ef 100644
--- a/test/ELF/start-lib.s
+++ b/test/ELF/start-lib.s
@@ -21,5 +21,14 @@
// TEST3-NOT: Name: bar
// TEST3-NOT: Name: foo
+// RUN: not ld.lld %t1.o --start-lib --start-lib 2>&1 | FileCheck -check-prefix=NESTED-LIB %s
+// NESTED-LIB: nested --start-lib
+
+// RUN: not ld.lld %t1.o --start-group --start-lib 2>&1 | FileCheck -check-prefix=LIB-IN-GROUP %s
+// LIB-IN-GROUP: may not nest --start-lib in --start-group
+
+// RUN: not ld.lld --end-lib 2>&1 | FileCheck -check-prefix=END %s
+// END: stray --end-lib
+
.globl _start
_start:
diff --git a/test/ELF/symbol-ordering-file-warnings.s b/test/ELF/symbol-ordering-file-warnings.s
index aabac53..71414bf 100644
--- a/test/ELF/symbol-ordering-file-warnings.s
+++ b/test/ELF/symbol-ordering-file-warnings.s
@@ -39,11 +39,15 @@
# RUN: ld.lld %t1.o -o %t --symbol-ordering-file %t-order-gc.txt --gc-sections \
# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,GC
-# Check that a warning is emitted for the symbol removed due to --icf.
+# Check that a warning is not emitted for the symbol removed due to --icf.
# RUN: echo "icf1" > %t-order-icf.txt
# RUN: echo "icf2" >> %t-order-icf.txt
# RUN: ld.lld %t1.o -o %t --symbol-ordering-file %t-order-icf.txt --icf=all \
-# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,ICF
+# RUN: --unresolved-symbols=ignore-all --fatal-warnings
+
+# RUN: echo "_GLOBAL_OFFSET_TABLE_" > %t-order-synthetic.txt
+# RUN: ld.lld %t1.o -o %t --symbol-ordering-file %t-order-synthetic.txt --icf=all \
+# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,SYNTHETIC
# Check that a warning is emitted for symbols discarded due to a linker script /DISCARD/ section.
# RUN: echo "discard" > %t-order-discard.txt
@@ -90,30 +94,31 @@
# RUN: echo "absolute" >> %t-order-multi.txt
# RUN: echo "gc" >> %t-order-multi.txt
# RUN: echo "discard" >> %t-order-multi.txt
+# RUN: echo "_GLOBAL_OFFSET_TABLE_" >> %t-order-multi.txt
# RUN: echo "_start" >> %t-order-multi.txt
# RUN: ld.lld %t1.o %t3.o %t.so -o %t --symbol-ordering-file %t-order-multi.txt --gc-sections -T %t.script \
-# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,SAMESYM,ABSOLUTE,SHARED,UNDEFINED,GC,DISCARD,MISSING2
+# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,SAMESYM,ABSOLUTE,SHARED,UNDEFINED,GC,DISCARD,MISSING2,SYNTHETIC
# WARN-NOT: warning:
# SAMESYM: warning: {{.*}}.txt: duplicate ordered symbol: _start
# WARN-NOT: warning:
-# ABSOLUTE: warning: {{.*}}1.o: unable to order absolute symbol: absolute
+# SYNTHETIC: warning: <internal>: unable to order synthetic symbol: _GLOBAL_OFFSET_TABLE_
# WARN-NOT: warning:
# DISCARD: warning: {{.*}}1.o: unable to order discarded symbol: discard
# WARN-NOT: warning:
# GC: warning: {{.*}}1.o: unable to order discarded symbol: gc
# WARN-NOT: warning:
-# SHARED: warning: {{.*}}1.o: unable to order shared symbol: shared
+# SHARED: warning: {{.*}}.so: unable to order shared symbol: shared
# WARN-NOT: warning:
# UNDEFINED: warning: {{.*}}3.o: unable to order undefined symbol: undefined
# WARN-NOT: warning:
+# ABSOLUTE: warning: {{.*}}1.o: unable to order absolute symbol: absolute
+# WARN-NOT: warning:
# MISSING: warning: symbol ordering file: no such symbol: missing
# MISSING2: warning: symbol ordering file: no such symbol: missing_sym
-# ICF: warning: {{.*}}1.o: unable to order discarded symbol: icf2
# COMDAT: warning: {{.*}}1.o: unable to order discarded symbol: comdat
-# COMDAT-NEXT: warning: {{.*}}2.o: unable to order discarded symbol: comdat
-# MULTI: warning: {{.*}}2.o: unable to order absolute symbol: multi
-# MULTI-NEXT: warning: {{.*}}3.o: unable to order undefined symbol: multi
+# MULTI: warning: {{.*}}3.o: unable to order undefined symbol: multi
+# MULTI-NEXT: warning: {{.*}}2.o: unable to order absolute symbol: multi
# WARN-NOT: warning:
absolute = 0x1234
@@ -157,4 +162,4 @@
# This is a "good" instance of the symbol
.section .text.multi,"ax",@progbits
multi:
- nop
+ .quad _GLOBAL_OFFSET_TABLE_
diff --git a/test/ELF/synthetic-got.s b/test/ELF/synthetic-got.s
index 375a438..8bc7fc5 100644
--- a/test/ELF/synthetic-got.s
+++ b/test/ELF/synthetic-got.s
@@ -7,13 +7,13 @@
# RUN: | FileCheck %s --check-prefix=GOTDATA
# GOT: Sections:
-# GOT: 8 .got.plt 00000020 00000000000000e0 DATA
-# GOT: 10 .got 00000008 00000000000001d0 DATA
+# GOT: 8 .got.plt 00000020 00000000000000d0 DATA
+# GOT: 10 .got 00000008 00000000000001c0 DATA
# GOTDATA: Contents of section .got.plt:
-# GOTDATA-NEXT: 00e0 00010000 00000000 00000000 00000000
-# GOTDATA-NEXT: 00f0 00000000 00000000 d6000000 00000000
+# GOTDATA-NEXT: 00d0 f0000000 00000000 00000000 00000000
+# GOTDATA-NEXT: 00e0 00000000 00000000 c6000000 00000000
# GOTDATA-NEXT: Contents of section .got:
-# GOTDATA-NEXT: 01d0 00000000 00000000
+# GOTDATA-NEXT: 01c0 00000000 00000000
# RUN: echo "SECTIONS { .mygot : { *(.got) *(.got.plt) } }" > %t1.script
# RUN: ld.lld --hash-style=sysv -shared %t.o -o %t1.out --script %t1.script
@@ -21,12 +21,12 @@
# RUN: llvm-objdump -s -section=.mygot %t1.out | FileCheck %s --check-prefix=MYGOTDATA
# MYGOT: Sections:
-# MYGOT: 8 .mygot 00000028 00000000000000e0 DATA
+# MYGOT: 8 .mygot 00000028 00000000000000d0 DATA
# MYGOT-NOT: .got
# MYGOT-NOT: .got.plt
-# MYGOTDATA: 00e0 00000000 00000000 08010000 00000000
-# MYGOTDATA-NEXT: 00f0 00000000 00000000 00000000 00000000
-# MYGOTDATA-NEXT: 0100 d6000000 00000000
+# MYGOTDATA: 00d0 00000000 00000000 f8000000 00000000
+# MYGOTDATA-NEXT: 00e0 00000000 00000000 00000000 00000000
+# MYGOTDATA-NEXT: 00f0 c6000000 00000000
mov bar@gotpcrel(%rip), %rax
call foo@plt
diff --git a/test/ELF/text-section-prefix.s b/test/ELF/text-section-prefix.s
new file mode 100644
index 0000000..b9e9a60
--- /dev/null
+++ b/test/ELF/text-section-prefix.s
@@ -0,0 +1,38 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld -z keep-text-section-prefix %t -o %t2
+# RUN: llvm-readelf -l %t2 | FileCheck %s
+# RUN: ld.lld %t -o %t3
+# RUN: llvm-readelf -l %t3 | FileCheck --check-prefix=CHECKNO %s
+# RUN: ld.lld -z nokeep-text-section-prefix %t -o %t4
+# RUN: llvm-readelf -l %t4 | FileCheck --check-prefix=CHECKNO %s
+
+# CHECK: .text
+# CHECK: .text.hot
+# CHECK: .text.startup
+# CHECK: .text.exit
+# CHECK: .text.unlikely
+# CHECKNO: .text
+# CHECKNO-NOT: .text.hot
+
+_start:
+ ret
+
+.section .text.f,"ax"
+f:
+ nop
+
+.section .text.hot.f_hot,"ax"
+f_hot:
+ nop
+
+.section .text.startup.f_startup,"ax"
+f_startup:
+ nop
+
+.section .text.exit.f_exit,"ax"
+f_exit:
+ nop
+
+.section .text.unlikely.f_unlikely,"ax"
+f_unlikely:
+ nop
diff --git a/test/ELF/undef-start.s b/test/ELF/undef-start.s
index 590d0a8..d0e0147 100644
--- a/test/ELF/undef-start.s
+++ b/test/ELF/undef-start.s
@@ -1,3 +1,5 @@
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-# RUN: ld.lld %t -o %t2 2>&1
# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t 2>&1 | FileCheck %s
+
+# CHECK: warning: cannot find entry symbol _start
diff --git a/test/ELF/undef.s b/test/ELF/undef.s
index aabcbbc..07e3b68 100644
--- a/test/ELF/undef.s
+++ b/test/ELF/undef.s
@@ -34,9 +34,19 @@
# CHECK: >>> referenced by undef-debug.s:11 (dir{{/|\\}}undef-debug.s:11)
# CHECK: >>> {{.*}}.o:(.text.2+0x0)
+# Show that all line table problems are mentioned as soon as the object's line information
+# is requested, even if that particular part of the line information is not currently required.
+# CHECK: warning: parsing line table prologue at 0x00000000 should have ended at 0x00000038 but it ended at 0x00000037
+# CHECK: warning: last sequence in debug line table is not terminated!
# CHECK: error: undefined symbol: zed6
# CHECK: >>> referenced by {{.*}}tmp4.o:(.text+0x0)
+# Show that a problem with one line table's information doesn't affect getting information from
+# a different one in the same object.
+# CHECK: error: undefined symbol: zed7
+# CHECK: >>> referenced by undef-bad-debug2.s:11 (dir2{{/|\\}}undef-bad-debug2.s:11)
+# CHECK: >>> {{.*}}tmp4.o:(.text+0x8)
+
# RUN: not ld.lld %t.o %t2.a -o %t.exe -no-demangle 2>&1 | \
# RUN: FileCheck -check-prefix=NO-DEMANGLE %s
# NO-DEMANGLE: error: undefined symbol: _Z3fooi
diff --git a/test/ELF/verdef-defaultver.s b/test/ELF/verdef-defaultver.s
index c8444c4..4f01f17 100644
--- a/test/ELF/verdef-defaultver.s
+++ b/test/ELF/verdef-defaultver.s
@@ -55,8 +55,8 @@
# DSO-NEXT: ]
# DSO-NEXT: Version symbols {
# DSO-NEXT: Section Name: .gnu.version
-# DSO-NEXT: Address: 0x240
-# DSO-NEXT: Offset: 0x240
+# DSO-NEXT: Address: 0x256
+# DSO-NEXT: Offset: 0x256
# DSO-NEXT: Link: 1
# DSO-NEXT: Symbols [
# DSO-NEXT: Symbol {
@@ -150,8 +150,8 @@
# EXE-NEXT: ]
# EXE-NEXT: Version symbols {
# EXE-NEXT: Section Name: .gnu.version
-# EXE-NEXT: Address: 0x200228
-# EXE-NEXT: Offset: 0x228
+# EXE-NEXT: Address: 0x20023C
+# EXE-NEXT: Offset: 0x23C
# EXE-NEXT: Link: 1
# EXE-NEXT: Symbols [
# EXE-NEXT: Symbol {
diff --git a/test/ELF/verdef.s b/test/ELF/verdef.s
index b5d12ee..af7c2ad 100644
--- a/test/ELF/verdef.s
+++ b/test/ELF/verdef.s
@@ -8,8 +8,8 @@
# DSO: Version symbols {
# DSO-NEXT: Section Name: .gnu.version
-# DSO-NEXT: Address: 0x228
-# DSO-NEXT: Offset: 0x228
+# DSO-NEXT: Address: 0x260
+# DSO-NEXT: Offset: 0x260
# DSO-NEXT: Link: 1
# DSO-NEXT: Symbols [
# DSO-NEXT: Symbol {
@@ -70,8 +70,8 @@
# MAIN: Version symbols {
# MAIN-NEXT: Section Name: .gnu.version
-# MAIN-NEXT: Address: 0x200228
-# MAIN-NEXT: Offset: 0x228
+# MAIN-NEXT: Address: 0x200260
+# MAIN-NEXT: Offset: 0x260
# MAIN-NEXT: Link: 1
# MAIN-NEXT: Symbols [
# MAIN-NEXT: Symbol {
diff --git a/test/ELF/verneed.s b/test/ELF/verneed.s
index 27ab047..3c92336 100644
--- a/test/ELF/verneed.s
+++ b/test/ELF/verneed.s
@@ -10,67 +10,70 @@
# RUN: llvm-readobj -V -sections -section-data -dyn-symbols -dynamic-table %t | FileCheck %s
# CHECK: Section {
-# CHECK: Index: 1
-# CHECK-NEXT: Name: .dynsym
-# CHECK-NEXT: Type: SHT_DYNSYM (0xB)
+# CHECK: Index: 1
+# CHECK-NEXT: Name: .dynsym
+# CHECK-NEXT: Type: SHT_DYNSYM (0xB)
+# CHECK-NEXT: Flags [ (0x2)
+# CHECK-NEXT: SHF_ALLOC (0x2)
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x2001C8
+# CHECK-NEXT: Offset: 0x1C8
+# CHECK-NEXT: Size: 96
+# CHECK-NEXT: Link: 2
+# CHECK-NEXT: Info: 1
+# CHECK-NEXT: AddressAlignment: 8
+# CHECK-NEXT: EntrySize: 24
+
+# CHECK: Section {
+# CHECK-NEXT: Index: 2
+# CHECK-NEXT: Name: .dynstr
+# CHECK-NEXT: Type: SHT_STRTAB (0x3)
+# CHECK-NEXT: Flags [ (0x2)
+# CHECK-NEXT: SHF_ALLOC (0x2)
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x200228
+# CHECK-NEXT: Offset: 0x228
+# CHECK-NEXT: Size: 47
+# CHECK-NEXT: Link: 0
+# CHECK-NEXT: Info: 0
+# CHECK-NEXT: AddressAlignment: 1
+# CHECK-NEXT: EntrySize: 0
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT: 0000: 00766572 6E656564 312E736F 2E300076 |.verneed1.so.0.v|
+# CHECK-NEXT: 0010: 65726E65 6564322E 736F2E30 00663100 |erneed2.so.0.f1.|
+# CHECK-NEXT: 0020: 76330066 32007632 00673100 763100 |v3.f2.v2.g1.v1.|
+# CHECK-NEXT: )
+# CHECK-NEXT: }
+
+# CHECK: Section {
+# CHECK-NEXT: Index: 3
+# CHECK-NEXT: Name: .gnu.version
+# CHECK-NEXT: Type: SHT_GNU_versym (0x6FFFFFFF)
# CHECK-NEXT: Flags [ (0x2)
# CHECK-NEXT: SHF_ALLOC (0x2)
# CHECK-NEXT: ]
-# CHECK-NEXT: Address: 0x2001C8
-# CHECK-NEXT: Offset: 0x1C8
-# CHECK-NEXT: Size: 96
-# CHECK-NEXT: Link: 5
-# CHECK-NEXT: Info: 1
-# CHECK-NEXT: AddressAlignment: 8
-# CHECK-NEXT: EntrySize: 24
+# CHECK-NEXT: Address: 0x200258
+# CHECK-NEXT: Offset: 0x258
+# CHECK-NEXT: Size: 8
+# CHECK-NEXT: Link: 1
+# CHECK-NEXT: Info: 0
+# CHECK-NEXT: AddressAlignment: 2
+# CHECK-NEXT: EntrySize: 2
+
# CHECK: Section {
-# CHECK-NEXT: Index: 2
-# CHECK-NEXT: Name: .gnu.version
-# CHECK-NEXT: Type: SHT_GNU_versym (0x6FFFFFFF)
-# CHECK-NEXT: Flags [ (0x2)
-# CHECK-NEXT: SHF_ALLOC (0x2)
-# CHECK-NEXT: ]
-# CHECK-NEXT: Address: 0x200228
-# CHECK-NEXT: Offset: 0x228
-# CHECK-NEXT: Size: 8
-# CHECK-NEXT: Link: 1
-# CHECK-NEXT: Info: 0
-# CHECK-NEXT: AddressAlignment: 2
-# CHECK-NEXT: EntrySize: 2
-# CHECK: Section {
-# CHECK-NEXT: Index: 3
-# CHECK-NEXT: Name: .gnu.version_r
-# CHECK-NEXT: Type: SHT_GNU_verneed (0x6FFFFFFE)
-# CHECK-NEXT: Flags [ (0x2)
-# CHECK-NEXT: SHF_ALLOC (0x2)
-# CHECK-NEXT: ]
-# CHECK-NEXT: Address: 0x200230
-# CHECK-NEXT: Offset: 0x230
-# CHECK-NEXT: Size: 80
-# CHECK-NEXT: Link: 5
-# CHECK-NEXT: Info: 2
-# CHECK-NEXT: AddressAlignment: 4
-# CHECK-NEXT: EntrySize: 0
-# CHECK: Section {
-# CHECK: Index: 5
-# CHECK-NEXT: Name: .dynstr
-# CHECK-NEXT: Type: SHT_STRTAB
-# CHECK-NEXT: Flags [ (0x2)
-# CHECK-NEXT: SHF_ALLOC (0x2)
-# CHECK-NEXT: ]
-# CHECK-NEXT: Address: 0x2002A8
-# CHECK-NEXT: Offset: 0x2A8
-# CHECK-NEXT: Size: 47
-# CHECK-NEXT: Link: 0
-# CHECK-NEXT: Info: 0
-# CHECK-NEXT: AddressAlignment: 1
-# CHECK-NEXT: EntrySize: 0
-# CHECK-NEXT: SectionData (
-# CHECK-NEXT: 0000: 00766572 6E656564 312E736F 2E300076 |.verneed1.so.0.v|
-# CHECK-NEXT: 0010: 65726E65 6564322E 736F2E30 00663100 |erneed2.so.0.f1.|
-# CHECK-NEXT: 0020: 76330066 32007632 00673100 763100 |v3.f2.v2.g1.v1.|
-# CHECK-NEXT: )
-# CHECK-NEXT: }
+# CHECK-NEXT: Index: 4
+# CHECK-NEXT: Name: .gnu.version_r
+# CHECK-NEXT: Type: SHT_GNU_verneed (0x6FFFFFFE)
+# CHECK-NEXT: Flags [ (0x2)
+# CHECK-NEXT: SHF_ALLOC (0x2)
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x200260
+# CHECK-NEXT: Offset: 0x260
+# CHECK-NEXT: Size: 80
+# CHECK-NEXT: Link: 2
+# CHECK-NEXT: Info: 2
+# CHECK-NEXT: AddressAlignment: 4
+# CHECK-NEXT: EntrySize: 0
# CHECK: DynamicSymbols [
# CHECK-NEXT: Symbol {
@@ -111,14 +114,14 @@
# CHECK-NEXT: }
# CHECK-NEXT: ]
-# CHECK: 0x000000006FFFFFF0 VERSYM 0x200228
-# CHECK-NEXT: 0x000000006FFFFFFE VERNEED 0x200230
+# CHECK: 0x000000006FFFFFF0 VERSYM 0x200258
+# CHECK-NEXT: 0x000000006FFFFFFE VERNEED 0x200260
# CHECK-NEXT: 0x000000006FFFFFFF VERNEEDNUM 2
# CHECK: Version symbols {
# CHECK-NEXT: Section Name: .gnu.version
-# CHECK-NEXT: Address: 0x200228
-# CHECK-NEXT: Offset: 0x228
+# CHECK-NEXT: Address: 0x200258
+# CHECK-NEXT: Offset: 0x258
# CHECK-NEXT: Link: 1
# CHECK-NEXT: Symbols [
# CHECK-NEXT: Symbol {
diff --git a/test/ELF/version-exclude-libs.s b/test/ELF/version-exclude-libs.s
new file mode 100644
index 0000000..7335c23
--- /dev/null
+++ b/test/ELF/version-exclude-libs.s
@@ -0,0 +1,30 @@
+// REQUIRES: x86
+// RUN: llvm-mc %p/Inputs/versiondef.s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: llvm-ar -r %t.a %t.o
+// RUN: llvm-mc %s -o %t2.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t2.o %t.a --shared --exclude-libs ALL -o %t.so
+// RUN: llvm-readobj -symbols %t.so | FileCheck %s
+// RUN: llvm-readobj -dyn-symbols %t.so | FileCheck -check-prefix CHECK-DYN %s
+// RUN: not ld.lld %t2.o %t.a --shared -o %t.so 2>&1 | FileCheck -check-prefix=CHECK-ERR %s
+
+// Test that we do not give an error message for undefined versions when the
+// symbol is not exported to the dynamic symbol table.
+
+// CHECK: Name: func
+// CHECK-NEXT: Value:
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Binding: Local (0x0)
+
+// CHECK-DYN-NOT: func
+
+// CHECK-ERR: symbol func@@VER2 has undefined version VER2
+// CHECK-ERR-NEXT: symbol func@VER has undefined version VER
+
+ .text
+ .globl _start
+ .globl func
+_start:
+ ret
+
+ .data
+ .quad func
diff --git a/test/ELF/version-script-extern.s b/test/ELF/version-script-extern.s
index c63ff81..3125f62 100644
--- a/test/ELF/version-script-extern.s
+++ b/test/ELF/version-script-extern.s
@@ -7,7 +7,7 @@
# RUN: echo "LIBSAMPLE_2.0 { global:" >> %t.script
# RUN: echo ' extern "C" { _Z3bari; };' >> %t.script
# RUN: echo "};" >> %t.script
-# RUN: ld.lld --hash-style=sysv --version-script %t.script -shared %t.o -o %t.so
+# RUN: ld.lld --hash-style=sysv --version-script %t.script -soname fixed-length-string -shared %t.o -o %t.so
# RUN: llvm-readobj -V -dyn-symbols %t.so | FileCheck --check-prefix=DSO %s
# DSO: DynamicSymbols [
@@ -68,8 +68,8 @@
# DSO-NEXT: ]
# DSO-NEXT: Version symbols {
# DSO-NEXT: Section Name: .gnu.version
-# DSO-NEXT: Address: 0x258
-# DSO-NEXT: Offset: 0x258
+# DSO-NEXT: Address: 0x2BA
+# DSO-NEXT: Offset: 0x2BA
# DSO-NEXT: Link: 1
# DSO-NEXT: Symbols [
# DSO-NEXT: Symbol {
diff --git a/test/ELF/warn-backrefs.s b/test/ELF/warn-backrefs.s
new file mode 100644
index 0000000..d51e1f5
--- /dev/null
+++ b/test/ELF/warn-backrefs.s
@@ -0,0 +1,48 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: echo ".globl foo; foo:" | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t2.o
+# RUN: rm -f %t2.a
+# RUN: llvm-ar rcs %t2.a %t2.o
+
+# RUN: ld.lld --fatal-warnings -o %t.exe %t1.o %t2.a
+# RUN: ld.lld --fatal-warnings -o %t.exe %t2.a %t1.o
+# RUN: ld.lld --fatal-warnings --warn-backrefs -o %t.exe %t1.o %t2.a
+# RUN: ld.lld --fatal-warnings --warn-backrefs -o %t.exe %t1.o --start-lib %t2.o --end-lib
+
+# RUN: ld.lld --fatal-warnings --warn-backrefs -o %t.exe --start-group %t2.a %t1.o --end-group
+# RUN: ld.lld --fatal-warnings --warn-backrefs -o %t.exe "-(" %t2.a %t1.o "-)"
+
+# RUN: echo "INPUT(\"%t1.o\" \"%t2.a\")" > %t1.script
+# RUN: ld.lld --fatal-warnings --warn-backrefs -o %t.exe %t1.script
+
+# RUN: echo "GROUP(\"%t2.a\" \"%t1.o\")" > %t2.script
+# RUN: ld.lld --fatal-warnings --warn-backrefs -o %t.exe %t2.script
+
+# RUN: not ld.lld --fatal-warnings --warn-backrefs -o %t.exe %t2.a %t1.o 2>&1 | FileCheck %s
+# RUN: not ld.lld --fatal-warnings --warn-backrefs -o %t.exe %t2.a "-(" %t1.o "-)" 2>&1 | FileCheck %s
+# RUN: not ld.lld --fatal-warnings --warn-backrefs -o %t.exe --start-group %t2.a --end-group %t1.o 2>&1 | FileCheck %s
+
+# RUN: echo "GROUP(\"%t2.a\")" > %t3.script
+# RUN: not ld.lld --fatal-warnings --warn-backrefs -o %t.exe %t3.script %t1.o 2>&1 | FileCheck %s
+# RUN: ld.lld --fatal-warnings --warn-backrefs -o %t.exe "-(" %t3.script %t1.o "-)"
+
+# CHECK: backward reference detected: foo in {{.*}}1.o refers to {{.*}}2.a
+
+# RUN: not ld.lld --fatal-warnings --start-group --start-group 2>&1 | FileCheck -check-prefix=START %s
+# START: nested --start-group
+
+# RUN: not ld.lld --fatal-warnings --end-group 2>&1 | FileCheck -check-prefix=END %s
+# END: stray --end-group
+
+# RUN: echo ".globl bar; bar:" | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t3.o
+# RUN: echo ".globl foo; foo: call bar" | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t4.o
+# RUN: ld.lld --fatal-warnings --warn-backrefs %t1.o --start-lib %t3.o %t4.o --end-lib -o %t.exe
+
+# We don't report backward references to weak symbols as they can be overriden later.
+# RUN: echo ".weak foo; foo:" | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t5.o
+# RUN: ld.lld --fatal-warnings --warn-backrefs --start-lib %t5.o --end-lib %t1.o %t2.o -o %t.exe
+
+.globl _start, foo
+_start:
+ call foo
diff --git a/test/ELF/weak-and-strong-undef.s b/test/ELF/weak-and-strong-undef.s
index db93470..32ce649 100644
--- a/test/ELF/weak-and-strong-undef.s
+++ b/test/ELF/weak-and-strong-undef.s
@@ -1,6 +1,6 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
-# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/weak-and-strong-undef.s -o %t2.o
+# RUN: echo ".weak foo" | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t2.o
# RUN: not ld.lld %t1.o %t2.o -o %t 2>&1 | FileCheck %s
# RUN: not ld.lld %t2.o %t1.o -o %t 2>&1 | FileCheck %s
diff --git a/test/ELF/weak-shared-gc.s b/test/ELF/weak-shared-gc.s
new file mode 100644
index 0000000..2cafbe8
--- /dev/null
+++ b/test/ELF/weak-shared-gc.s
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
+# RUN: echo -e '.globl __cxa_finalize\n__cxa_finalize:' | \
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t2.o
+# RUN: ld.lld %t2.o -o %t2.so -shared
+# RUN: ld.lld %t1.o --as-needed --gc-sections %t2.so -o %t
+# RUN: llvm-readelf -dynamic-table -dyn-symbols %t | FileCheck %s
+
+# The crt files on linux have a weak reference to __cxa_finalize. It
+# is important that a weak undefined reference is produced. Like
+# other weak undefined references, the shared library is not marked as
+# needed.
+
+# CHECK-NOT: NEEDED
+# CHECK: WEAK DEFAULT UND __cxa_finalize
+# CHECK-NOT: NEEDED
+
+ .global _start
+_start:
+ .weak __cxa_finalize
+ call __cxa_finalize@PLT
diff --git a/test/ELF/x86-64-dyn-rel-error3.s b/test/ELF/x86-64-dyn-rel-error3.s
new file mode 100644
index 0000000..82a580d
--- /dev/null
+++ b/test/ELF/x86-64-dyn-rel-error3.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 %t.o -shared -o %t.so 2>&1 | FileCheck %s
+
+# CHECK: relocation R_X86_64_8 cannot be used against symbol foo; recompile with -fPIC
+# CHECK: relocation R_X86_64_16 cannot be used against symbol foo; recompile with -fPIC
+# CHECK: relocation R_X86_64_PC8 cannot be used against symbol foo; recompile with -fPIC
+# CHECK: relocation R_X86_64_PC16 cannot be used against symbol foo; recompile with -fPIC
+
+.global foo
+
+.data
+.byte foo # R_X86_64_8
+.short foo # R_X86_64_16
+.byte foo - . # R_X86_64_PC8
+.short foo - . # R_X86_64_PC16
diff --git a/test/ELF/x86-64-plt-high-addr.s b/test/ELF/x86-64-plt-high-addr.s
new file mode 100644
index 0000000..4acccb6
--- /dev/null
+++ b/test/ELF/x86-64-plt-high-addr.s
@@ -0,0 +1,24 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t1.o
+// RUN: ld.lld -o %t.so -shared %t1.o
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2.o
+// RUN: ld.lld -o %t1.exe %t2.o %t.so -image-base=0xcafe00000000
+// RUN: llvm-objdump -s -j .got.plt %t1.exe | FileCheck %s
+
+// CHECK: Contents of section .got.plt:
+// CHECK-NEXT: cafe00002000 00300000 feca0000 00000000 00000000
+// CHECK-NEXT: cafe00002010 00000000 00000000 26100000 feca0000
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2.o
+// RUN: ld.lld -o %t2.exe %t2.o %t.so -image-base=0xcafe00000000 -z retpolineplt
+// RUN: llvm-objdump -s -j .got.plt %t2.exe | FileCheck -check-prefix=RETPOLINE %s
+
+// RETPOLINE: Contents of section .got.plt:
+// RETPOLINE-NEXT: cafe00002000 00300000 feca0000 00000000 00000000
+// RETPOLINE-NEXT: cafe00002010 00000000 00000000 51100000 feca0000
+
+.global _start
+_start:
+ jmp bar@PLT
diff --git a/test/ELF/x86-64-retpoline-linkerscript.s b/test/ELF/x86-64-retpoline-linkerscript.s
index d173cf5..03c3ef2 100644
--- a/test/ELF/x86-64-retpoline-linkerscript.s
+++ b/test/ELF/x86-64-retpoline-linkerscript.s
@@ -14,8 +14,8 @@
// CHECK: Disassembly of section .plt:
// CHECK-NEXT: .plt:
-// CHECK-NEXT: 10: ff 35 4a 01 00 00 pushq 330(%rip)
-// CHECK-NEXT: 16: 4c 8b 1d 4b 01 00 00 movq 331(%rip), %r11
+// CHECK-NEXT: 10: ff 35 ea 00 00 00 pushq 234(%rip)
+// CHECK-NEXT: 16: 4c 8b 1d eb 00 00 00 movq 235(%rip), %r11
// CHECK-NEXT: 1d: e8 0e 00 00 00 callq 14 <.plt+0x20>
// CHECK-NEXT: 22: f3 90 pause
// CHECK-NEXT: 24: 0f ae e8 lfence
@@ -40,7 +40,7 @@
// CHECK-NEXT: 3d: cc int3
// CHECK-NEXT: 3e: cc int3
// CHECK-NEXT: 3f: cc int3
-// CHECK-NEXT: 40: 4c 8b 1d 29 01 00 00 movq 297(%rip), %r11
+// CHECK-NEXT: 40: 4c 8b 1d c9 00 00 00 movq 201(%rip), %r11
// CHECK-NEXT: 47: e8 e4 ff ff ff callq -28 <.plt+0x20>
// CHECK-NEXT: 4c: e9 d1 ff ff ff jmp -47 <.plt+0x12>
// CHECK-NEXT: 51: 68 00 00 00 00 pushq $0
@@ -50,7 +50,7 @@
// CHECK-NEXT: 5d: cc int3
// CHECK-NEXT: 5e: cc int3
// CHECK-NEXT: 5f: cc int3
-// CHECK-NEXT: 60: 4c 8b 1d 11 01 00 00 movq 273(%rip), %r11
+// CHECK-NEXT: 60: 4c 8b 1d b1 00 00 00 movq 177(%rip), %r11
// CHECK-NEXT: 67: e8 c4 ff ff ff callq -60 <.plt+0x20>
// CHECK-NEXT: 6c: e9 b1 ff ff ff jmp -79 <.plt+0x12>
// CHECK-NEXT: 71: 68 01 00 00 00 pushq $1
diff --git a/test/ELF/x86-64-retpoline-znow-linkerscript.s b/test/ELF/x86-64-retpoline-znow-linkerscript.s
index 27737b8..e4eed84 100644
--- a/test/ELF/x86-64-retpoline-znow-linkerscript.s
+++ b/test/ELF/x86-64-retpoline-znow-linkerscript.s
@@ -35,13 +35,13 @@
// CHECK-NEXT: 2d: cc int3
// CHECK-NEXT: 2e: cc int3
// CHECK-NEXT: 2f: cc int3
-// CHECK-NEXT: 30: 4c 8b 1d 09 01 00 00 movq 265(%rip), %r11
+// CHECK-NEXT: 30: 4c 8b 1d a9 00 00 00 movq 169(%rip), %r11
// CHECK-NEXT: 37: e9 d4 ff ff ff jmp -44 <.plt>
// CHECK-NEXT: 3c: cc int3
// CHECK-NEXT: 3d: cc int3
// CHECK-NEXT: 3e: cc int3
// CHECK-NEXT: 3f: cc int3
-// CHECK-NEXT: 40: 4c 8b 1d 01 01 00 00 movq 257(%rip), %r11
+// CHECK-NEXT: 40: 4c 8b 1d a1 00 00 00 movq 161(%rip), %r11
// CHECK-NEXT: 47: e9 c4 ff ff ff jmp -60 <.plt>
// CHECK-NEXT: 4c: cc int3
// CHECK-NEXT: 4d: cc int3
diff --git a/test/ELF/x86-64-tls-ld-local.s b/test/ELF/x86-64-tls-ld-local.s
new file mode 100644
index 0000000..6daba63
--- /dev/null
+++ b/test/ELF/x86-64-tls-ld-local.s
@@ -0,0 +1,29 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -r -s %t.so | FileCheck %s
+
+// CHECK: Relocations [
+// CHECK-NEXT: Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT: R_X86_64_DTPMOD64 - 0x0
+// CHECK-NEXT: R_X86_64_DTPMOD64 - 0x0
+// CHECK-NEXT: }
+// CHECK-NEXT: Section ({{.*}}) .rela.plt {
+// CHECK-NEXT: R_X86_64_JUMP_SLOT __tls_get_addr 0x0
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+
+ data16
+ leaq bar@TLSGD(%rip), %rdi
+ data16
+ data16
+ rex64
+ callq __tls_get_addr@PLT
+
+ leaq bar@TLSLD(%rip), %rdi
+ callq __tls_get_addr@PLT
+ leaq bar@DTPOFF(%rax), %rax
+
+ .section .tdata,"awT",@progbits
+bar:
+ .long 42
diff --git a/test/ELF/ztext.s b/test/ELF/ztext.s
index 1ce19cf..1757769 100644
--- a/test/ELF/ztext.s
+++ b/test/ELF/ztext.s
@@ -2,6 +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/ztext.s -o %t2.o
# RUN: ld.lld %t2.o -o %t2.so -shared
+
# RUN: ld.lld -z notext %t.o %t2.so -o %t -shared
# RUN: llvm-readobj -dynamic-table -r %t | FileCheck %s
# RUN: ld.lld -z notext %t.o %t2.so -o %t2 -pie
@@ -9,6 +10,10 @@
# RUN: ld.lld -z notext %t.o %t2.so -o %t3
# RUN: llvm-readobj -dynamic-table -r %t3 | FileCheck --check-prefix=STATIC %s
+# RUN: not ld.lld %t.o %t2.so -o %t -shared 2>&1 | FileCheck --check-prefix=ERR %s
+# RUN: not ld.lld -z text %t.o %t2.so -o %t -shared 2>&1 | FileCheck --check-prefix=ERR %s
+# ERR: error: can't create dynamic relocation
+
# If the preference is to have text relocations, don't create plt of copy relocations.
# CHECK: Relocations [
diff --git a/test/MinGW/driver.test b/test/MinGW/driver.test
index 1a95d23..e7c608a 100644
--- a/test/MinGW/driver.test
+++ b/test/MinGW/driver.test
@@ -90,6 +90,10 @@
RUN: ld.lld -### -m i386pep foo.o --strip-all | FileCheck -check-prefix STRIP %s
STRIP-NOT: -debug:dwarf
+RUN: ld.lld -### -m i386pep foo.o -pdb out.pdb | FileCheck -check-prefix PDB %s
+PDB: -debug -pdb:out.pdb
+PDB-NOT: -debug:dwarf
+
RUN: ld.lld -### -m i386pep foo.o --large-address-aware | FileCheck -check-prefix LARGE-ADDRESS-AWARE %s
LARGE-ADDRESS-AWARE: -largeaddressaware
@@ -130,3 +134,9 @@
RUN: ld.lld -### foo.o -m i386pe -shared --kill-at | FileCheck -check-prefix=KILL-AT %s
RUN: ld.lld -### foo.o -m i386pe -shared -kill-at | FileCheck -check-prefix=KILL-AT %s
KILL-AT: -kill-at
+
+RUN: ld.lld -### foo.o -m i386pep -Map bar.map | FileCheck -check-prefix=MAP %s
+RUN: ld.lld -### foo.o -m i386pep --Map bar.map | FileCheck -check-prefix=MAP %s
+RUN: ld.lld -### foo.o -m i386pep -Map=bar.map | FileCheck -check-prefix=MAP %s
+RUN: ld.lld -### foo.o -m i386pep --Map=bar.map | FileCheck -check-prefix=MAP %s
+MAP: -lldmap:bar.map
diff --git a/test/lit.cfg.py b/test/lit.cfg.py
index 8fd1a60..41b57e5 100644
--- a/test/lit.cfg.py
+++ b/test/lit.cfg.py
@@ -40,7 +40,8 @@
tool_patterns = [
'llc', 'llvm-as', 'llvm-mc', 'llvm-nm', 'llvm-objdump', 'llvm-pdbutil',
- 'llvm-readelf', 'llvm-readobj', 'obj2yaml', 'yaml2obj']
+ 'llvm-dwarfdump', 'llvm-readelf', 'llvm-readobj', 'obj2yaml', 'yaml2obj',
+ 'opt', 'llvm-dis']
llvm_config.add_tool_substitutions(tool_patterns)
diff --git a/test/wasm/Inputs/archive1.ll b/test/wasm/Inputs/archive1.ll
index d0722e6..7f61479 100644
--- a/test/wasm/Inputs/archive1.ll
+++ b/test/wasm/Inputs/archive1.ll
@@ -1,4 +1,4 @@
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
declare i32 @bar() local_unnamed_addr #1
diff --git a/test/wasm/Inputs/archive2.ll b/test/wasm/Inputs/archive2.ll
index f0e00ba..c4903cb 100644
--- a/test/wasm/Inputs/archive2.ll
+++ b/test/wasm/Inputs/archive2.ll
@@ -1,4 +1,4 @@
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
declare i32 @foo() local_unnamed_addr #1
diff --git a/test/wasm/Inputs/call-indirect.ll b/test/wasm/Inputs/call-indirect.ll
index eaa7bb9..6afcf30 100644
--- a/test/wasm/Inputs/call-indirect.ll
+++ b/test/wasm/Inputs/call-indirect.ll
@@ -1,4 +1,4 @@
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
@indirect_bar = internal local_unnamed_addr global i64 ()* @bar, align 4
@indirect_foo = internal local_unnamed_addr global i32 ()* @foo, align 4
diff --git a/test/wasm/Inputs/comdat1.ll b/test/wasm/Inputs/comdat1.ll
index ff4f3c0..12678b0 100644
--- a/test/wasm/Inputs/comdat1.ll
+++ b/test/wasm/Inputs/comdat1.ll
@@ -1,4 +1,4 @@
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
$inlineFn = comdat any
@constantData = weak_odr constant [3 x i8] c"abc", comdat($inlineFn)
diff --git a/test/wasm/Inputs/comdat2.ll b/test/wasm/Inputs/comdat2.ll
index 6b7ca4a..d910e1a 100644
--- a/test/wasm/Inputs/comdat2.ll
+++ b/test/wasm/Inputs/comdat2.ll
@@ -1,4 +1,4 @@
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
$inlineFn = comdat any
@constantData = weak_odr constant [3 x i8] c"abc", comdat($inlineFn)
@@ -9,5 +9,5 @@
define i32 @callInline2() {
entry:
- ret i32 ptrtoint (i32 ()* @inlineFn to i32)
+ ret i32 ptrtoint (i32 ()* @inlineFn to i32)
}
diff --git a/test/wasm/Inputs/custom.ll b/test/wasm/Inputs/custom.ll
new file mode 100644
index 0000000..30b4ef0
--- /dev/null
+++ b/test/wasm/Inputs/custom.ll
@@ -0,0 +1,6 @@
+target triple = "wasm32-unknown-unknown"
+
+!0 = !{ !"red", !"foo" }
+!1 = !{ !"green", !"bar" }
+!2 = !{ !"green", !"qux" }
+!wasm.custom_sections = !{ !0, !1, !2 }
diff --git a/test/wasm/Inputs/debuginfo1.ll b/test/wasm/Inputs/debuginfo1.ll
new file mode 100644
index 0000000..7f37fd4
--- /dev/null
+++ b/test/wasm/Inputs/debuginfo1.ll
@@ -0,0 +1,68 @@
+; ModuleID = 'hi.c'
+source_filename = "hi.c"
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+; // hi.c:
+; extern void foo(int);
+;
+; int test(int t) {
+; return t * t;
+; }
+;
+; int _start() {
+; foo(test(10));
+; return 0;
+; }
+
+; Function Attrs: nounwind readnone
+define hidden i32 @test(i32 %t) local_unnamed_addr #0 !dbg !7 {
+entry:
+ call void @llvm.dbg.value(metadata i32 %t, metadata !12, metadata !DIExpression()), !dbg !13
+ %mul = mul nsw i32 %t, %t, !dbg !14
+ ret i32 %mul, !dbg !15
+}
+
+; Function Attrs: nounwind
+define hidden i32 @_start() local_unnamed_addr #1 !dbg !16 {
+entry:
+ tail call void @foo(i32 100) #4, !dbg !19
+ ret i32 0, !dbg !20
+}
+
+declare void @foo(i32) local_unnamed_addr #2
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
+
+attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #3 = { nounwind readnone speculatable }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 7.0.0 (trunk 331321)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "hi.c", directory: "/Users/yury/llvmwasm")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!"clang version 7.0.0 (trunk 331321)"}
+!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 3, type: !8, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !11)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10, !10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !{!12}
+!12 = !DILocalVariable(name: "t", arg: 1, scope: !7, file: !1, line: 3, type: !10)
+!13 = !DILocation(line: 3, column: 14, scope: !7)
+!14 = !DILocation(line: 4, column: 12, scope: !7)
+!15 = !DILocation(line: 4, column: 3, scope: !7)
+!16 = distinct !DISubprogram(name: "_start", scope: !1, file: !1, line: 7, type: !17, isLocal: false, isDefinition: true, scopeLine: 7, isOptimized: true, unit: !0, retainedNodes: !2)
+!17 = !DISubroutineType(types: !18)
+!18 = !{!10}
+!19 = !DILocation(line: 8, column: 3, scope: !16)
+!20 = !DILocation(line: 9, column: 3, scope: !16)
diff --git a/test/wasm/Inputs/debuginfo2.ll b/test/wasm/Inputs/debuginfo2.ll
new file mode 100644
index 0000000..72f94e0
--- /dev/null
+++ b/test/wasm/Inputs/debuginfo2.ll
@@ -0,0 +1,70 @@
+; ModuleID = 'hi_foo.c'
+source_filename = "hi_foo.c"
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+; // hi_foo.c:
+; int y[2] = {23, 41};
+;
+; void foo(int p) {
+; y[p & 1]++;
+; }
+;
+; // Will be GCed, but remain visible in debug info
+; int z[2] = {1, 2};
+
+@y = hidden local_unnamed_addr global [2 x i32] [i32 23, i32 41], align 4, !dbg !0
+@z = hidden local_unnamed_addr global [2 x i32] [i32 1, i32 2], align 4, !dbg !6
+
+; Function Attrs: nounwind
+define hidden void @foo(i32 %p) local_unnamed_addr #0 !dbg !16 {
+entry:
+ call void @llvm.dbg.value(metadata i32 %p, metadata !20, metadata !DIExpression()), !dbg !21
+ %and = and i32 %p, 1, !dbg !22
+ %arrayidx = getelementptr inbounds [2 x i32], [2 x i32]* @y, i32 0, i32 %and, !dbg !23
+ %0 = load i32, i32* %arrayidx, align 4, !dbg !24, !tbaa !25
+ %inc = add nsw i32 %0, 1, !dbg !24
+ store i32 %inc, i32* %arrayidx, align 4, !dbg !24, !tbaa !25
+ ret void, !dbg !29
+}
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.value(metadata, metadata, metadata) #1
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone speculatable }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!12, !13, !14}
+!llvm.ident = !{!15}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "y", scope: !2, file: !3, line: 1, type: !8, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 7.0.0 (trunk 332913) (llvm/trunk 332919)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5)
+!3 = !DIFile(filename: "hi_foo.c", directory: "/usr/local/google/home/sbc/dev/wasm/llvm-build")
+!4 = !{}
+!5 = !{!0, !6}
+!6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression())
+!7 = distinct !DIGlobalVariable(name: "z", scope: !2, file: !3, line: 8, type: !8, isLocal: false, isDefinition: true)
+!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 64, elements: !10)
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!10 = !{!11}
+!11 = !DISubrange(count: 2)
+!12 = !{i32 2, !"Dwarf Version", i32 4}
+!13 = !{i32 2, !"Debug Info Version", i32 3}
+!14 = !{i32 1, !"wchar_size", i32 4}
+!15 = !{!"clang version 7.0.0 (trunk 332913) (llvm/trunk 332919)"}
+!16 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, line: 3, type: !17, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !2, retainedNodes: !19)
+!17 = !DISubroutineType(types: !18)
+!18 = !{null, !9}
+!19 = !{!20}
+!20 = !DILocalVariable(name: "p", arg: 1, scope: !16, file: !3, line: 3, type: !9)
+!21 = !DILocation(line: 3, column: 14, scope: !16)
+!22 = !DILocation(line: 4, column: 7, scope: !16)
+!23 = !DILocation(line: 4, column: 3, scope: !16)
+!24 = !DILocation(line: 4, column: 11, scope: !16)
+!25 = !{!26, !26, i64 0}
+!26 = !{!"int", !27, i64 0}
+!27 = !{!"omnipotent char", !28, i64 0}
+!28 = !{!"Simple C/C++ TBAA"}
+!29 = !DILocation(line: 5, column: 1, scope: !16)
diff --git a/test/wasm/Inputs/global-ctor-dtor.ll b/test/wasm/Inputs/global-ctor-dtor.ll
index f934b83..5e73f06 100644
--- a/test/wasm/Inputs/global-ctor-dtor.ll
+++ b/test/wasm/Inputs/global-ctor-dtor.ll
@@ -1,4 +1,4 @@
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
define hidden void @myctor() {
entry:
diff --git a/test/wasm/Inputs/globals.yaml b/test/wasm/Inputs/globals.yaml
new file mode 100644
index 0000000..c08a304
--- /dev/null
+++ b/test/wasm/Inputs/globals.yaml
@@ -0,0 +1,54 @@
+--- !WASM
+FileHeader:
+ Version: 0x00000001
+Sections:
+ - Type: TYPE
+ Signatures:
+ - Index: 0
+ ReturnType: I64
+ ParamTypes:
+ - Type: FUNCTION
+ FunctionTypes: [ 0 ]
+ - Type: GLOBAL
+ Globals:
+ - Index: 0
+ Type: I64
+ Mutable: true
+ InitExpr:
+ Opcode: I64_CONST
+ Value: 123
+ - Index: 1
+ Type: I64
+ Mutable: true
+ InitExpr:
+ Opcode: I64_CONST
+ Value: 456
+ - Type: CODE
+ Functions:
+ - Index: 0
+ Locals:
+ Body: 2381808080000B
+ Relocations:
+ - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB
+ Index: 1
+ Offset: 0x00000004
+ - Type: CUSTOM
+ Name: linking
+ Version: 1
+ SymbolTable:
+ - Index: 0
+ Kind: GLOBAL
+ Name: unused_global
+ Flags: [ VISIBILITY_HIDDEN ]
+ Global: 0
+ - Index: 1
+ Kind: GLOBAL
+ Name: used_global
+ Flags: [ VISIBILITY_HIDDEN ]
+ Global: 1
+ - Index: 2
+ Kind: FUNCTION
+ Name: use_global
+ Flags: [ VISIBILITY_HIDDEN ]
+ Function: 0
+...
diff --git a/test/wasm/Inputs/hello.ll b/test/wasm/Inputs/hello.ll
index a00c4d8..6755668 100644
--- a/test/wasm/Inputs/hello.ll
+++ b/test/wasm/Inputs/hello.ll
@@ -1,4 +1,4 @@
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
; Wasm module generated from the following C code:
; void puts(const char*);
diff --git a/test/wasm/Inputs/hidden.ll b/test/wasm/Inputs/hidden.ll
index e3471ac..4af16b3 100644
--- a/test/wasm/Inputs/hidden.ll
+++ b/test/wasm/Inputs/hidden.ll
@@ -1,4 +1,4 @@
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
; Function Attrs: norecurse nounwind readnone
define hidden i32 @archiveHidden() #0 {
diff --git a/test/wasm/Inputs/locals-duplicate1.ll b/test/wasm/Inputs/locals-duplicate1.ll
index 9d4092b..f118dd4 100644
--- a/test/wasm/Inputs/locals-duplicate1.ll
+++ b/test/wasm/Inputs/locals-duplicate1.ll
@@ -1,4 +1,4 @@
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
; Will collide: local (internal linkage) with global (external) linkage
@colliding_global1 = internal default global i32 0, align 4
diff --git a/test/wasm/Inputs/locals-duplicate2.ll b/test/wasm/Inputs/locals-duplicate2.ll
index bc1e2c6..617abfe 100644
--- a/test/wasm/Inputs/locals-duplicate2.ll
+++ b/test/wasm/Inputs/locals-duplicate2.ll
@@ -1,4 +1,4 @@
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
; Will collide: local (internal linkage) with global (external) linkage
@colliding_global1 = default global i32 0, align 4
diff --git a/test/wasm/Inputs/many-funcs.ll b/test/wasm/Inputs/many-funcs.ll
index a54cbb8..1829d7d 100644
--- a/test/wasm/Inputs/many-funcs.ll
+++ b/test/wasm/Inputs/many-funcs.ll
@@ -1,4 +1,4 @@
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
@g0 = global i32 1, align 4
@foo = global i32 1, align 4
diff --git a/test/wasm/Inputs/ret32.ll b/test/wasm/Inputs/ret32.ll
index f5a70be..b1ccd64 100644
--- a/test/wasm/Inputs/ret32.ll
+++ b/test/wasm/Inputs/ret32.ll
@@ -1,4 +1,4 @@
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
; Function Attrs: norecurse nounwind readnone
define i32 @ret32(float %arg) #0 {
diff --git a/test/wasm/Inputs/ret64.ll b/test/wasm/Inputs/ret64.ll
index d39026e..034260d 100644
--- a/test/wasm/Inputs/ret64.ll
+++ b/test/wasm/Inputs/ret64.ll
@@ -1,4 +1,4 @@
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
define i64 @ret64(double %arg) local_unnamed_addr #0 {
entry:
diff --git a/test/wasm/Inputs/start.ll b/test/wasm/Inputs/start.ll
index 66f4b17..e262965 100644
--- a/test/wasm/Inputs/start.ll
+++ b/test/wasm/Inputs/start.ll
@@ -1,4 +1,4 @@
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
define void @_start() local_unnamed_addr {
entry:
diff --git a/test/wasm/Inputs/strong-symbol.ll b/test/wasm/Inputs/strong-symbol.ll
index 59bce52..cc2aa8a 100644
--- a/test/wasm/Inputs/strong-symbol.ll
+++ b/test/wasm/Inputs/strong-symbol.ll
@@ -1,4 +1,4 @@
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
define i64 @weakFn() #0 {
entry:
diff --git a/test/wasm/Inputs/undefined-globals.yaml b/test/wasm/Inputs/undefined-globals.yaml
new file mode 100644
index 0000000..440a538
--- /dev/null
+++ b/test/wasm/Inputs/undefined-globals.yaml
@@ -0,0 +1,52 @@
+--- !WASM
+FileHeader:
+ Version: 0x00000001
+Sections:
+ - Type: TYPE
+ Signatures:
+ - Index: 0
+ ReturnType: I64
+ ParamTypes:
+ - Type: IMPORT
+ Imports:
+ - Module: env
+ Field: unused_undef_global
+ Kind: GLOBAL
+ GlobalType: I64
+ GlobalMutable: true
+ - Module: env
+ Field: used_undef_global
+ Kind: GLOBAL
+ GlobalType: I64
+ GlobalMutable: true
+ - Type: FUNCTION
+ FunctionTypes: [ 0 ]
+ - Type: CODE
+ Functions:
+ - Index: 0
+ Locals:
+ Body: 2381808080000B
+ Relocations:
+ - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB
+ Index: 1
+ Offset: 0x00000004
+ - Type: CUSTOM
+ Name: linking
+ Version: 1
+ SymbolTable:
+ - Index: 0
+ Kind: GLOBAL
+ Name: unused_undef_global
+ Flags: [ VISIBILITY_HIDDEN, UNDEFINED ]
+ Global: 0
+ - Index: 1
+ Kind: GLOBAL
+ Name: used_undef_global
+ Flags: [ VISIBILITY_HIDDEN, UNDEFINED ]
+ Global: 1
+ - Index: 2
+ Kind: FUNCTION
+ Name: use_undef_global
+ Flags: [ VISIBILITY_HIDDEN ]
+ Function: 0
+...
diff --git a/test/wasm/Inputs/weak-alias.ll b/test/wasm/Inputs/weak-alias.ll
index d4f1326..1840ffd 100644
--- a/test/wasm/Inputs/weak-alias.ll
+++ b/test/wasm/Inputs/weak-alias.ll
@@ -1,4 +1,4 @@
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
; Function Attrs: norecurse nounwind readnone
define i32 @direct_fn() #0 {
diff --git a/test/wasm/Inputs/weak-symbol1.ll b/test/wasm/Inputs/weak-symbol1.ll
index 0541f38..6e394ff 100644
--- a/test/wasm/Inputs/weak-symbol1.ll
+++ b/test/wasm/Inputs/weak-symbol1.ll
@@ -1,4 +1,4 @@
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
define weak i32 @weakFn() #0 {
entry:
diff --git a/test/wasm/Inputs/weak-symbol2.ll b/test/wasm/Inputs/weak-symbol2.ll
index 3b989c1..e9c30c1 100644
--- a/test/wasm/Inputs/weak-symbol2.ll
+++ b/test/wasm/Inputs/weak-symbol2.ll
@@ -1,4 +1,4 @@
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
define weak i32 @weakFn() #0 {
entry:
diff --git a/test/wasm/alias.ll b/test/wasm/alias.ll
index c12ef2d..f88452e 100644
--- a/test/wasm/alias.ll
+++ b/test/wasm/alias.ll
@@ -1,8 +1,8 @@
; RUN: llc -filetype=obj -o %t.o %s
-; RUN: wasm-ld --check-signatures %t.o -o %t.wasm
+; RUN: wasm-ld %t.o -o %t.wasm
; RUN: obj2yaml %t.wasm | FileCheck %s
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
@start_alias = alias void (), void ()* @_start
diff --git a/test/wasm/archive.ll b/test/wasm/archive.ll
index 78daff0..b2499ea 100644
--- a/test/wasm/archive.ll
+++ b/test/wasm/archive.ll
@@ -4,16 +4,16 @@
; RUN: llc -filetype=obj %S/Inputs/hello.ll -o %t.a3.o
; RUN: llvm-ar rcs %t.a %t.a1.o %t.a2.o %t.a3.o
; RUN: rm -f %t.imports
-; RUN: not wasm-ld --check-signatures %t.a %t.o -o %t.wasm 2>&1 | FileCheck -check-prefix=CHECK-UNDEFINED %s
+; RUN: not wasm-ld %t.a %t.o -o %t.wasm 2>&1 | FileCheck -check-prefix=CHECK-UNDEFINED %s
; CHECK-UNDEFINED: undefined symbol: missing_func
; RUN: echo 'missing_func' > %t.imports
-; RUN: wasm-ld --check-signatures -r %t.a %t.o -o %t.wasm
+; RUN: wasm-ld -r %t.a %t.o -o %t.wasm
; RUN: llvm-nm -a %t.wasm | FileCheck %s
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
declare i32 @foo() local_unnamed_addr #1
declare i32 @missing_func() local_unnamed_addr #1
@@ -40,4 +40,4 @@
; CHECK-NOT: hello
; Specifying the same archive twice is allowed.
-; RUN: wasm-ld --check-signatures %t.a %t.a %t.o -o %t.wasm
+; RUN: wasm-ld %t.a %t.a %t.o -o %t.wasm
diff --git a/test/wasm/call-indirect.ll b/test/wasm/call-indirect.ll
index 9a6d64f..63a6def 100644
--- a/test/wasm/call-indirect.ll
+++ b/test/wasm/call-indirect.ll
@@ -1,6 +1,6 @@
; RUN: llc -filetype=obj %p/Inputs/call-indirect.ll -o %t2.o
; RUN: llc -filetype=obj %s -o %t.o
-; RUN: wasm-ld --check-signatures -o %t.wasm %t2.o %t.o
+; RUN: wasm-ld -o %t.wasm %t2.o %t.o
; RUN: obj2yaml %t.wasm | FileCheck %s
; bitcode generated from the following C code:
@@ -8,7 +8,7 @@
; int (*indirect_func)(void) = &foo;
; void _start(void) { indirect_func(); }
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
@indirect_func = local_unnamed_addr global i32 ()* @foo, align 4
diff --git a/test/wasm/comdats.ll b/test/wasm/comdats.ll
index d737132..d0bec4c 100644
--- a/test/wasm/comdats.ll
+++ b/test/wasm/comdats.ll
@@ -1,10 +1,10 @@
; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/comdat1.ll -o %t1.o
; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/comdat2.ll -o %t2.o
; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o
-; RUN: wasm-ld --check-signatures -o %t.wasm %t.o %t1.o %t2.o
+; RUN: wasm-ld -o %t.wasm %t.o %t1.o %t2.o
; RUN: obj2yaml %t.wasm | FileCheck %s
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
declare i32 @inlineFn()
diff --git a/test/wasm/compress-relocs.ll b/test/wasm/compress-relocs.ll
new file mode 100644
index 0000000..b137d5a
--- /dev/null
+++ b/test/wasm/compress-relocs.ll
@@ -0,0 +1,22 @@
+; RUN: llc -filetype=obj %p/Inputs/call-indirect.ll -o %t2.o
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: wasm-ld -o %t.wasm %t2.o %t.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+; RUN: wasm-ld -O2 -o %t-compressed.wasm %t2.o %t.o
+; RUN: obj2yaml %t-compressed.wasm | FileCheck %s -check-prefix=COMPRESS
+
+target triple = "wasm32-unknown-unknown-wasm"
+
+define i32 @foo() {
+entry:
+ ret i32 2
+}
+
+define void @_start() local_unnamed_addr {
+entry:
+ ret void
+}
+
+; CHECK: Body: 4100280284888080002100410028028088808000118080808000001A2000118180808000001A0B
+; COMPRESS: Body: 41002802840821004100280280081100001A20001101001A0B
diff --git a/test/wasm/conflict.test b/test/wasm/conflict.test
index c869802..9adc92e 100644
--- a/test/wasm/conflict.test
+++ b/test/wasm/conflict.test
@@ -1,5 +1,5 @@
# RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
-# RUN: not wasm-ld --check-signatures -o %t.wasm %t.ret32.o %t.ret32.o 2>&1 | FileCheck %s
+# RUN: not wasm-ld -o %t.wasm %t.ret32.o %t.ret32.o 2>&1 | FileCheck %s
# CHECK: duplicate symbol: ret32
# CHECK-NEXT: >>> defined in {{.*}}conflict.test.tmp.ret32.o
diff --git a/test/wasm/custom-sections.ll b/test/wasm/custom-sections.ll
new file mode 100644
index 0000000..c33ca27
--- /dev/null
+++ b/test/wasm/custom-sections.ll
@@ -0,0 +1,22 @@
+; RUN: llc -filetype=obj %s -o %t1.o
+; RUN: llc -filetype=obj %S/Inputs/custom.ll -o %t2.o
+; RUN: wasm-ld --relocatable -o %t.wasm %t1.o %t2.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+target triple = "wasm32-unknown-unknown"
+
+define i32 @_start() local_unnamed_addr {
+entry:
+ %retval = alloca i32, align 4
+ ret i32 0
+}
+
+!0 = !{ !"red", !"extra" }
+!wasm.custom_sections = !{ !0 }
+
+; CHECK: - Type: CUSTOM
+; CHECK-NEXT: Name: green
+; CHECK-NEXT: Payload: '626172717578'
+; CHECK-NEXT: - Type: CUSTOM
+; CHECK-NEXT: Name: red
+; CHECK-NEXT: Payload: 6578747261666F6F
diff --git a/test/wasm/cxx-mangling.ll b/test/wasm/cxx-mangling.ll
index 8b73ca9..67f3594 100644
--- a/test/wasm/cxx-mangling.ll
+++ b/test/wasm/cxx-mangling.ll
@@ -1,10 +1,10 @@
; RUN: llc -filetype=obj %s -o %t.o
-; RUN: wasm-ld --demangle --check-signatures -o %t_demangle.wasm %t.o
+; RUN: wasm-ld --demangle -o %t_demangle.wasm %t.o
; RUN: obj2yaml %t_demangle.wasm | FileCheck %s
-; RUN: wasm-ld --no-demangle --check-signatures -o %t_nodemangle.wasm %t.o
+; RUN: wasm-ld --no-demangle -o %t_nodemangle.wasm %t.o
; RUN: obj2yaml %t_nodemangle.wasm | FileCheck %s
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
; Check that the EXPORT name is still mangled, but that the "name" custom
; section contains the unmangled name.
diff --git a/test/wasm/data-layout.ll b/test/wasm/data-layout.ll
index ece5f20..5fd3f2d 100644
--- a/test/wasm/data-layout.ll
+++ b/test/wasm/data-layout.ll
@@ -1,7 +1,7 @@
; RUN: llc -filetype=obj %p/Inputs/hello.ll -o %t.hello.o
; RUN: llc -filetype=obj %s -o %t.o
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
@foo = hidden global i32 1, align 4
@aligned_bar = hidden global i32 3, align 16
@@ -13,7 +13,7 @@
@local_struct = hidden global %struct.s zeroinitializer, align 4
@local_struct_internal_ptr = hidden local_unnamed_addr global i32* getelementptr inbounds (%struct.s, %struct.s* @local_struct, i32 0, i32 1), align 4
-; RUN: wasm-ld -no-gc-sections --check-signatures --allow-undefined -o %t.wasm %t.o %t.hello.o
+; RUN: wasm-ld -no-gc-sections --allow-undefined --no-entry -o %t.wasm %t.o %t.hello.o
; RUN: obj2yaml %t.wasm | FileCheck %s
; CHECK: - Type: MEMORY
@@ -57,7 +57,7 @@
; CHECK-NEXT: - Type: CUSTOM
-; RUN: wasm-ld -no-gc-sections --check-signatures --allow-undefined \
+; RUN: wasm-ld -no-gc-sections --allow-undefined --no-entry \
; RUN: --initial-memory=131072 --max-memory=131072 -o %t_max.wasm %t.o \
; RUN: %t.hello.o
; RUN: obj2yaml %t_max.wasm | FileCheck %s -check-prefix=CHECK-MAX
@@ -69,7 +69,7 @@
; CHECK-MAX-NEXT: Maximum: 0x00000002
-; RUN: wasm-ld --check-signatures --relocatable -o %t_reloc.wasm %t.o %t.hello.o
+; RUN: wasm-ld --relocatable -o %t_reloc.wasm %t.o %t.hello.o
; RUN: obj2yaml %t_reloc.wasm | FileCheck %s -check-prefix=RELOC
; RELOC: - Type: DATA
@@ -119,9 +119,7 @@
; RELOC-NEXT: Value: 40
; RELOC-NEXT: Content: 68656C6C6F0A00
-; RELOC: - Type: CUSTOM
-; RELOC-NEXT: Name: linking
-; RELOC-NEXT: SymbolTable:
+; RELOC: SymbolTable:
; RELOC-NEXT: - Index: 0
; RELOC-NEXT: Kind: DATA
; RELOC-NEXT: Name: foo
diff --git a/test/wasm/data-segment-merging.ll b/test/wasm/data-segment-merging.ll
new file mode 100644
index 0000000..d0df84d
--- /dev/null
+++ b/test/wasm/data-segment-merging.ll
@@ -0,0 +1,48 @@
+target triple = "wasm32-unknown-unknown"
+
+@a = hidden global [6 x i8] c"hello\00", align 1
+@b = hidden global [8 x i8] c"goodbye\00", align 1
+@c = hidden global [9 x i8] c"whatever\00", align 1
+@d = hidden global i32 42, align 4
+
+; RUN: llc -filetype=obj %s -o %t.data-segment-merging.o
+
+; RUN: wasm-ld -no-gc-sections --no-entry -o %t.merged.wasm %t.data-segment-merging.o
+; RUN: obj2yaml %t.merged.wasm | FileCheck %s --check-prefix=MERGE
+; MERGE: - Type: DATA
+; MERGE-NEXT: Segments:
+; MERGE-NEXT: - SectionOffset: 7
+; MERGE-NEXT: MemoryIndex: 0
+; MERGE-NEXT: Offset:
+; MERGE-NEXT: Opcode: I32_CONST
+; MERGE-NEXT: Value: 1024
+; MERGE-NEXT: Content: 68656C6C6F00676F6F6462796500776861746576657200002A000000
+
+; RUN: wasm-ld -no-gc-sections --no-entry --no-merge-data-segments -o %t.separate.wasm %t.data-segment-merging.o
+; RUN: obj2yaml %t.separate.wasm | FileCheck %s --check-prefix=SEPARATE
+; SEPARATE: - Type: DATA
+; SEPARATE-NEXT: Segments:
+; SEPARATE-NEXT: - SectionOffset: 7
+; SEPARATE-NEXT: MemoryIndex: 0
+; SEPARATE-NEXT: Offset:
+; SEPARATE-NEXT: Opcode: I32_CONST
+; SEPARATE-NEXT: Value: 1024
+; SEPARATE-NEXT: Content: 68656C6C6F00
+; SEPARATE-NEXT: - SectionOffset: 19
+; SEPARATE-NEXT: MemoryIndex: 0
+; SEPARATE-NEXT: Offset:
+; SEPARATE-NEXT: Opcode: I32_CONST
+; SEPARATE-NEXT: Value: 1030
+; SEPARATE-NEXT: Content: 676F6F6462796500
+; SEPARATE-NEXT: - SectionOffset: 33
+; SEPARATE-NEXT: MemoryIndex: 0
+; SEPARATE-NEXT: Offset:
+; SEPARATE-NEXT: Opcode: I32_CONST
+; SEPARATE-NEXT: Value: 1038
+; SEPARATE-NEXT: Content: '776861746576657200'
+; SEPARATE-NEXT: - SectionOffset: 48
+; SEPARATE-NEXT: MemoryIndex: 0
+; SEPARATE-NEXT: Offset:
+; SEPARATE-NEXT: Opcode: I32_CONST
+; SEPARATE-NEXT: Value: 1048
+; SEPARATE-NEXT: Content: 2A000000
diff --git a/test/wasm/debuginfo.test b/test/wasm/debuginfo.test
new file mode 100644
index 0000000..ce68a03
--- /dev/null
+++ b/test/wasm/debuginfo.test
@@ -0,0 +1,85 @@
+RUN: llc -filetype=obj %p/Inputs/debuginfo1.ll -o %t.debuginfo1.o
+RUN: llc -filetype=obj %p/Inputs/debuginfo2.ll -o %t.debuginfo2.o
+RUN: wasm-ld -o %t.wasm %t.debuginfo1.o %t.debuginfo2.o
+RUN: llvm-dwarfdump %t.wasm | FileCheck %s
+
+CHECK: file format WASM
+
+CHECK: .debug_info contents:
+CHECK: DW_TAG_compile_unit
+CHECK-NEXT: DW_AT_producer ("clang version 7.0.0 (trunk {{.*}})")
+CHECK-NEXT: DW_AT_language (DW_LANG_C99)
+CHECK-NEXT: DW_AT_name ("hi.c")
+
+CHECK: DW_TAG_subprogram
+CHECK-NEXT: DW_AT_low_pc
+CHECK-NEXT: DW_AT_high_pc
+CHECK-NEXT: DW_AT_name ("test")
+CHECK-NEXT: DW_AT_decl_file ("/Users/yury/llvmwasm{{(/|\\)}}hi.c")
+CHECK-NEXT: DW_AT_decl_line (3)
+CHECK-NEXT: DW_AT_prototyped (true)
+
+CHECK: DW_TAG_formal_parameter
+CHECK-NEXT: DW_AT_name ("t")
+CHECK-NEXT: DW_AT_decl_file ("/Users/yury/llvmwasm{{(/|\\)}}hi.c")
+CHECK-NEXT: DW_AT_decl_line (3)
+
+CHECK: DW_TAG_subprogram
+CHECK-NEXT: DW_AT_low_pc
+CHECK-NEXT: DW_AT_high_pc
+CHECK-NEXT: DW_AT_name ("_start")
+CHECK-NEXT: DW_AT_decl_file ("/Users/yury/llvmwasm{{(/|\\)}}hi.c")
+CHECK-NEXT: DW_AT_decl_line (7)
+
+CHECK: DW_TAG_base_type
+CHECK-NEXT: DW_AT_name ("int")
+CHECK-NEXT: DW_AT_encoding (DW_ATE_signed)
+CHECK-NEXT: DW_AT_byte_size (0x04)
+
+CHECK: DW_TAG_compile_unit
+CHECK-NEXT: DW_AT_producer ("clang version 7.0.0 (trunk {{.*}})")
+CHECK-NEXT: DW_AT_language (DW_LANG_C99)
+CHECK-NEXT: DW_AT_name ("hi_foo.c")
+
+CHECK: DW_TAG_variable
+CHECK-NEXT: DW_AT_name ("y")
+CHECK-NEXT: DW_AT_type (0x00000097 "int[]")
+CHECK-NEXT: DW_AT_external (true)
+CHECK-NEXT: DW_AT_decl_file ("{{.*}}hi_foo.c")
+CHECK-NEXT: DW_AT_decl_line (1)
+CHECK: DW_AT_location (DW_OP_addr 0x400)
+
+CHECK: DW_TAG_array_type
+
+CHECK: DW_TAG_subrange_type
+
+CHECK: DW_TAG_base_type
+CHECK-NEXT: DW_AT_name ("int")
+CHECK-NEXT: DW_AT_encoding (DW_ATE_signed)
+CHECK-NEXT: DW_AT_byte_size (0x04)
+
+CHECK: DW_TAG_base_type
+CHECK-NEXT: DW_AT_name ("__ARRAY_SIZE_TYPE__")
+CHECK-NEXT: DW_AT_byte_size (0x08)
+CHECK-NEXT: DW_AT_encoding (DW_ATE_unsigned)
+
+CHECK: DW_TAG_variable
+CHECK-NEXT: DW_AT_name ("z")
+CHECK-NEXT: DW_AT_type (0x00000097 "int[]")
+CHECK-NEXT: DW_AT_external (true)
+CHECK-NEXT: DW_AT_decl_file ("{{.*}}hi_foo.c")
+CHECK-NEXT: DW_AT_decl_line (8)
+CHECK-NEXT: DW_AT_location (DW_OP_addr 0x0)
+
+CHECK: DW_TAG_subprogram
+CHECK-NEXT: DW_AT_low_pc
+CHECK-NEXT: DW_AT_high_pc
+CHECK-NEXT: DW_AT_name ("foo")
+CHECK-NEXT: DW_AT_decl_file ("{{.*}}hi_foo.c")
+CHECK-NEXT: DW_AT_decl_line (3)
+
+CHECK: DW_TAG_formal_parameter
+CHECK-NEXT: DW_AT_name ("p")
+CHECK-NEXT: DW_AT_decl_file ("{{.*}}hi_foo.c")
+CHECK-NEXT: DW_AT_decl_line (3)
+
diff --git a/test/wasm/demangle.ll b/test/wasm/demangle.ll
index 07f9927..f0416bb 100644
--- a/test/wasm/demangle.ll
+++ b/test/wasm/demangle.ll
@@ -1,15 +1,15 @@
; RUN: llc -filetype=obj %s -o %t.o
-; RUN: not wasm-ld --check-signatures --undefined _Z3fooi \
+; RUN: not wasm-ld --undefined _Z3fooi \
; RUN: -o %t.wasm %t.o 2>&1 | FileCheck %s
; CHECK: error: undefined symbol: foo(int)
-; RUN: not wasm-ld --check-signatures --no-demangle --undefined _Z3fooi \
+; RUN: not wasm-ld --no-demangle --undefined _Z3fooi \
; RUN: -o %t.wasm %t.o 2>&1 | FileCheck -check-prefix=CHECK-NODEMANGLE %s
; CHECK-NODEMANGLE: error: undefined symbol: _Z3fooi
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
define hidden void @_start() local_unnamed_addr {
entry:
diff --git a/test/wasm/driver.ll b/test/wasm/driver.ll
index 7222cb5..22e6bc1 100644
--- a/test/wasm/driver.ll
+++ b/test/wasm/driver.ll
@@ -1,6 +1,6 @@
; RUN: llc -filetype=obj %s -o %t.o
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
define hidden void @entry() local_unnamed_addr #0 {
entry:
diff --git a/test/wasm/entry-signature.ll b/test/wasm/entry-signature.ll
new file mode 100644
index 0000000..8e245b1
--- /dev/null
+++ b/test/wasm/entry-signature.ll
@@ -0,0 +1,10 @@
+; Verify that the entry point signauture can be flexible.
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: wasm-ld -o %t1.wasm %t.o
+
+target triple = "wasm32-unknown-unknown-wasm"
+
+define hidden i32 @_start(i32, i64) local_unnamed_addr #0 {
+entry:
+ ret i32 0
+}
diff --git a/test/wasm/entry.ll b/test/wasm/entry.ll
index 083bf97..30fff9a 100644
--- a/test/wasm/entry.ll
+++ b/test/wasm/entry.ll
@@ -1,15 +1,15 @@
; RUN: llc -filetype=obj %s -o %t.o
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
define hidden void @entry() local_unnamed_addr #0 {
entry:
ret void
}
-; RUN: wasm-ld --check-signatures -e entry -o %t1.wasm %t.o
+; RUN: wasm-ld -e entry -o %t1.wasm %t.o
; RUN: obj2yaml %t1.wasm | FileCheck %s
-; RUN: wasm-ld --check-signatures --entry=entry -o %t2.wasm %t.o
+; RUN: wasm-ld --entry=entry -o %t2.wasm %t.o
; RUN: obj2yaml %t2.wasm | FileCheck %s
; CHECK: - Type: EXPORT
@@ -28,9 +28,9 @@
; CHECK-NEXT: Index: 1
; CHECK-NEXT: - Type:
-; The __wasm_call_ctors is somewhat special. Make sure we can use it
-; as the entry point if we choose
-; RUN: wasm-ld --check-signatures --entry=__wasm_call_ctors -o %t3.wasm %t.o
+; The __wasm_call_ctors is somewhat special since its created by the linker.
+; Make sure we can use it as the entry point if we choose
+; RUN: wasm-ld --entry=__wasm_call_ctors -o %t3.wasm %t.o
; RUN: obj2yaml %t3.wasm | FileCheck %s -check-prefix=CHECK-CTOR
; CHECK-CTOR: - Type: EXPORT
diff --git a/test/wasm/export-table.test b/test/wasm/export-table.test
index 0923af6..58775b9 100644
--- a/test/wasm/export-table.test
+++ b/test/wasm/export-table.test
@@ -1,5 +1,5 @@
# RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.start.o
-# RUN: wasm-ld --check-signatures --export-table -o %t.wasm %t.start.o
+# RUN: wasm-ld --export-table -o %t.wasm %t.start.o
# RUN: obj2yaml %t.wasm | FileCheck %s
# Verify the --export-table flag creates a table export
diff --git a/test/wasm/export.ll b/test/wasm/export.ll
index f2a4fff..16b2b6c 100644
--- a/test/wasm/export.ll
+++ b/test/wasm/export.ll
@@ -1,9 +1,9 @@
; RUN: llc -filetype=obj %s -o %t.o
-; RUN: not wasm-ld --check-signatures --export=missing -o %t.wasm %t.o 2>&1 | FileCheck -check-prefix=CHECK-ERROR %s
-; RUN: wasm-ld --check-signatures --export=hidden_function -o %t.wasm %t.o
+; RUN: not wasm-ld --export=missing -o %t.wasm %t.o 2>&1 | FileCheck -check-prefix=CHECK-ERROR %s
+; RUN: wasm-ld --export=hidden_function -o %t.wasm %t.o
; RUN: obj2yaml %t.wasm | FileCheck %s
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
define hidden i32 @hidden_function() local_unnamed_addr {
entry:
diff --git a/test/wasm/fatal-warnings.ll b/test/wasm/fatal-warnings.ll
new file mode 100644
index 0000000..9bfe95e
--- /dev/null
+++ b/test/wasm/fatal-warnings.ll
@@ -0,0 +1,17 @@
+; RUN: llc -filetype=obj %s -o %t.main.o
+; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
+; RUN: lld -flavor wasm -o %t.wasm %t.main.o %t.ret32.o 2>&1 | FileCheck %s -check-prefix=CHECK-WARN
+; RUN: not lld -flavor wasm --fatal-warnings -o %t.wasm %t.main.o %t.ret32.o 2>&1 | FileCheck %s -check-prefix=CHECK-FATAL
+
+; CHECK-WARN: warning: Function type mismatch: ret32
+; CHECK-FATAL: error: Function type mismatch: ret32
+
+target triple = "wasm32-unknown-unknown"
+
+define hidden void @_start() local_unnamed_addr #0 {
+entry:
+ %call = tail call i32 @ret32(i32 1, i64 2, i32 3) #2
+ ret void
+}
+
+declare i32 @ret32(i32, i64, i32) local_unnamed_addr #1
diff --git a/test/wasm/function-imports-first.ll b/test/wasm/function-imports-first.ll
index be71d7c..00c7374 100644
--- a/test/wasm/function-imports-first.ll
+++ b/test/wasm/function-imports-first.ll
@@ -1,9 +1,9 @@
; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
; RUN: llc -filetype=obj %s -o %t.o
-; RUN: wasm-ld --check-signatures -o %t.wasm %t.o %t.ret32.o
+; RUN: wasm-ld -o %t.wasm %t.o %t.ret32.o
; RUN: obj2yaml %t.wasm | FileCheck %s
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
; Function Attrs: nounwind
define hidden void @_start() local_unnamed_addr #0 {
diff --git a/test/wasm/function-imports.ll b/test/wasm/function-imports.ll
index 742cec2..a2c6405 100644
--- a/test/wasm/function-imports.ll
+++ b/test/wasm/function-imports.ll
@@ -1,9 +1,9 @@
; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
; RUN: llc -filetype=obj %s -o %t.o
-; RUN: wasm-ld --check-signatures -o %t.wasm %t.ret32.o %t.o
+; RUN: wasm-ld -o %t.wasm %t.ret32.o %t.o
; RUN: obj2yaml %t.wasm | FileCheck %s
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
; Function Attrs: nounwind
define hidden void @_start() local_unnamed_addr #0 {
diff --git a/test/wasm/function-index.test b/test/wasm/function-index.test
index 8784271..82f5d0c 100644
--- a/test/wasm/function-index.test
+++ b/test/wasm/function-index.test
@@ -1,6 +1,6 @@
# RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
# RUN: llc -filetype=obj %p/Inputs/ret64.ll -o %t.ret64.o
-# RUN: wasm-ld --check-signatures -r -o %t.wasm %t.ret32.o %t.ret64.o
+# RUN: wasm-ld -r -o %t.wasm %t.ret32.o %t.ret64.o
# RUN: obj2yaml %t.wasm | FileCheck %s
CHECK: Sections:
diff --git a/test/wasm/gc-imports.ll b/test/wasm/gc-imports.ll
new file mode 100644
index 0000000..066cd88
--- /dev/null
+++ b/test/wasm/gc-imports.ll
@@ -0,0 +1,111 @@
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: yaml2obj %S/Inputs/undefined-globals.yaml -o %t_globals.o
+; RUN: wasm-ld -print-gc-sections --allow-undefined -o %t1.wasm %t.o %t_globals.o
+
+target triple = "wasm32-unknown-unknown"
+
+declare hidden i64 @unused_undef_function(i64 %arg)
+
+declare hidden i32 @used_undef_function()
+
+declare i64 @use_undef_global()
+
+define hidden void @_start() {
+entry:
+ call i32 @used_undef_function()
+ call i64 @use_undef_global()
+ ret void
+}
+
+; RUN: obj2yaml %t1.wasm | FileCheck %s
+
+; CHECK: - Type: TYPE
+; CHECK-NEXT: Signatures:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: ReturnType: I32
+; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: ReturnType: NORESULT
+; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: ReturnType: I64
+; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - Type: IMPORT
+; CHECK-NEXT: Imports:
+; CHECK-NEXT: - Module: env
+; CHECK-NEXT: Field: used_undef_function
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: SigIndex: 0
+; CHECK-NEXT: - Module: env
+; CHECK-NEXT: Field: used_undef_global
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: GlobalType: I64
+; CHECK-NEXT: GlobalMutable: true
+; CHECK-NEXT: - Type:
+; CHECK: - Type: CUSTOM
+; CHECK-NEXT: Name: name
+; CHECK-NEXT: FunctionNames:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Name: used_undef_function
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Name: __wasm_call_ctors
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Name: _start
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Name: use_undef_global
+; CHECK-NEXT: ...
+
+; RUN: wasm-ld -print-gc-sections --no-gc-sections --allow-undefined \
+; RUN: -o %t1.no-gc.wasm %t.o %t_globals.o
+; RUN: obj2yaml %t1.no-gc.wasm | FileCheck %s -check-prefix=NO-GC
+
+; NO-GC: - Type: TYPE
+; NO-GC-NEXT: Signatures:
+; NO-GC-NEXT: - Index: 0
+; NO-GC-NEXT: ReturnType: I32
+; NO-GC-NEXT: ParamTypes:
+; NO-GC-NEXT: - Index: 1
+; NO-GC-NEXT: ReturnType: I64
+; NO-GC-NEXT: ParamTypes:
+; NO-GC-NEXT: - I64
+; NO-GC-NEXT: - Index: 2
+; NO-GC-NEXT: ReturnType: NORESULT
+; NO-GC-NEXT: ParamTypes:
+; NO-GC-NEXT: - Index: 3
+; NO-GC-NEXT: ReturnType: I64
+; NO-GC-NEXT: ParamTypes:
+; NO-GC-NEXT: - Type: IMPORT
+; NO-GC-NEXT: Imports:
+; NO-GC-NEXT: - Module: env
+; NO-GC-NEXT: Field: used_undef_function
+; NO-GC-NEXT: Kind: FUNCTION
+; NO-GC-NEXT: SigIndex: 0
+; NO-GC-NEXT: - Module: env
+; NO-GC-NEXT: Field: unused_undef_function
+; NO-GC-NEXT: Kind: FUNCTION
+; NO-GC-NEXT: SigIndex: 1
+; NO-GC-NEXT: - Module: env
+; NO-GC-NEXT: Field: unused_undef_global
+; NO-GC-NEXT: Kind: GLOBAL
+; NO-GC-NEXT: GlobalType: I64
+; NO-GC-NEXT: GlobalMutable: true
+; NO-GC-NEXT: - Module: env
+; NO-GC-NEXT: Field: used_undef_global
+; NO-GC-NEXT: Kind: GLOBAL
+; NO-GC-NEXT: GlobalType: I64
+; NO-GC-NEXT: GlobalMutable: true
+; NO-GC-NEXT: - Type:
+; NO-GC: - Type: CUSTOM
+; NO-GC-NEXT: Name: name
+; NO-GC-NEXT: FunctionNames:
+; NO-GC-NEXT: - Index: 0
+; NO-GC-NEXT: Name: used_undef_function
+; NO-GC-NEXT: - Index: 1
+; NO-GC-NEXT: Name: unused_undef_function
+; NO-GC-NEXT: - Index: 2
+; NO-GC-NEXT: Name: __wasm_call_ctors
+; NO-GC-NEXT: - Index: 3
+; NO-GC-NEXT: Name: _start
+; NO-GC-NEXT: - Index: 4
+; NO-GC-NEXT: Name: use_undef_global
+; NO-GC-NEXT: ...
diff --git a/test/wasm/gc-sections.ll b/test/wasm/gc-sections.ll
index dec455e..57b6973 100644
--- a/test/wasm/gc-sections.ll
+++ b/test/wasm/gc-sections.ll
@@ -1,16 +1,20 @@
; RUN: llc -filetype=obj %s -o %t.o
-; RUN: wasm-ld -print-gc-sections -o %t1.wasm %t.o | FileCheck %s -check-prefix=PRINT-GC
+; RUN: yaml2obj %S/Inputs/globals.yaml -o %t_globals.o
+; RUN: wasm-ld -print-gc-sections -o %t1.wasm %t.o %t_globals.o | \
+; RUN: FileCheck %s -check-prefix=PRINT-GC
; PRINT-GC: removing unused section {{.*}}:(unused_function)
; PRINT-GC-NOT: removing unused section {{.*}}:(used_function)
; PRINT-GC: removing unused section {{.*}}:(.data.unused_data)
; PRINT-GC-NOT: removing unused section {{.*}}:(.data.used_data)
+; PRINT-GC: removing unused section {{.*}}:(unused_global)
+; PRINT-GC-NOT: removing unused section {{.*}}:(used_global)
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
@unused_data = hidden global i64 1, align 4
@used_data = hidden global i32 2, align 4
-define hidden i64 @unused_function() {
+define hidden i64 @unused_function(i64 %arg) {
%1 = load i64, i64* @unused_data, align 4
ret i64 %1
}
@@ -20,24 +24,45 @@
ret i32 %1
}
+declare i64 @use_global()
+
define hidden void @_start() {
entry:
call i32 @used_function()
+ call i64 @use_global()
ret void
}
; RUN: obj2yaml %t1.wasm | FileCheck %s
; CHECK: - Type: TYPE
-; CHECK-NEXT: Signatures:
+; CHECK-NEXT: Signatures:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: ReturnType: NORESULT
-; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: ReturnType: I32
-; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: ReturnType: I64
+; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Type: FUNCTION
+; CHECK: - Type: GLOBAL
+; CHECK-NEXT: Globals:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Type: I32
+; CHECK-NEXT: Mutable: true
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 66576
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Type: I64
+; CHECK-NEXT: Mutable: true
+; CHECK-NEXT: InitExpr:
+; CHECK-NEXT: Opcode: I64_CONST
+; CHECK-NEXT: Value: 456
+
; CHECK: - Type: DATA
; CHECK-NEXT: Segments:
; CHECK-NEXT: - SectionOffset: 7
@@ -55,24 +80,52 @@
; CHECK-NEXT: Name: used_function
; CHECK-NEXT: - Index: 2
; CHECK-NEXT: Name: _start
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Name: use_global
; CHECK-NEXT: ...
-; RUN: wasm-ld -print-gc-sections --no-gc-sections -o %t1.no-gc.wasm %t.o
+; RUN: wasm-ld -print-gc-sections --no-gc-sections -o %t1.no-gc.wasm \
+; RUN: %t.o %t_globals.o
; RUN: obj2yaml %t1.no-gc.wasm | FileCheck %s -check-prefix=NO-GC
; NO-GC: - Type: TYPE
-; NO-GC-NEXT: Signatures:
+; NO-GC-NEXT: Signatures:
; NO-GC-NEXT: - Index: 0
; NO-GC-NEXT: ReturnType: NORESULT
; NO-GC-NEXT: ParamTypes:
; NO-GC-NEXT: - Index: 1
; NO-GC-NEXT: ReturnType: I64
-; NO-GC-NEXT: ParamTypes:
+; NO-GC-NEXT: ParamTypes:
+; NO-GC-NEXT: - I64
; NO-GC-NEXT: - Index: 2
; NO-GC-NEXT: ReturnType: I32
-; NO-GC-NEXT: ParamTypes:
+; NO-GC-NEXT: ParamTypes:
+; NO-GC-NEXT: - Index: 3
+; NO-GC-NEXT: ReturnType: I64
+; NO-GC-NEXT: ParamTypes:
; NO-GC-NEXT: - Type: FUNCTION
+; NO-GC: - Type: GLOBAL
+; NO-GC-NEXT: Globals:
+; NO-GC-NEXT: - Index: 0
+; NO-GC-NEXT: Type: I32
+; NO-GC-NEXT: Mutable: true
+; NO-GC-NEXT: InitExpr:
+; NO-GC-NEXT: Opcode: I32_CONST
+; NO-GC-NEXT: Value: 66576
+; NO-GC-NEXT: - Index: 1
+; NO-GC-NEXT: Type: I64
+; NO-GC-NEXT: Mutable: true
+; NO-GC-NEXT: InitExpr:
+; NO-GC-NEXT: Opcode: I64_CONST
+; NO-GC-NEXT: Value: 123
+; NO-GC-NEXT: - Index: 2
+; NO-GC-NEXT: Type: I64
+; NO-GC-NEXT: Mutable: true
+; NO-GC-NEXT: InitExpr:
+; NO-GC-NEXT: Opcode: I64_CONST
+; NO-GC-NEXT: Value: 456
+
; NO-GC: - Type: DATA
; NO-GC-NEXT: Segments:
; NO-GC-NEXT: - SectionOffset: 7
@@ -92,6 +145,8 @@
; NO-GC-NEXT: Name: used_function
; NO-GC-NEXT: - Index: 3
; NO-GC-NEXT: Name: _start
+; NO-GC-NEXT: - Index: 4
+; NO-GC-NEXT: Name: use_global
; NO-GC-NEXT: ...
; RUN: not wasm-ld --gc-sections --relocatable -o %t1.no-gc.wasm %t.o 2>&1 | FileCheck %s -check-prefix=CHECK-ERROR
diff --git a/test/wasm/import-memory.test b/test/wasm/import-memory.test
index 955d2df..49bf06b 100644
--- a/test/wasm/import-memory.test
+++ b/test/wasm/import-memory.test
@@ -1,5 +1,5 @@
# RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.start.o
-# RUN: wasm-ld --check-signatures --import-memory -o %t.wasm %t.start.o
+# RUN: wasm-ld --import-memory -o %t.wasm %t.start.o
# RUN: obj2yaml %t.wasm | FileCheck %s
# Verify the --import-memory flag creates a memory import
@@ -15,7 +15,7 @@
-# RUN: wasm-ld --check-signatures --import-memory --initial-memory=262144 \
+# RUN: wasm-ld --import-memory --initial-memory=262144 \
# RUN: --max-memory=327680 -o %t.max.wasm %t.start.o
# RUN: obj2yaml %t.max.wasm | FileCheck -check-prefix=CHECK-MAX %s
diff --git a/test/wasm/import-table.test b/test/wasm/import-table.test
index 98e0749..eb76709 100644
--- a/test/wasm/import-table.test
+++ b/test/wasm/import-table.test
@@ -1,5 +1,5 @@
# RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.start.o
-# RUN: wasm-ld --check-signatures --import-table -o %t.wasm %t.start.o
+# RUN: wasm-ld --import-table -o %t.wasm %t.start.o
# RUN: obj2yaml %t.wasm | FileCheck %s
# Verify the --import-table flag creates a table import
diff --git a/test/wasm/init-fini.ll b/test/wasm/init-fini.ll
index 1ca2008..9a7f535 100644
--- a/test/wasm/init-fini.ll
+++ b/test/wasm/init-fini.ll
@@ -1,7 +1,7 @@
; RUN: llc -filetype=obj -o %t.o %s
; RUN: llc -filetype=obj %S/Inputs/global-ctor-dtor.ll -o %t.global-ctor-dtor.o
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
define hidden void @func1() {
entry:
@@ -49,7 +49,7 @@
{ i32, void ()*, i8* } { i32 4000, void ()* @externDtor, i8* null }
]
-; RUN: wasm-ld --check-signatures --allow-undefined %t.o %t.global-ctor-dtor.o -o %t.wasm
+; RUN: wasm-ld --allow-undefined %t.o %t.global-ctor-dtor.o -o %t.wasm
; RUN: obj2yaml %t.wasm | FileCheck %s
; CHECK: - Type: IMPORT
@@ -128,11 +128,10 @@
; CHECK-NEXT: ...
-; RUN: wasm-ld --check-signatures -r %t.o %t.global-ctor-dtor.o -o %t.reloc.wasm
+; RUN: wasm-ld -r %t.o %t.global-ctor-dtor.o -o %t.reloc.wasm
; RUN: obj2yaml %t.reloc.wasm | FileCheck -check-prefix=RELOC %s
-; RELOC: Name: linking
-; RELOC-NEXT: SymbolTable:
+; RELOC: SymbolTable:
; RELOC-NEXT: - Index: 0
; RELOC-NEXT: Kind: FUNCTION
; RELOC-NEXT: Name: func1
diff --git a/test/wasm/invalid-stack-size.test b/test/wasm/invalid-stack-size.test
index da47c68..90c9fda 100644
--- a/test/wasm/invalid-stack-size.test
+++ b/test/wasm/invalid-stack-size.test
@@ -1,4 +1,4 @@
; RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.o
-; RUN: not wasm-ld --check-signatures -o %t.wasm -z stack-size=1 %t.o 2>&1 | FileCheck %s
+; RUN: not wasm-ld -o %t.wasm -z stack-size=1 %t.o 2>&1 | FileCheck %s
; CHECK: error: stack size must be 16-byte aligned
diff --git a/test/wasm/load-undefined.test b/test/wasm/load-undefined.test
index 7e78bf0..52a4a04 100644
--- a/test/wasm/load-undefined.test
+++ b/test/wasm/load-undefined.test
@@ -5,7 +5,7 @@
; RUN: llc -filetype=obj %S/Inputs/ret32.ll -o %t2.o
; RUN: llc -filetype=obj %S/Inputs/start.ll -o %t.start.o
; RUN: llvm-ar rcs %t2.a %t2.o
-; RUN: wasm-ld --check-signatures %t.start.o %t2.a %t.o -o %t.wasm -u ret32 --undefined ret64
+; RUN: wasm-ld %t.start.o %t2.a %t.o -o %t.wasm -u ret32 --undefined ret64
; RUN: obj2yaml %t.wasm | FileCheck %s
; CHECK: - Type: EXPORT
@@ -32,8 +32,8 @@
; Verify that referencing a symbol that doesn't exist won't work
-; RUN: not wasm-ld --check-signatures %t.start.o -o %t.wasm -u symboldoesnotexist 2>&1 | FileCheck -check-prefix=CHECK-UNDEFINED1 %s
+; RUN: not wasm-ld %t.start.o -o %t.wasm -u symboldoesnotexist 2>&1 | FileCheck -check-prefix=CHECK-UNDEFINED1 %s
; CHECK-UNDEFINED1: error: undefined symbol: symboldoesnotexist
-; RUN: not wasm-ld --check-signatures %t.start.o -o %t.wasm --undefined symboldoesnotexist --allow-undefined 2>&1 | FileCheck -check-prefix=CHECK-UNDEFINED2 %s
-; CHECK-UNDEFINED2: function forced with --undefined not found: symboldoesnotexist
+; RUN: not wasm-ld %t.start.o -o %t.wasm --undefined symboldoesnotexist --allow-undefined 2>&1 | FileCheck -check-prefix=CHECK-UNDEFINED2 %s
+; CHECK-UNDEFINED2: symbol forced with --undefined not found: symboldoesnotexist
diff --git a/test/wasm/local-symbols.ll b/test/wasm/local-symbols.ll
index fcb3c42..5471466 100644
--- a/test/wasm/local-symbols.ll
+++ b/test/wasm/local-symbols.ll
@@ -1,8 +1,8 @@
; RUN: llc -filetype=obj %s -o %t.o
-; RUN: wasm-ld --check-signatures -o %t.wasm %t.o
+; RUN: wasm-ld -o %t.wasm %t.o
; RUN: obj2yaml %t.wasm | FileCheck %s
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
@foo = default global i32 1, align 4
@bar = internal default global i32 3, align 4
diff --git a/test/wasm/locals-duplicate.test b/test/wasm/locals-duplicate.test
index 017bc09..3c67cdd 100644
--- a/test/wasm/locals-duplicate.test
+++ b/test/wasm/locals-duplicate.test
@@ -1,6 +1,6 @@
; RUN: llc -filetype=obj %p/Inputs/locals-duplicate1.ll -o %t1.o
; RUN: llc -filetype=obj %p/Inputs/locals-duplicate2.ll -o %t2.o
-; RUN: wasm-ld --check-signatures --no-entry -o %t.wasm %t1.o %t2.o
+; RUN: wasm-ld --no-entry -o %t.wasm %t1.o %t2.o
; RUN: obj2yaml %t.wasm | FileCheck %s
; CHECK: --- !WASM
@@ -236,7 +236,7 @@
; CHECK-NEXT: ...
-; RUN: wasm-ld --check-signatures -r --no-entry -o %t.reloc.wasm %t1.o %t2.o
+; RUN: wasm-ld -r --no-entry -o %t.reloc.wasm %t1.o %t2.o
; RUN: obj2yaml %t.reloc.wasm | FileCheck -check-prefix=RELOC %s
; RELOC: --- !WASM
@@ -382,6 +382,7 @@
; RELOC-NEXT: Content: '0000000000000000'
; RELOC-NEXT: - Type: CUSTOM
; RELOC-NEXT: Name: linking
+; RELOC-NEXT: Version: 1
; RELOC-NEXT: SymbolTable:
; RELOC-NEXT: - Index: 0
; RELOC-NEXT: Kind: FUNCTION
diff --git a/test/wasm/lto/Inputs/cache.ll b/test/wasm/lto/Inputs/cache.ll
new file mode 100644
index 0000000..a66f36a
--- /dev/null
+++ b/test/wasm/lto/Inputs/cache.ll
@@ -0,0 +1,10 @@
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+define i32 @_start() {
+entry:
+ call void (...) @globalfunc()
+ ret i32 0
+}
+
+declare void @globalfunc(...)
diff --git a/test/wasm/lto/Inputs/save-temps.ll b/test/wasm/lto/Inputs/save-temps.ll
new file mode 100644
index 0000000..6f4de41
--- /dev/null
+++ b/test/wasm/lto/Inputs/save-temps.ll
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+define void @bar() {
+ ret void
+}
diff --git a/test/wasm/lto/Inputs/thinlto.ll b/test/wasm/lto/Inputs/thinlto.ll
new file mode 100644
index 0000000..39e573b
--- /dev/null
+++ b/test/wasm/lto/Inputs/thinlto.ll
@@ -0,0 +1,7 @@
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+define void @g() {
+entry:
+ ret void
+}
diff --git a/test/wasm/lto/cache.ll b/test/wasm/lto/cache.ll
new file mode 100644
index 0000000..b0a7820
--- /dev/null
+++ b/test/wasm/lto/cache.ll
@@ -0,0 +1,38 @@
+; RUN: opt -module-hash -module-summary %s -o %t.o
+; RUN: opt -module-hash -module-summary %p/Inputs/cache.ll -o %t2.o
+
+; RUN: rm -Rf %t.cache && mkdir %t.cache
+; Create two files that would be removed by cache pruning due to age.
+; We should only remove files matching the pattern "llvmcache-*".
+; RUN: touch -t 197001011200 %t.cache/llvmcache-foo %t.cache/foo
+; RUN: wasm-ld --thinlto-cache-dir=%t.cache --thinlto-cache-policy prune_after=1h:prune_interval=0s -o %t.wasm %t2.o %t.o
+
+; Two cached objects, plus a timestamp file and "foo", minus the file we removed.
+; RUN: ls %t.cache | count 4
+
+; Create a file of size 64KB.
+; RUN: "%python" -c "print(' ' * 65536)" > %t.cache/llvmcache-foo
+
+; This should leave the file in place.
+; RUN: wasm-ld --thinlto-cache-dir=%t.cache --thinlto-cache-policy cache_size_bytes=128k:prune_interval=0s -o %t.wasm %t2.o %t.o
+; RUN: ls %t.cache | count 5
+
+; This should remove it.
+; RUN: wasm-ld --thinlto-cache-dir=%t.cache --thinlto-cache-policy cache_size_bytes=32k:prune_interval=0s -o %t.wasm %t2.o %t.o
+; RUN: ls %t.cache | count 4
+
+; Setting max number of files to 0 should disable the limit, not delete everything.
+; RUN: wasm-ld --thinlto-cache-dir=%t.cache --thinlto-cache-policy prune_after=0s:cache_size=0%:cache_size_files=0:prune_interval=0s -o %t.wasm %t2.o %t.o
+; RUN: ls %t.cache | count 4
+
+; Delete everything except for the timestamp, "foo" and one cache file.
+; RUN: wasm-ld --thinlto-cache-dir=%t.cache --thinlto-cache-policy prune_after=0s:cache_size=0%:cache_size_files=1:prune_interval=0s -o %t.wasm %t2.o %t.o
+; RUN: ls %t.cache | count 3
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+define void @globalfunc() #0 {
+entry:
+ ret void
+}
diff --git a/test/wasm/lto/incompatible.ll b/test/wasm/lto/incompatible.ll
new file mode 100644
index 0000000..ee98cb4
--- /dev/null
+++ b/test/wasm/lto/incompatible.ll
@@ -0,0 +1,8 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.bc
+; RUN: not wasm-ld %t.bc -o out.wasm 2>&1 | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; CHECK: {{.*}}incompatible.ll.tmp.bc: machine type must be wasm32
diff --git a/test/wasm/lto/internalize-basic.ll b/test/wasm/lto/internalize-basic.ll
new file mode 100644
index 0000000..313a05e
--- /dev/null
+++ b/test/wasm/lto/internalize-basic.ll
@@ -0,0 +1,20 @@
+; RUN: llvm-as %s -o %t.o
+; RUN: wasm-ld %t.o -o %t2 -save-temps
+; RUN: llvm-dis < %t2.0.2.internalize.bc | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+define void @_start() {
+ ret void
+}
+
+define hidden void @foo() {
+ ret void
+}
+
+; Check that _start is not internalized.
+; CHECK: define void @_start()
+
+; Check that foo function is correctly internalized.
+; CHECK: define internal void @foo()
diff --git a/test/wasm/lto/lto-start.ll b/test/wasm/lto/lto-start.ll
new file mode 100644
index 0000000..6e8f99c
--- /dev/null
+++ b/test/wasm/lto/lto-start.ll
@@ -0,0 +1,18 @@
+; RUN: llvm-as %s -o %t.o
+; RUN: wasm-ld %t.o -o %t.wasm
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+; CHECK: - Type: CUSTOM
+; CHECK-NEXT: Name: name
+; CHECK-NEXT: FunctionNames:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Name: __wasm_call_ctors
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Name: _start
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+define void @_start() {
+ ret void
+}
diff --git a/test/wasm/lto/opt-level.ll b/test/wasm/lto/opt-level.ll
new file mode 100644
index 0000000..b7e6a4c
--- /dev/null
+++ b/test/wasm/lto/opt-level.ll
@@ -0,0 +1,30 @@
+; RUN: llvm-as -o %t.o %s
+; RUN: wasm-ld -o %t0 -e main --lto-O0 %t.o
+; RUN: obj2yaml %t0 | FileCheck --check-prefix=CHECK-O0 %s
+; RUN: wasm-ld -o %t2 -e main --lto-O2 %t.o
+; RUN: obj2yaml %t2 | FileCheck --check-prefix=CHECK-O2 %s
+; RUN: wasm-ld -o %t2a -e main %t.o
+; RUN: obj2yaml %t2a | FileCheck --check-prefix=CHECK-O2 %s
+
+; Reject invalid optimization levels.
+; RUN: not ld.lld -o %t3 -e main --lto-O6 %t.o 2>&1 | \
+; RUN: FileCheck --check-prefix=INVALID %s
+; INVALID: invalid optimization level for LTO: 6
+
+; RUN: not ld.lld -o %t3 -m elf_x86_64 -e main --lto-O-1 %t.o 2>&1 | \
+; RUN: FileCheck --check-prefix=INVALIDNEGATIVE %s
+; INVALIDNEGATIVE: invalid optimization level for LTO: 4294967295
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+; CHECK-O0: Name: foo
+; CHECK-O2-NOT: Name: foo
+define internal void @foo() {
+ ret void
+}
+
+define void @main() {
+ call void @foo()
+ ret void
+}
diff --git a/test/wasm/lto/parallel.ll b/test/wasm/lto/parallel.ll
new file mode 100644
index 0000000..a93c355
--- /dev/null
+++ b/test/wasm/lto/parallel.ll
@@ -0,0 +1,24 @@
+; RUN: llvm-as -o %t.bc %s
+; RUN: rm -f %t.lto.o %t1.lto.o
+; RUN: wasm-ld --lto-partitions=2 -save-temps -o %t %t.bc -r
+; RUN: llvm-nm %t.lto.o | FileCheck --check-prefix=CHECK0 %s
+; RUN: llvm-nm %t1.lto.o | FileCheck --check-prefix=CHECK1 %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+; CHECK0-NOT: bar
+; CHECK0: T foo
+; CHECK0-NOT: bar
+define void @foo() {
+ call void @bar()
+ ret void
+}
+
+; CHECK1-NOT: foo
+; CHECK1: T bar
+; CHECK1-NOT: foo
+define void @bar() {
+ call void @foo()
+ ret void
+}
diff --git a/test/wasm/lto/save-temps.ll b/test/wasm/lto/save-temps.ll
new file mode 100644
index 0000000..2734d86
--- /dev/null
+++ b/test/wasm/lto/save-temps.ll
@@ -0,0 +1,19 @@
+; RUN: cd %T
+; RUN: rm -f a.out a.out.lto.bc a.out.lto.o
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-as %p/Inputs/save-temps.ll -o %t2.o
+; RUN: wasm-ld -r -o a.out %t.o %t2.o -save-temps
+; RUN: llvm-nm a.out | FileCheck %s
+; RUN: llvm-nm a.out.0.0.preopt.bc | FileCheck %s
+; RUN: llvm-nm a.out.lto.o | FileCheck %s
+; RUN: llvm-dis a.out.0.0.preopt.bc
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+define void @foo() {
+ ret void
+}
+
+; CHECK: T bar
+; CHECK: T foo
diff --git a/test/wasm/lto/thinlto.ll b/test/wasm/lto/thinlto.ll
new file mode 100644
index 0000000..062da1a
--- /dev/null
+++ b/test/wasm/lto/thinlto.ll
@@ -0,0 +1,34 @@
+; Basic ThinLTO tests.
+; RUN: opt -module-summary %s -o %t1.o
+; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o
+
+; First force single-threaded mode
+; RUN: rm -f %t31.lto.o %t32.lto.o
+; RUN: wasm-ld -r -save-temps --thinlto-jobs=1 %t1.o %t2.o -o %t3
+; RUN: llvm-nm %t31.lto.o | FileCheck %s --check-prefix=NM1
+; RUN: llvm-nm %t32.lto.o | FileCheck %s --check-prefix=NM2
+
+; Next force multi-threaded mode
+; RUN: rm -f %t31.lto.o %t32.lto.o
+; RUN: wasm-ld -r -save-temps --thinlto-jobs=2 %t1.o %t2.o -o %t3
+; RUN: llvm-nm %t31.lto.o | FileCheck %s --check-prefix=NM1
+; RUN: llvm-nm %t32.lto.o | FileCheck %s --check-prefix=NM2
+
+; Check without --thinlto-jobs (which currently default to hardware_concurrency)
+; RUN: wasm-ld -r %t1.o %t2.o -o %t3
+; RUN: llvm-nm %t31.lto.o | FileCheck %s --check-prefix=NM1
+; RUN: llvm-nm %t32.lto.o | FileCheck %s --check-prefix=NM2
+
+; NM1: T f
+; NM2: T g
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+declare void @g(...)
+
+define void @f() {
+entry:
+ call void (...) @g()
+ ret void
+}
diff --git a/test/wasm/lto/verify-invalid.ll b/test/wasm/lto/verify-invalid.ll
new file mode 100644
index 0000000..c4a5bcd
--- /dev/null
+++ b/test/wasm/lto/verify-invalid.ll
@@ -0,0 +1,16 @@
+; RUN: llvm-as %s -o %t.o
+; RUN: wasm-ld %t.o -o %t2 -mllvm -debug-pass=Arguments \
+; RUN: 2>&1 | FileCheck -check-prefix=DEFAULT %s
+; RUN: wasm-ld %t.o -o %t2 -mllvm -debug-pass=Arguments \
+; RUN: -disable-verify 2>&1 | FileCheck -check-prefix=DISABLE %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+define void @_start() {
+ ret void
+}
+
+; -disable-verify should disable the verification of bitcode.
+; DEFAULT: Pass Arguments: {{.*}} -verify {{.*}} -verify
+; DISABLE-NOT: Pass Arguments: {{.*}} -verify {{.*}} -verify
diff --git a/test/wasm/lto/weak.ll b/test/wasm/lto/weak.ll
new file mode 100644
index 0000000..03a017c
--- /dev/null
+++ b/test/wasm/lto/weak.ll
@@ -0,0 +1,16 @@
+; RUN: llvm-as %s -o %t.o
+; RUN: wasm-ld %t.o %t.o -o %t.wasm -r
+; RUN: llvm-readobj -t %t.wasm | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+define weak void @f() {
+ ret void
+}
+
+; CHECK: Symbol {
+; CHECK-NEXT: Name: f
+; CHECK-NEXT: Type: FUNCTION (0x0)
+; CHECK-NEXT: Flags: 0x1
+; CHECK-NEXT: }
diff --git a/test/wasm/many-functions.ll b/test/wasm/many-functions.ll
index 9d08c67..02ad9aa 100644
--- a/test/wasm/many-functions.ll
+++ b/test/wasm/many-functions.ll
@@ -1,6 +1,6 @@
; RUN: llc -filetype=obj %p/Inputs/many-funcs.ll -o %t.many.o
; RUN: llc -filetype=obj %s -o %t.o
-; RUN: wasm-ld --check-signatures -r -o %t.wasm %t.many.o %t.o
+; RUN: wasm-ld -r -o %t.wasm %t.many.o %t.o
; RUN: obj2yaml %t.wasm | FileCheck %s
; Test that relocations within the CODE section correctly handle
@@ -8,7 +8,7 @@
; 128 function and so the final output requires a 2-byte LEB in
; the CODE section header to store the function count.
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
define i32 @func() {
entry:
@@ -815,6 +815,7 @@
; CHECK-NEXT: Content: '01000000'
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: linking
+; CHECK-NEXT: Version: 1
; CHECK-NEXT: SymbolTable:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: Kind: FUNCTION
diff --git a/test/wasm/reloc-addend.ll b/test/wasm/reloc-addend.ll
new file mode 100644
index 0000000..f678a3d
--- /dev/null
+++ b/test/wasm/reloc-addend.ll
@@ -0,0 +1,19 @@
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: wasm-ld -r -o %t.wasm %t.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+target triple = "wasm32-unknown-unknown"
+
+@foo = hidden global [76 x i32] zeroinitializer, align 16
+
+; bar points to the 16th element, which happens to be 64 bytes
+; This generates an addend of 64 which, is the value at which
+; signed and unsigned LEB encodes will differ.
+@bar = hidden local_unnamed_addr global i32* getelementptr inbounds ([76 x i32], [76 x i32]* @foo, i32 0, i32 16), align 4
+
+; CHECK: - Type: DATA
+; CHECK-NEXT: Relocations:
+; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_I32
+; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Offset: 0x0000013D
+; CHECK-NEXT: Addend: 64
diff --git a/test/wasm/relocatable.ll b/test/wasm/relocatable.ll
index 2c3cf61..4e8a887 100644
--- a/test/wasm/relocatable.ll
+++ b/test/wasm/relocatable.ll
@@ -1,9 +1,9 @@
; RUN: llc -filetype=obj %p/Inputs/hello.ll -o %t.hello.o
; RUN: llc -filetype=obj %s -o %t.o
-; RUN: wasm-ld --check-signatures -r -o %t.wasm %t.hello.o %t.o
+; RUN: wasm-ld -r -o %t.wasm %t.hello.o %t.o
; RUN: obj2yaml %t.wasm | FileCheck %s
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
; Function Attrs: nounwind
define hidden i32 @my_func() local_unnamed_addr {
@@ -157,6 +157,7 @@
; CHECK-NEXT: Content: '616263'
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: linking
+; CHECK-NEXT: Version: 1
; CHECK-NEXT: SymbolTable:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: Kind: FUNCTION
diff --git a/test/wasm/responsefile.test b/test/wasm/responsefile.test
new file mode 100644
index 0000000..d5e262c
--- /dev/null
+++ b/test/wasm/responsefile.test
@@ -0,0 +1,10 @@
+RUN: llc -filetype=obj -o %t.o %p/Inputs/ret32.ll
+
+RUN: echo "%t.o -o %t.wasm -e ret32" > %t.rsp
+RUN: wasm-ld @%t.rsp --initial-memory=655360
+RUN: llvm-readobj --sections %t.wasm | FileCheck %s
+CHECK: InitialPages: 10
+
+RUN: echo "blah\foo" > %t.rsp
+RUN: not wasm-ld @%t.rsp 2>&1 | FileCheck --check-prefix=ESCAPE %s
+ESCAPE: error: cannot open blahfoo: No such file or directory
diff --git a/test/wasm/signature-mismatch-weak.ll b/test/wasm/signature-mismatch-weak.ll
index fcf9646..8123b60 100644
--- a/test/wasm/signature-mismatch-weak.ll
+++ b/test/wasm/signature-mismatch-weak.ll
@@ -1,10 +1,9 @@
; RUN: llc -filetype=obj %p/Inputs/weak-symbol1.ll -o %t.weak.o
; RUN: llc -filetype=obj %p/Inputs/strong-symbol.ll -o %t.strong.o
; RUN: llc -filetype=obj %s -o %t.o
-; RUN: not wasm-ld --check-signatures -o %t.wasm %t.o %t.strong.o %t.weak.o 2>&1 | FileCheck %s
-; RUN: wasm-ld -o %t.wasm %t.o %t.strong.o %t.weak.o
+; RUN: wasm-ld -o %t.wasm %t.o %t.strong.o %t.weak.o 2>&1 | FileCheck %s
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
declare i32 @weakFn() local_unnamed_addr
@@ -14,6 +13,6 @@
ret void
}
-; CHECK: error: Function type mismatch: weakFn
+; CHECK: warning: Function type mismatch: weakFn
; CHECK-NEXT: >>> defined as () -> I32 in {{.*}}signature-mismatch-weak.ll.tmp.o
; CHECK-NEXT: >>> defined as () -> I64 in {{.*}}signature-mismatch-weak.ll.tmp.strong.o
diff --git a/test/wasm/signature-mismatch.ll b/test/wasm/signature-mismatch.ll
index 602239d..5b91c19 100644
--- a/test/wasm/signature-mismatch.ll
+++ b/test/wasm/signature-mismatch.ll
@@ -1,12 +1,12 @@
; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
; RUN: llc -filetype=obj %s -o %t.main.o
-; RUN: not wasm-ld --check-signatures -o %t.wasm %t.main.o %t.ret32.o 2>&1 | FileCheck %s
+; RUN: not wasm-ld --fatal-warnings -o %t.wasm %t.main.o %t.ret32.o 2>&1 | FileCheck %s
; Run the test again by with the object files in the other order to verify
; the check works when the undefined symbol is resolved by an existing defined
; one.
-; RUN: not wasm-ld --check-signatures -o %t.wasm %t.ret32.o %t.main.o 2>&1 | FileCheck %s -check-prefix=REVERSE
+; RUN: not wasm-ld --fatal-warnings -o %t.wasm %t.ret32.o %t.main.o 2>&1 | FileCheck %s -check-prefix=REVERSE
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
; Function Attrs: nounwind
define hidden void @_start() local_unnamed_addr #0 {
diff --git a/test/wasm/stack-first.test b/test/wasm/stack-first.test
new file mode 100644
index 0000000..71d1e9d
--- /dev/null
+++ b/test/wasm/stack-first.test
@@ -0,0 +1,42 @@
+; Test that the --stack-first option places the stack at the start of linear
+; memory. In this case the --stack-first option is being passed along with a
+; stack size of 512. This means (since the stack grows down) the stack pointer
+; global should be initialized to 512.
+
+RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.o
+
+RUN: wasm-ld -z stack-size=512 --stack-first --allow-undefined -o %t.wasm %t.o
+RUN: obj2yaml %t.wasm | FileCheck %s
+
+CHECK: - Type: GLOBAL
+CHECK-NEXT: Globals:
+CHECK-NEXT: - Index: 0
+CHECK-NEXT: Type: I32
+CHECK-NEXT: Mutable: true
+CHECK-NEXT: InitExpr:
+CHECK-NEXT: Opcode: I32_CONST
+CHECK-NEXT: Value: 512
+CHECK-NEXT: - Index: 1
+CHECK-NEXT: Type: I32
+CHECK-NEXT: Mutable: false
+CHECK-NEXT: InitExpr:
+CHECK-NEXT: Opcode: I32_CONST
+CHECK-NEXT: Value: 512
+CHECK-NEXT: - Index: 2
+CHECK-NEXT: Type: I32
+CHECK-NEXT: Mutable: false
+CHECK-NEXT: InitExpr:
+CHECK-NEXT: Opcode: I32_CONST
+CHECK-NEXT: Value: 512
+CHECK-NEXT: - Type: EXPORT
+CHECK-NEXT: Exports:
+CHECK-NEXT: - Name: memory
+CHECK-NEXT: Kind: MEMORY
+CHECK-NEXT: Index: 0
+CHECK-NEXT: - Name: __heap_base
+CHECK-NEXT: Kind: GLOBAL
+CHECK-NEXT: Index: 1
+CHECK-NEXT: - Name: __data_end
+CHECK-NEXT: Kind: GLOBAL
+CHECK-NEXT: Index: 2
+
diff --git a/test/wasm/stack-pointer.ll b/test/wasm/stack-pointer.ll
index 8aaa319..888c938 100644
--- a/test/wasm/stack-pointer.ll
+++ b/test/wasm/stack-pointer.ll
@@ -1,8 +1,8 @@
; RUN: llc -filetype=obj %s -o %t.o
-; RUN: wasm-ld --check-signatures --relocatable -o %t.wasm %t.o
+; RUN: wasm-ld --relocatable -o %t.wasm %t.o
; RUN: obj2yaml %t.wasm | FileCheck %s
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
; Function Attrs: nounwind
define i32 @_start() local_unnamed_addr {
@@ -50,6 +50,7 @@
; CHECK-NEXT: Body: 23808080800041106B1A41000B
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: linking
+; CHECK-NEXT: Version: 1
; CHECK-NEXT: SymbolTable:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: Kind: FUNCTION
diff --git a/test/wasm/strip-debug.test b/test/wasm/strip-debug.test
index 5a74ac8..be5ba70 100644
--- a/test/wasm/strip-debug.test
+++ b/test/wasm/strip-debug.test
@@ -1,5 +1,5 @@
RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.start.o
-RUN: wasm-ld --check-signatures --strip-debug -o %t.wasm %t.start.o
+RUN: wasm-ld --strip-debug -o %t.wasm %t.start.o
RUN: obj2yaml %t.wasm | FileCheck %s
# Check that there is no name section
diff --git a/test/wasm/symbol-type-mismatch.ll b/test/wasm/symbol-type-mismatch.ll
index 16e0f4d..4738c4b 100644
--- a/test/wasm/symbol-type-mismatch.ll
+++ b/test/wasm/symbol-type-mismatch.ll
@@ -1,11 +1,11 @@
; RUN: llc -filetype=obj %s -o %t.o
; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
-; RUN: not wasm-ld --check-signatures -o %t.wasm %t.o %t.ret32.o 2>&1 | FileCheck %s
+; RUN: not wasm-ld -o %t.wasm %t.o %t.ret32.o 2>&1 | FileCheck %s
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
@ret32 = extern_weak global i32, align 4
; CHECK: error: symbol type mismatch: ret32
-; CHECK: >>> defined as Data in {{.*}}symbol-type-mismatch.ll.tmp.o
-; CHECK: >>> defined as Function in {{.*}}.ret32.o
+; CHECK: >>> defined as WASM_SYMBOL_TYPE_DATA in {{.*}}symbol-type-mismatch.ll.tmp.o
+; CHECK: >>> defined as WASM_SYMBOL_TYPE_FUNCTION in {{.*}}.ret32.o
diff --git a/test/wasm/undefined-entry.test b/test/wasm/undefined-entry.test
index 7906ec9..ffa079c 100644
--- a/test/wasm/undefined-entry.test
+++ b/test/wasm/undefined-entry.test
@@ -1,10 +1,11 @@
RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
-RUN: not wasm-ld --check-signatures -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s
+RUN: not wasm-ld -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s
+RUN: not wasm-ld -entry=foo -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s -check-prefix=CHECK-CUSTOM
+RUN: not wasm-ld --allow-undefined -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s -check-prefix=CHECK-ALLOW
CHECK: error: undefined symbol: _start
-
-RUN: not wasm-ld --check-signatures -entry=foo -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s -check-prefix=CHECK-CUSTOM
-
CHECK-CUSTOM: error: undefined symbol: foo
+CHECK-ALLOW: error: entry symbol not defined (pass --no-entry to supress):
+_start
-RUN: wasm-ld --check-signatures -entry=foo --allow-undefined -o %t.wasm %t.ret32.o
+RUN: wasm-ld --no-entry -o %t.wasm %t.ret32.o
diff --git a/test/wasm/undefined-weak-call.ll b/test/wasm/undefined-weak-call.ll
index cd26e05..c13f5c1 100644
--- a/test/wasm/undefined-weak-call.ll
+++ b/test/wasm/undefined-weak-call.ll
@@ -1,17 +1,20 @@
; RUN: llc -filetype=obj %s -o %t.o
-; RUN: wasm-ld --check-signatures --no-entry %t.o -o %t.wasm
+; RUN: wasm-ld --no-entry --print-gc-sections %t.o \
+; RUN: -o %t.wasm 2>&1 | FileCheck -check-prefix=CHECK-GC %s
; RUN: obj2yaml %t.wasm | FileCheck %s
; Check that calling an undefined weak function generates an appropriate stub
; that will fail at runtime with "unreachable".
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
declare extern_weak void @weakFunc1()
declare extern_weak void @weakFunc2() ; same signature
declare extern_weak void @weakFunc3(i32 %arg) ; different
declare extern_weak void @weakFunc4() ; should be GC'd as not called
+; CHECK-GC: removing unused section {{.*}}:(weakFunc4)
+
define i32 @callWeakFuncs() {
call void @weakFunc1()
call void @weakFunc2()
diff --git a/test/wasm/undefined.ll b/test/wasm/undefined.ll
index a74dd6d..7d2161d 100644
--- a/test/wasm/undefined.ll
+++ b/test/wasm/undefined.ll
@@ -1,19 +1,19 @@
; RUN: llc -filetype=obj %s -o %t.o
-; RUN: wasm-ld --check-signatures --allow-undefined -o %t.wasm %t.o
+; RUN: wasm-ld --allow-undefined -o %t.wasm %t.o
; Fails due to undefined 'foo' and also 'baz'
-; RUN: not wasm-ld --check-signatures --undefined=baz -o %t.wasm %t.o 2>&1 | FileCheck %s
+; RUN: not wasm-ld --undefined=baz -o %t.wasm %t.o 2>&1 | FileCheck %s
; CHECK: error: {{.*}}.o: undefined symbol: foo
; CHECK: error: undefined symbol: baz
; Succeeds if we pass a file containing 'foo' as --allow-undefined-file.
; RUN: echo 'foo' > %t.txt
-; RUN: wasm-ld --check-signatures --allow-undefined-file=%t.txt -o %t.wasm %t.o
+; RUN: wasm-ld --allow-undefined-file=%t.txt -o %t.wasm %t.o
; Succeeds even if a missing symbol is added via --export
-; RUN: wasm-ld --check-signatures --allow-undefined --export=xxx -o %t.wasm %t.o
+; RUN: wasm-ld --allow-undefined --export=xxx -o %t.wasm %t.o
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
; Takes the address of the external foo() resulting in undefined external
@bar = hidden local_unnamed_addr global i8* bitcast (i32 ()* @foo to i8*), align 4
diff --git a/test/wasm/version.ll b/test/wasm/version.ll
index 3b20b39..ea5b41f 100644
--- a/test/wasm/version.ll
+++ b/test/wasm/version.ll
@@ -1,8 +1,8 @@
; RUN: llc -filetype=obj %s -o %t.o
-; RUN: wasm-ld --check-signatures -o %t.wasm %t.o
+; RUN: wasm-ld -o %t.wasm %t.o
; RUN: llvm-readobj -file-headers %t.wasm | FileCheck %s
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
define hidden void @_start() local_unnamed_addr #0 {
entry:
diff --git a/test/wasm/visibility-hidden.ll b/test/wasm/visibility-hidden.ll
index 530649b..af973df 100644
--- a/test/wasm/visibility-hidden.ll
+++ b/test/wasm/visibility-hidden.ll
@@ -1,13 +1,13 @@
; RUN: llc -filetype=obj -o %t.o %s
; RUN: llc -filetype=obj %S/Inputs/hidden.ll -o %t2.o
; RUN: llvm-ar rcs %t2.a %t2.o
-; RUN: wasm-ld --check-signatures %t.o %t2.a -o %t.wasm
+; RUN: wasm-ld %t.o %t2.a -o %t.wasm
; RUN: obj2yaml %t.wasm | FileCheck %s
; Test that hidden symbols are not exported, whether pulled in from an archive
; or directly.
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
define hidden i32 @objectHidden() {
entry:
diff --git a/test/wasm/weak-alias-overide.ll b/test/wasm/weak-alias-overide.ll
index 2252298..8b98f33 100644
--- a/test/wasm/weak-alias-overide.ll
+++ b/test/wasm/weak-alias-overide.ll
@@ -1,12 +1,12 @@
; RUN: llc -filetype=obj -o %t.o %s
; RUN: llc -filetype=obj %S/Inputs/weak-alias.ll -o %t2.o
-; RUN: wasm-ld --check-signatures %t.o %t2.o -o %t.wasm
+; RUN: wasm-ld %t.o %t2.o -o %t.wasm
; RUN: obj2yaml %t.wasm | FileCheck %s
; Test that the strongly defined alias_fn from this file is used both here
; and in call_alias.
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
define i32 @alias_fn() local_unnamed_addr #1 {
ret i32 1
diff --git a/test/wasm/weak-alias.ll b/test/wasm/weak-alias.ll
index 1df16e2..227906a 100644
--- a/test/wasm/weak-alias.ll
+++ b/test/wasm/weak-alias.ll
@@ -1,11 +1,11 @@
; RUN: llc -filetype=obj -o %t.o %s
; RUN: llc -filetype=obj %S/Inputs/weak-alias.ll -o %t2.o
-; RUN: wasm-ld --check-signatures %t.o %t2.o -o %t.wasm
+; RUN: wasm-ld %t.o %t2.o -o %t.wasm
; RUN: obj2yaml %t.wasm | FileCheck %s
; Test that weak aliases (alias_fn is a weak alias of direct_fn) are linked correctly
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
declare i32 @alias_fn() local_unnamed_addr #1
@@ -144,7 +144,7 @@
; CHECK-NEXT: Name: call_direct_ptr
; CHECK-NEXT: ...
-; RUN: wasm-ld --check-signatures --relocatable %t.o %t2.o -o %t.reloc.o
+; RUN: wasm-ld --relocatable %t.o %t2.o -o %t.reloc.o
; RUN: obj2yaml %t.reloc.o | FileCheck %s -check-prefix=RELOC
; RELOC: --- !WASM
@@ -250,6 +250,7 @@
; RELOC-NEXT: Body: 23808080800041106B220024808080800020004181808080003602081081808080002101200041106A24808080800020010B
; RELOC-NEXT: - Type: CUSTOM
; RELOC-NEXT: Name: linking
+; RELOC-NEXT: Version: 1
; RELOC-NEXT: SymbolTable:
; RELOC-NEXT: - Index: 0
; RELOC-NEXT: Kind: FUNCTION
diff --git a/test/wasm/weak-symbols.ll b/test/wasm/weak-symbols.ll
index 7ecb900..bd45de3 100644
--- a/test/wasm/weak-symbols.ll
+++ b/test/wasm/weak-symbols.ll
@@ -1,10 +1,10 @@
; RUN: llc -filetype=obj %p/Inputs/weak-symbol1.ll -o %t1.o
; RUN: llc -filetype=obj %p/Inputs/weak-symbol2.ll -o %t2.o
; RUN: llc -filetype=obj %s -o %t.o
-; RUN: wasm-ld -no-gc-sections --check-signatures -o %t.wasm %t.o %t1.o %t2.o
+; RUN: wasm-ld -no-gc-sections -o %t.wasm %t.o %t1.o %t2.o
; RUN: obj2yaml %t.wasm | FileCheck %s
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
declare i32 @weakFn() local_unnamed_addr
@weakGlobal = external global i32
diff --git a/test/wasm/weak-undefined.ll b/test/wasm/weak-undefined.ll
index ce68e54..53b38bc 100644
--- a/test/wasm/weak-undefined.ll
+++ b/test/wasm/weak-undefined.ll
@@ -1,11 +1,11 @@
; RUN: llc -filetype=obj -o %t.o %s
-; RUN: wasm-ld --check-signatures -strip-debug %t.o -o %t.wasm
+; RUN: wasm-ld -strip-debug %t.o -o %t.wasm
; RUN: obj2yaml %t.wasm | FileCheck %s
; Test that undefined weak externals (global_var) and (foo) don't cause
; link failures and resolve to zero.
-target triple = "wasm32-unknown-unknown-wasm"
+target triple = "wasm32-unknown-unknown"
@global_var = extern_weak global i32, align 4
diff --git a/tools/lld/lld.cpp b/tools/lld/lld.cpp
index 164a2aa..2c00a13 100644
--- a/tools/lld/lld.cpp
+++ b/tools/lld/lld.cpp
@@ -20,10 +20,8 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
-#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/Signals.h"
#include <cstdlib>
using namespace lld;
@@ -114,10 +112,7 @@
/// Universal linker main(). This linker emulates the gnu, darwin, or
/// windows linker based on the argv[0] or -flavor option.
int main(int Argc, const char **Argv) {
- // Standard set up, so program fails gracefully.
- sys::PrintStackTraceOnErrorSignal(Argv[0]);
- PrettyStackTraceProgram StackPrinter(Argc, Argv);
- llvm_shutdown_obj Shutdown;
+ InitLLVM X(Argc, Argv);
std::vector<const char *> Args(Argv, Argv + Argc);
switch (parseFlavor(Args)) {
diff --git a/unittests/DriverTests/DarwinLdDriverTest.cpp b/unittests/DriverTests/DarwinLdDriverTest.cpp
index 696be69..0c1d779 100644
--- a/unittests/DriverTests/DarwinLdDriverTest.cpp
+++ b/unittests/DriverTests/DarwinLdDriverTest.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// \brief Darwin's ld driver tests.
+/// Darwin's ld driver tests.
///
//===----------------------------------------------------------------------===//
diff --git a/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp b/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp
index 3e8793a..336bbdb 100644
--- a/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp
+++ b/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp
@@ -12,14 +12,17 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/YAMLTraits.h"
#include "gtest/gtest.h"
#include <cstdint>
#include <memory>
+using llvm::SmallString;
using llvm::StringRef;
using llvm::MemoryBuffer;
+using llvm::Twine;
using namespace lld::mach_o::normalized;
using namespace llvm::MachO;
@@ -741,9 +744,11 @@
EXPECT_EQ(printfLabel.type, N_UNDF);
EXPECT_EQ(printfLabel.scope, SymbolScope(N_EXT));
- auto ec = writeBinary(*f, "/tmp/foo.o");
- // FIXME: We want to do EXPECT_FALSE(ec) but that fails on some Windows bots,
- // probably due to /tmp not being available.
- // For now just consume the error without checking it.
- consumeError(std::move(ec));
+ SmallString<128> tmpFl;
+ std::error_code ec =
+ llvm::sys::fs::createTemporaryFile(Twine("xx"), "o", tmpFl);
+ EXPECT_FALSE(ec);
+ llvm::Error ec2 = writeBinary(*f, tmpFl);
+ EXPECT_FALSE(ec2);
+ llvm::sys::fs::remove(tmpFl);
}
diff --git a/wasm/CMakeLists.txt b/wasm/CMakeLists.txt
index d3bef0f..308c4e2 100644
--- a/wasm/CMakeLists.txt
+++ b/wasm/CMakeLists.txt
@@ -6,6 +6,7 @@
Driver.cpp
InputChunks.cpp
InputFiles.cpp
+ LTO.cpp
MarkLive.cpp
OutputSections.cpp
SymbolTable.cpp
@@ -18,6 +19,8 @@
BinaryFormat
Core
Demangle
+ LTO
+ MC
Object
Option
Support
diff --git a/wasm/Config.h b/wasm/Config.h
index adccbfe..4b11320 100644
--- a/wasm/Config.h
+++ b/wasm/Config.h
@@ -13,31 +13,42 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/BinaryFormat/Wasm.h"
+#include "llvm/Support/CachePruning.h"
namespace lld {
namespace wasm {
struct Configuration {
bool AllowUndefined;
- bool CheckSignatures;
+ bool CompressRelocTargets;
bool Demangle;
+ bool DisableVerify;
bool ExportTable;
bool GcSections;
bool ImportMemory;
bool ImportTable;
+ bool MergeDataSegments;
bool PrintGcSections;
bool Relocatable;
+ bool SaveTemps;
bool StripAll;
bool StripDebug;
+ bool StackFirst;
uint32_t GlobalBase;
uint32_t InitialMemory;
uint32_t MaxMemory;
uint32_t ZStackSize;
+ unsigned LTOPartitions;
+ unsigned LTOO;
+ unsigned Optimize;
+ unsigned ThinLTOJobs;
llvm::StringRef Entry;
llvm::StringRef OutputFile;
+ llvm::StringRef ThinLTOCacheDir;
llvm::StringSet<> AllowUndefinedSymbols;
std::vector<llvm::StringRef> SearchPaths;
+ llvm::CachePruningPolicy ThinLTOCachePolicy;
};
// The only instance of Configuration struct.
diff --git a/wasm/Driver.cpp b/wasm/Driver.cpp
index 97a8159..5a9fe36 100644
--- a/wasm/Driver.cpp
+++ b/wasm/Driver.cpp
@@ -26,6 +26,7 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
+#include "llvm/Support/TargetSelect.h"
#define DEBUG_TYPE "lld"
@@ -48,6 +49,17 @@
#undef OPTION
};
+// This function is called on startup. We need this for LTO since
+// LTO calls LLVM functions to compile bitcode files to native code.
+// Technically this can be delayed until we read bitcode files, but
+// we don't bother to do lazily because the initialization is fast.
+static void initLLVM() {
+ InitializeAllTargets();
+ InitializeAllTargetMCs();
+ InitializeAllAsmPrinters();
+ InitializeAllAsmParsers();
+}
+
class LinkerDriver {
public:
void link(ArrayRef<const char *> ArgsArr);
@@ -57,7 +69,6 @@
void addFile(StringRef Path);
void addLibrary(StringRef Name);
std::vector<InputFile *> Files;
- llvm::wasm::WasmGlobal StackPointerGlobal;
};
} // anonymous namespace
@@ -73,6 +84,7 @@
Config = make<Configuration>();
Symtab = make<SymbolTable>();
+ initLLVM();
LinkerDriver().link(Args);
// Exit immediately if we don't need to return to the caller.
@@ -99,11 +111,13 @@
#undef OPTION
};
+namespace {
class WasmOptTable : public llvm::opt::OptTable {
public:
WasmOptTable() : OptTable(OptInfo) {}
opt::InputArgList parse(ArrayRef<const char *> Argv);
};
+} // namespace
// Set color diagnostics according to -color-diagnostics={auto,always,never}
// or -no-color-diagnostics flags.
@@ -112,19 +126,18 @@
OPT_no_color_diagnostics);
if (!Arg)
return;
-
- if (Arg->getOption().getID() == OPT_color_diagnostics)
+ if (Arg->getOption().getID() == OPT_color_diagnostics) {
errorHandler().ColorDiagnostics = true;
- else if (Arg->getOption().getID() == OPT_no_color_diagnostics)
+ } else if (Arg->getOption().getID() == OPT_no_color_diagnostics) {
errorHandler().ColorDiagnostics = false;
- else {
+ } else {
StringRef S = Arg->getValue();
if (S == "always")
errorHandler().ColorDiagnostics = true;
- if (S == "never")
+ else if (S == "never")
errorHandler().ColorDiagnostics = false;
- if (S != "auto")
- error("unknown option: -color-diagnostics=" + S);
+ else if (S != "auto")
+ error("unknown option: --color-diagnostics=" + S);
}
}
@@ -142,6 +155,10 @@
unsigned MissingIndex;
unsigned MissingCount;
+
+ // Expand response files (arguments in the form of @<filename>)
+ cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Vec);
+
opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount);
handleColorDiagnostics(Args);
@@ -169,7 +186,8 @@
return;
MemoryBufferRef MBRef = *Buffer;
- if (identify_magic(MBRef.getBuffer()) == file_magic::archive) {
+ switch (identify_magic(MBRef.getBuffer())) {
+ case file_magic::archive: {
SmallString<128> ImportFile = Path;
path::replace_extension(ImportFile, ".imports");
if (fs::exists(ImportFile))
@@ -178,8 +196,12 @@
Files.push_back(make<ArchiveFile>(MBRef));
return;
}
-
- Files.push_back(make<ObjFile>(MBRef));
+ case file_magic::bitcode:
+ Files.push_back(make<BitcodeFile>(MBRef));
+ break;
+ default:
+ Files.push_back(make<ObjFile>(MBRef));
+ }
}
// Add a given library by searching it from input search paths.
@@ -241,10 +263,11 @@
// Add a synthetic dummy for weak undefined functions. These dummies will
// be GC'd if not used as the target of any "call" instructions.
Optional<std::string> SymName = demangleItanium(Sym->getName());
- StringRef StubName =
+ StringRef DebugName =
Saver.save("undefined function " +
(SymName ? StringRef(*SymName) : Sym->getName()));
- SyntheticFunction *Func = make<SyntheticFunction>(Sig, StubName);
+ SyntheticFunction *Func =
+ make<SyntheticFunction>(Sig, Sym->getName(), DebugName);
Func->setBody(UnreachableFn);
// Ensure it compares equal to the null pointer, and so that table relocs
// don't pull in the stub body (only call-operand relocs should do that).
@@ -256,6 +279,17 @@
}
}
+// Force Sym to be entered in the output. Used for -u or equivalent.
+static Symbol *addUndefined(StringRef Name) {
+ Symbol *S = Symtab->addUndefinedFunction(Name, 0, nullptr, nullptr);
+
+ // Since symbol S may not be used inside the program, LTO may
+ // eliminate it. Mark the symbol as "used" to prevent it.
+ S->IsUsedInRegularObj = true;
+
+ return S;
+}
+
void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
WasmOptTable Parser;
opt::InputArgList Args = Parser.parse(ArgsArr.slice(1));
@@ -282,22 +316,36 @@
errorHandler().ErrorLimit = args::getInteger(Args, OPT_error_limit, 20);
Config->AllowUndefined = Args.hasArg(OPT_allow_undefined);
- Config->CheckSignatures =
- Args.hasFlag(OPT_check_signatures, OPT_no_check_signatures, false);
Config->Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, true);
+ Config->DisableVerify = Args.hasArg(OPT_disable_verify);
Config->Entry = getEntry(Args, Args.hasArg(OPT_relocatable) ? "" : "_start");
Config->ExportTable = Args.hasArg(OPT_export_table);
+ errorHandler().FatalWarnings =
+ Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false);
Config->ImportMemory = Args.hasArg(OPT_import_memory);
Config->ImportTable = Args.hasArg(OPT_import_table);
+ Config->LTOO = args::getInteger(Args, OPT_lto_O, 2);
+ Config->LTOPartitions = args::getInteger(Args, OPT_lto_partitions, 1);
+ Config->Optimize = args::getInteger(Args, OPT_O, 0);
Config->OutputFile = Args.getLastArgValue(OPT_o);
Config->Relocatable = Args.hasArg(OPT_relocatable);
Config->GcSections =
Args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, !Config->Relocatable);
+ Config->MergeDataSegments =
+ Args.hasFlag(OPT_merge_data_segments, OPT_no_merge_data_segments,
+ !Config->Relocatable);
Config->PrintGcSections =
Args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false);
+ Config->SaveTemps = Args.hasArg(OPT_save_temps);
Config->SearchPaths = args::getStrings(Args, OPT_L);
Config->StripAll = Args.hasArg(OPT_strip_all);
Config->StripDebug = Args.hasArg(OPT_strip_debug);
+ Config->StackFirst = Args.hasArg(OPT_stack_first);
+ Config->ThinLTOCacheDir = Args.getLastArgValue(OPT_thinlto_cache_dir);
+ Config->ThinLTOCachePolicy = CHECK(
+ parseCachePruningPolicy(Args.getLastArgValue(OPT_thinlto_cache_policy)),
+ "--thinlto-cache-policy: invalid cache policy");
+ Config->ThinLTOJobs = args::getInteger(Args, OPT_thinlto_jobs, -1u);
errorHandler().Verbose = Args.hasArg(OPT_verbose);
ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true);
@@ -307,6 +355,15 @@
Config->ZStackSize =
args::getZOptionValue(Args, OPT_z, "stack-size", WasmPageSize);
+ Config->CompressRelocTargets = Config->Optimize > 0 && !Config->Relocatable;
+
+ if (Config->LTOO > 3)
+ error("invalid optimization level for LTO: " + Twine(Config->LTOO));
+ if (Config->LTOPartitions == 0)
+ error("--lto-partitions: number of threads must be > 0");
+ if (Config->ThinLTOJobs == 0)
+ error("--thinlto-jobs: number of threads must be > 0");
+
if (auto *Arg = Args.getLastArg(OPT_allow_undefined_file))
readImportFile(Arg->getValue());
@@ -336,10 +393,12 @@
// globals aren't yet supported in the official binary format.
// TODO(sbc): Remove WASM_SYMBOL_VISIBILITY_HIDDEN if/when the
// "mutable global" proposal is accepted.
- StackPointerGlobal.Type = {WASM_TYPE_I32, true};
- StackPointerGlobal.InitExpr.Value.Int32 = 0;
- StackPointerGlobal.InitExpr.Opcode = WASM_OPCODE_I32_CONST;
- InputGlobal *StackPointer = make<InputGlobal>(StackPointerGlobal);
+ llvm::wasm::WasmGlobal Global;
+ Global.Type = {WASM_TYPE_I32, true};
+ Global.InitExpr.Value.Int32 = 0;
+ Global.InitExpr.Opcode = WASM_OPCODE_I32_CONST;
+ Global.SymbolName = "__stack_pointer";
+ InputGlobal *StackPointer = make<InputGlobal>(Global, nullptr);
StackPointer->Live = true;
static WasmSignature NullSignature = {{}, WASM_TYPE_NORESULT};
@@ -355,13 +414,14 @@
"__dso_handle", WASM_SYMBOL_VISIBILITY_HIDDEN);
WasmSym::DataEnd = Symtab->addSyntheticDataSymbol("__data_end", 0);
+ // For now, since we don't actually use the start function as the
+ // wasm start symbol, we don't need to care about it signature.
if (!Config->Entry.empty())
- EntrySym = Symtab->addUndefinedFunction(Config->Entry, 0, nullptr,
- &NullSignature);
+ EntrySym = addUndefined(Config->Entry);
// Handle the `--undefined <sym>` options.
for (auto *Arg : Args.filtered(OPT_undefined))
- Symtab->addUndefinedFunction(Arg->getValue(), 0, nullptr, nullptr);
+ addUndefined(Arg->getValue());
}
createFiles(Args);
@@ -372,24 +432,36 @@
// symbols that we need to the symbol table.
for (InputFile *F : Files)
Symtab->addFile(F);
+ if (errorCount())
+ return;
// Add synthetic dummies for weak undefined functions.
if (!Config->Relocatable)
handleWeakUndefines();
+ // Do link-time optimization if given files are LLVM bitcode files.
+ // This compiles bitcode files into real object files.
+ Symtab->addCombinedLTOObject();
+ if (errorCount())
+ return;
+
// Make sure we have resolved all symbols.
if (!Config->Relocatable && !Config->AllowUndefined) {
Symtab->reportRemainingUndefines();
} else {
- // When we allow undefined symbols we cannot include those defined in
- // -u/--undefined since these undefined symbols have only names and no
- // function signature, which means they cannot be written to the final
- // output.
+ // Even when using --allow-undefined we still want to report the absence of
+ // our initial set of undefined symbols (i.e. the entry point and symbols
+ // specified via --undefined).
+ // Part of the reason for this is that these function don't have signatures
+ // so which means they cannot be written as wasm function imports.
for (auto *Arg : Args.filtered(OPT_undefined)) {
Symbol *Sym = Symtab->find(Arg->getValue());
if (!Sym->isDefined())
- error("function forced with --undefined not found: " + Sym->getName());
+ error("symbol forced with --undefined not found: " + Sym->getName());
}
+ if (EntrySym && !EntrySym->isDefined())
+ error("entry symbol not defined (pass --no-entry to supress): " +
+ EntrySym->getName());
}
if (errorCount())
return;
diff --git a/wasm/InputChunks.cpp b/wasm/InputChunks.cpp
index 0cac19b..fcefac7 100644
--- a/wasm/InputChunks.cpp
+++ b/wasm/InputChunks.cpp
@@ -23,7 +23,7 @@
using namespace lld;
using namespace lld::wasm;
-StringRef ReloctTypeToString(uint8_t RelocType) {
+static StringRef ReloctTypeToString(uint8_t RelocType) {
switch (RelocType) {
#define WASM_RELOC(NAME, REL) case REL: return #NAME;
#include "llvm/BinaryFormat/WasmRelocs.def"
@@ -47,12 +47,49 @@
if (Section.Relocations.empty())
return;
size_t Start = getInputSectionOffset();
- size_t Size = getSize();
+ size_t Size = getInputSize();
for (const WasmRelocation &R : Section.Relocations)
if (R.Offset >= Start && R.Offset < Start + Size)
Relocations.push_back(R);
}
+void InputChunk::verifyRelocTargets() const {
+ for (const WasmRelocation &Rel : Relocations) {
+ uint32_t ExistingValue;
+ unsigned BytesRead = 0;
+ uint32_t Offset = Rel.Offset - getInputSectionOffset();
+ const uint8_t *Loc = data().data() + Offset;
+ switch (Rel.Type) {
+ case R_WEBASSEMBLY_TYPE_INDEX_LEB:
+ case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
+ case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
+ case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
+ ExistingValue = decodeULEB128(Loc, &BytesRead);
+ break;
+ case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
+ case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
+ ExistingValue = static_cast<uint32_t>(decodeSLEB128(Loc, &BytesRead));
+ break;
+ case R_WEBASSEMBLY_TABLE_INDEX_I32:
+ case R_WEBASSEMBLY_MEMORY_ADDR_I32:
+ case R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
+ case R_WEBASSEMBLY_SECTION_OFFSET_I32:
+ ExistingValue = static_cast<uint32_t>(read32le(Loc));
+ break;
+ default:
+ llvm_unreachable("unknown relocation type");
+ }
+
+ if (BytesRead && BytesRead != 5)
+ warn("expected LEB at relocation site be 5-byte padded");
+ uint32_t ExpectedValue = File->calcExpectedValue(Rel);
+ if (ExpectedValue != ExistingValue)
+ warn("unexpected existing value for " + ReloctTypeToString(Rel.Type) +
+ ": existing=" + Twine(ExistingValue) +
+ " expected=" + Twine(ExpectedValue));
+ }
+}
+
// Copy this input chunk to an mmap'ed output file and apply relocations.
void InputChunk::writeTo(uint8_t *Buf) const {
// Copy contents
@@ -62,45 +99,42 @@
if (Relocations.empty())
return;
- DEBUG(dbgs() << "applying relocations: " << getName()
- << " count=" << Relocations.size() << "\n");
+#ifndef NDEBUG
+ verifyRelocTargets();
+#endif
+
+ LLVM_DEBUG(dbgs() << "applying relocations: " << getName()
+ << " count=" << Relocations.size() << "\n");
int32_t Off = OutputOffset - getInputSectionOffset();
for (const WasmRelocation &Rel : Relocations) {
uint8_t *Loc = Buf + Rel.Offset + Off;
uint32_t Value = File->calcNewValue(Rel);
- uint32_t ExistingValue;
- DEBUG(dbgs() << "apply reloc: type=" << ReloctTypeToString(Rel.Type)
- << " addend=" << Rel.Addend << " index=" << Rel.Index
- << " value=" << Value << " offset=" << Rel.Offset << "\n");
+ LLVM_DEBUG(dbgs() << "apply reloc: type=" << ReloctTypeToString(Rel.Type)
+ << " addend=" << Rel.Addend << " index=" << Rel.Index
+ << " value=" << Value << " offset=" << Rel.Offset
+ << "\n");
switch (Rel.Type) {
case R_WEBASSEMBLY_TYPE_INDEX_LEB:
case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
- ExistingValue = decodeULEB128(Loc);
encodeULEB128(Value, Loc, 5);
break;
case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
- ExistingValue = static_cast<uint32_t>(decodeSLEB128(Loc));
encodeSLEB128(static_cast<int32_t>(Value), Loc, 5);
break;
case R_WEBASSEMBLY_TABLE_INDEX_I32:
case R_WEBASSEMBLY_MEMORY_ADDR_I32:
- ExistingValue = static_cast<uint32_t>(read32le(Loc));
+ case R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
+ case R_WEBASSEMBLY_SECTION_OFFSET_I32:
write32le(Loc, Value);
break;
default:
llvm_unreachable("unknown relocation type");
}
-
- uint32_t ExpectedValue = File->calcExpectedValue(Rel);
- if (ExpectedValue != ExistingValue)
- error("unexpected existing value for " + ReloctTypeToString(Rel.Type) +
- ": existing=" + Twine(ExistingValue) +
- " expected=" + Twine(ExpectedValue));
}
}
@@ -112,8 +146,8 @@
return;
int32_t Off = OutputOffset - getInputSectionOffset();
- DEBUG(dbgs() << "writeRelocations: " << File->getName()
- << " offset=" << Twine(Off) << "\n");
+ LLVM_DEBUG(dbgs() << "writeRelocations: " << File->getName()
+ << " offset=" << Twine(Off) << "\n");
for (const WasmRelocation &Rel : Relocations) {
writeUleb128(OS, Rel.Type, "reloc type");
@@ -124,22 +158,138 @@
case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
case R_WEBASSEMBLY_MEMORY_ADDR_I32:
- writeUleb128(OS, Rel.Addend, "reloc addend");
+ case R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
+ case R_WEBASSEMBLY_SECTION_OFFSET_I32:
+ writeSleb128(OS, File->calcNewAddend(Rel), "reloc addend");
break;
}
}
}
void InputFunction::setFunctionIndex(uint32_t Index) {
- DEBUG(dbgs() << "InputFunction::setFunctionIndex: " << getName() << " -> "
- << Index << "\n");
+ LLVM_DEBUG(dbgs() << "InputFunction::setFunctionIndex: " << getName()
+ << " -> " << Index << "\n");
assert(!hasFunctionIndex());
FunctionIndex = Index;
}
void InputFunction::setTableIndex(uint32_t Index) {
- DEBUG(dbgs() << "InputFunction::setTableIndex: " << getName() << " -> "
- << Index << "\n");
+ LLVM_DEBUG(dbgs() << "InputFunction::setTableIndex: " << getName() << " -> "
+ << Index << "\n");
assert(!hasTableIndex());
TableIndex = Index;
}
+
+// Write a relocation value without padding and return the number of bytes
+// witten.
+static unsigned writeCompressedReloc(uint8_t *Buf, const WasmRelocation &Rel,
+ uint32_t Value) {
+ switch (Rel.Type) {
+ case R_WEBASSEMBLY_TYPE_INDEX_LEB:
+ case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
+ case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
+ case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
+ return encodeULEB128(Value, Buf);
+ case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
+ case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
+ return encodeSLEB128(static_cast<int32_t>(Value), Buf);
+ default:
+ llvm_unreachable("unexpected relocation type");
+ }
+}
+
+static unsigned getRelocWidthPadded(const WasmRelocation &Rel) {
+ switch (Rel.Type) {
+ case R_WEBASSEMBLY_TYPE_INDEX_LEB:
+ case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
+ case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
+ case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
+ case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
+ case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
+ return 5;
+ default:
+ llvm_unreachable("unexpected relocation type");
+ }
+}
+
+static unsigned getRelocWidth(const WasmRelocation &Rel, uint32_t Value) {
+ uint8_t Buf[5];
+ return writeCompressedReloc(Buf, Rel, Value);
+}
+
+// Relocations of type LEB and SLEB in the code section are padded to 5 bytes
+// so that a fast linker can blindly overwrite them without needing to worry
+// about the number of bytes needed to encode the values.
+// However, for optimal output the code section can be compressed to remove
+// the padding then outputting non-relocatable files.
+// In this case we need to perform a size calculation based on the value at each
+// relocation. At best we end up saving 4 bytes for each relocation entry.
+//
+// This function only computes the final output size. It must be called
+// before getSize() is used to calculate of layout of the code section.
+void InputFunction::calculateSize() {
+ if (!File || !Config->CompressRelocTargets)
+ return;
+
+ LLVM_DEBUG(dbgs() << "calculateSize: " << getName() << "\n");
+
+ const uint8_t *SecStart = File->CodeSection->Content.data();
+ const uint8_t *FuncStart = SecStart + getInputSectionOffset();
+ uint32_t FunctionSizeLength;
+ decodeULEB128(FuncStart, &FunctionSizeLength);
+
+ uint32_t Start = getInputSectionOffset();
+ uint32_t End = Start + Function->Size;
+
+ uint32_t LastRelocEnd = Start + FunctionSizeLength;
+ for (WasmRelocation &Rel : Relocations) {
+ LLVM_DEBUG(dbgs() << " region: " << (Rel.Offset - LastRelocEnd) << "\n");
+ CompressedFuncSize += Rel.Offset - LastRelocEnd;
+ CompressedFuncSize += getRelocWidth(Rel, File->calcNewValue(Rel));
+ LastRelocEnd = Rel.Offset + getRelocWidthPadded(Rel);
+ }
+ LLVM_DEBUG(dbgs() << " final region: " << (End - LastRelocEnd) << "\n");
+ CompressedFuncSize += End - LastRelocEnd;
+
+ // Now we know how long the resulting function is we can add the encoding
+ // of its length
+ uint8_t Buf[5];
+ CompressedSize = CompressedFuncSize + encodeULEB128(CompressedFuncSize, Buf);
+
+ LLVM_DEBUG(dbgs() << " calculateSize orig: " << Function->Size << "\n");
+ LLVM_DEBUG(dbgs() << " calculateSize new: " << CompressedSize << "\n");
+}
+
+// Override the default writeTo method so that we can (optionally) write the
+// compressed version of the function.
+void InputFunction::writeTo(uint8_t *Buf) const {
+ if (!File || !Config->CompressRelocTargets)
+ return InputChunk::writeTo(Buf);
+
+ Buf += OutputOffset;
+ uint8_t *Orig = Buf; (void)Orig;
+
+ const uint8_t *SecStart = File->CodeSection->Content.data();
+ const uint8_t *FuncStart = SecStart + getInputSectionOffset();
+ const uint8_t *End = FuncStart + Function->Size;
+ uint32_t Count;
+ decodeULEB128(FuncStart, &Count);
+ FuncStart += Count;
+
+ LLVM_DEBUG(dbgs() << "write func: " << getName() << "\n");
+ Buf += encodeULEB128(CompressedFuncSize, Buf);
+ const uint8_t *LastRelocEnd = FuncStart;
+ for (const WasmRelocation &Rel : Relocations) {
+ unsigned ChunkSize = (SecStart + Rel.Offset) - LastRelocEnd;
+ LLVM_DEBUG(dbgs() << " write chunk: " << ChunkSize << "\n");
+ memcpy(Buf, LastRelocEnd, ChunkSize);
+ Buf += ChunkSize;
+ Buf += writeCompressedReloc(Buf, Rel, File->calcNewValue(Rel));
+ LastRelocEnd = SecStart + Rel.Offset + getRelocWidthPadded(Rel);
+ }
+
+ unsigned ChunkSize = End - LastRelocEnd;
+ LLVM_DEBUG(dbgs() << " write final chunk: " << ChunkSize << "\n");
+ memcpy(Buf, LastRelocEnd, ChunkSize);
+ LLVM_DEBUG(dbgs() << " total: " << (Buf + ChunkSize - Orig) << "\n");
+}
diff --git a/wasm/InputChunks.h b/wasm/InputChunks.h
index 3d6ea23..526e298 100644
--- a/wasm/InputChunks.h
+++ b/wasm/InputChunks.h
@@ -44,19 +44,20 @@
class InputChunk {
public:
- enum Kind { DataSegment, Function, SyntheticFunction };
+ enum Kind { DataSegment, Function, SyntheticFunction, Section };
Kind kind() const { return SectionKind; }
- uint32_t getSize() const { return data().size(); }
+ virtual uint32_t getSize() const { return data().size(); }
void copyRelocations(const WasmSection &Section);
- void writeTo(uint8_t *SectionStart) const;
+ virtual void writeTo(uint8_t *SectionStart) const;
ArrayRef<WasmRelocation> getRelocations() const { return Relocations; }
virtual StringRef getName() const = 0;
+ virtual StringRef getDebugName() const = 0;
virtual uint32_t getComdat() const = 0;
StringRef getComdatName() const;
@@ -77,6 +78,11 @@
virtual ~InputChunk() = default;
virtual ArrayRef<uint8_t> data() const = 0;
virtual uint32_t getInputSectionOffset() const = 0;
+ virtual uint32_t getInputSize() const { return getSize(); };
+
+ // Verifies the existing data at relocation targets matches our expectations.
+ // This is performed only debug builds as an extra sanity check.
+ void verifyRelocTargets() const;
std::vector<WasmRelocation> Relocations;
Kind SectionKind;
@@ -99,6 +105,7 @@
uint32_t getAlignment() const { return Segment.Data.Alignment; }
StringRef getName() const override { return Segment.Data.Name; }
+ StringRef getDebugName() const override { return StringRef(); }
uint32_t getComdat() const override { return Segment.Data.Comdat; }
const OutputSegment *OutputSeg = nullptr;
@@ -125,8 +132,19 @@
C->kind() == InputChunk::SyntheticFunction;
}
- StringRef getName() const override { return Function->Name; }
+ void writeTo(uint8_t *SectionStart) const override;
+ StringRef getName() const override { return Function->SymbolName; }
+ StringRef getDebugName() const override { return Function->DebugName; }
uint32_t getComdat() const override { return Function->Comdat; }
+ uint32_t getFunctionInputOffset() const { return getInputSectionOffset(); }
+ uint32_t getFunctionCodeOffset() const { return Function->CodeOffset; }
+ uint32_t getSize() const override {
+ if (Config->CompressRelocTargets && File) {
+ assert(CompressedSize);
+ return CompressedSize;
+ }
+ return data().size();
+ }
uint32_t getFunctionIndex() const { return FunctionIndex.getValue(); }
bool hasFunctionIndex() const { return FunctionIndex.hasValue(); }
void setFunctionIndex(uint32_t Index);
@@ -134,13 +152,23 @@
bool hasTableIndex() const { return TableIndex.hasValue(); }
void setTableIndex(uint32_t Index);
+ // The size of a given input function can depend on the values of the
+ // LEB relocations within it. This finalizeContents method is called after
+ // all the symbol values have be calcualted but before getSize() is ever
+ // called.
+ void calculateSize();
+
const WasmSignature &Signature;
protected:
ArrayRef<uint8_t> data() const override {
+ assert(!Config->CompressRelocTargets);
return File->CodeSection->Content.slice(getInputSectionOffset(),
Function->Size);
}
+
+ uint32_t getInputSize() const override { return Function->Size; }
+
uint32_t getInputSectionOffset() const override {
return Function->CodeSectionOffset;
}
@@ -148,12 +176,15 @@
const WasmFunction *Function;
llvm::Optional<uint32_t> FunctionIndex;
llvm::Optional<uint32_t> TableIndex;
+ uint32_t CompressedFuncSize = 0;
+ uint32_t CompressedSize = 0;
};
class SyntheticFunction : public InputFunction {
public:
- SyntheticFunction(const WasmSignature &S, StringRef Name)
- : InputFunction(S, nullptr, nullptr), Name(Name) {
+ SyntheticFunction(const WasmSignature &S, StringRef Name,
+ StringRef DebugName = {})
+ : InputFunction(S, nullptr, nullptr), Name(Name), DebugName(DebugName) {
SectionKind = InputChunk::SyntheticFunction;
}
@@ -162,6 +193,7 @@
}
StringRef getName() const override { return Name; }
+ StringRef getDebugName() const override { return DebugName; }
uint32_t getComdat() const override { return UINT32_MAX; }
void setBody(ArrayRef<uint8_t> Body_) { Body = Body_; }
@@ -170,9 +202,32 @@
ArrayRef<uint8_t> data() const override { return Body; }
StringRef Name;
+ StringRef DebugName;
ArrayRef<uint8_t> Body;
};
+// Represents a single Wasm Section within an input file.
+class InputSection : public InputChunk {
+public:
+ InputSection(const WasmSection &S, ObjFile *F)
+ : InputChunk(F, InputChunk::Section), Section(S) {
+ assert(Section.Type == llvm::wasm::WASM_SEC_CUSTOM);
+ }
+
+ StringRef getName() const override { return Section.Name; }
+ StringRef getDebugName() const override { return StringRef(); }
+ uint32_t getComdat() const override { return UINT32_MAX; }
+
+protected:
+ ArrayRef<uint8_t> data() const override { return Section.Content; }
+
+ // Offset within the input section. This is only zero since this chunk
+ // type represents an entire input section, not part of one.
+ uint32_t getInputSectionOffset() const override { return 0; }
+
+ const WasmSection &Section;
+};
+
} // namespace wasm
std::string toString(const wasm::InputChunk *);
diff --git a/wasm/InputFiles.cpp b/wasm/InputFiles.cpp
index e743686..ee9e99b 100644
--- a/wasm/InputFiles.cpp
+++ b/wasm/InputFiles.cpp
@@ -60,6 +60,22 @@
return Symbols[Reloc.Index]->getOutputSymbolIndex();
}
+// Relocations can contain addend for combined sections. This function takes a
+// relocation and returns updated addend by offset in the output section.
+uint32_t ObjFile::calcNewAddend(const WasmRelocation &Reloc) const {
+ switch (Reloc.Type) {
+ case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
+ case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
+ case R_WEBASSEMBLY_MEMORY_ADDR_I32:
+ case R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
+ return Reloc.Addend;
+ case R_WEBASSEMBLY_SECTION_OFFSET_I32:
+ return getSectionSymbol(Reloc.Index)->Section->OutputOffset + Reloc.Addend;
+ default:
+ llvm_unreachable("unexpected relocation type");
+ }
+}
+
// Calculate the value we expect to find at the relocation location.
// This is used as a sanity check before applying a relocation to a given
// location. It is useful for catching bugs in the compiler and linker.
@@ -80,6 +96,14 @@
return Segment.Data.Offset.Value.Int32 + Sym.Info.DataRef.Offset +
Reloc.Addend;
}
+ case R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
+ if (auto *Sym = dyn_cast<DefinedFunction>(getFunctionSymbol(Reloc.Index))) {
+ return Sym->Function->getFunctionInputOffset() +
+ Sym->Function->getFunctionCodeOffset() + Reloc.Addend;
+ }
+ return 0;
+ case R_WEBASSEMBLY_SECTION_OFFSET_I32:
+ return Reloc.Addend;
case R_WEBASSEMBLY_TYPE_INDEX_LEB:
return Reloc.Index;
case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
@@ -102,7 +126,8 @@
case R_WEBASSEMBLY_MEMORY_ADDR_I32:
case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
if (auto *Sym = dyn_cast<DefinedData>(getDataSymbol(Reloc.Index)))
- return Sym->getVirtualAddress() + Reloc.Addend;
+ if (Sym->isLive())
+ return Sym->getVirtualAddress() + Reloc.Addend;
return 0;
case R_WEBASSEMBLY_TYPE_INDEX_LEB:
return TypeMap[Reloc.Index];
@@ -110,6 +135,14 @@
return getFunctionSymbol(Reloc.Index)->getFunctionIndex();
case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
return getGlobalSymbol(Reloc.Index)->getGlobalIndex();
+ case R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
+ if (auto *Sym = dyn_cast<DefinedFunction>(getFunctionSymbol(Reloc.Index))) {
+ return Sym->Function->OutputOffset +
+ Sym->Function->getFunctionCodeOffset() + Reloc.Addend;
+ }
+ return 0;
+ case R_WEBASSEMBLY_SECTION_OFFSET_I32:
+ return getSectionSymbol(Reloc.Index)->Section->OutputOffset + Reloc.Addend;
default:
llvm_unreachable("unknown relocation type");
}
@@ -117,7 +150,7 @@
void ObjFile::parse() {
// Parse a memory buffer as a wasm file.
- DEBUG(dbgs() << "Parsing object: " << toString(this) << "\n");
+ LLVM_DEBUG(dbgs() << "Parsing object: " << toString(this) << "\n");
std::unique_ptr<Binary> Bin = CHECK(createBinary(MB), toString(this));
auto *Obj = dyn_cast<WasmObjectFile>(Bin.get());
@@ -147,12 +180,19 @@
// Find the code and data sections. Wasm objects can have at most one code
// and one data section.
+ uint32_t SectionIndex = 0;
for (const SectionRef &Sec : WasmObj->sections()) {
const WasmSection &Section = WasmObj->getWasmSection(Sec);
- if (Section.Type == WASM_SEC_CODE)
+ if (Section.Type == WASM_SEC_CODE) {
CodeSection = &Section;
- else if (Section.Type == WASM_SEC_DATA)
+ } else if (Section.Type == WASM_SEC_DATA) {
DataSection = &Section;
+ } else if (Section.Type == WASM_SEC_CUSTOM) {
+ CustomSections.emplace_back(make<InputSection>(Section, this));
+ CustomSections.back()->copyRelocations(Section);
+ CustomSectionsByIndex[SectionIndex] = CustomSections.back();
+ }
+ SectionIndex++;
}
TypeMap.resize(getWasmObj()->types().size());
@@ -185,7 +225,7 @@
// Populate `Globals`.
for (const WasmGlobal &G : WasmObj->globals())
- Globals.emplace_back(make<InputGlobal>(G));
+ Globals.emplace_back(make<InputGlobal>(G, this));
// Populate `Symbols` based on the WasmSymbols in the object.
Symbols.reserve(WasmObj->getNumberOfSymbols());
@@ -213,6 +253,10 @@
return cast<GlobalSymbol>(Symbols[Index]);
}
+SectionSymbol *ObjFile::getSectionSymbol(uint32_t Index) const {
+ return cast<SectionSymbol>(Symbols[Index]);
+}
+
DataSymbol *ObjFile::getDataSymbol(uint32_t Index) const {
return cast<DataSymbol>(Symbols[Index]);
}
@@ -251,14 +295,20 @@
return make<DefinedData>(Name, Flags, this, Seg, Offset, Size);
return Symtab->addDefinedData(Name, Flags, this, Seg, Offset, Size);
}
- case WASM_SYMBOL_TYPE_GLOBAL:
+ case WASM_SYMBOL_TYPE_GLOBAL: {
InputGlobal *Global =
Globals[Sym.Info.ElementIndex - WasmObj->getNumImportedGlobals()];
if (Sym.isBindingLocal())
return make<DefinedGlobal>(Name, Flags, this, Global);
return Symtab->addDefinedGlobal(Name, Flags, this, Global);
}
- llvm_unreachable("unkown symbol kind");
+ case WASM_SYMBOL_TYPE_SECTION: {
+ InputSection *Section = CustomSectionsByIndex[Sym.Info.ElementIndex];
+ assert(Sym.isBindingLocal());
+ return make<SectionSymbol>(Name, Flags, Section, this);
+ }
+ }
+ llvm_unreachable("unknown symbol kind");
}
Symbol *ObjFile::createUndefined(const WasmSymbol &Sym) {
@@ -272,13 +322,15 @@
return Symtab->addUndefinedData(Name, Flags, this);
case WASM_SYMBOL_TYPE_GLOBAL:
return Symtab->addUndefinedGlobal(Name, Flags, this, Sym.GlobalType);
+ case WASM_SYMBOL_TYPE_SECTION:
+ llvm_unreachable("section symbols cannot be undefined");
}
- llvm_unreachable("unkown symbol kind");
+ llvm_unreachable("unknown symbol kind");
}
void ArchiveFile::parse() {
// Parse a MemoryBufferRef as an archive file.
- DEBUG(dbgs() << "Parsing library: " << toString(this) << "\n");
+ LLVM_DEBUG(dbgs() << "Parsing library: " << toString(this) << "\n");
File = CHECK(Archive::create(MB), toString(this));
// Read the symbol table to construct Lazy symbols.
@@ -287,7 +339,7 @@
Symtab->addLazy(this, &Sym);
++Count;
}
- DEBUG(dbgs() << "Read " << Count << " symbols\n");
+ LLVM_DEBUG(dbgs() << "Read " << Count << " symbols\n");
}
void ArchiveFile::addMember(const Archive::Symbol *Sym) {
@@ -300,8 +352,8 @@
if (!Seen.insert(C.getChildOffset()).second)
return;
- DEBUG(dbgs() << "loading lazy: " << Sym->getName() << "\n");
- DEBUG(dbgs() << "from archive: " << toString(this) << "\n");
+ LLVM_DEBUG(dbgs() << "loading lazy: " << Sym->getName() << "\n");
+ LLVM_DEBUG(dbgs() << "from archive: " << toString(this) << "\n");
MemoryBufferRef MB =
CHECK(C.getMemoryBufferRef(),
@@ -318,6 +370,48 @@
Symtab->addFile(Obj);
}
+static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) {
+ switch (GvVisibility) {
+ case GlobalValue::DefaultVisibility:
+ return WASM_SYMBOL_VISIBILITY_DEFAULT;
+ case GlobalValue::HiddenVisibility:
+ case GlobalValue::ProtectedVisibility:
+ return WASM_SYMBOL_VISIBILITY_HIDDEN;
+ }
+ llvm_unreachable("unknown visibility");
+}
+
+static Symbol *createBitcodeSymbol(const lto::InputFile::Symbol &ObjSym,
+ BitcodeFile &F) {
+ StringRef Name = Saver.save(ObjSym.getName());
+
+ uint32_t Flags = ObjSym.isWeak() ? WASM_SYMBOL_BINDING_WEAK : 0;
+ Flags |= mapVisibility(ObjSym.getVisibility());
+
+ if (ObjSym.isUndefined()) {
+ if (ObjSym.isExecutable())
+ return Symtab->addUndefinedFunction(Name, Flags, &F, nullptr);
+ return Symtab->addUndefinedData(Name, Flags, &F);
+ }
+
+ if (ObjSym.isExecutable())
+ return Symtab->addDefinedFunction(Name, Flags, &F, nullptr);
+ return Symtab->addDefinedData(Name, Flags, &F, nullptr, 0, 0);
+}
+
+void BitcodeFile::parse() {
+ Obj = check(lto::InputFile::create(MemoryBufferRef(
+ MB.getBuffer(), Saver.save(ParentName + MB.getBufferIdentifier()))));
+ Triple T(Obj->getTargetTriple());
+ if (T.getArch() != Triple::wasm32) {
+ error(toString(MB.getBufferIdentifier()) + ": machine type must be wasm32");
+ return;
+ }
+
+ for (const lto::InputFile::Symbol &ObjSym : Obj->symbols())
+ Symbols.push_back(createBitcodeSymbol(ObjSym, *this));
+}
+
// Returns a string in the format of "foo.o" or "foo.a(bar.o)".
std::string lld::toString(const wasm::InputFile *File) {
if (!File)
diff --git a/wasm/InputFiles.h b/wasm/InputFiles.h
index f0fd267..75d20e6 100644
--- a/wasm/InputFiles.h
+++ b/wasm/InputFiles.h
@@ -14,6 +14,7 @@
#include "lld/Common/LLVM.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/LTO/LTO.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/Wasm.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -28,6 +29,12 @@
using llvm::wasm::WasmRelocation;
using llvm::wasm::WasmSignature;
+namespace llvm {
+namespace lto {
+class InputFile;
+}
+} // namespace llvm
+
namespace lld {
namespace wasm {
@@ -35,12 +42,14 @@
class InputFunction;
class InputSegment;
class InputGlobal;
+class InputSection;
class InputFile {
public:
enum Kind {
ObjectKind,
ArchiveKind,
+ BitcodeKind,
};
virtual ~InputFile() {}
@@ -56,10 +65,15 @@
// An archive file name if this file is created from an archive.
StringRef ParentName;
+ ArrayRef<Symbol *> getSymbols() const { return Symbols; }
+
protected:
InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
MemoryBufferRef MB;
+ // List of all symbols referenced or defined by this file.
+ std::vector<Symbol *> Symbols;
+
private:
const Kind FileKind;
};
@@ -94,6 +108,7 @@
uint32_t calcNewIndex(const WasmRelocation &Reloc) const;
uint32_t calcNewValue(const WasmRelocation &Reloc) const;
+ uint32_t calcNewAddend(const WasmRelocation &Reloc) const;
uint32_t calcExpectedValue(const WasmRelocation &Reloc) const;
const WasmSection *CodeSection = nullptr;
@@ -108,12 +123,14 @@
std::vector<InputSegment *> Segments;
std::vector<InputFunction *> Functions;
std::vector<InputGlobal *> Globals;
+ std::vector<InputSection *> CustomSections;
+ llvm::DenseMap<uint32_t, InputSection *> CustomSectionsByIndex;
- ArrayRef<Symbol *> getSymbols() const { return Symbols; }
Symbol *getSymbol(uint32_t Index) const { return Symbols[Index]; }
FunctionSymbol *getFunctionSymbol(uint32_t Index) const;
DataSymbol *getDataSymbol(uint32_t Index) const;
GlobalSymbol *getGlobalSymbol(uint32_t Index) const;
+ SectionSymbol *getSectionSymbol(uint32_t Index) const;
private:
Symbol *createDefined(const WasmSymbol &Sym);
@@ -121,12 +138,18 @@
bool isExcludedByComdat(InputChunk *Chunk) const;
- // List of all symbols referenced or defined by this file.
- std::vector<Symbol *> Symbols;
-
std::unique_ptr<WasmObjectFile> WasmObj;
};
+class BitcodeFile : public InputFile {
+public:
+ explicit BitcodeFile(MemoryBufferRef M) : InputFile(BitcodeKind, M) {}
+ static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
+
+ void parse() override;
+ std::unique_ptr<llvm::lto::InputFile> Obj;
+};
+
// Opens a given file.
llvm::Optional<MemoryBufferRef> readFile(StringRef Path);
diff --git a/wasm/InputGlobal.h b/wasm/InputGlobal.h
index 16a6b7d..37d0ab9 100644
--- a/wasm/InputGlobal.h
+++ b/wasm/InputGlobal.h
@@ -26,8 +26,10 @@
// combined to form the final GLOBALS section.
class InputGlobal {
public:
- InputGlobal(const WasmGlobal &G) : Global(G) {}
+ InputGlobal(const WasmGlobal &G, ObjFile *F)
+ : File(F), Global(G), Live(!Config->GcSections) {}
+ StringRef getName() const { return Global.SymbolName; }
const WasmGlobalType &getType() const { return Global.Type; }
uint32_t getGlobalIndex() const { return GlobalIndex.getValue(); }
@@ -37,16 +39,21 @@
GlobalIndex = Index;
}
- bool Live = false;
-
+ ObjFile *File;
WasmGlobal Global;
+ bool Live = false;
+
protected:
llvm::Optional<uint32_t> GlobalIndex;
};
} // namespace wasm
+inline std::string toString(const wasm::InputGlobal *G) {
+ return (toString(G->File) + ":(" + G->getName() + ")").str();
+}
+
} // namespace lld
#endif // LLD_WASM_INPUT_GLOBAL_H
diff --git a/wasm/LTO.cpp b/wasm/LTO.cpp
new file mode 100644
index 0000000..58f32aa
--- /dev/null
+++ b/wasm/LTO.cpp
@@ -0,0 +1,151 @@
+//===- LTO.cpp ------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LTO.h"
+#include "Config.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Strings.h"
+#include "lld/Common/TargetOptionsCommandFlags.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/LTO/Caching.h"
+#include "llvm/LTO/Config.h"
+#include "llvm/LTO/LTO.h"
+#include "llvm/Object/SymbolicFile.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::object;
+
+using namespace lld;
+using namespace lld::wasm;
+
+static std::unique_ptr<lto::LTO> createLTO() {
+ lto::Config C;
+ C.Options = InitTargetOptionsFromCodeGenFlags();
+
+ // Always emit a section per function/datum with LTO.
+ C.Options.FunctionSections = true;
+ C.Options.DataSections = true;
+
+ C.DisableVerify = Config->DisableVerify;
+ C.DiagHandler = diagnosticHandler;
+ C.OptLevel = Config->LTOO;
+
+ if (Config->SaveTemps)
+ checkError(C.addSaveTemps(Config->OutputFile.str() + ".",
+ /*UseInputModulePath*/ true));
+
+ lto::ThinBackend Backend;
+ if (Config->ThinLTOJobs != -1U)
+ Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs);
+ return llvm::make_unique<lto::LTO>(std::move(C), Backend,
+ Config->LTOPartitions);
+}
+
+BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {}
+
+BitcodeCompiler::~BitcodeCompiler() = default;
+
+static void undefine(Symbol *S) {
+ if (isa<DefinedFunction>(S))
+ replaceSymbol<UndefinedFunction>(S, S->getName(), 0);
+ else if (isa<DefinedData>(S))
+ replaceSymbol<UndefinedData>(S, S->getName(), 0);
+ else
+ llvm_unreachable("unexpected symbol kind");
+}
+
+void BitcodeCompiler::add(BitcodeFile &F) {
+ lto::InputFile &Obj = *F.Obj;
+ unsigned SymNum = 0;
+ ArrayRef<Symbol *> Syms = F.getSymbols();
+ std::vector<lto::SymbolResolution> Resols(Syms.size());
+
+ // Provide a resolution to the LTO API for each symbol.
+ for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) {
+ Symbol *Sym = Syms[SymNum];
+ lto::SymbolResolution &R = Resols[SymNum];
+ ++SymNum;
+
+ // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
+ // reports two symbols for module ASM defined. Without this check, lld
+ // flags an undefined in IR with a definition in ASM as prevailing.
+ // Once IRObjectFile is fixed to report only one symbol this hack can
+ // be removed.
+ R.Prevailing = !ObjSym.isUndefined() && Sym->getFile() == &F;
+ R.VisibleToRegularObj = Config->Relocatable || Sym->IsUsedInRegularObj;
+ if (R.Prevailing)
+ undefine(Sym);
+ }
+ checkError(LTOObj->add(std::move(F.Obj), Resols));
+}
+
+// Merge all the bitcode files we have seen, codegen the result
+// and return the resulting objects.
+std::vector<StringRef> BitcodeCompiler::compile() {
+ unsigned MaxTasks = LTOObj->getMaxTasks();
+ Buf.resize(MaxTasks);
+ Files.resize(MaxTasks);
+
+ // The --thinlto-cache-dir option specifies the path to a directory in which
+ // to cache native object files for ThinLTO incremental builds. If a path was
+ // specified, configure LTO to use it as the cache directory.
+ lto::NativeObjectCache Cache;
+ if (!Config->ThinLTOCacheDir.empty())
+ Cache = check(
+ lto::localCache(Config->ThinLTOCacheDir,
+ [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
+ Files[Task] = std::move(MB);
+ }));
+
+ checkError(LTOObj->run(
+ [&](size_t Task) {
+ return llvm::make_unique<lto::NativeObjectStream>(
+ llvm::make_unique<raw_svector_ostream>(Buf[Task]));
+ },
+ Cache));
+
+ if (!Config->ThinLTOCacheDir.empty())
+ pruneCache(Config->ThinLTOCacheDir, Config->ThinLTOCachePolicy);
+
+ std::vector<StringRef> Ret;
+ for (unsigned I = 0; I != MaxTasks; ++I) {
+ if (Buf[I].empty())
+ continue;
+ if (Config->SaveTemps) {
+ if (I == 0)
+ saveBuffer(Buf[I], Config->OutputFile + ".lto.o");
+ else
+ saveBuffer(Buf[I], Config->OutputFile + Twine(I) + ".lto.o");
+ }
+ Ret.emplace_back(Buf[I].data(), Buf[I].size());
+ }
+
+ for (std::unique_ptr<MemoryBuffer> &File : Files)
+ if (File)
+ Ret.push_back(File->getBuffer());
+
+ return Ret;
+}
diff --git a/wasm/LTO.h b/wasm/LTO.h
new file mode 100644
index 0000000..cf726de
--- /dev/null
+++ b/wasm/LTO.h
@@ -0,0 +1,57 @@
+//===- LTO.h ----------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides a way to combine bitcode files into one wasm
+// file by compiling them using LLVM.
+//
+// If LTO is in use, your input files are not in regular wasm files
+// but instead LLVM bitcode files. In that case, the linker has to
+// convert bitcode files into the native format so that we can create
+// a wasm file that contains native code. This file provides that
+// functionality.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_WASM_LTO_H
+#define LLD_WASM_LTO_H
+
+#include "lld/Common/LLVM.h"
+#include "llvm/ADT/SmallString.h"
+#include <memory>
+#include <vector>
+
+namespace llvm {
+namespace lto {
+class LTO;
+}
+} // namespace llvm
+
+namespace lld {
+namespace wasm {
+
+class BitcodeFile;
+class InputFile;
+
+class BitcodeCompiler {
+public:
+ BitcodeCompiler();
+ ~BitcodeCompiler();
+
+ void add(BitcodeFile &F);
+ std::vector<StringRef> compile();
+
+private:
+ std::unique_ptr<llvm::lto::LTO> LTOObj;
+ std::vector<SmallString<0>> Buf;
+ std::vector<std::unique_ptr<MemoryBuffer>> Files;
+};
+} // namespace wasm
+} // namespace lld
+
+#endif
diff --git a/wasm/MarkLive.cpp b/wasm/MarkLive.cpp
index 9b72697..7c4670d 100644
--- a/wasm/MarkLive.cpp
+++ b/wasm/MarkLive.cpp
@@ -22,6 +22,7 @@
#include "MarkLive.h"
#include "Config.h"
#include "InputChunks.h"
+#include "InputGlobal.h"
#include "SymbolTable.h"
#include "Symbols.h"
@@ -36,17 +37,15 @@
if (!Config->GcSections)
return;
- DEBUG(dbgs() << "markLive\n");
+ LLVM_DEBUG(dbgs() << "markLive\n");
SmallVector<InputChunk *, 256> Q;
auto Enqueue = [&](Symbol *Sym) {
- if (!Sym)
+ if (!Sym || Sym->isLive())
return;
- InputChunk *Chunk = Sym->getChunk();
- if (!Chunk || Chunk->Live)
- return;
- Chunk->Live = true;
- Q.push_back(Chunk);
+ Sym->markLive();
+ if (InputChunk *Chunk = Sym->getChunk())
+ Q.push_back(Chunk);
};
// Add GC root symbols.
@@ -104,6 +103,15 @@
for (InputChunk *C : Obj->Segments)
if (!C->Live)
message("removing unused section " + toString(C));
+ for (InputGlobal *G : Obj->Globals)
+ if (!G->Live)
+ message("removing unused section " + toString(G));
}
+ for (InputChunk *C : Symtab->SyntheticFunctions)
+ if (!C->Live)
+ message("removing unused section " + toString(C));
+ for (InputGlobal *G : Symtab->SyntheticGlobals)
+ if (!G->Live)
+ message("removing unused section " + toString(G));
}
}
diff --git a/wasm/Options.td b/wasm/Options.td
index a68e350..4dbed35 100644
--- a/wasm/Options.td
+++ b/wasm/Options.td
@@ -21,7 +21,7 @@
HelpText<"Use colors in diagnostics">;
def color_diagnostics_eq: J<"color-diagnostics=">,
- HelpText<"Use colors in diagnostics">;
+ HelpText<"Use colors in diagnostics; one of 'always', 'never', 'auto'">;
defm demangle: B<"demangle",
"Demangle symbol names",
@@ -40,6 +40,10 @@
"Enable garbage collection of unused sections",
"Disable garbage collection of unused sections">;
+defm merge_data_segments: B<"merge-data-segments",
+ "Enable merging data segments",
+ "Disable merging data segments">;
+
def help: F<"help">, HelpText<"Print option help">;
def l: JoinedOrSeparate<["-"], "l">, MetaVarName<"<libName>">,
@@ -61,6 +65,8 @@
def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">,
HelpText<"Path to file to write output">;
+def O: JoinedOrSeparate<["-"], "O">, HelpText<"Optimize output file size">;
+
defm print_gc_sections: B<"print-gc-sections",
"List removed unused sections",
"Do not list removed unused sections">;
@@ -96,10 +102,6 @@
def allow_undefined_file_s: Separate<["-"], "allow-undefined-file">,
Alias<allow_undefined_file>;
-defm check_signatures: B<"check-signatures",
- "Check function signatures",
- "Don't check function signatures">;
-
defm export: Eq<"export">,
HelpText<"Force a symbol to be exported">;
@@ -124,6 +126,9 @@
def no_entry: F<"no-entry">,
HelpText<"Do not output any entry point">;
+def stack_first: F<"stack-first">,
+ HelpText<"Place stack at start of linear memory rather than after data">;
+
// Aliases
def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>;
def alias_entry_entry: J<"entry=">, Alias<entry>;
@@ -131,3 +136,16 @@
def alias_max_memory_m: Flag<["-"], "m">, Alias<max_memory>;
def alias_relocatable_r: Flag<["-"], "r">, Alias<relocatable>;
def alias_undefined_u: JoinedOrSeparate<["-"], "u">, Alias<undefined>;
+
+// LTO-related options.
+def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">,
+ HelpText<"Optimization level for LTO">;
+def lto_partitions: J<"lto-partitions=">,
+ HelpText<"Number of LTO codegen partitions">;
+def disable_verify: F<"disable-verify">;
+def save_temps: F<"save-temps">;
+def thinlto_cache_dir: J<"thinlto-cache-dir=">,
+ HelpText<"Path to ThinLTO cached object file directory">;
+defm thinlto_cache_policy: Eq<"thinlto-cache-policy">,
+ HelpText<"Pruning policy for the ThinLTO cache">;
+def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">;
diff --git a/wasm/OutputSections.cpp b/wasm/OutputSections.cpp
index 9683a2d..256a988 100644
--- a/wasm/OutputSections.cpp
+++ b/wasm/OutputSections.cpp
@@ -85,8 +85,9 @@
OS.flush();
BodySize = CodeSectionHeader.size();
- for (InputChunk *Func : Functions) {
+ for (InputFunction *Func : Functions) {
Func->OutputOffset = BodySize;
+ Func->calculateSize();
BodySize += Func->getSize();
}
@@ -140,12 +141,13 @@
writeUleb128(OS, WASM_OPCODE_END, "opcode:end");
writeUleb128(OS, Segment->Size, "segment size");
OS.flush();
- Segment->setSectionOffset(BodySize);
+
+ Segment->SectionOffset = BodySize;
BodySize += Segment->Header.size() + Segment->Size;
log("Data segment: size=" + Twine(Segment->Size));
+
for (InputSegment *InputSeg : Segment->InputSegments)
- InputSeg->OutputOffset = Segment->getSectionOffset() +
- Segment->Header.size() +
+ InputSeg->OutputOffset = Segment->SectionOffset + Segment->Header.size() +
InputSeg->OutputSegmentOffset;
}
@@ -166,7 +168,7 @@
parallelForEach(Segments, [&](const OutputSegment *Segment) {
// Write data segment header
- uint8_t *SegStart = Buf + Segment->getSectionOffset();
+ uint8_t *SegStart = Buf + Segment->SectionOffset;
memcpy(SegStart, Segment->Header.data(), Segment->Header.size());
// Write segment data payload
@@ -188,3 +190,50 @@
for (const InputChunk *C : Seg->InputSegments)
C->writeRelocations(OS);
}
+
+CustomSection::CustomSection(std::string Name,
+ ArrayRef<InputSection *> InputSections)
+ : OutputSection(WASM_SEC_CUSTOM, Name), PayloadSize(0),
+ InputSections(InputSections) {
+ raw_string_ostream OS(NameData);
+ encodeULEB128(Name.size(), OS);
+ OS << Name;
+ OS.flush();
+
+ for (InputSection *Section : InputSections) {
+ Section->OutputOffset = PayloadSize;
+ PayloadSize += Section->getSize();
+ }
+
+ createHeader(PayloadSize + NameData.size());
+}
+
+void CustomSection::writeTo(uint8_t *Buf) {
+ log("writing " + toString(*this) + " size=" + Twine(getSize()) +
+ " chunks=" + Twine(InputSections.size()));
+
+ assert(Offset);
+ Buf += Offset;
+
+ // Write section header
+ memcpy(Buf, Header.data(), Header.size());
+ Buf += Header.size();
+ memcpy(Buf, NameData.data(), NameData.size());
+ Buf += NameData.size();
+
+ // Write custom sections payload
+ parallelForEach(InputSections,
+ [&](const InputSection *Section) { Section->writeTo(Buf); });
+}
+
+uint32_t CustomSection::numRelocations() const {
+ uint32_t Count = 0;
+ for (const InputSection *InputSect : InputSections)
+ Count += InputSect->NumRelocations();
+ return Count;
+}
+
+void CustomSection::writeRelocations(raw_ostream &OS) const {
+ for (const InputSection *S : InputSections)
+ S->writeRelocations(OS);
+}
diff --git a/wasm/OutputSections.h b/wasm/OutputSections.h
index 2ecee95..189d650 100644
--- a/wasm/OutputSections.h
+++ b/wasm/OutputSections.h
@@ -113,6 +113,29 @@
size_t BodySize = 0;
};
+// Represents a custom section in the output file. Wasm custom sections are
+// used for storing user-defined metadata. Unlike the core sections types
+// they are identified by their string name.
+// The linker combines custom sections that have the same name by simply
+// concatenating them.
+// Note that some custom sections such as "name" and "linking" are handled
+// separately and are instead synthesized by the linker.
+class CustomSection : public OutputSection {
+public:
+ CustomSection(std::string Name, ArrayRef<InputSection *> InputSections);
+ size_t getSize() const override {
+ return Header.size() + NameData.size() + PayloadSize;
+ }
+ void writeTo(uint8_t *Buf) override;
+ uint32_t numRelocations() const override;
+ void writeRelocations(raw_ostream &OS) const override;
+
+protected:
+ size_t PayloadSize;
+ ArrayRef<InputSection *> InputSections;
+ std::string NameData;
+};
+
} // namespace wasm
} // namespace lld
diff --git a/wasm/OutputSegment.h b/wasm/OutputSegment.h
index 7973013..d5c89cd 100644
--- a/wasm/OutputSegment.h
+++ b/wasm/OutputSegment.h
@@ -32,12 +32,9 @@
Size += InSeg->getSize();
}
- uint32_t getSectionOffset() const { return SectionOffset; }
-
- void setSectionOffset(uint32_t Offset) { SectionOffset = Offset; }
-
StringRef Name;
const uint32_t Index;
+ uint32_t SectionOffset = 0;
uint32_t Alignment = 0;
uint32_t StartVA = 0;
std::vector<InputSegment *> InputSegments;
@@ -47,9 +44,6 @@
// Segment header
std::string Header;
-
-private:
- uint32_t SectionOffset = 0;
};
} // namespace wasm
diff --git a/wasm/SymbolTable.cpp b/wasm/SymbolTable.cpp
index 153b507..6cc7c36 100644
--- a/wasm/SymbolTable.cpp
+++ b/wasm/SymbolTable.cpp
@@ -29,17 +29,46 @@
log("Processing: " + toString(File));
File->parse();
- if (auto *F = dyn_cast<ObjFile>(File))
+ // LLVM bitcode file
+ if (auto *F = dyn_cast<BitcodeFile>(File))
+ BitcodeFiles.push_back(F);
+ else if (auto *F = dyn_cast<ObjFile>(File))
ObjectFiles.push_back(F);
}
+// This function is where all the optimizations of link-time
+// optimization happens. When LTO is in use, some input files are
+// not in native object file format but in the LLVM bitcode format.
+// This function compiles bitcode files into a few big native files
+// using LLVM functions and replaces bitcode symbols with the results.
+// Because all bitcode files that the program consists of are passed
+// to the compiler at once, it can do whole-program optimization.
+void SymbolTable::addCombinedLTOObject() {
+ if (BitcodeFiles.empty())
+ return;
+
+ // Compile bitcode files and replace bitcode symbols.
+ LTO.reset(new BitcodeCompiler);
+ for (BitcodeFile *F : BitcodeFiles)
+ LTO->add(*F);
+
+ for (StringRef Filename : LTO->compile()) {
+ auto *Obj = make<ObjFile>(MemoryBufferRef(Filename, "lto.tmp"));
+ Obj->parse();
+ ObjectFiles.push_back(Obj);
+ }
+}
+
void SymbolTable::reportRemainingUndefines() {
SetVector<Symbol *> Undefs;
for (Symbol *Sym : SymVector) {
- if (Sym->isUndefined() && !Sym->isWeak() &&
- Config->AllowUndefinedSymbols.count(Sym->getName()) == 0) {
- Undefs.insert(Sym);
- }
+ if (!Sym->isUndefined() || Sym->isWeak())
+ continue;
+ if (Config->AllowUndefinedSymbols.count(Sym->getName()) != 0)
+ continue;
+ if (!Sym->IsUsedInRegularObj)
+ continue;
+ Undefs.insert(Sym);
}
if (Undefs.empty())
@@ -64,35 +93,33 @@
if (Sym)
return {Sym, false};
Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
+ Sym->IsUsedInRegularObj = false;
SymVector.emplace_back(Sym);
return {Sym, true};
}
static void reportTypeError(const Symbol *Existing, const InputFile *File,
- StringRef Type) {
+ llvm::wasm::WasmSymbolType Type) {
error("symbol type mismatch: " + toString(*Existing) + "\n>>> defined as " +
toString(Existing->getWasmType()) + " in " +
- toString(Existing->getFile()) + "\n>>> defined as " + Type + " in " +
- toString(File));
+ toString(Existing->getFile()) + "\n>>> defined as " + toString(Type) +
+ " in " + toString(File));
}
static void checkFunctionType(const Symbol *Existing, const InputFile *File,
const WasmSignature *NewSig) {
- if (!isa<FunctionSymbol>(Existing)) {
- reportTypeError(Existing, File, "Function");
+ auto ExistingFunction = dyn_cast<FunctionSymbol>(Existing);
+ if (!ExistingFunction) {
+ reportTypeError(Existing, File, WASM_SYMBOL_TYPE_FUNCTION);
return;
}
- if (!Config->CheckSignatures)
- return;
-
- const WasmSignature *OldSig =
- cast<FunctionSymbol>(Existing)->getFunctionType();
- if (OldSig && *NewSig != *OldSig) {
- error("Function type mismatch: " + Existing->getName() +
- "\n>>> defined as " + toString(*OldSig) + " in " +
- toString(Existing->getFile()) + "\n>>> defined as " +
- toString(*NewSig) + " in " + toString(File));
+ const WasmSignature *OldSig = ExistingFunction->getFunctionType();
+ if (OldSig && NewSig && *NewSig != *OldSig) {
+ warn("Function type mismatch: " + Existing->getName() +
+ "\n>>> defined as " + toString(*OldSig) + " in " +
+ toString(Existing->getFile()) + "\n>>> defined as " +
+ toString(*NewSig) + " in " + toString(File));
}
}
@@ -101,7 +128,7 @@
static void checkGlobalType(const Symbol *Existing, const InputFile *File,
const WasmGlobalType *NewType) {
if (!isa<GlobalSymbol>(Existing)) {
- reportTypeError(Existing, File, "Global");
+ reportTypeError(Existing, File, WASM_SYMBOL_TYPE_GLOBAL);
return;
}
@@ -115,13 +142,13 @@
static void checkDataType(const Symbol *Existing, const InputFile *File) {
if (!isa<DataSymbol>(Existing))
- reportTypeError(Existing, File, "Data");
+ reportTypeError(Existing, File, WASM_SYMBOL_TYPE_DATA);
}
DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name,
uint32_t Flags,
InputFunction *Function) {
- DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n");
+ LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n");
assert(!find(Name));
SyntheticFunctions.emplace_back(Function);
return replaceSymbol<DefinedFunction>(insert(Name).first, Name, Flags,
@@ -130,14 +157,15 @@
DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name,
uint32_t Flags) {
- DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n");
+ LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n");
assert(!find(Name));
return replaceSymbol<DefinedData>(insert(Name).first, Name, Flags);
}
DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags,
InputGlobal *Global) {
- DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global << "\n");
+ LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global
+ << "\n");
assert(!find(Name));
SyntheticGlobals.emplace_back(Global);
return replaceSymbol<DefinedGlobal>(insert(Name).first, Name, Flags, nullptr,
@@ -148,20 +176,20 @@
uint32_t NewFlags) {
// If existing symbol is undefined, replace it.
if (!Existing->isDefined()) {
- DEBUG(dbgs() << "resolving existing undefined symbol: "
- << Existing->getName() << "\n");
+ LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: "
+ << Existing->getName() << "\n");
return true;
}
// Now we have two defined symbols. If the new one is weak, we can ignore it.
if ((NewFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
- DEBUG(dbgs() << "existing symbol takes precedence\n");
+ LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n");
return false;
}
// If the existing symbol is weak, we should replace it.
if (Existing->isWeak()) {
- DEBUG(dbgs() << "replacing existing weak symbol\n");
+ LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n");
return true;
}
@@ -175,17 +203,21 @@
Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
InputFile *File,
InputFunction *Function) {
- DEBUG(dbgs() << "addDefinedFunction: " << Name << "\n");
+ LLVM_DEBUG(dbgs() << "addDefinedFunction: " << Name << "\n");
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
+ if (!File || File->kind() == InputFile::ObjectKind)
+ S->IsUsedInRegularObj = true;
+
if (WasInserted || S->isLazy()) {
replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
return S;
}
- checkFunctionType(S, File, &Function->Signature);
+ if (Function)
+ checkFunctionType(S, File, &Function->Signature);
if (shouldReplace(S, File, Flags))
replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
@@ -195,11 +227,15 @@
Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags,
InputFile *File, InputSegment *Segment,
uint32_t Address, uint32_t Size) {
- DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address << "\n");
+ LLVM_DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address
+ << "\n");
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
+ if (!File || File->kind() == InputFile::ObjectKind)
+ S->IsUsedInRegularObj = true;
+
if (WasInserted || S->isLazy()) {
replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
return S;
@@ -214,11 +250,14 @@
Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags,
InputFile *File, InputGlobal *Global) {
- DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n");
+ LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n");
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
+ if (!File || File->kind() == InputFile::ObjectKind)
+ S->IsUsedInRegularObj = true;
+
if (WasInserted || S->isLazy()) {
replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
return S;
@@ -234,12 +273,15 @@
Symbol *SymbolTable::addUndefinedFunction(StringRef Name, uint32_t Flags,
InputFile *File,
const WasmSignature *Sig) {
- DEBUG(dbgs() << "addUndefinedFunction: " << Name << "\n");
+ LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name << "\n");
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
+ if (!File || File->kind() == InputFile::ObjectKind)
+ S->IsUsedInRegularObj = true;
+
if (WasInserted)
replaceSymbol<UndefinedFunction>(S, Name, Flags, File, Sig);
else if (auto *Lazy = dyn_cast<LazySymbol>(S))
@@ -251,7 +293,7 @@
Symbol *SymbolTable::addUndefinedData(StringRef Name, uint32_t Flags,
InputFile *File) {
- DEBUG(dbgs() << "addUndefinedData: " << Name << "\n");
+ LLVM_DEBUG(dbgs() << "addUndefinedData: " << Name << "\n");
Symbol *S;
bool WasInserted;
@@ -269,12 +311,15 @@
Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, uint32_t Flags,
InputFile *File,
const WasmGlobalType *Type) {
- DEBUG(dbgs() << "addUndefinedGlobal: " << Name << "\n");
+ LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << Name << "\n");
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
+ if (!File || File->kind() == InputFile::ObjectKind)
+ S->IsUsedInRegularObj = true;
+
if (WasInserted)
replaceSymbol<UndefinedGlobal>(S, Name, Flags, File, Type);
else if (auto *Lazy = dyn_cast<LazySymbol>(S))
@@ -285,7 +330,7 @@
}
void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) {
- DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n");
+ LLVM_DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n");
StringRef Name = Sym->getName();
Symbol *S;
@@ -299,7 +344,7 @@
// If there is an existing undefined symbol, load a new one from the archive.
if (S->isUndefined()) {
- DEBUG(dbgs() << "replacing existing undefined\n");
+ LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
File->addMember(Sym);
}
}
diff --git a/wasm/SymbolTable.h b/wasm/SymbolTable.h
index 6fb5c15..26242e6 100644
--- a/wasm/SymbolTable.h
+++ b/wasm/SymbolTable.h
@@ -11,6 +11,7 @@
#define LLD_WASM_SYMBOL_TABLE_H
#include "InputFiles.h"
+#include "LTO.h"
#include "Symbols.h"
#include "llvm/ADT/CachedHashString.h"
#include "llvm/ADT/DenseSet.h"
@@ -39,8 +40,10 @@
class SymbolTable {
public:
void addFile(InputFile *File);
+ void addCombinedLTOObject();
std::vector<ObjFile *> ObjectFiles;
+ std::vector<BitcodeFile *> BitcodeFiles;
std::vector<InputFunction *> SyntheticFunctions;
std::vector<InputGlobal *> SyntheticGlobals;
@@ -80,6 +83,9 @@
std::vector<Symbol *> SymVector;
llvm::DenseSet<llvm::CachedHashStringRef> Comdats;
+
+ // For LTO.
+ std::unique_ptr<BitcodeCompiler> LTO;
};
extern SymbolTable *Symtab;
diff --git a/wasm/Symbols.cpp b/wasm/Symbols.cpp
index bcebcdc..6b43eb3 100644
--- a/wasm/Symbols.cpp
+++ b/wasm/Symbols.cpp
@@ -31,11 +31,13 @@
WasmSymbolType Symbol::getWasmType() const {
if (isa<FunctionSymbol>(this))
- return llvm::wasm::WASM_SYMBOL_TYPE_FUNCTION;
+ return WASM_SYMBOL_TYPE_FUNCTION;
if (isa<DataSymbol>(this))
- return llvm::wasm::WASM_SYMBOL_TYPE_DATA;
+ return WASM_SYMBOL_TYPE_DATA;
if (isa<GlobalSymbol>(this))
- return llvm::wasm::WASM_SYMBOL_TYPE_GLOBAL;
+ return WASM_SYMBOL_TYPE_GLOBAL;
+ if (isa<SectionSymbol>(this))
+ return WASM_SYMBOL_TYPE_SECTION;
llvm_unreachable("invalid symbol kind");
}
@@ -52,8 +54,15 @@
return G->Global->Live;
if (InputChunk *C = getChunk())
return C->Live;
- // Assume any other kind of symbol is live.
- return true;
+ return Referenced;
+}
+
+void Symbol::markLive() {
+ if (auto *G = dyn_cast<DefinedGlobal>(this))
+ G->Global->Live = true;
+ if (InputChunk *C = getChunk())
+ C->Live = true;
+ Referenced = true;
}
uint32_t Symbol::getOutputSymbolIndex() const {
@@ -62,7 +71,8 @@
}
void Symbol::setOutputSymbolIndex(uint32_t Index) {
- DEBUG(dbgs() << "setOutputSymbolIndex " << Name << " -> " << Index << "\n");
+ LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << Name << " -> " << Index
+ << "\n");
assert(OutputSymbolIndex == INVALID_INDEX);
OutputSymbolIndex = Index;
}
@@ -80,7 +90,7 @@
}
void Symbol::setHidden(bool IsHidden) {
- DEBUG(dbgs() << "setHidden: " << Name << " -> " << IsHidden << "\n");
+ LLVM_DEBUG(dbgs() << "setHidden: " << Name << " -> " << IsHidden << "\n");
Flags &= ~WASM_SYMBOL_VISIBILITY_MASK;
if (IsHidden)
Flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
@@ -96,7 +106,7 @@
}
void FunctionSymbol::setFunctionIndex(uint32_t Index) {
- DEBUG(dbgs() << "setFunctionIndex " << Name << " -> " << Index << "\n");
+ LLVM_DEBUG(dbgs() << "setFunctionIndex " << Name << " -> " << Index << "\n");
assert(FunctionIndex == INVALID_INDEX);
FunctionIndex = Index;
}
@@ -128,7 +138,7 @@
F->Function->setTableIndex(Index);
return;
}
- DEBUG(dbgs() << "setTableIndex " << Name << " -> " << Index << "\n");
+ LLVM_DEBUG(dbgs() << "setTableIndex " << Name << " -> " << Index << "\n");
assert(TableIndex == INVALID_INDEX);
TableIndex = Index;
}
@@ -140,25 +150,25 @@
Function(Function) {}
uint32_t DefinedData::getVirtualAddress() const {
- DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n");
+ LLVM_DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n");
if (Segment)
return Segment->OutputSeg->StartVA + Segment->OutputSegmentOffset + Offset;
return Offset;
}
void DefinedData::setVirtualAddress(uint32_t Value) {
- DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n");
+ LLVM_DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n");
assert(!Segment);
Offset = Value;
}
uint32_t DefinedData::getOutputSegmentOffset() const {
- DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n");
+ LLVM_DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n");
return Segment->OutputSegmentOffset + Offset;
}
uint32_t DefinedData::getOutputSegmentIndex() const {
- DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n");
+ LLVM_DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n");
return Segment->OutputSeg->Index;
}
@@ -170,7 +180,7 @@
}
void GlobalSymbol::setGlobalIndex(uint32_t Index) {
- DEBUG(dbgs() << "setGlobalIndex " << Name << " -> " << Index << "\n");
+ LLVM_DEBUG(dbgs() << "setGlobalIndex " << Name << " -> " << Index << "\n");
assert(GlobalIndex == INVALID_INDEX);
GlobalIndex = Index;
}
@@ -187,6 +197,19 @@
Global ? &Global->getType() : nullptr),
Global(Global) {}
+uint32_t SectionSymbol::getOutputSectionIndex() const {
+ LLVM_DEBUG(dbgs() << "getOutputSectionIndex: " << getName() << "\n");
+ assert(OutputSectionIndex != INVALID_INDEX);
+ return OutputSectionIndex;
+}
+
+void SectionSymbol::setOutputSectionIndex(uint32_t Index) {
+ LLVM_DEBUG(dbgs() << "setOutputSectionIndex: " << getName() << " -> " << Index
+ << "\n");
+ assert(Index != INVALID_INDEX);
+ OutputSectionIndex = Index;
+}
+
void LazySymbol::fetch() { cast<ArchiveFile>(File)->addMember(&ArchiveSymbol); }
std::string lld::toString(const wasm::Symbol &Sym) {
@@ -212,18 +235,8 @@
return "UndefinedGlobal";
case wasm::Symbol::LazyKind:
return "LazyKind";
+ case wasm::Symbol::SectionKind:
+ return "SectionKind";
}
llvm_unreachable("invalid symbol kind");
}
-
-std::string lld::toString(WasmSymbolType Type) {
- switch (Type) {
- case llvm::wasm::WASM_SYMBOL_TYPE_FUNCTION:
- return "Function";
- case llvm::wasm::WASM_SYMBOL_TYPE_DATA:
- return "Data";
- case llvm::wasm::WASM_SYMBOL_TYPE_GLOBAL:
- return "Global";
- }
- llvm_unreachable("invalid symbol type");
-}
diff --git a/wasm/Symbols.h b/wasm/Symbols.h
index 92084f7..b2ec1e8 100644
--- a/wasm/Symbols.h
+++ b/wasm/Symbols.h
@@ -10,6 +10,7 @@
#ifndef LLD_WASM_SYMBOLS_H
#define LLD_WASM_SYMBOLS_H
+#include "Config.h"
#include "lld/Common/LLVM.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/Wasm.h"
@@ -29,6 +30,7 @@
class InputSegment;
class InputFunction;
class InputGlobal;
+class InputSection;
#define INVALID_INDEX UINT32_MAX
@@ -39,6 +41,7 @@
DefinedFunctionKind,
DefinedDataKind,
DefinedGlobalKind,
+ SectionKind,
UndefinedFunctionKind,
UndefinedDataKind,
UndefinedGlobalKind,
@@ -49,7 +52,7 @@
bool isDefined() const {
return SymbolKind == DefinedFunctionKind || SymbolKind == DefinedDataKind ||
- SymbolKind == DefinedGlobalKind;
+ SymbolKind == DefinedGlobalKind || SymbolKind == SectionKind;
}
bool isUndefined() const {
@@ -71,9 +74,14 @@
InputChunk *getChunk() const;
- // Indicates that this symbol will be included in the final image.
+ // Indicates that the section or import for this symbol will be included in
+ // the final image.
bool isLive() const;
+ // Marks the symbol's InputChunk as Live, so that it will be included in the
+ // final image.
+ void markLive();
+
void setHidden(bool IsHidden);
// Get/set the index in the output symbol table. This is only used for
@@ -83,15 +91,20 @@
WasmSymbolType getWasmType() const;
+ // True if this symbol was referenced by a regular (non-bitcode) object.
+ unsigned IsUsedInRegularObj : 1;
+
protected:
Symbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F)
- : Name(Name), SymbolKind(K), Flags(Flags), File(F) {}
+ : IsUsedInRegularObj(false), Name(Name), SymbolKind(K), Flags(Flags),
+ File(F), Referenced(!Config->GcSections) {}
StringRef Name;
Kind SymbolKind;
uint32_t Flags;
InputFile *File;
uint32_t OutputSymbolIndex = INVALID_INDEX;
+ bool Referenced = false;
};
class FunctionSymbol : public Symbol {
@@ -147,6 +160,23 @@
}
};
+class SectionSymbol : public Symbol {
+public:
+ static bool classof(const Symbol *S) { return S->kind() == SectionKind; }
+
+ SectionSymbol(StringRef Name, uint32_t Flags, const InputSection *S,
+ InputFile *F = nullptr)
+ : Symbol(Name, SectionKind, Flags, F), Section(S) {}
+
+ const InputSection *Section;
+
+ uint32_t getOutputSectionIndex() const;
+ void setOutputSectionIndex(uint32_t Index);
+
+protected:
+ uint32_t OutputSectionIndex = INVALID_INDEX;
+};
+
class DataSymbol : public Symbol {
public:
static bool classof(const Symbol *S) {
@@ -160,7 +190,7 @@
class DefinedData : public DataSymbol {
public:
- // Constructor for for regular data symbols originating from input files.
+ // Constructor for regular data symbols originating from input files.
DefinedData(StringRef Name, uint32_t Flags, InputFile *F,
InputSegment *Segment, uint32_t Offset, uint32_t Size)
: DataSymbol(Name, DefinedDataKind, Flags, F), Segment(Segment),
@@ -293,6 +323,7 @@
alignas(UndefinedFunction) char E[sizeof(UndefinedFunction)];
alignas(UndefinedData) char F[sizeof(UndefinedData)];
alignas(UndefinedGlobal) char G[sizeof(UndefinedGlobal)];
+ alignas(SectionSymbol) char I[sizeof(SectionSymbol)];
};
template <typename T, typename... ArgT>
@@ -304,7 +335,12 @@
"SymbolUnion not aligned enough");
assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr &&
"Not a Symbol");
- return new (S) T(std::forward<ArgT>(Arg)...);
+
+ Symbol SymCopy = *S;
+
+ T *S2 = new (S) T(std::forward<ArgT>(Arg)...);
+ S2->IsUsedInRegularObj = SymCopy.IsUsedInRegularObj;
+ return S2;
}
} // namespace wasm
@@ -312,7 +348,6 @@
// Returns a symbol name for an error message.
std::string toString(const wasm::Symbol &Sym);
std::string toString(wasm::Symbol::Kind Kind);
-std::string toString(WasmSymbolType Type);
} // namespace lld
diff --git a/wasm/Writer.cpp b/wasm/Writer.cpp
index a98cfc6..ee6056a 100644
--- a/wasm/Writer.cpp
+++ b/wasm/Writer.cpp
@@ -20,6 +20,7 @@
#include "lld/Common/Strings.h"
#include "lld/Common/Threads.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/StringMap.h"
#include "llvm/BinaryFormat/Wasm.h"
#include "llvm/Object/WasmTraits.h"
#include "llvm/Support/FileOutputBuffer.h"
@@ -66,6 +67,7 @@
void assignIndexes();
void calculateImports();
void calculateExports();
+ void calculateCustomSections();
void assignSymtab();
void calculateTypes();
void createOutputSegments();
@@ -85,6 +87,7 @@
void createElemSection();
void createCodeSection();
void createDataSection();
+ void createCustomSections();
// Custom sections
void createRelocSections();
@@ -103,7 +106,7 @@
std::vector<const Symbol *> ImportedSymbols;
unsigned NumImportedFunctions = 0;
unsigned NumImportedGlobals = 0;
- std::vector<Symbol *> ExportedSymbols;
+ std::vector<WasmExport> Exports;
std::vector<const DefinedData *> DefinedFakeGlobals;
std::vector<InputGlobal *> InputGlobals;
std::vector<InputFunction *> InputFunctions;
@@ -111,6 +114,9 @@
std::vector<const Symbol *> SymtabEntries;
std::vector<WasmInitEntry> InitFunctions;
+ llvm::StringMap<std::vector<InputSection *>> CustomSectionMapping;
+ llvm::StringMap<SectionSymbol *> CustomSectionSymbols;
+
// Elements that are used to construct the final output
std::string Header;
std::vector<OutputSection *> OutputSections;
@@ -258,40 +264,48 @@
}
void Writer::createExportSection() {
- bool ExportMemory = !Config->Relocatable && !Config->ImportMemory;
- bool ExportTable = !Config->Relocatable && Config->ExportTable;
-
- uint32_t NumExports =
- (ExportMemory ? 1 : 0) + (ExportTable ? 1 : 0) + ExportedSymbols.size();
- if (!NumExports)
+ if (!Exports.size())
return;
SyntheticSection *Section = createSyntheticSection(WASM_SEC_EXPORT);
raw_ostream &OS = Section->getStream();
- writeUleb128(OS, NumExports, "export count");
-
- if (ExportMemory)
- writeExport(OS, {"memory", WASM_EXTERNAL_MEMORY, 0});
- if (ExportTable)
- writeExport(OS, {kFunctionTableName, WASM_EXTERNAL_TABLE, 0});
-
- unsigned FakeGlobalIndex = NumImportedGlobals + InputGlobals.size();
-
- for (const Symbol *Sym : ExportedSymbols) {
- StringRef Name = Sym->getName();
- WasmExport Export;
- DEBUG(dbgs() << "Export: " << Name << "\n");
-
- if (auto *F = dyn_cast<DefinedFunction>(Sym))
- Export = {Name, WASM_EXTERNAL_FUNCTION, F->getFunctionIndex()};
- else if (auto *G = dyn_cast<DefinedGlobal>(Sym))
- Export = {Name, WASM_EXTERNAL_GLOBAL, G->getGlobalIndex()};
- else if (isa<DefinedData>(Sym))
- Export = {Name, WASM_EXTERNAL_GLOBAL, FakeGlobalIndex++};
- else
- llvm_unreachable("unexpected symbol type");
+ writeUleb128(OS, Exports.size(), "export count");
+ for (const WasmExport &Export : Exports)
writeExport(OS, Export);
+}
+
+void Writer::calculateCustomSections() {
+ log("calculateCustomSections");
+ bool StripDebug = Config->StripDebug || Config->StripAll;
+ for (ObjFile *File : Symtab->ObjectFiles) {
+ for (InputSection *Section : File->CustomSections) {
+ StringRef Name = Section->getName();
+ // These custom sections are known the linker and synthesized rather than
+ // blindly copied
+ if (Name == "linking" || Name == "name" || Name.startswith("reloc."))
+ continue;
+ // .. or it is a debug section
+ if (StripDebug && Name.startswith(".debug_"))
+ continue;
+ CustomSectionMapping[Name].push_back(Section);
+ }
+ }
+}
+
+void Writer::createCustomSections() {
+ log("createCustomSections");
+ for (auto &Pair : CustomSectionMapping) {
+ StringRef Name = Pair.first();
+
+ auto P = CustomSectionSymbols.find(Name);
+ if (P != CustomSectionSymbols.end()) {
+ uint32_t SectionIndex = OutputSections.size();
+ P->second->setOutputSectionIndex(SectionIndex);
+ }
+
+ LLVM_DEBUG(dbgs() << "createCustomSection: " << Name << "\n");
+ OutputSections.push_back(make<CustomSection>(Name, Pair.second));
}
}
@@ -343,8 +357,8 @@
log("createRelocSections");
// Don't use iterator here since we are adding to OutputSection
size_t OrigSize = OutputSections.size();
- for (size_t i = 0; i < OrigSize; i++) {
- OutputSection *OSec = OutputSections[i];
+ for (size_t I = 0; I < OrigSize; I++) {
+ OutputSection *OSec = OutputSections[I];
uint32_t Count = OSec->numRelocations();
if (!Count)
continue;
@@ -354,12 +368,15 @@
Name = "reloc.DATA";
else if (OSec->Type == WASM_SEC_CODE)
Name = "reloc.CODE";
+ else if (OSec->Type == WASM_SEC_CUSTOM)
+ Name = Saver.save("reloc." + OSec->Name);
else
- llvm_unreachable("relocations only supported for code and data");
+ llvm_unreachable(
+ "relocations only supported for code, data, or custom sections");
SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, Name);
raw_ostream &OS = Section->getStream();
- writeUleb128(OS, OSec->Type, "reloc section");
+ writeUleb128(OS, I, "reloc section");
writeUleb128(OS, Count, "reloc count");
OSec->writeRelocations(OS);
}
@@ -409,8 +426,7 @@
createSyntheticSection(WASM_SEC_CUSTOM, "linking");
raw_ostream &OS = Section->getStream();
- if (!Config->Relocatable)
- return;
+ writeUleb128(OS, WasmMetadataVersion, "Version");
if (!SymtabEntries.empty()) {
SubSection Sub(WASM_SYMBOL_TABLE);
@@ -432,8 +448,7 @@
writeUleb128(Sub.OS, G->getGlobalIndex(), "index");
if (Sym->isDefined())
writeStr(Sub.OS, Sym->getName(), "sym name");
- } else {
- assert(isa<DataSymbol>(Sym));
+ } else if (isa<DataSymbol>(Sym)) {
writeStr(Sub.OS, Sym->getName(), "sym name");
if (auto *DataSym = dyn_cast<DefinedData>(Sym)) {
writeUleb128(Sub.OS, DataSym->getOutputSegmentIndex(), "index");
@@ -441,6 +456,9 @@
"data offset");
writeUleb128(Sub.OS, DataSym->getSize(), "data size");
}
+ } else {
+ auto *S = cast<SectionSymbol>(Sym);
+ writeUleb128(Sub.OS, S->getOutputSectionIndex(), "sym section index");
}
}
@@ -513,7 +531,7 @@
void Writer::createNameSection() {
unsigned NumNames = NumImportedFunctions;
for (const InputFunction *F : InputFunctions)
- if (!F->getName().empty())
+ if (!F->getName().empty() || !F->getDebugName().empty())
++NumNames;
if (NumNames == 0)
@@ -537,8 +555,12 @@
for (const InputFunction *F : InputFunctions) {
if (!F->getName().empty()) {
writeUleb128(Sub.OS, F->getFunctionIndex(), "func index");
- Optional<std::string> Name = demangleItanium(F->getName());
- writeStr(Sub.OS, Name ? StringRef(*Name) : F->getName(), "symbol name");
+ if (!F->getDebugName().empty()) {
+ writeStr(Sub.OS, F->getDebugName(), "symbol name");
+ } else {
+ Optional<std::string> Name = demangleItanium(F->getName());
+ writeStr(Sub.OS, Name ? StringRef(*Name) : F->getName(), "symbol name");
+ }
}
}
@@ -556,22 +578,48 @@
// Fix the memory layout of the output binary. This assigns memory offsets
// to each of the input data sections as well as the explicit stack region.
-// The memory layout is as follows, from low to high.
+// The default memory layout is as follows, from low to high.
+//
// - initialized data (starting at Config->GlobalBase)
// - BSS data (not currently implemented in llvm)
// - explicit stack (Config->ZStackSize)
// - heap start / unallocated
+//
+// The --stack-first option means that stack is placed before any static data.
+// This can be useful since it means that stack overflow traps immediately rather
+// than overwriting global data, but also increases code size since all static
+// data loads and stores requires larger offsets.
void Writer::layoutMemory() {
- uint32_t MemoryPtr = 0;
- MemoryPtr = Config->GlobalBase;
- log("mem: global base = " + Twine(Config->GlobalBase));
-
createOutputSegments();
+ uint32_t MemoryPtr = 0;
+
+ auto PlaceStack = [&]() {
+ if (Config->Relocatable)
+ return;
+ MemoryPtr = alignTo(MemoryPtr, kStackAlignment);
+ if (Config->ZStackSize != alignTo(Config->ZStackSize, kStackAlignment))
+ error("stack size must be " + Twine(kStackAlignment) + "-byte aligned");
+ log("mem: stack size = " + Twine(Config->ZStackSize));
+ log("mem: stack base = " + Twine(MemoryPtr));
+ MemoryPtr += Config->ZStackSize;
+ WasmSym::StackPointer->Global->Global.InitExpr.Value.Int32 = MemoryPtr;
+ log("mem: stack top = " + Twine(MemoryPtr));
+ };
+
+ if (Config->StackFirst) {
+ PlaceStack();
+ } else {
+ MemoryPtr = Config->GlobalBase;
+ log("mem: global base = " + Twine(Config->GlobalBase));
+ }
+
+ uint32_t DataStart = MemoryPtr;
+
// Arbitrarily set __dso_handle handle to point to the start of the data
// segments.
if (WasmSym::DsoHandle)
- WasmSym::DsoHandle->setVirtualAddress(MemoryPtr);
+ WasmSym::DsoHandle->setVirtualAddress(DataStart);
for (OutputSegment *Seg : Segments) {
MemoryPtr = alignTo(MemoryPtr, Seg->Alignment);
@@ -585,22 +633,15 @@
if (WasmSym::DataEnd)
WasmSym::DataEnd->setVirtualAddress(MemoryPtr);
- log("mem: static data = " + Twine(MemoryPtr - Config->GlobalBase));
+ log("mem: static data = " + Twine(MemoryPtr - DataStart));
- // Stack comes after static data and bss
+ if (!Config->StackFirst)
+ PlaceStack();
+
+ // Set `__heap_base` to directly follow the end of the stack or global data.
+ // The fact that this comes last means that a malloc/brk implementation
+ // can grow the heap at runtime.
if (!Config->Relocatable) {
- MemoryPtr = alignTo(MemoryPtr, kStackAlignment);
- if (Config->ZStackSize != alignTo(Config->ZStackSize, kStackAlignment))
- error("stack size must be " + Twine(kStackAlignment) + "-byte aligned");
- log("mem: stack size = " + Twine(Config->ZStackSize));
- log("mem: stack base = " + Twine(MemoryPtr));
- MemoryPtr += Config->ZStackSize;
- WasmSym::StackPointer->Global->Global.InitExpr.Value.Int32 = MemoryPtr;
- log("mem: stack top = " + Twine(MemoryPtr));
-
- // Set `__heap_base` to directly follow the end of the stack. We don't
- // allocate any heap memory up front, but instead really on the malloc/brk
- // implementation growing the memory at runtime.
WasmSym::HeapBase->setVirtualAddress(MemoryPtr);
log("mem: heap base = " + Twine(MemoryPtr));
}
@@ -647,6 +688,7 @@
createElemSection();
createCodeSection();
createDataSection();
+ createCustomSections();
// Custom sections
if (Config->Relocatable) {
@@ -671,8 +713,12 @@
continue;
if (Sym->isWeak() && !Config->Relocatable)
continue;
+ if (!Sym->isLive())
+ continue;
+ if (!Sym->IsUsedInRegularObj)
+ continue;
- DEBUG(dbgs() << "import: " << Sym->getName() << "\n");
+ LLVM_DEBUG(dbgs() << "import: " << Sym->getName() << "\n");
ImportedSymbols.emplace_back(Sym);
if (auto *F = dyn_cast<FunctionSymbol>(Sym))
F->setFunctionIndex(NumImportedFunctions++);
@@ -685,6 +731,14 @@
if (Config->Relocatable)
return;
+ if (!Config->Relocatable && !Config->ImportMemory)
+ Exports.push_back(WasmExport{"memory", WASM_EXTERNAL_MEMORY, 0});
+
+ if (!Config->Relocatable && Config->ExportTable)
+ Exports.push_back(WasmExport{kFunctionTableName, WASM_EXTERNAL_TABLE, 0});
+
+ unsigned FakeGlobalIndex = NumImportedGlobals + InputGlobals.size();
+
for (Symbol *Sym : Symtab->getSymbols()) {
if (!Sym->isDefined())
continue;
@@ -693,11 +747,20 @@
if (!Sym->isLive())
continue;
- DEBUG(dbgs() << "exporting sym: " << Sym->getName() << "\n");
-
- if (auto *D = dyn_cast<DefinedData>(Sym))
+ StringRef Name = Sym->getName();
+ WasmExport Export;
+ if (auto *F = dyn_cast<DefinedFunction>(Sym)) {
+ Export = {Name, WASM_EXTERNAL_FUNCTION, F->getFunctionIndex()};
+ } else if (auto *G = dyn_cast<DefinedGlobal>(Sym)) {
+ Export = {Name, WASM_EXTERNAL_GLOBAL, G->getGlobalIndex()};
+ } else {
+ auto *D = cast<DefinedData>(Sym);
DefinedFakeGlobals.emplace_back(D);
- ExportedSymbols.emplace_back(Sym);
+ Export = {Name, WASM_EXTERNAL_GLOBAL, FakeGlobalIndex++};
+ }
+
+ LLVM_DEBUG(dbgs() << "Export: " << Name << "\n");
+ Exports.push_back(Export);
}
}
@@ -705,12 +768,32 @@
if (!Config->Relocatable)
return;
+ StringMap<uint32_t> SectionSymbolIndices;
+
unsigned SymbolIndex = SymtabEntries.size();
for (ObjFile *File : Symtab->ObjectFiles) {
- DEBUG(dbgs() << "Symtab entries: " << File->getName() << "\n");
+ LLVM_DEBUG(dbgs() << "Symtab entries: " << File->getName() << "\n");
for (Symbol *Sym : File->getSymbols()) {
if (Sym->getFile() != File)
continue;
+
+ if (auto *S = dyn_cast<SectionSymbol>(Sym)) {
+ StringRef Name = S->getName();
+ if (CustomSectionMapping.count(Name) == 0)
+ continue;
+
+ auto SSI = SectionSymbolIndices.find(Name);
+ if (SSI != SectionSymbolIndices.end()) {
+ Sym->setOutputSymbolIndex(SSI->second);
+ continue;
+ }
+
+ SectionSymbolIndices[Name] = SymbolIndex;
+ CustomSectionSymbols[Name] = cast<SectionSymbol>(Sym);
+
+ Sym->markLive();
+ }
+
// (Since this is relocatable output, GC is not performed so symbols must
// be live.)
assert(Sym->isLive());
@@ -736,7 +819,7 @@
uint32_t Writer::registerType(const WasmSignature &Sig) {
auto Pair = TypeIndices.insert(std::make_pair(Sig, Types.size()));
if (Pair.second) {
- DEBUG(dbgs() << "type " << toString(Sig) << "\n");
+ LLVM_DEBUG(dbgs() << "type " << toString(Sig) << "\n");
Types.push_back(&Sig);
}
return Pair.first->second;
@@ -776,7 +859,7 @@
AddDefinedFunction(Func);
for (ObjFile *File : Symtab->ObjectFiles) {
- DEBUG(dbgs() << "Functions: " << File->getName() << "\n");
+ LLVM_DEBUG(dbgs() << "Functions: " << File->getName() << "\n");
for (InputFunction *Func : File->Functions)
AddDefinedFunction(Func);
}
@@ -799,29 +882,24 @@
// Mark target type as live
File->TypeMap[Reloc.Index] = registerType(Types[Reloc.Index]);
File->TypeIsUsed[Reloc.Index] = true;
- } else if (Reloc.Type == R_WEBASSEMBLY_GLOBAL_INDEX_LEB) {
- // Mark target global as live
- GlobalSymbol *Sym = File->getGlobalSymbol(Reloc.Index);
- if (auto *G = dyn_cast<DefinedGlobal>(Sym)) {
- DEBUG(dbgs() << "marking global live: " << Sym->getName() << "\n");
- G->Global->Live = true;
- }
}
}
};
for (ObjFile *File : Symtab->ObjectFiles) {
- DEBUG(dbgs() << "Handle relocs: " << File->getName() << "\n");
+ LLVM_DEBUG(dbgs() << "Handle relocs: " << File->getName() << "\n");
for (InputChunk *Chunk : File->Functions)
HandleRelocs(Chunk);
for (InputChunk *Chunk : File->Segments)
HandleRelocs(Chunk);
+ for (auto &P : File->CustomSections)
+ HandleRelocs(P);
}
uint32_t GlobalIndex = NumImportedGlobals + InputGlobals.size();
auto AddDefinedGlobal = [&](InputGlobal *Global) {
if (Global->Live) {
- DEBUG(dbgs() << "AddDefinedGlobal: " << GlobalIndex << "\n");
+ LLVM_DEBUG(dbgs() << "AddDefinedGlobal: " << GlobalIndex << "\n");
Global->setGlobalIndex(GlobalIndex++);
InputGlobals.push_back(Global);
}
@@ -831,14 +909,14 @@
AddDefinedGlobal(Global);
for (ObjFile *File : Symtab->ObjectFiles) {
- DEBUG(dbgs() << "Globals: " << File->getName() << "\n");
+ LLVM_DEBUG(dbgs() << "Globals: " << File->getName() << "\n");
for (InputGlobal *Global : File->Globals)
AddDefinedGlobal(Global);
}
}
static StringRef getOutputDataSegmentName(StringRef Name) {
- if (Config->Relocatable)
+ if (!Config->MergeDataSegments)
return Name;
if (Name.startswith(".text."))
return ".text";
@@ -857,12 +935,12 @@
StringRef Name = getOutputDataSegmentName(Segment->getName());
OutputSegment *&S = SegmentMap[Name];
if (S == nullptr) {
- DEBUG(dbgs() << "new segment: " << Name << "\n");
+ LLVM_DEBUG(dbgs() << "new segment: " << Name << "\n");
S = make<OutputSegment>(Name, Segments.size());
Segments.push_back(S);
}
S->addInputSegment(Segment);
- DEBUG(dbgs() << "added data: " << Name << ": " << S->Size << "\n");
+ LLVM_DEBUG(dbgs() << "added data: " << Name << ": " << S->Size << "\n");
}
}
}
@@ -937,6 +1015,8 @@
layoutMemory();
log("-- calculateExports");
calculateExports();
+ log("-- calculateCustomSections");
+ calculateCustomSections();
log("-- assignSymtab");
assignSymtab();
diff --git a/wasm/WriterUtils.cpp b/wasm/WriterUtils.cpp
index 4c0d09e..201529e 100644
--- a/wasm/WriterUtils.cpp
+++ b/wasm/WriterUtils.cpp
@@ -37,7 +37,7 @@
namespace lld {
void wasm::debugWrite(uint64_t Offset, const Twine &Msg) {
- DEBUG(dbgs() << format(" | %08lld: ", Offset) << Msg << "\n");
+ LLVM_DEBUG(dbgs() << format(" | %08lld: ", Offset) << Msg << "\n");
}
void wasm::writeUleb128(raw_ostream &OS, uint32_t Number, const Twine &Msg) {
@@ -70,7 +70,7 @@
void wasm::writeU32(raw_ostream &OS, uint32_t Number, const Twine &Msg) {
debugWrite(OS.tell(), Msg + "[0x" + utohexstr(Number) + "]");
- support::endian::Writer<support::little>(OS).write(Number);
+ support::endian::write(OS, Number, support::little);
}
void wasm::writeValueType(raw_ostream &OS, uint8_t Type, const Twine &Msg) {