aboutsummaryrefslogtreecommitdiff
path: root/lld
diff options
context:
space:
mode:
Diffstat (limited to 'lld')
-rw-r--r--lld/COFF/Chunks.cpp22
-rw-r--r--lld/COFF/Chunks.h32
-rw-r--r--lld/COFF/Config.h3
-rw-r--r--lld/COFF/DLL.cpp58
-rw-r--r--lld/COFF/Driver.cpp111
-rw-r--r--lld/COFF/Driver.h2
-rw-r--r--lld/COFF/DriverUtils.cpp16
-rw-r--r--lld/COFF/InputFiles.cpp5
-rw-r--r--lld/COFF/MarkLive.cpp5
-rw-r--r--lld/COFF/Options.td10
-rw-r--r--lld/COFF/PDB.cpp9
-rw-r--r--lld/COFF/SymbolTable.cpp79
-rw-r--r--lld/COFF/SymbolTable.h9
-rw-r--r--lld/COFF/Symbols.cpp8
-rw-r--r--lld/COFF/Symbols.h4
-rw-r--r--lld/COFF/Writer.cpp29
-rw-r--r--lld/ELF/Arch/LoongArch.cpp9
-rw-r--r--lld/ELF/Arch/Mips.cpp4
-rw-r--r--lld/ELF/Config.h2
-rw-r--r--lld/ELF/Driver.cpp1
-rw-r--r--lld/ELF/InputSection.cpp5
-rw-r--r--lld/ELF/Relocations.cpp29
-rw-r--r--lld/ELF/Relocations.h1
-rw-r--r--lld/ELF/SyntheticSections.cpp56
-rw-r--r--lld/ELF/SyntheticSections.h71
-rw-r--r--lld/ELF/Target.cpp3
-rw-r--r--lld/ELF/Target.h35
-rw-r--r--lld/ELF/Writer.cpp5
-rw-r--r--lld/test/COFF/alternatename-alias.s15
-rw-r--r--lld/test/COFF/alternatename-antidep.s16
-rw-r--r--lld/test/COFF/alternatename-lib.s43
-rw-r--r--lld/test/COFF/arm64ec-altnames.s39
-rw-r--r--lld/test/COFF/arm64ec-delayimport.test48
-rw-r--r--lld/test/COFF/arm64x-delayimport.test98
-rw-r--r--lld/test/COFF/arm64x-sameaddress.test107
-rw-r--r--lld/test/COFF/delayimports.test14
-rw-r--r--lld/test/COFF/delayimporttables.yaml8
-rw-r--r--lld/test/COFF/embed-bitcode.test30
-rw-r--r--lld/test/COFF/giats.s4
-rw-r--r--lld/test/COFF/pdb-empty-sec.s19
-rw-r--r--lld/test/ELF/loongarch-relax-pc-hi20-lo12.s59
41 files changed, 775 insertions, 348 deletions
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index 01752cd..39fc250 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -422,12 +422,6 @@ void SectionChunk::writeTo(uint8_t *buf) const {
applyRelocation(buf + rel.VirtualAddress, rel);
}
-
- // Write the offset to EC entry thunk preceding section contents. The low bit
- // is always set, so it's effectively an offset from the last byte of the
- // offset.
- if (Defined *entryThunk = getEntryThunk())
- write32le(buf - sizeof(uint32_t), entryThunk->getRVA() - rva + 1);
}
void SectionChunk::applyRelocation(uint8_t *off,
@@ -881,6 +875,19 @@ void RangeExtensionThunkARM64::writeTo(uint8_t *buf) const {
applyArm64Imm(buf + 4, target->getRVA() & 0xfff, 0);
}
+void SameAddressThunkARM64EC::setDynamicRelocs(COFFLinkerContext &ctx) const {
+ // Add ARM64X relocations replacing adrp/add instructions with a version using
+ // the hybrid target.
+ RangeExtensionThunkARM64 hybridView(ARM64EC, hybridTarget);
+ uint8_t buf[sizeof(arm64Thunk)];
+ hybridView.setRVA(rva);
+ hybridView.writeTo(buf);
+ uint32_t addrp = *reinterpret_cast<ulittle32_t *>(buf);
+ uint32_t add = *reinterpret_cast<ulittle32_t *>(buf + sizeof(uint32_t));
+ ctx.dynamicRelocs->set(this, addrp);
+ ctx.dynamicRelocs->set(Arm64XRelocVal(this, sizeof(uint32_t)), add);
+}
+
LocalImportChunk::LocalImportChunk(COFFLinkerContext &c, Defined *s)
: sym(s), ctx(c) {
setAlignment(ctx.config.wordsize);
@@ -1264,7 +1271,8 @@ void DynamicRelocsChunk::finalize() {
}
// Set the reloc value. The reloc entry must be allocated beforehand.
-void DynamicRelocsChunk::set(uint32_t rva, Arm64XRelocVal value) {
+void DynamicRelocsChunk::set(Arm64XRelocVal offset, Arm64XRelocVal value) {
+ uint32_t rva = offset.get();
auto entry =
llvm::find_if(arm64xRelocs, [rva](const Arm64XDynamicRelocEntry &e) {
return e.offset.get() == rva;
diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h
index d03a64c..6d88f5e 100644
--- a/lld/COFF/Chunks.h
+++ b/lld/COFF/Chunks.h
@@ -193,6 +193,8 @@ public:
// allowed ranges. Return the additional space required for the extension.
virtual uint32_t extendRanges() { return 0; };
+ virtual Defined *getEntryThunk() const { return nullptr; };
+
static bool classof(const Chunk *c) { return c->kind() >= OtherKind; }
protected:
@@ -633,7 +635,7 @@ public:
bool verifyRanges() override;
uint32_t extendRanges() override;
- Defined *exitThunk;
+ Defined *exitThunk = nullptr;
Defined *sym = nullptr;
bool extended = false;
@@ -675,6 +677,26 @@ private:
MachineTypes machine;
};
+// A chunk used to guarantee the same address for a function in both views of
+// a hybrid image. Similar to RangeExtensionThunkARM64 chunks, it calls the
+// target symbol using a BR instruction. It also contains an entry thunk for EC
+// compatibility and additional ARM64X relocations that swap targets between
+// views.
+class SameAddressThunkARM64EC : public RangeExtensionThunkARM64 {
+public:
+ explicit SameAddressThunkARM64EC(Defined *t, Defined *hybridTarget,
+ Defined *entryThunk)
+ : RangeExtensionThunkARM64(ARM64EC, t), hybridTarget(hybridTarget),
+ entryThunk(entryThunk) {}
+
+ Defined *getEntryThunk() const override { return entryThunk; }
+ void setDynamicRelocs(COFFLinkerContext &ctx) const;
+
+private:
+ Defined *hybridTarget;
+ Defined *entryThunk;
+};
+
// Windows-specific.
// See comments for DefinedLocalImport class.
class LocalImportChunk : public NonSectionChunk {
@@ -843,13 +865,13 @@ class Arm64XRelocVal {
public:
Arm64XRelocVal(uint64_t value = 0) : value(value) {}
Arm64XRelocVal(Defined *sym, int32_t offset = 0) : sym(sym), value(offset) {}
- Arm64XRelocVal(Chunk *chunk, int32_t offset = 0)
+ Arm64XRelocVal(const Chunk *chunk, int32_t offset = 0)
: chunk(chunk), value(offset) {}
uint64_t get() const;
private:
Defined *sym = nullptr;
- Chunk *chunk = nullptr;
+ const Chunk *chunk = nullptr;
uint64_t value;
};
@@ -884,7 +906,7 @@ public:
arm64xRelocs.emplace_back(type, size, offset, value);
}
- void set(uint32_t rva, Arm64XRelocVal value);
+ void set(Arm64XRelocVal offset, Arm64XRelocVal value);
private:
std::vector<Arm64XDynamicRelocEntry> arm64xRelocs;
@@ -940,6 +962,8 @@ inline bool Chunk::isHotPatchable() const {
inline Defined *Chunk::getEntryThunk() const {
if (auto *c = dyn_cast<const SectionChunkEC>(this))
return c->entryThunk;
+ if (auto *c = dyn_cast<const NonSectionChunk>(this))
+ return c->getEntryThunk();
return nullptr;
}
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index 91b6e63..a03bb57 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -223,6 +223,9 @@ struct Configuration {
StringRef manifestUIAccess = "'false'";
StringRef manifestFile;
+ // used for /arm64xsameaddress
+ std::vector<std::pair<Symbol *, Symbol *>> sameAddresses;
+
// used for /dwodir
StringRef dwoDir;
diff --git a/lld/COFF/DLL.cpp b/lld/COFF/DLL.cpp
index c327da2..3ce8853 100644
--- a/lld/COFF/DLL.cpp
+++ b/lld/COFF/DLL.cpp
@@ -244,40 +244,36 @@ static const uint8_t thunkX64[] = {
};
static const uint8_t tailMergeX64[] = {
- 0x51, // push rcx
- 0x52, // push rdx
- 0x41, 0x50, // push r8
- 0x41, 0x51, // push r9
- 0x48, 0x83, 0xEC, 0x48, // sub rsp, 48h
- 0x66, 0x0F, 0x7F, 0x04, 0x24, // movdqa xmmword ptr [rsp], xmm0
- 0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x10, // movdqa xmmword ptr [rsp+10h], xmm1
- 0x66, 0x0F, 0x7F, 0x54, 0x24, 0x20, // movdqa xmmword ptr [rsp+20h], xmm2
- 0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x30, // movdqa xmmword ptr [rsp+30h], xmm3
- 0x48, 0x8B, 0xD0, // mov rdx, rax
- 0x48, 0x8D, 0x0D, 0, 0, 0, 0, // lea rcx, [___DELAY_IMPORT_...]
- 0xE8, 0, 0, 0, 0, // call __delayLoadHelper2
- 0x66, 0x0F, 0x6F, 0x04, 0x24, // movdqa xmm0, xmmword ptr [rsp]
- 0x66, 0x0F, 0x6F, 0x4C, 0x24, 0x10, // movdqa xmm1, xmmword ptr [rsp+10h]
- 0x66, 0x0F, 0x6F, 0x54, 0x24, 0x20, // movdqa xmm2, xmmword ptr [rsp+20h]
- 0x66, 0x0F, 0x6F, 0x5C, 0x24, 0x30, // movdqa xmm3, xmmword ptr [rsp+30h]
- 0x48, 0x83, 0xC4, 0x48, // add rsp, 48h
- 0x41, 0x59, // pop r9
- 0x41, 0x58, // pop r8
- 0x5A, // pop rdx
- 0x59, // pop rcx
- 0xFF, 0xE0, // jmp rax
+ 0x48, 0x89, 0x4C, 0x24, 0x08, // mov qword ptr [rsp+8], rcx
+ 0x48, 0x89, 0x54, 0x24, 0x10, // mov qword ptr [rsp+10h], rdx
+ 0x4C, 0x89, 0x44, 0x24, 0x18, // mov qword ptr [rsp+18h], r8
+ 0x4C, 0x89, 0x4C, 0x24, 0x20, // mov qword ptr [rsp+20h], r9
+ 0x48, 0x83, 0xEC, 0x68, // sub rsp, 68h
+ 0x66, 0x0F, 0x7F, 0x44, 0x24, 0x20, // movdqa xmmword ptr [rsp+20h], xmm0
+ 0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x30, // movdqa xmmword ptr [rsp+30h], xmm1
+ 0x66, 0x0F, 0x7F, 0x54, 0x24, 0x40, // movdqa xmmword ptr [rsp+40h], xmm2
+ 0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x50, // movdqa xmmword ptr [rsp+50h], xmm3
+ 0x48, 0x8B, 0xD0, // mov rdx, rax
+ 0x48, 0x8D, 0x0D, 0, 0, 0, 0, // lea rcx, [___DELAY_IMPORT_...]
+ 0xE8, 0, 0, 0, 0, // call __delayLoadHelper2
+ 0x66, 0x0F, 0x6F, 0x44, 0x24, 0x20, // movdqa xmm0, xmmword ptr [rsp+20h]
+ 0x66, 0x0F, 0x6F, 0x4C, 0x24, 0x30, // movdqa xmm1, xmmword ptr [rsp+30h]
+ 0x66, 0x0F, 0x6F, 0x54, 0x24, 0x40, // movdqa xmm2, xmmword ptr [rsp+40h]
+ 0x66, 0x0F, 0x6F, 0x5C, 0x24, 0x50, // movdqa xmm3, xmmword ptr [rsp+50h]
+ 0x48, 0x8B, 0x4C, 0x24, 0x70, // mov rcx, qword ptr [rsp+70h]
+ 0x48, 0x8B, 0x54, 0x24, 0x78, // mov rdx, qword ptr [rsp+78h]
+ 0x4C, 0x8B, 0x84, 0x24, 0x80, 0, 0, 0, // mov r8, qword ptr [rsp+80h]
+ 0x4C, 0x8B, 0x8C, 0x24, 0x88, 0, 0, 0, // mov r9, qword ptr [rsp+88h]
+ 0x48, 0x83, 0xC4, 0x68, // add rsp, 68h
+ 0xFF, 0xE0, // jmp rax
};
static const uint8_t tailMergeUnwindInfoX64[] = {
0x01, // Version=1, Flags=UNW_FLAG_NHANDLER
- 0x0a, // Size of prolog
- 0x05, // Count of unwind codes
+ 0x18, // Size of prolog
+ 0x01, // Count of unwind codes
0x00, // No frame register
- 0x0a, 0x82, // Offset 0xa: UWOP_ALLOC_SMALL(0x48)
- 0x06, 0x02, // Offset 6: UWOP_ALLOC_SMALL(8)
- 0x04, 0x02, // Offset 4: UWOP_ALLOC_SMALL(8)
- 0x02, 0x02, // Offset 2: UWOP_ALLOC_SMALL(8)
- 0x01, 0x02, // Offset 1: UWOP_ALLOC_SMALL(8)
+ 0x18, 0xC2, // Offset 0x18: UWOP_ALLOC_SMALL(0x68)
0x00, 0x00 // Padding to align on 32-bits
};
@@ -378,8 +374,8 @@ public:
void writeTo(uint8_t *buf) const override {
memcpy(buf, tailMergeX64, sizeof(tailMergeX64));
- write32le(buf + 39, desc->getRVA() - rva - 43);
- write32le(buf + 44, helper->getRVA() - rva - 48);
+ write32le(buf + 54, desc->getRVA() - rva - 58);
+ write32le(buf + 59, helper->getRVA() - rva - 63);
}
Chunk *desc = nullptr;
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index 83040b5..7580b469 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -500,7 +500,9 @@ void LinkerDriver::parseDirectives(InputFile *file) {
file->symtab.parseAlternateName(arg->getValue());
break;
case OPT_arm64xsameaddress:
- if (!file->symtab.isEC())
+ if (file->symtab.isEC())
+ parseSameAddress(arg->getValue());
+ else
Warn(ctx) << arg->getSpelling()
<< " is not allowed in non-ARM64EC files (" << toString(file)
<< ")";
@@ -1318,13 +1320,9 @@ void LinkerDriver::convertResources() {
}
void LinkerDriver::maybeCreateECExportThunk(StringRef name, Symbol *&sym) {
- Defined *def;
if (!sym)
return;
- if (auto undef = dyn_cast<Undefined>(sym))
- def = undef->getDefinedWeakAlias();
- else
- def = dyn_cast<Defined>(sym);
+ Defined *def = sym->getDefined();
if (!def)
return;
@@ -1356,11 +1354,7 @@ void LinkerDriver::createECExportThunks() {
Symbol *sym = ctx.symtab.find(targetName);
if (!sym)
continue;
- Defined *targetSym;
- if (auto undef = dyn_cast<Undefined>(sym))
- targetSym = undef->getDefinedWeakAlias();
- else
- targetSym = dyn_cast<Defined>(sym);
+ Defined *targetSym = sym->getDefined();
if (!targetSym)
continue;
@@ -2303,6 +2297,13 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
args.filtered(OPT_dependentloadflag, OPT_dependentloadflag_opt))
parseDependentLoadFlags(arg);
+ for (auto *arg : args.filtered(OPT_arm64xsameaddress)) {
+ if (ctx.hybridSymtab)
+ parseSameAddress(arg->getValue());
+ else
+ Warn(ctx) << arg->getSpelling() << " is allowed only on EC targets";
+ }
+
if (tar) {
llvm::TimeTraceScope timeScope("Reproducer: response file");
tar->append(
@@ -2554,28 +2555,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
e.symbolName = symtab.mangleMaybe(e.sym);
}
- // Add weak aliases. Weak aliases is a mechanism to give remaining
- // undefined symbols final chance to be resolved successfully.
- for (auto pair : symtab.alternateNames) {
- StringRef from = pair.first;
- StringRef to = pair.second;
- Symbol *sym = symtab.find(from);
- if (!sym)
- continue;
- if (auto *u = dyn_cast<Undefined>(sym)) {
- if (u->weakAlias) {
- // On ARM64EC, anti-dependency aliases are treated as undefined
- // symbols unless a demangled symbol aliases a defined one, which
- // is part of the implementation.
- if (!symtab.isEC() || !u->isAntiDep)
- continue;
- if (!isa<Undefined>(u->weakAlias) &&
- !isArm64ECMangledFunctionName(u->getName()))
- continue;
- }
- u->setWeakAlias(symtab.addUndefined(to));
- }
- }
+ symtab.resolveAlternateNames();
});
ctx.forEachActiveSymtab([&](SymbolTable &symtab) {
@@ -2697,12 +2677,46 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
createECExportThunks();
// Resolve remaining undefined symbols and warn about imported locals.
+ std::vector<Undefined *> aliases;
ctx.forEachSymtab(
- [&](SymbolTable &symtab) { symtab.resolveRemainingUndefines(); });
+ [&](SymbolTable &symtab) { symtab.resolveRemainingUndefines(aliases); });
if (errorCount())
return;
+ ctx.forEachActiveSymtab([](SymbolTable &symtab) {
+ symtab.initializeECThunks();
+ symtab.initializeLoadConfig();
+ });
+
+ // Identify unreferenced COMDAT sections.
+ if (config->doGC) {
+ if (config->mingw) {
+ // markLive doesn't traverse .eh_frame, but the personality function is
+ // only reached that way. The proper solution would be to parse and
+ // traverse the .eh_frame section, like the ELF linker does.
+ // For now, just manually try to retain the known possible personality
+ // functions. This doesn't bring in more object files, but only marks
+ // functions that already have been included to be retained.
+ ctx.forEachSymtab([&](SymbolTable &symtab) {
+ for (const char *n : {"__gxx_personality_v0", "__gcc_personality_v0",
+ "rust_eh_personality"}) {
+ Defined *d = dyn_cast_or_null<Defined>(symtab.findUnderscore(n));
+ if (d && !d->isGCRoot) {
+ d->isGCRoot = true;
+ config->gcroot.push_back(d);
+ }
+ }
+ });
+ }
+
+ markLive(ctx);
+ }
+
+ ctx.symtab.initializeSameAddressThunks();
+ for (auto alias : aliases)
+ alias->resolveWeakAlias();
+
if (config->mingw) {
// Make sure the crtend.o object is the last object file. This object
// file can contain terminating section chunks that need to be placed
@@ -2794,35 +2808,6 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
if (auto *arg = args.getLastArg(OPT_print_symbol_order))
config->printSymbolOrder = arg->getValue();
- if (ctx.symtab.isEC())
- ctx.symtab.initializeECThunks();
- ctx.forEachActiveSymtab(
- [](SymbolTable &symtab) { symtab.initializeLoadConfig(); });
-
- // Identify unreferenced COMDAT sections.
- if (config->doGC) {
- if (config->mingw) {
- // markLive doesn't traverse .eh_frame, but the personality function is
- // only reached that way. The proper solution would be to parse and
- // traverse the .eh_frame section, like the ELF linker does.
- // For now, just manually try to retain the known possible personality
- // functions. This doesn't bring in more object files, but only marks
- // functions that already have been included to be retained.
- ctx.forEachSymtab([&](SymbolTable &symtab) {
- for (const char *n : {"__gxx_personality_v0", "__gcc_personality_v0",
- "rust_eh_personality"}) {
- Defined *d = dyn_cast_or_null<Defined>(symtab.findUnderscore(n));
- if (d && !d->isGCRoot) {
- d->isGCRoot = true;
- config->gcroot.push_back(d);
- }
- }
- });
- }
-
- markLive(ctx);
- }
-
// Needs to happen after the last call to addFile().
convertResources();
diff --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h
index 5a9bd5c..b500ac8 100644
--- a/lld/COFF/Driver.h
+++ b/lld/COFF/Driver.h
@@ -214,6 +214,8 @@ private:
void parsePDBPageSize(StringRef);
void parseSection(StringRef);
+ void parseSameAddress(StringRef);
+
// Parses a MS-DOS stub file
void parseDosStub(StringRef path);
diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp
index d8b41c7..dc4039f 100644
--- a/lld/COFF/DriverUtils.cpp
+++ b/lld/COFF/DriverUtils.cpp
@@ -328,6 +328,22 @@ void LinkerDriver::parseSwaprun(StringRef arg) {
} while (!arg.empty());
}
+void LinkerDriver::parseSameAddress(StringRef arg) {
+ auto mangledName = getArm64ECMangledFunctionName(arg);
+ Symbol *sym = ctx.symtab.addUndefined(mangledName ? *mangledName : arg);
+
+ // MSVC appears to generate thunks even for non-hybrid ARM64EC images.
+ // As a side effect, the native symbol is pulled in. Since this is used
+ // in the CRT for thread-local constructors, it results in the image
+ // containing unnecessary native code. As these thunks don't appear to
+ // be useful, we limit this behavior to actual hybrid targets. This may
+ // change if compatibility becomes necessary.
+ if (ctx.config.machine != ARM64X)
+ return;
+ Symbol *nativeSym = ctx.hybridSymtab->addUndefined(arg);
+ ctx.config.sameAddresses.emplace_back(sym, nativeSym);
+}
+
// An RAII temporary file class that automatically removes a temporary file.
namespace {
class TemporaryFile {
diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp
index 2a6b63c..c08099b 100644
--- a/lld/COFF/InputFiles.cpp
+++ b/lld/COFF/InputFiles.cpp
@@ -403,6 +403,11 @@ SectionChunk *ObjFile::readSection(uint32_t sectionNumber,
return nullptr;
}
+ // Those sections are generated by -fembed-bitcode and do not need to be kept
+ // in executable files.
+ if (name == ".llvmbc" || name == ".llvmcmd")
+ return nullptr;
+
// Object files may have DWARF debug info or MS CodeView debug info
// (or both).
//
diff --git a/lld/COFF/MarkLive.cpp b/lld/COFF/MarkLive.cpp
index f40810c..78f5030 100644
--- a/lld/COFF/MarkLive.cpp
+++ b/lld/COFF/MarkLive.cpp
@@ -49,7 +49,10 @@ void markLive(COFFLinkerContext &ctx) {
addSym(file->impchkThunk->exitThunk);
};
- addSym = [&](Symbol *b) {
+ addSym = [&](Symbol *s) {
+ Defined *b = s->getDefined();
+ if (!b)
+ return;
if (auto *sym = dyn_cast<DefinedRegular>(b)) {
enqueue(sym->getChunk());
} else if (auto *sym = dyn_cast<DefinedImportData>(b)) {
diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td
index 2a82fb5..2c393cc 100644
--- a/lld/COFF/Options.td
+++ b/lld/COFF/Options.td
@@ -31,6 +31,9 @@ multiclass B_priv<string name> {
def align : P<"align", "Section alignment">;
def aligncomm : P<"aligncomm", "Set common symbol alignment">;
def alternatename : P<"alternatename", "Define weak alias">;
+def arm64xsameaddress
+ : P<"arm64xsameaddress", "Generate a thunk for the symbol with the same "
+ "address in both native and EC views on ARM64X.">;
def base : P<"base", "Base address of the program">;
def color_diagnostics: Flag<["--"], "color-diagnostics">,
HelpText<"Alias for --color-diagnostics=always">;
@@ -353,7 +356,13 @@ def fastfail : F<"fastfail">;
def kernel : F<"kernel">;
def pdbcompress : F<"pdbcompress">;
def emitpogophaseinfo : F<"emitpogophaseinfo">;
+defm emittoolversioninfo: B<
+ "emittoolversioninfo",
+ "Emit a tool version info after DOS header (so-called Rich header, default)",
+ "Do not emit a tool version info after DOS header (so-called Rich header)">;
+def nocoffgrpinfo: F<"nocoffgrpinfo">;
def noexp : F<"noexp">;
+def novcfeature: F<"novcfeature">;
def delay : P_priv<"delay">;
def errorreport : P_priv<"errorreport">;
@@ -367,4 +376,3 @@ def tlbid : P_priv<"tlbid">;
def tlbout : P_priv<"tlbout">;
def verbose_all : P_priv<"verbose">;
def guardsym : P_priv<"guardsym">;
-def arm64xsameaddress : P_priv<"arm64xsameaddress">;
diff --git a/lld/COFF/PDB.cpp b/lld/COFF/PDB.cpp
index a54ea40..94eeae2 100644
--- a/lld/COFF/PDB.cpp
+++ b/lld/COFF/PDB.cpp
@@ -1135,9 +1135,12 @@ static pdb::BulkPublic createPublic(COFFLinkerContext &ctx, Defined *def) {
pub.setFlags(flags);
OutputSection *os = ctx.getOutputSection(def->getChunk());
- assert(os && "all publics should be in final image");
- pub.Offset = def->getRVA() - os->getRVA();
- pub.Segment = os->sectionIndex;
+ assert((os || !def->getChunk()->getSize()) &&
+ "all publics should be in final image");
+ if (os) {
+ pub.Offset = def->getRVA() - os->getRVA();
+ pub.Segment = os->sectionIndex;
+ }
return pub;
}
diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp
index 0062df5..de04cdf 100644
--- a/lld/COFF/SymbolTable.cpp
+++ b/lld/COFF/SymbolTable.cpp
@@ -452,7 +452,7 @@ void SymbolTable::reportUnresolvable() {
reportProblemSymbols(undefs, /*localImports=*/nullptr, true);
}
-void SymbolTable::resolveRemainingUndefines() {
+void SymbolTable::resolveRemainingUndefines(std::vector<Undefined *> &aliases) {
llvm::TimeTraceScope timeScope("Resolve remaining undefined symbols");
SmallPtrSet<Symbol *, 8> undefs;
DenseMap<Symbol *, Symbol *> localImports;
@@ -468,8 +468,10 @@ void SymbolTable::resolveRemainingUndefines() {
StringRef name = undef->getName();
// A weak alias may have been resolved, so check for that.
- if (undef->resolveWeakAlias())
+ if (undef->getWeakAlias()) {
+ aliases.push_back(undef);
continue;
+ }
// If we can resolve a symbol by removing __imp_ prefix, do that.
// This odd rule is for compatibility with MSVC linker.
@@ -620,10 +622,10 @@ void SymbolTable::initializeECThunks() {
return;
for (auto it : entryThunks) {
- auto *to = dyn_cast<Defined>(it.second);
+ Defined *to = it.second->getDefined();
if (!to)
continue;
- auto *from = dyn_cast<DefinedRegular>(it.first);
+ auto *from = dyn_cast_or_null<DefinedRegular>(it.first->getDefined());
// We need to be able to add padding to the function and fill it with an
// offset to its entry thunks. To ensure that padding the function is
// feasible, functions are required to be COMDAT symbols with no offset.
@@ -642,7 +644,8 @@ void SymbolTable::initializeECThunks() {
Symbol *sym = exitThunks.lookup(file->thunkSym);
if (!sym)
sym = exitThunks.lookup(file->impECSym);
- file->impchkThunk->exitThunk = dyn_cast_or_null<Defined>(sym);
+ if (sym)
+ file->impchkThunk->exitThunk = sym->getDefined();
}
// On ARM64EC, the __imp_ symbol references the auxiliary IAT, while the
@@ -659,6 +662,35 @@ void SymbolTable::initializeECThunks() {
});
}
+void SymbolTable::initializeSameAddressThunks() {
+ for (auto iter : ctx.config.sameAddresses) {
+ auto sym = dyn_cast_or_null<DefinedRegular>(iter.first->getDefined());
+ if (!sym || !sym->isLive())
+ continue;
+ auto nativeSym =
+ dyn_cast_or_null<DefinedRegular>(iter.second->getDefined());
+ if (!nativeSym || !nativeSym->isLive())
+ continue;
+ Defined *entryThunk = sym->getChunk()->getEntryThunk();
+ if (!entryThunk)
+ continue;
+
+ // Replace symbols with symbols referencing the thunk. Store the original
+ // symbol as equivalent DefinedSynthetic instances for use in the thunk
+ // itself.
+ auto symClone = make<DefinedSynthetic>(sym->getName(), sym->getChunk(),
+ sym->getValue());
+ auto nativeSymClone = make<DefinedSynthetic>(
+ nativeSym->getName(), nativeSym->getChunk(), nativeSym->getValue());
+ SameAddressThunkARM64EC *thunk =
+ make<SameAddressThunkARM64EC>(nativeSymClone, symClone, entryThunk);
+ sameAddressThunks.push_back(thunk);
+
+ replaceSymbol<DefinedSynthetic>(sym, sym->getName(), thunk);
+ replaceSymbol<DefinedSynthetic>(nativeSym, nativeSym->getName(), thunk);
+ }
+}
+
Symbol *SymbolTable::addUndefined(StringRef name, InputFile *f,
bool overrideLazy) {
auto [s, wasInserted] = insert(name, f);
@@ -1344,6 +1376,43 @@ void SymbolTable::parseAlternateName(StringRef s) {
alternateNames.insert(it, std::make_pair(from, to));
}
+void SymbolTable::resolveAlternateNames() {
+ // Add weak aliases. Weak aliases is a mechanism to give remaining
+ // undefined symbols final chance to be resolved successfully.
+ for (auto pair : alternateNames) {
+ StringRef from = pair.first;
+ StringRef to = pair.second;
+ Symbol *sym = find(from);
+ if (!sym)
+ continue;
+ if (auto *u = dyn_cast<Undefined>(sym)) {
+ if (u->weakAlias) {
+ // On ARM64EC, anti-dependency aliases are treated as undefined
+ // symbols unless a demangled symbol aliases a defined one, which
+ // is part of the implementation.
+ if (!isEC() || !u->isAntiDep)
+ continue;
+ if (!isa<Undefined>(u->weakAlias) &&
+ !isArm64ECMangledFunctionName(u->getName()))
+ continue;
+ }
+
+ // Check if the destination symbol is defined. If not, skip it.
+ // It may still be resolved later if more input files are added.
+ // Also skip anti-dependency targets, as they can't be chained anyway.
+ Symbol *toSym = find(to);
+ if (!toSym)
+ continue;
+ auto toUndef = dyn_cast<Undefined>(toSym);
+ if (toUndef && (!toUndef->weakAlias || toUndef->isAntiDep))
+ continue;
+ if (toSym->isLazy())
+ forceLazy(toSym);
+ u->setWeakAlias(toSym);
+ }
+ }
+}
+
// Parses /aligncomm option argument.
void SymbolTable::parseAligncomm(StringRef s) {
auto [name, align] = s.split(',');
diff --git a/lld/COFF/SymbolTable.h b/lld/COFF/SymbolTable.h
index 15e2644..aadd366 100644
--- a/lld/COFF/SymbolTable.h
+++ b/lld/COFF/SymbolTable.h
@@ -31,6 +31,7 @@ class DefinedAbsolute;
class DefinedRegular;
class ImportThunkChunk;
class LazyArchive;
+class SameAddressThunkARM64EC;
class SectionChunk;
class Symbol;
@@ -67,7 +68,10 @@ public:
// Try to resolve any undefined symbols and update the symbol table
// accordingly, then print an error message for any remaining undefined
// symbols and warn about imported local symbols.
- void resolveRemainingUndefines();
+ void resolveRemainingUndefines(std::vector<Undefined *> &aliases);
+
+ // Try to resolve undefined symbols with alternate names.
+ void resolveAlternateNames();
// Load lazy objects that are needed for MinGW automatic import and for
// doing stdcall fixups.
@@ -137,6 +141,7 @@ public:
void addEntryThunk(Symbol *from, Symbol *to);
void addExitThunk(Symbol *from, Symbol *to);
void initializeECThunks();
+ void initializeSameAddressThunks();
void reportDuplicate(Symbol *existing, InputFile *newFile,
SectionChunk *newSc = nullptr,
@@ -156,6 +161,8 @@ public:
// A list of EC EXP+ symbols.
std::vector<Symbol *> expSymbols;
+ std::vector<SameAddressThunkARM64EC *> sameAddressThunks;
+
// A list of DLL exports.
std::vector<Export> exports;
llvm::DenseSet<StringRef> directivesExports;
diff --git a/lld/COFF/Symbols.cpp b/lld/COFF/Symbols.cpp
index b571ce9..ba4f95d1 100644
--- a/lld/COFF/Symbols.cpp
+++ b/lld/COFF/Symbols.cpp
@@ -91,6 +91,14 @@ bool Symbol::isLive() const {
return true;
}
+Defined *Symbol::getDefined() {
+ if (auto d = dyn_cast<Defined>(this))
+ return d;
+ if (auto u = dyn_cast<Undefined>(this))
+ return u->getDefinedWeakAlias();
+ return nullptr;
+}
+
void Symbol::replaceKeepingName(Symbol *other, size_t size) {
StringRef origName = getName();
memcpy(this, other, size);
diff --git a/lld/COFF/Symbols.h b/lld/COFF/Symbols.h
index fd3d8ce..c86ded8 100644
--- a/lld/COFF/Symbols.h
+++ b/lld/COFF/Symbols.h
@@ -95,6 +95,10 @@ public:
symbolKind == LazyDLLSymbolKind;
}
+ // Get the Defined symbol associated with this symbol, either itself or its
+ // weak alias.
+ Defined *getDefined();
+
private:
void computeName();
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 0765618..21ab9d1 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -314,6 +314,7 @@ private:
uint32_t dataDirOffset64;
OutputSection *textSec;
+ OutputSection *wowthkSec;
OutputSection *hexpthkSec;
OutputSection *bssSec;
OutputSection *rdataSec;
@@ -1076,8 +1077,10 @@ void Writer::createSections() {
// Try to match the section order used by link.exe.
textSec = createSection(".text", code | r | x);
- if (isArm64EC(ctx.config.machine))
+ if (isArm64EC(ctx.config.machine)) {
+ wowthkSec = createSection(".wowthk", code | r | x);
hexpthkSec = createSection(".hexpthk", code | r | x);
+ }
bssSec = createSection(".bss", bss | r | w);
rdataSec = createSection(".rdata", data | r);
buildidSec = createSection(".buildid", data | r);
@@ -1129,6 +1132,9 @@ void Writer::createSections() {
if (hasIdata)
locateImportTables();
+ for (auto thunk : ctx.symtab.sameAddressThunks)
+ wowthkSec->addChunk(thunk);
+
// Then create an OutputSection for each section.
// '$' and all following characters in input section names are
// discarded when determining output section. So, .text$foo
@@ -2310,6 +2316,14 @@ void Writer::createECChunks() {
ctx.symtab.findUnderscore("__arm64x_redirection_metadata");
replaceSymbol<DefinedSynthetic>(entryPointsSym, entryPointsSym->getName(),
entryPoints);
+
+ for (auto thunk : ctx.symtab.sameAddressThunks) {
+ // Relocation values are set later in setECSymbols.
+ ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),
+ thunk);
+ ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),
+ Arm64XRelocVal(thunk, sizeof(uint32_t)));
+ }
}
// MinGW specific. Gather all relocations that are imported from a DLL even
@@ -2519,6 +2533,9 @@ void Writer::setECSymbols() {
chpeSym->getRVA() + offsetof(chpe_metadata, ExtraRFETableSize),
pdata.last->getRVA() + pdata.last->getSize() - pdata.first->getRVA());
}
+
+ for (SameAddressThunkARM64EC *thunk : ctx.symtab.sameAddressThunks)
+ thunk->setDynamicRelocs(ctx);
}
// Write section contents to a mmap'ed file.
@@ -2544,7 +2561,15 @@ void Writer::writeSections() {
}
parallelForEach(sec->chunks, [&](Chunk *c) {
- c->writeTo(secBuf + c->getRVA() - sec->getRVA());
+ uint8_t *buf = secBuf + c->getRVA() - sec->getRVA();
+ c->writeTo(buf);
+
+ // Write the offset to EC entry thunk preceding section contents. The low
+ // bit is always set, so it's effectively an offset from the last byte of
+ // the offset.
+ if (Defined *entryThunk = c->getEntryThunk())
+ write32le(buf - sizeof(uint32_t),
+ entryThunk->getRVA() - c->getRVA() + 1);
});
}
}
diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index 15dcddb..a145530 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -809,10 +809,13 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
// address.
// Meanwhile skip undefined, preemptible and STT_GNU_IFUNC symbols, because
// these symbols may be resolve in runtime.
+ // Moreover, relaxation can only occur if the addends of both relocations are
+ // zero for GOT references.
if (rHi20.type == R_LARCH_GOT_PC_HI20 &&
- (!rHi20.sym->isDefined() || rHi20.sym->isPreemptible ||
- rHi20.sym->isGnuIFunc() ||
- (ctx.arg.isPic && !cast<Defined>(*rHi20.sym).section)))
+ (!rHi20.sym || rHi20.sym != rLo12.sym || !rHi20.sym->isDefined() ||
+ rHi20.sym->isPreemptible || rHi20.sym->isGnuIFunc() ||
+ (ctx.arg.isPic && !cast<Defined>(*rHi20.sym).section) ||
+ rHi20.addend != 0 || rLo12.addend != 0))
return;
uint64_t dest = 0;
diff --git a/lld/ELF/Arch/Mips.cpp b/lld/ELF/Arch/Mips.cpp
index 91c7f15..f88b021c 100644
--- a/lld/ELF/Arch/Mips.cpp
+++ b/lld/ELF/Arch/Mips.cpp
@@ -40,6 +40,10 @@ public:
};
} // namespace
+uint64_t elf::getMipsPageAddr(uint64_t addr) {
+ return (addr + 0x8000) & ~0xffff;
+}
+
template <class ELFT> MIPS<ELFT>::MIPS(Ctx &ctx) : TargetInfo(ctx) {
gotPltHeaderEntriesNum = 2;
defaultMaxPageSize = 65536;
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index e7622dd..a83a4c1 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -702,6 +702,8 @@ struct Ctx : CommonLinkerContext {
std::unique_ptr<llvm::TarWriter> tar;
// InputFile for linker created symbols with no source location.
InputFile *internalFile = nullptr;
+ // Dummy Undefined for relocations without a symbol.
+ Undefined *dummySym = nullptr;
// True if symbols can be exported (isExported) or preemptible.
bool hasDynsym = false;
// True if SHT_LLVM_SYMPART is used.
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 91e11bc..6c2f318 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -3140,6 +3140,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
ctx.symtab->insert(arg->getValue())->traced = true;
ctx.internalFile = createInternalFile(ctx, "<internal>");
+ ctx.dummySym = make<Undefined>(ctx.internalFile, "", STB_LOCAL, 0, 0);
// Handle -u/--undefined before input files. If both a.a and b.so define foo,
// -u foo a.a b.so will extract a.a.
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 68e3feb..784ff7c 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -861,6 +861,11 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
return ctx.in.mipsGot->getVA() +
ctx.in.mipsGot->getPageEntryOffset(file, *r.sym, a) -
ctx.in.mipsGot->getGp(file);
+ case RE_MIPS_OSEC_LOCAL_PAGE:
+ // This is used by the MIPS multi-GOT implementation. It relocates
+ // addresses of 64kb pages that lie inside the output section that sym is
+ // a representative for.
+ return getMipsPageAddr(r.sym->getOutputSection()->addr) + a;
case RE_MIPS_GOT_OFF:
case RE_MIPS_GOT_OFF32:
// In case of MIPS if a GOT relocation has non-zero addend this addend
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index bd22fe2..32ac28d6 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -885,10 +885,12 @@ static void addPltEntry(Ctx &ctx, PltSection &plt, GotPltSection &gotPlt,
RelocationBaseSection &rel, RelType type, Symbol &sym) {
plt.addEntry(sym);
gotPlt.addEntry(sym);
- rel.addReloc({type, &gotPlt, sym.getGotPltOffset(ctx),
- sym.isPreemptible ? DynamicReloc::AgainstSymbol
- : DynamicReloc::AddendOnlyWithTargetVA,
- sym, 0, R_ABS});
+ if (sym.isPreemptible)
+ rel.addReloc(
+ {type, &gotPlt, sym.getGotPltOffset(ctx), true, sym, 0, R_ADDEND});
+ else
+ rel.addReloc(
+ {type, &gotPlt, sym.getGotPltOffset(ctx), false, sym, 0, R_ABS});
}
void elf::addGotEntry(Ctx &ctx, Symbol &sym) {
@@ -897,9 +899,8 @@ void elf::addGotEntry(Ctx &ctx, Symbol &sym) {
// If preemptible, emit a GLOB_DAT relocation.
if (sym.isPreemptible) {
- ctx.mainPart->relaDyn->addReloc({ctx.target->gotRel, ctx.in.got.get(), off,
- DynamicReloc::AgainstSymbol, sym, 0,
- R_ABS});
+ ctx.mainPart->relaDyn->addReloc(
+ {ctx.target->gotRel, ctx.in.got.get(), off, true, sym, 0, R_ADDEND});
return;
}
@@ -920,15 +921,13 @@ static void addGotAuthEntry(Ctx &ctx, Symbol &sym) {
// If preemptible, emit a GLOB_DAT relocation.
if (sym.isPreemptible) {
ctx.mainPart->relaDyn->addReloc({R_AARCH64_AUTH_GLOB_DAT, ctx.in.got.get(),
- off, DynamicReloc::AgainstSymbol, sym, 0,
- R_ABS});
+ off, true, sym, 0, R_ADDEND});
return;
}
// Signed GOT requires dynamic relocation.
ctx.in.got->getPartition(ctx).relaDyn->addReloc(
- {R_AARCH64_AUTH_RELATIVE, ctx.in.got.get(), off,
- DynamicReloc::AddendOnlyWithTargetVA, sym, 0, R_ABS});
+ {R_AARCH64_AUTH_RELATIVE, ctx.in.got.get(), off, false, sym, 0, R_ABS});
}
static void addTpOffsetGotEntry(Ctx &ctx, Symbol &sym) {
@@ -1159,9 +1158,8 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
sec->addReloc({expr, type, offset, addend, &sym});
part.relrAuthDyn->relocs.push_back({sec, sec->relocs().size() - 1});
} else {
- part.relaDyn->addReloc({R_AARCH64_AUTH_RELATIVE, sec, offset,
- DynamicReloc::AddendOnlyWithTargetVA, sym,
- addend, R_ABS});
+ part.relaDyn->addReloc({R_AARCH64_AUTH_RELATIVE, sec, offset, false,
+ sym, addend, R_ABS});
}
return;
}
@@ -1948,13 +1946,12 @@ void elf::postScanRelocations(Ctx &ctx) {
GotSection *got = ctx.in.got.get();
if (ctx.needsTlsLd.load(std::memory_order_relaxed) && got->addTlsIndex()) {
- static Undefined dummy(ctx.internalFile, "", STB_LOCAL, 0, 0);
if (ctx.arg.shared)
ctx.mainPart->relaDyn->addReloc(
{ctx.target->tlsModuleIndexRel, got, got->getTlsIndexOff()});
else
got->addConstant({R_ADDEND, ctx.target->symbolicRel,
- got->getTlsIndexOff(), 1, &dummy});
+ got->getTlsIndexOff(), 1, ctx.dummySym});
}
assert(ctx.symAux.size() == 1);
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index 02ddf70..c1c4860 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -110,6 +110,7 @@ enum RelExpr {
RE_MIPS_GOT_LOCAL_PAGE,
RE_MIPS_GOT_OFF,
RE_MIPS_GOT_OFF32,
+ RE_MIPS_OSEC_LOCAL_PAGE,
RE_MIPS_TLSGD,
RE_MIPS_TLSLD,
RE_PPC32_PLTREL,
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index efec41a..0d87f9a 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -769,10 +769,6 @@ void GotSection::writeTo(uint8_t *buf) {
}
}
-static uint64_t getMipsPageAddr(uint64_t addr) {
- return (addr + 0x8000) & ~0xffff;
-}
-
static uint64_t getMipsPageCount(uint64_t size) {
return (size + 0xfffe) / 0xffff + 1;
}
@@ -786,7 +782,7 @@ void MipsGotSection::addEntry(InputFile &file, Symbol &sym, int64_t addend,
FileGot &g = getGot(file);
if (expr == RE_MIPS_GOT_LOCAL_PAGE) {
if (const OutputSection *os = sym.getOutputSection())
- g.pagesMap.insert({os, {}});
+ g.pagesMap.insert({os, {&sym}});
else
g.local16.insert({{nullptr, getMipsPageAddr(sym.getVA(ctx, addend))}, 0});
} else if (sym.isTls())
@@ -1066,8 +1062,7 @@ void MipsGotSection::build() {
// be allocated before us in the static TLS block.
if (s->isPreemptible || ctx.arg.shared)
ctx.mainPart->relaDyn->addReloc(
- {ctx.target->tlsGotRel, this, offset,
- DynamicReloc::AgainstSymbolWithTargetVA, *s, 0, R_ABS});
+ {ctx.target->tlsGotRel, this, offset, true, *s, 0, R_ABS});
}
for (std::pair<Symbol *, size_t> &p : got.dynTlsSymbols) {
Symbol *s = p.first;
@@ -1115,15 +1110,16 @@ void MipsGotSection::build() {
size_t pageCount = l.second.count;
for (size_t pi = 0; pi < pageCount; ++pi) {
uint64_t offset = (l.second.firstIndex + pi) * ctx.arg.wordsize;
- ctx.mainPart->relaDyn->addReloc({ctx.target->relativeRel, this, offset,
- l.first, int64_t(pi * 0x10000)});
+ ctx.mainPart->relaDyn->addReloc(
+ {ctx.target->relativeRel, this, offset, false, *l.second.repSym,
+ int64_t(pi * 0x10000), RE_MIPS_OSEC_LOCAL_PAGE});
}
}
for (const std::pair<GotEntry, size_t> &p : got.local16) {
uint64_t offset = p.second * ctx.arg.wordsize;
ctx.mainPart->relaDyn->addReloc({ctx.target->relativeRel, this, offset,
- DynamicReloc::AddendOnlyWithTargetVA,
- *p.first.first, p.first.second, R_ABS});
+ false, *p.first.first, p.first.second,
+ R_ABS});
}
}
}
@@ -1646,24 +1642,10 @@ uint64_t DynamicReloc::getOffset() const {
}
int64_t DynamicReloc::computeAddend(Ctx &ctx) const {
- switch (kind) {
- case AddendOnly:
- assert(sym == nullptr);
- return addend;
- case AgainstSymbol:
- assert(sym != nullptr);
- return addend;
- case AddendOnlyWithTargetVA:
- case AgainstSymbolWithTargetVA: {
- uint64_t ca = inputSec->getRelocTargetVA(
- ctx, Relocation{expr, type, 0, addend, sym}, getOffset());
- return ctx.arg.is64 ? ca : SignExtend64<32>(ca);
- }
- case MipsMultiGotPage:
- assert(sym == nullptr);
- return getMipsPageAddr(outputSec->addr) + addend;
- }
- llvm_unreachable("Unknown DynamicReloc::Kind enum");
+ assert(!isFinal && "addend already computed");
+ uint64_t ca = inputSec->getRelocTargetVA(
+ ctx, Relocation{expr, type, 0, addend, sym}, getOffset());
+ return ctx.arg.is64 ? ca : SignExtend64<32>(ca);
}
uint32_t DynamicReloc::getSymIndex(SymbolTableBaseSection *symTab) const {
@@ -1691,8 +1673,8 @@ RelocationBaseSection::RelocationBaseSection(Ctx &ctx, StringRef name,
void RelocationBaseSection::addSymbolReloc(
RelType dynType, InputSectionBase &isec, uint64_t offsetInSec, Symbol &sym,
int64_t addend, std::optional<RelType> addendRelType) {
- addReloc(DynamicReloc::AgainstSymbol, dynType, isec, offsetInSec, sym, addend,
- R_ADDEND, addendRelType ? *addendRelType : ctx.target->noneRel);
+ addReloc(true, dynType, isec, offsetInSec, sym, addend, R_ADDEND,
+ addendRelType ? *addendRelType : ctx.target->noneRel);
}
void RelocationBaseSection::addAddendOnlyRelocIfNonPreemptible(
@@ -1700,11 +1682,9 @@ void RelocationBaseSection::addAddendOnlyRelocIfNonPreemptible(
RelType addendRelType) {
// No need to write an addend to the section for preemptible symbols.
if (sym.isPreemptible)
- addReloc({dynType, &isec, offsetInSec, DynamicReloc::AgainstSymbol, sym, 0,
- R_ABS});
+ addReloc({dynType, &isec, offsetInSec, true, sym, 0, R_ADDEND});
else
- addReloc(DynamicReloc::AddendOnlyWithTargetVA, dynType, isec, offsetInSec,
- sym, 0, R_ABS, addendRelType);
+ addReloc(false, dynType, isec, offsetInSec, sym, 0, R_ABS, addendRelType);
}
void RelocationBaseSection::mergeRels() {
@@ -1744,17 +1724,17 @@ void RelocationBaseSection::finalizeContents() {
}
}
-void DynamicReloc::computeRaw(Ctx &ctx, SymbolTableBaseSection *symt) {
+void DynamicReloc::finalize(Ctx &ctx, SymbolTableBaseSection *symt) {
r_offset = getOffset();
r_sym = getSymIndex(symt);
addend = computeAddend(ctx);
- kind = AddendOnly; // Catch errors
+ isFinal = true; // Catch errors
}
void RelocationBaseSection::computeRels() {
SymbolTableBaseSection *symTab = getPartition(ctx).dynSymTab.get();
parallelForEach(relocs, [&ctx = ctx, symTab](DynamicReloc &rel) {
- rel.computeRaw(ctx, symTab);
+ rel.finalize(ctx, symTab);
});
auto irelative = std::stable_partition(
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 5f01513..223dfe3 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -327,9 +327,11 @@ private:
size_t startIndex = 0;
struct PageBlock {
+ Symbol *repSym; // Representative symbol for the OutputSection
size_t firstIndex;
size_t count;
- PageBlock() : firstIndex(0), count(0) {}
+ PageBlock(Symbol *repSym = nullptr)
+ : repSym(repSym), firstIndex(0), count(0) {}
};
// Map output sections referenced by MIPS GOT relocations
@@ -418,61 +420,31 @@ private:
class DynamicReloc {
public:
- enum Kind {
- /// The resulting dynamic relocation does not reference a symbol (#sym must
- /// be nullptr) and uses #addend as the result of computeAddend(ctx).
- AddendOnly,
- /// The resulting dynamic relocation will not reference a symbol: #sym is
- /// only used to compute the addend with InputSection::getRelocTargetVA().
- /// Useful for various relative and TLS relocations (e.g. R_X86_64_TPOFF64).
- AddendOnlyWithTargetVA,
- /// The resulting dynamic relocation references symbol #sym from the dynamic
- /// symbol table and uses #addend as the value of computeAddend(ctx).
- AgainstSymbol,
- /// The resulting dynamic relocation references symbol #sym from the dynamic
- /// symbol table and uses InputSection::getRelocTargetVA() + #addend for the
- /// final addend. It can be used for relocations that write the symbol VA as
- // the addend (e.g. R_MIPS_TLS_TPREL64) but still reference the symbol.
- AgainstSymbolWithTargetVA,
- /// This is used by the MIPS multi-GOT implementation. It relocates
- /// addresses of 64kb pages that lie inside the output section.
- MipsMultiGotPage,
- };
- /// This constructor records a relocation against a symbol.
+ /// This constructor records a normal relocation.
DynamicReloc(RelType type, const InputSectionBase *inputSec,
- uint64_t offsetInSec, Kind kind, Symbol &sym, int64_t addend,
- RelExpr expr)
+ uint64_t offsetInSec, bool isAgainstSymbol, Symbol &sym,
+ int64_t addend, RelExpr expr)
: sym(&sym), inputSec(inputSec), offsetInSec(offsetInSec), type(type),
- addend(addend), kind(kind), expr(expr) {}
+ addend(addend), isAgainstSymbol(isAgainstSymbol), isFinal(false),
+ expr(expr) {}
/// This constructor records a relative relocation with no symbol.
DynamicReloc(RelType type, const InputSectionBase *inputSec,
uint64_t offsetInSec, int64_t addend = 0)
- : sym(nullptr), inputSec(inputSec), offsetInSec(offsetInSec), type(type),
- addend(addend), kind(AddendOnly), expr(R_ADDEND) {}
- /// This constructor records dynamic relocation settings used by the MIPS
- /// multi-GOT implementation.
- DynamicReloc(RelType type, const InputSectionBase *inputSec,
- uint64_t offsetInSec, const OutputSection *outputSec,
- int64_t addend)
- : sym(nullptr), outputSec(outputSec), inputSec(inputSec),
- offsetInSec(offsetInSec), type(type), addend(addend),
- kind(MipsMultiGotPage), expr(R_ADDEND) {}
+ : DynamicReloc(type, inputSec, offsetInSec, false,
+ *inputSec->getCtx().dummySym, addend, R_ADDEND) {}
uint64_t getOffset() const;
uint32_t getSymIndex(SymbolTableBaseSection *symTab) const;
- bool needsDynSymIndex() const {
- return kind == AgainstSymbol || kind == AgainstSymbolWithTargetVA;
- }
+ bool needsDynSymIndex() const { return isAgainstSymbol; }
/// Computes the addend of the dynamic relocation. Note that this is not the
/// same as the #addend member variable as it may also include the symbol
/// address/the address of the corresponding GOT entry/etc.
int64_t computeAddend(Ctx &) const;
- void computeRaw(Ctx &, SymbolTableBaseSection *symt);
+ void finalize(Ctx &, SymbolTableBaseSection *symt);
Symbol *sym;
- const OutputSection *outputSec = nullptr;
const InputSectionBase *inputSec;
uint64_t offsetInSec;
uint64_t r_offset;
@@ -483,7 +455,15 @@ public:
int64_t addend;
private:
- Kind kind;
+ /// Whether this was constructed with a Kind of AgainstSymbol.
+ LLVM_PREFERRED_TYPE(bool)
+ uint8_t isAgainstSymbol : 1;
+
+ /// The resulting dynamic relocation has already had its addend computed.
+ /// Calling computeAddend() is an error.
+ LLVM_PREFERRED_TYPE(bool)
+ uint8_t isFinal : 1;
+
// The kind of expression used to calculate the added (required e.g. for
// relative GOT relocations).
RelExpr expr;
@@ -528,8 +508,8 @@ public:
uint64_t offsetInSec, Symbol &sym, int64_t addend,
RelType addendRelType, RelExpr expr) {
assert(expr != R_ADDEND && "expected non-addend relocation expression");
- addReloc<shard>(DynamicReloc::AddendOnlyWithTargetVA, dynType, isec,
- offsetInSec, sym, addend, expr, addendRelType);
+ addReloc<shard>(false, dynType, isec, offsetInSec, sym, addend, expr,
+ addendRelType);
}
/// Add a dynamic relocation using the target address of \p sym as the addend
/// if \p sym is non-preemptible. Otherwise add a relocation against \p sym.
@@ -538,14 +518,15 @@ public:
uint64_t offsetInSec, Symbol &sym,
RelType addendRelType);
template <bool shard = false>
- void addReloc(DynamicReloc::Kind kind, RelType dynType, InputSectionBase &sec,
+ void addReloc(bool isAgainstSymbol, RelType dynType, InputSectionBase &sec,
uint64_t offsetInSec, Symbol &sym, int64_t addend, RelExpr expr,
RelType addendRelType) {
// Write the addends to the relocated address if required. We skip
// it if the written value would be zero.
if (ctx.arg.writeAddends && (expr != R_ADDEND || addend != 0))
sec.addReloc({expr, addendRelType, offsetInSec, addend, &sym});
- addReloc<shard>({dynType, &sec, offsetInSec, kind, sym, addend, expr});
+ addReloc<shard>(
+ {dynType, &sec, offsetInSec, isAgainstSymbol, sym, addend, expr});
}
bool isNeeded() const override {
return !relocs.empty() ||
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index ad7d57d..4946484 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -105,10 +105,9 @@ ErrorPlace elf::getErrorPlace(Ctx &ctx, const uint8_t *loc) {
if (isecLoc <= loc && loc < isecLoc + isec->getSize()) {
std::string objLoc = isec->getLocation(loc - isecLoc);
// Return object file location and source file location.
- Undefined dummy(ctx.internalFile, "", STB_LOCAL, 0, 0);
ELFSyncStream msg(ctx, DiagLevel::None);
if (isec->file)
- msg << isec->getSrcMsg(dummy, loc - isecLoc);
+ msg << isec->getSrcMsg(*ctx.dummySym, loc - isecLoc);
return {isec, objLoc + ": ", std::string(msg.str())};
}
}
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
index 93f1592..fdc0c20 100644
--- a/lld/ELF/Target.h
+++ b/lld/ELF/Target.h
@@ -214,6 +214,7 @@ void processArmCmseSymbols(Ctx &);
template <class ELFT> uint32_t calcMipsEFlags(Ctx &);
uint8_t getMipsFpAbiFlag(Ctx &, InputFile *file, uint8_t oldFlag,
uint8_t newFlag);
+uint64_t getMipsPageAddr(uint64_t addr);
bool isMipsN32Abi(Ctx &, const InputFile &f);
bool isMicroMips(Ctx &);
bool isMipsR6(Ctx &);
@@ -338,21 +339,23 @@ inline uint64_t overwriteULEB128(uint8_t *bufLoc, uint64_t val) {
#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
#endif
#define invokeELFT(f, ...) \
- switch (ctx.arg.ekind) { \
- case lld::elf::ELF32LEKind: \
- f<llvm::object::ELF32LE>(__VA_ARGS__); \
- break; \
- case lld::elf::ELF32BEKind: \
- f<llvm::object::ELF32BE>(__VA_ARGS__); \
- break; \
- case lld::elf::ELF64LEKind: \
- f<llvm::object::ELF64LE>(__VA_ARGS__); \
- break; \
- case lld::elf::ELF64BEKind: \
- f<llvm::object::ELF64BE>(__VA_ARGS__); \
- break; \
- default: \
- llvm_unreachable("unknown ctx.arg.ekind"); \
- }
+ do { \
+ switch (ctx.arg.ekind) { \
+ case lld::elf::ELF32LEKind: \
+ f<llvm::object::ELF32LE>(__VA_ARGS__); \
+ break; \
+ case lld::elf::ELF32BEKind: \
+ f<llvm::object::ELF32BE>(__VA_ARGS__); \
+ break; \
+ case lld::elf::ELF64LEKind: \
+ f<llvm::object::ELF64LE>(__VA_ARGS__); \
+ break; \
+ case lld::elf::ELF64BEKind: \
+ f<llvm::object::ELF64BE>(__VA_ARGS__); \
+ break; \
+ default: \
+ llvm_unreachable("unknown ctx.arg.ekind"); \
+ } \
+ } while (0)
#endif
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index c3c0578..2b0e097 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -1586,9 +1586,8 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
if (isInt<32>(reloc.sym->getVA(ctx, reloc.addend)))
return false;
part.relaDyn->addReloc({R_AARCH64_AUTH_RELATIVE, elem.inputSec,
- reloc.offset,
- DynamicReloc::AddendOnlyWithTargetVA,
- *reloc.sym, reloc.addend, R_ABS});
+ reloc.offset, false, *reloc.sym,
+ reloc.addend, R_ABS});
return true;
});
changed |= (it != part.relrAuthDyn->relocs.end());
diff --git a/lld/test/COFF/alternatename-alias.s b/lld/test/COFF/alternatename-alias.s
new file mode 100644
index 0000000..bd0a861
--- /dev/null
+++ b/lld/test/COFF/alternatename-alias.s
@@ -0,0 +1,15 @@
+// REQUIRES: x86
+
+// Check that a weak alias can be used as an alternate name target.
+// RUN: llvm-mc -filetype=obj -triple=x86_64-windows %s -o %t.obj
+// RUN: lld-link -dll -noentry %t.obj -alternatename:sym=altsym
+
+ .data
+ .rva sym
+
+ .weak altsym
+ .set altsym,a
+
+ .globl a
+a:
+ .word 1
diff --git a/lld/test/COFF/alternatename-antidep.s b/lld/test/COFF/alternatename-antidep.s
new file mode 100644
index 0000000..1188a9b
--- /dev/null
+++ b/lld/test/COFF/alternatename-antidep.s
@@ -0,0 +1,16 @@
+// REQUIRES: x86
+
+// Check that an anti-dependency alias can't be used as an alternate name target.
+// RUN: llvm-mc -filetype=obj -triple=x86_64-windows %s -o %t.obj
+// RUN: not lld-link -dll -noentry %t.obj -alternatename:sym=altsym 2>&1 | FileCheck %s
+// CHECK: error: undefined symbol: sym
+
+ .data
+ .rva sym
+
+ .weak_anti_dep altsym
+ .set altsym,a
+
+ .globl a
+a:
+ .word 1
diff --git a/lld/test/COFF/alternatename-lib.s b/lld/test/COFF/alternatename-lib.s
new file mode 100644
index 0000000..206fe6b
--- /dev/null
+++ b/lld/test/COFF/alternatename-lib.s
@@ -0,0 +1,43 @@
+// REQUIRES: x86
+// RUN: split-file %s %t.dir && cd %t.dir
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-windows refab.s -o refab.obj
+// RUN: llvm-mc -filetype=obj -triple=x86_64-windows aa.s -o aa.obj
+// RUN: llvm-mc -filetype=obj -triple=x86_64-windows b.s -o b.obj
+// RUN: llvm-mc -filetype=obj -triple=x86_64-windows antidep.s -o antidep.obj
+// RUN: llvm-lib -out:aa.lib aa.obj
+// RUN: llvm-lib -out:b.lib b.obj
+
+// Check that -alternatename with an undefined target does not prevent the symbol from being resolved to a library,
+// once another alternate name is resolved and pulls in the source symbol.
+// RUN: lld-link -out:out.dll -dll -noentry -machine:amd64 refab.obj aa.lib -alternatename:a=aa -alternatename:b=undef
+
+// Check that -alternatename with an anti-dependency target does not prevent the symbol from being resolved to a library,
+// after another alternate name is resolved and pulls in the source symbol.
+// RUN: lld-link -out:out2.dll -dll -noentry -machine:amd64 antidep.obj refab.obj aa.lib -alternatename:a=aa -alternatename:b=u
+
+#--- refab.s
+ .data
+ .rva a
+ .rva b
+
+#--- aa.s
+ .globl aa
+aa:
+ .word 1
+
+ .section .drectve, "yn"
+ .ascii "/defaultlib:b.lib"
+
+#--- b.s
+ .globl b
+b:
+ .word 2
+
+#--- antidep.s
+ .weak_anti_dep u
+ .set u,d
+
+ .globl d
+d:
+ .word 3
diff --git a/lld/test/COFF/arm64ec-altnames.s b/lld/test/COFF/arm64ec-altnames.s
index b2abb24..cca778a 100644
--- a/lld/test/COFF/arm64ec-altnames.s
+++ b/lld/test/COFF/arm64ec-altnames.s
@@ -2,6 +2,7 @@ REQUIRES: aarch64
RUN: split-file %s %t.dir && cd %t.dir
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows ext.s -o ext.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows ext-mangled.s -o ext-mangled.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows impl.s -o impl.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows impl-cpp.s -o impl-cpp.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig.obj
@@ -49,6 +50,20 @@ RUN: lld-link -machine:arm64ec -dll -noentry -out:out4.dll impl-cpp.obj loadconf
RUN: llvm-objdump -d out4.dll | FileCheck --check-prefix=DISASM %s
RUN: llvm-readobj --hex-dump=.test out4.dll | FileCheck --check-prefix=TESTSEC %s
+# Check that when both mangled and demangled alternate names are used,
+# only the one whose target is defined is used (the mangled one in this case).
+
+RUN: lld-link -machine:arm64ec -dll -noentry -out:out5.dll ext-mangled.obj loadconfig.obj "-alternatename:#func=#altsym" -alternatename:func=altsym
+RUN: llvm-objdump -d out5.dll | FileCheck --check-prefix=DISASM %s
+RUN: llvm-readobj --hex-dump=.test out5.dll | FileCheck --check-prefix=TESTSEC %s
+
+# Check that when both mangled and demangled alternate names are used,
+# only the one whose target is defined is used (the demangled one in this case).
+
+RUN: lld-link -machine:arm64ec -dll -noentry -out:out6.dll ext.obj loadconfig.obj "-alternatename:#func=#altsym" -alternatename:func=altsym
+RUN: llvm-objdump -d out6.dll | FileCheck --check-prefix=DISASM2 %s
+RUN: llvm-readobj --hex-dump=.test out6.dll | FileCheck --check-prefix=TESTSEC2 %s
+
#--- ext.s
.weak_anti_dep func
.set func, "#func"
@@ -70,6 +85,30 @@ altsym:
mov w0, #1
ret
+#--- ext-mangled.s
+ .weak_anti_dep func
+.set func, "#func"
+ .weak_anti_dep "#func"
+.set "#func", thunksym
+
+ .section .test, "r"
+ .rva func
+ .rva "#func"
+
+ .section .thnk,"xr",discard,thunksym
+thunksym:
+ mov w0, #2
+ ret
+
+ .section .text,"xr",discard,"#altsym"
+ .globl "#altsym"
+"#altsym":
+ mov w0, #1
+ ret
+
+ .weak_anti_dep altsym
+ .set altsym,"#altsym"
+
#--- impl.s
.weak_anti_dep func
.set func, "#func"
diff --git a/lld/test/COFF/arm64ec-delayimport.test b/lld/test/COFF/arm64ec-delayimport.test
index 1e0bd89..01d4ab8 100644
--- a/lld/test/COFF/arm64ec-delayimport.test
+++ b/lld/test/COFF/arm64ec-delayimport.test
@@ -51,28 +51,28 @@ DISASM-NEXT: 180002016: 48 8d 05 6b 50 00 00 leaq 0x506b(%rip), %rax
DISASM-NEXT: 18000201d: e9 0c 00 00 00 jmp 0x18000202e <.text+0x102e>
DISASM-NEXT: 180002022: 48 8d 05 67 50 00 00 leaq 0x5067(%rip), %rax # 0x180007090
DISASM-NEXT: 180002029: e9 00 00 00 00 jmp 0x18000202e <.text+0x102e>
-DISASM-NEXT: 18000202e: 51 pushq %rcx
-DISASM-NEXT: 18000202f: 52 pushq %rdx
-DISASM-NEXT: 180002030: 41 50 pushq %r8
-DISASM-NEXT: 180002032: 41 51 pushq %r9
-DISASM-NEXT: 180002034: 48 83 ec 48 subq $0x48, %rsp
-DISASM-NEXT: 180002038: 66 0f 7f 04 24 movdqa %xmm0, (%rsp)
-DISASM-NEXT: 18000203d: 66 0f 7f 4c 24 10 movdqa %xmm1, 0x10(%rsp)
-DISASM-NEXT: 180002043: 66 0f 7f 54 24 20 movdqa %xmm2, 0x20(%rsp)
-DISASM-NEXT: 180002049: 66 0f 7f 5c 24 30 movdqa %xmm3, 0x30(%rsp)
-DISASM-NEXT: 18000204f: 48 8b d0 movq %rax, %rdx
-DISASM-NEXT: 180002052: 48 8d 0d a7 21 00 00 leaq 0x21a7(%rip), %rcx # 0x180004200
-DISASM-NEXT: 180002059: e8 aa ef ff ff callq 0x180001008 <.text+0x8>
-DISASM-NEXT: 18000205e: 66 0f 6f 04 24 movdqa (%rsp), %xmm0
-DISASM-NEXT: 180002063: 66 0f 6f 4c 24 10 movdqa 0x10(%rsp), %xmm1
-DISASM-NEXT: 180002069: 66 0f 6f 54 24 20 movdqa 0x20(%rsp), %xmm2
-DISASM-NEXT: 18000206f: 66 0f 6f 5c 24 30 movdqa 0x30(%rsp), %xmm3
-DISASM-NEXT: 180002075: 48 83 c4 48 addq $0x48, %rsp
-DISASM-NEXT: 180002079: 41 59 popq %r9
-DISASM-NEXT: 18000207b: 41 58 popq %r8
-DISASM-NEXT: 18000207d: 5a popq %rdx
-DISASM-NEXT: 18000207e: 59 popq %rcx
-DISASM-NEXT: 18000207f: ff e0 jmpq *%rax
+DISASM-NEXT: 18000202e: 48 89 4c 24 08 movq %rcx, 0x8(%rsp)
+DISASM-NEXT: 180002033: 48 89 54 24 10 movq %rdx, 0x10(%rsp)
+DISASM-NEXT: 180002038: 4c 89 44 24 18 movq %r8, 0x18(%rsp)
+DISASM-NEXT: 18000203d: 4c 89 4c 24 20 movq %r9, 0x20(%rsp)
+DISASM-NEXT: 180002042: 48 83 ec 68 subq $0x68, %rsp
+DISASM-NEXT: 180002046: 66 0f 7f 44 24 20 movdqa %xmm0, 0x20(%rsp)
+DISASM-NEXT: 18000204c: 66 0f 7f 4c 24 30 movdqa %xmm1, 0x30(%rsp)
+DISASM-NEXT: 180002052: 66 0f 7f 54 24 40 movdqa %xmm2, 0x40(%rsp)
+DISASM-NEXT: 180002058: 66 0f 7f 5c 24 50 movdqa %xmm3, 0x50(%rsp)
+DISASM-NEXT: 18000205e: 48 8b d0 movq %rax, %rdx
+DISASM-NEXT: 180002061: 48 8d 0d 90 21 00 00 leaq 0x2190(%rip), %rcx # 0x1800041f8
+DISASM-NEXT: 180002068: e8 9b ef ff ff callq 0x180001008 <.text+0x8>
+DISASM-NEXT: 18000206d: 66 0f 6f 44 24 20 movdqa 0x20(%rsp), %xmm0
+DISASM-NEXT: 180002073: 66 0f 6f 4c 24 30 movdqa 0x30(%rsp), %xmm1
+DISASM-NEXT: 180002079: 66 0f 6f 54 24 40 movdqa 0x40(%rsp), %xmm2
+DISASM-NEXT: 18000207f: 66 0f 6f 5c 24 50 movdqa 0x50(%rsp), %xmm3
+DISASM-NEXT: 180002085: 48 8b 4c 24 70 movq 0x70(%rsp), %rcx
+DISASM-NEXT: 18000208a: 48 8b 54 24 78 movq 0x78(%rsp), %rdx
+DISASM-NEXT: 18000208f: 4c 8b 84 24 80 00 00 00 movq 0x80(%rsp), %r8
+DISASM-NEXT: 180002097: 4c 8b 8c 24 88 00 00 00 movq 0x88(%rsp), %r9
+DISASM-NEXT: 18000209f: 48 83 c4 68 addq $0x68, %rsp
+DISASM-NEXT: 1800020a3: ff e0 jmpq *%rax
RUN: llvm-readobj --coff-load-config out.dll | FileCheck --check-prefix=LOADCFG %s
LOADCFG: CHPEMetadata [
@@ -85,7 +85,7 @@ IMPORTS-NEXT: Name: test.dll
IMPORTS-NEXT: Attributes: 0x1
IMPORTS-NEXT: ModuleHandle: 0x7080
IMPORTS-NEXT: ImportAddressTable: 0x7088
-IMPORTS-NEXT: ImportNameTable: 0x4240
+IMPORTS-NEXT: ImportNameTable: 0x4238
IMPORTS-NEXT: BoundDelayImportTable: 0x0
IMPORTS-NEXT: UnloadDelayImportTable: 0x0
IMPORTS-NEXT: Import {
@@ -141,7 +141,7 @@ RELOC-NEXT: Address: 0x6008
RELOC-NEXT: }
RUN: llvm-readobj --hex-dump=.pdata out.dll | FileCheck --check-prefix=PDATA %s
-PDATA: 0x180008000 2e200000 81200000 18400000
+PDATA: 0x180008000 2e200000 a5200000 18400000
Verify that a demangled version of __delayLoadHelper2 can be used.
diff --git a/lld/test/COFF/arm64x-delayimport.test b/lld/test/COFF/arm64x-delayimport.test
index 56923ef..2a68bce 100644
--- a/lld/test/COFF/arm64x-delayimport.test
+++ b/lld/test/COFF/arm64x-delayimport.test
@@ -21,7 +21,7 @@ IMPORTS-NEXT: Name: test.dll
IMPORTS-NEXT: Attributes: 0x1
IMPORTS-NEXT: ModuleHandle: 0x6080
IMPORTS-NEXT: ImportAddressTable: 0x6088
-IMPORTS-NEXT: ImportNameTable: 0x4390
+IMPORTS-NEXT: ImportNameTable: 0x4388
IMPORTS-NEXT: BoundDelayImportTable: 0x0
IMPORTS-NEXT: UnloadDelayImportTable: 0x0
IMPORTS-NEXT: Import {
@@ -35,7 +35,7 @@ IMPORTS-NEXT: Name: test.dll
IMPORTS-NEXT: Attributes: 0x1
IMPORTS-NEXT: ModuleHandle: 0x6080
IMPORTS-NEXT: ImportAddressTable: 0x6098
-IMPORTS-NEXT: ImportNameTable: 0x43A0
+IMPORTS-NEXT: ImportNameTable: 0x4398
IMPORTS-NEXT: BoundDelayImportTable: 0x0
IMPORTS-NEXT: UnloadDelayImportTable: 0x0
IMPORTS-NEXT: Import {
@@ -73,7 +73,7 @@ DISASM-NEXT: 180001040: ad0497e4 stp q4, q5, [sp, #0x90]
DISASM-NEXT: 180001044: ad059fe6 stp q6, q7, [sp, #0xb0]
DISASM-NEXT: 180001048: aa1103e1 mov x1, x17
DISASM-NEXT: 18000104c: f0000000 adrp x0, 0x180004000
-DISASM-NEXT: 180001050: 910d4000 add x0, x0, #0x350
+DISASM-NEXT: 180001050: 910d2000 add x0, x0, #0x348
DISASM-NEXT: 180001054: 97ffffeb bl 0x180001000 <.text>
DISASM-NEXT: 180001058: aa0003f0 mov x16, x0
DISASM-NEXT: 18000105c: ad459fe6 ldp q6, q7, [sp, #0xb0]
@@ -105,28 +105,28 @@ DISASM-NEXT: ...
DISASM-NEXT: 180003000: ff 25 92 30 00 00 jmpq *0x3092(%rip) # 0x180006098
DISASM-NEXT: 180003006: 48 8d 05 8b 30 00 00 leaq 0x308b(%rip), %rax # 0x180006098
DISASM-NEXT: 18000300d: e9 00 00 00 00 jmp 0x180003012 <.text+0x2012>
-DISASM-NEXT: 180003012: 51 pushq %rcx
-DISASM-NEXT: 180003013: 52 pushq %rdx
-DISASM-NEXT: 180003014: 41 50 pushq %r8
-DISASM-NEXT: 180003016: 41 51 pushq %r9
-DISASM-NEXT: 180003018: 48 83 ec 48 subq $0x48, %rsp
-DISASM-NEXT: 18000301c: 66 0f 7f 04 24 movdqa %xmm0, (%rsp)
-DISASM-NEXT: 180003021: 66 0f 7f 4c 24 10 movdqa %xmm1, 0x10(%rsp)
-DISASM-NEXT: 180003027: 66 0f 7f 54 24 20 movdqa %xmm2, 0x20(%rsp)
-DISASM-NEXT: 18000302d: 66 0f 7f 5c 24 30 movdqa %xmm3, 0x30(%rsp)
-DISASM-NEXT: 180003033: 48 8b d0 movq %rax, %rdx
-DISASM-NEXT: 180003036: 48 8d 0d 13 13 00 00 leaq 0x1313(%rip), %rcx # 0x180004350
-DISASM-NEXT: 18000303d: e8 c6 ef ff ff callq 0x180002008 <.text+0x1008>
-DISASM-NEXT: 180003042: 66 0f 6f 04 24 movdqa (%rsp), %xmm0
-DISASM-NEXT: 180003047: 66 0f 6f 4c 24 10 movdqa 0x10(%rsp), %xmm1
-DISASM-NEXT: 18000304d: 66 0f 6f 54 24 20 movdqa 0x20(%rsp), %xmm2
-DISASM-NEXT: 180003053: 66 0f 6f 5c 24 30 movdqa 0x30(%rsp), %xmm3
-DISASM-NEXT: 180003059: 48 83 c4 48 addq $0x48, %rsp
-DISASM-NEXT: 18000305d: 41 59 popq %r9
-DISASM-NEXT: 18000305f: 41 58 popq %r8
-DISASM-NEXT: 180003061: 5a popq %rdx
-DISASM-NEXT: 180003062: 59 popq %rcx
-DISASM-NEXT: 180003063: ff e0 jmpq *%rax
+DISASM-NEXT: 180003012: 48 89 4c 24 08 movq %rcx, 0x8(%rsp)
+DISASM-NEXT: 180003017: 48 89 54 24 10 movq %rdx, 0x10(%rsp)
+DISASM-NEXT: 18000301c: 4c 89 44 24 18 movq %r8, 0x18(%rsp)
+DISASM-NEXT: 180003021: 4c 89 4c 24 20 movq %r9, 0x20(%rsp)
+DISASM-NEXT: 180003026: 48 83 ec 68 subq $0x68, %rsp
+DISASM-NEXT: 18000302a: 66 0f 7f 44 24 20 movdqa %xmm0, 0x20(%rsp)
+DISASM-NEXT: 180003030: 66 0f 7f 4c 24 30 movdqa %xmm1, 0x30(%rsp)
+DISASM-NEXT: 180003036: 66 0f 7f 54 24 40 movdqa %xmm2, 0x40(%rsp)
+DISASM-NEXT: 18000303c: 66 0f 7f 5c 24 50 movdqa %xmm3, 0x50(%rsp)
+DISASM-NEXT: 180003042: 48 8b d0 movq %rax, %rdx
+DISASM-NEXT: 180003045: 48 8d 0d fc 12 00 00 leaq 0x12fc(%rip), %rcx # 0x180004348
+DISASM-NEXT: 18000304c: e8 b7 ef ff ff callq 0x180002008 <.text+0x1008>
+DISASM-NEXT: 180003051: 66 0f 6f 44 24 20 movdqa 0x20(%rsp), %xmm0
+DISASM-NEXT: 180003057: 66 0f 6f 4c 24 30 movdqa 0x30(%rsp), %xmm1
+DISASM-NEXT: 18000305d: 66 0f 6f 54 24 40 movdqa 0x40(%rsp), %xmm2
+DISASM-NEXT: 180003063: 66 0f 6f 5c 24 50 movdqa 0x50(%rsp), %xmm3
+DISASM-NEXT: 180003069: 48 8b 4c 24 70 movq 0x70(%rsp), %rcx
+DISASM-NEXT: 18000306e: 48 8b 54 24 78 movq 0x78(%rsp), %rdx
+DISASM-NEXT: 180003073: 4c 8b 84 24 80 00 00 00 movq 0x80(%rsp), %r8
+DISASM-NEXT: 18000307b: 4c 8b 8c 24 88 00 00 00 movq 0x88(%rsp), %r9
+DISASM-NEXT: 180003083: 48 83 c4 68 addq $0x68, %rsp
+DISASM-NEXT: 180003087: ff e0 jmpq *%rax
RUN: llvm-readobj --coff-load-config out.dll | FileCheck --check-prefix=LOADCFG %s
LOADCFG: AuxiliaryDelayloadIAT: 0x5000
@@ -230,7 +230,7 @@ EC-IMPORTS-NEXT: Name: test.dll
EC-IMPORTS-NEXT: Attributes: 0x1
EC-IMPORTS-NEXT: ModuleHandle: 0x6080
EC-IMPORTS-NEXT: ImportAddressTable: 0x6088
-EC-IMPORTS-NEXT: ImportNameTable: 0x4388
+EC-IMPORTS-NEXT: ImportNameTable: 0x4380
EC-IMPORTS-NEXT: BoundDelayImportTable: 0x0
EC-IMPORTS-NEXT: UnloadDelayImportTable: 0x0
EC-IMPORTS-NEXT: }
@@ -243,7 +243,7 @@ EC-IMPORTS-NEXT: Name: test.dll
EC-IMPORTS-NEXT: Attributes: 0x1
EC-IMPORTS-NEXT: ModuleHandle: 0x6080
EC-IMPORTS-NEXT: ImportAddressTable: 0x6090
-EC-IMPORTS-NEXT: ImportNameTable: 0x4390
+EC-IMPORTS-NEXT: ImportNameTable: 0x4388
EC-IMPORTS-NEXT: BoundDelayImportTable: 0x0
EC-IMPORTS-NEXT: UnloadDelayImportTable: 0x0
EC-IMPORTS-NEXT: Import {
@@ -279,28 +279,28 @@ EC-DISASM-NEXT: ...
EC-DISASM-NEXT: 180003000: ff 25 8a 30 00 00 jmpq *0x308a(%rip) # 0x180006090
EC-DISASM-NEXT: 180003006: 48 8d 05 83 30 00 00 leaq 0x3083(%rip), %rax # 0x180006090
EC-DISASM-NEXT: 18000300d: e9 00 00 00 00 jmp 0x180003012 <.text+0x2012>
-EC-DISASM-NEXT: 180003012: 51 pushq %rcx
-EC-DISASM-NEXT: 180003013: 52 pushq %rdx
-EC-DISASM-NEXT: 180003014: 41 50 pushq %r8
-EC-DISASM-NEXT: 180003016: 41 51 pushq %r9
-EC-DISASM-NEXT: 180003018: 48 83 ec 48 subq $0x48, %rsp
-EC-DISASM-NEXT: 18000301c: 66 0f 7f 04 24 movdqa %xmm0, (%rsp)
-EC-DISASM-NEXT: 180003021: 66 0f 7f 4c 24 10 movdqa %xmm1, 0x10(%rsp)
-EC-DISASM-NEXT: 180003027: 66 0f 7f 54 24 20 movdqa %xmm2, 0x20(%rsp)
-EC-DISASM-NEXT: 18000302d: 66 0f 7f 5c 24 30 movdqa %xmm3, 0x30(%rsp)
-EC-DISASM-NEXT: 180003033: 48 8b d0 movq %rax, %rdx
-EC-DISASM-NEXT: 180003036: 48 8d 0d 0b 13 00 00 leaq 0x130b(%rip), %rcx # 0x180004348
-EC-DISASM-NEXT: 18000303d: e8 c6 ef ff ff callq 0x180002008 <.text+0x1008>
-EC-DISASM-NEXT: 180003042: 66 0f 6f 04 24 movdqa (%rsp), %xmm0
-EC-DISASM-NEXT: 180003047: 66 0f 6f 4c 24 10 movdqa 0x10(%rsp), %xmm1
-EC-DISASM-NEXT: 18000304d: 66 0f 6f 54 24 20 movdqa 0x20(%rsp), %xmm2
-EC-DISASM-NEXT: 180003053: 66 0f 6f 5c 24 30 movdqa 0x30(%rsp), %xmm3
-EC-DISASM-NEXT: 180003059: 48 83 c4 48 addq $0x48, %rsp
-EC-DISASM-NEXT: 18000305d: 41 59 popq %r9
-EC-DISASM-NEXT: 18000305f: 41 58 popq %r8
-EC-DISASM-NEXT: 180003061: 5a popq %rdx
-EC-DISASM-NEXT: 180003062: 59 popq %rcx
-EC-DISASM-NEXT: 180003063: ff e0 jmpq *%rax
+EC-DISASM-NEXT: 180003012: 48 89 4c 24 08 movq %rcx, 0x8(%rsp)
+EC-DISASM-NEXT: 180003017: 48 89 54 24 10 movq %rdx, 0x10(%rsp)
+EC-DISASM-NEXT: 18000301c: 4c 89 44 24 18 movq %r8, 0x18(%rsp)
+EC-DISASM-NEXT: 180003021: 4c 89 4c 24 20 movq %r9, 0x20(%rsp)
+EC-DISASM-NEXT: 180003026: 48 83 ec 68 subq $0x68, %rsp
+EC-DISASM-NEXT: 18000302a: 66 0f 7f 44 24 20 movdqa %xmm0, 0x20(%rsp)
+EC-DISASM-NEXT: 180003030: 66 0f 7f 4c 24 30 movdqa %xmm1, 0x30(%rsp)
+EC-DISASM-NEXT: 180003036: 66 0f 7f 54 24 40 movdqa %xmm2, 0x40(%rsp)
+EC-DISASM-NEXT: 18000303c: 66 0f 7f 5c 24 50 movdqa %xmm3, 0x50(%rsp)
+EC-DISASM-NEXT: 180003042: 48 8b d0 movq %rax, %rdx
+EC-DISASM-NEXT: 180003045: 48 8d 0d f4 12 00 00 leaq 0x12f4(%rip), %rcx # 0x180004340
+EC-DISASM-NEXT: 18000304c: e8 b7 ef ff ff callq 0x180002008 <.text+0x1008>
+EC-DISASM-NEXT: 180003051: 66 0f 6f 44 24 20 movdqa 0x20(%rsp), %xmm0
+EC-DISASM-NEXT: 180003057: 66 0f 6f 4c 24 30 movdqa 0x30(%rsp), %xmm1
+EC-DISASM-NEXT: 18000305d: 66 0f 6f 54 24 40 movdqa 0x40(%rsp), %xmm2
+EC-DISASM-NEXT: 180003063: 66 0f 6f 5c 24 50 movdqa 0x50(%rsp), %xmm3
+EC-DISASM-NEXT: 180003069: 48 8b 4c 24 70 movq 0x70(%rsp), %rcx
+EC-DISASM-NEXT: 18000306e: 48 8b 54 24 78 movq 0x78(%rsp), %rdx
+EC-DISASM-NEXT: 180003073: 4c 8b 84 24 80 00 00 00 movq 0x80(%rsp), %r8
+EC-DISASM-NEXT: 18000307b: 4c 8b 8c 24 88 00 00 00 movq 0x88(%rsp), %r9
+EC-DISASM-NEXT: 180003083: 48 83 c4 68 addq $0x68, %rsp
+EC-DISASM-NEXT: 180003087: ff e0 jmpq *%rax
RUN: llvm-readobj --coff-load-config out-ec.dll | FileCheck --check-prefix=EC-LOADCFG %s
EC-LOADCFG: AuxiliaryDelayloadIAT: 0x5000
diff --git a/lld/test/COFF/arm64x-sameaddress.test b/lld/test/COFF/arm64x-sameaddress.test
index c69be9d..819d19b 100644
--- a/lld/test/COFF/arm64x-sameaddress.test
+++ b/lld/test/COFF/arm64x-sameaddress.test
@@ -3,16 +3,103 @@ RUN: split-file %s %t.dir && cd %t.dir
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows func-arm64ec.s -o func-arm64ec.obj
RUN: llvm-mc -filetype=obj -triple=aarch64-windows func-arm64.s -o func-arm64.obj
+RUN: llvm-mc -filetype=obj -triple=arm64ec-windows ref-arm64ec.s -o ref-arm64ec.obj
+RUN: llvm-mc -filetype=obj -triple=aarch64-windows ref-arm64.s -o ref-arm64.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows drectve.s -o drectve.obj
RUN: llvm-mc -filetype=obj -triple=aarch64-windows drectve.s -o drectve-arm64.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj
RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o loadconfig-arm64.obj
RUN: lld-link -machine:arm64x -dll -noentry -out:out.dll loadconfig-arm64.obj loadconfig-arm64ec.obj \
-RUN: func-arm64.obj func-arm64ec.obj drectve.obj
+RUN: func-arm64.obj func-arm64ec.obj ref-arm64.obj ref-arm64ec.obj drectve.obj
+
+RUN: llvm-objdump -d out.dll | FileCheck --check-prefix=DISASM %s
+DISASM: 000000180001000 <.text>:
+DISASM-NEXT: 180001000: d2800020 mov x0, #0x1 // =1
+DISASM-NEXT: 180001004: d65f03c0 ret
+DISASM-NEXT: ...
+DISASM-NEXT: 180002000: 00000019 udf #0x19
+DISASM-NEXT: 180002004: d2800040 mov x0, #0x2 // =2
+DISASM-NEXT: 180002008: d65f03c0 ret
+DISASM-NEXT: 18000200c: 0000000d udf #0xd
+DISASM-NEXT: 180002010: f0fffff0 adrp x16, 0x180001000 <.text>
+DISASM-NEXT: 180002014: 91000210 add x16, x16, #0x0
+DISASM-NEXT: 180002018: d61f0200 br x16
+DISASM-NEXT: 18000201c: d2800060 mov x0, #0x3 // =3
+DISASM-NEXT: 180002020: d65f03c0 ret
+
+RUN: llvm-readobj --hex-dump=.test out.dll | FileCheck --check-prefix=TESTSEC %s
+TESTSEC: 10200000 10200000 10200000
+
+RUN: llvm-readobj --coff-load-config out.dll | FileCheck --check-prefix=DYNRELOCS %s
+DYNRELOCS: DynamicRelocations [
+DYNRELOCS-NEXT: Version: 0x1
+DYNRELOCS-NEXT: Arm64X [
+DYNRELOCS-NEXT: Entry [
+DYNRELOCS-NEXT: RVA: 0x7C
+DYNRELOCS-NEXT: Type: VALUE
+DYNRELOCS-NEXT: Size: 0x2
+DYNRELOCS-NEXT: Value: 0x8664
+DYNRELOCS-NEXT: ]
+DYNRELOCS-NEXT: Entry [
+DYNRELOCS-NEXT: RVA: 0x150
+DYNRELOCS-NEXT: Type: VALUE
+DYNRELOCS-NEXT: Size: 0x4
+DYNRELOCS-NEXT: Value: 0x3150
+DYNRELOCS-NEXT: ]
+DYNRELOCS-NEXT: Entry [
+DYNRELOCS-NEXT: RVA: 0x154
+DYNRELOCS-NEXT: Type: VALUE
+DYNRELOCS-NEXT: Size: 0x4
+DYNRELOCS-NEXT: Value: 0x140
+DYNRELOCS-NEXT: ]
+DYNRELOCS-NEXT: Entry [
+DYNRELOCS-NEXT: RVA: 0x2010
+DYNRELOCS-NEXT: Type: VALUE
+DYNRELOCS-NEXT: Size: 0x4
+DYNRELOCS-NEXT: Value: 0x90000010
+DYNRELOCS-NEXT: ]
+DYNRELOCS-NEXT: Entry [
+DYNRELOCS-NEXT: RVA: 0x2014
+DYNRELOCS-NEXT: Type: VALUE
+DYNRELOCS-NEXT: Size: 0x4
+DYNRELOCS-NEXT: Value: 0x91001210
+DYNRELOCS-NEXT: ]
+DYNRELOCS-NEXT: ]
+DYNRELOCS-NEXT: ]
RUN: lld-link -machine:arm64x -dll -noentry -out:out-cmd.dll loadconfig-arm64.obj loadconfig-arm64ec.obj \
-RUN: func-arm64.obj func-arm64ec.obj -arm64xsameaddress:func
+RUN: func-arm64.obj func-arm64ec.obj ref-arm64.obj ref-arm64ec.obj -arm64xsameaddress:func
+RUN: llvm-objdump -d out-cmd.dll | FileCheck --check-prefix=DISASM %s
+RUN: llvm-readobj --hex-dump=.test out-cmd.dll | FileCheck --check-prefix=TESTSEC %s
+RUN: llvm-readobj --coff-load-config out-cmd.dll | FileCheck --check-prefix=DYNRELOCS %s
+
+RUN: lld-link -machine:arm64x -dll -noentry -out:out-both.dll loadconfig-arm64.obj loadconfig-arm64ec.obj \
+RUN: func-arm64.obj func-arm64ec.obj ref-arm64.obj ref-arm64ec.obj drectve.obj -arm64xsameaddress:func
+RUN: llvm-objdump -d out-both.dll | FileCheck --check-prefix=DISASM %s
+RUN: llvm-readobj --hex-dump=.test out-both.dll | FileCheck --check-prefix=TESTSEC %s
+RUN: llvm-readobj --coff-load-config out-both.dll | FileCheck --check-prefix=DYNRELOCS %s
+
+Check that if any of the sameaddress symbols is not alive, the thunk is not generated.
+
+RUN: lld-link -machine:arm64x -dll -noentry -out:out-live1.dll loadconfig-arm64.obj loadconfig-arm64ec.obj \
+RUN: func-arm64.obj func-arm64ec.obj ref-arm64ec.obj drectve.obj
+RUN: llvm-objdump -d out-live1.dll | FileCheck --check-prefix=DISASM-LIVE1 %s
+DISASM-LIVE1: 0000000180001000 <.text>:
+DISASM-LIVE1-NEXT: 180001000: 00000009 udf #0x9
+DISASM-LIVE1-NEXT: 180001004: d2800040 mov x0, #0x2 // =2
+DISASM-LIVE1-NEXT: 180001008: d65f03c0 ret
+DISASM-LIVE1-NEXT: 18000100c: d2800060 mov x0, #0x3 // =3
+DISASM-LIVE1-NEXT: 180001010: d65f03c0 ret
+DISASM-LIVE1-NOT: br
+
+RUN: lld-link -machine:arm64x -dll -noentry -out:out-live2.dll loadconfig-arm64.obj loadconfig-arm64ec.obj \
+RUN: func-arm64.obj func-arm64ec.obj ref-arm64.obj drectve.obj
+RUN: llvm-objdump -d out-live2.dll | FileCheck --check-prefix=DISASM-LIVE2 %s
+DISASM-LIVE2: 0000000180001000 <.text>:
+DISASM-LIVE2-NEXT: 180001000: d2800020 mov x0, #0x1 // =1
+DISASM-LIVE2-NEXT: 180001004: d65f03c0 ret
+DISASM-LIVE2-NOT: br
RUN: lld-link -machine:arm64ec -dll -noentry -out:out-ec.dll loadconfig-arm64ec.obj func-arm64ec.obj drectve.obj
@@ -20,6 +107,10 @@ RUN: lld-link -machine:arm64x -dll -noentry -out:out-warn.dll loadconfig-arm64.o
RUN: func-arm64.obj func-arm64ec.obj drectve-arm64.obj 2>&1 | FileCheck --check-prefix=WARN %s
WARN: lld-link: warning: -arm64xsameaddress: is not allowed in non-ARM64EC files (drectve-arm64.obj)
+RUN: lld-link -machine:arm64 -dll -noentry -out:out-warn2.dll loadconfig-arm64.obj \
+RUN: func-arm64.obj -arm64xsameaddress:func 2>&1 | FileCheck --check-prefix=WARN2 %s
+WARN2: lld-link: warning: -arm64xsameaddress: is allowed only on EC targets
+
#--- func-arm64.s
.section .text,"xr",discard,func
.globl func
@@ -27,6 +118,10 @@ func:
mov x0, #1
ret
+#--- ref-arm64.s
+ .section .test,"dr"
+ .rva func
+
#--- func-arm64ec.s
.section .text,"xr",discard,"#func"
.globl "#func"
@@ -43,14 +138,16 @@ entry_thunk:
mov x0, #3
ret
- .section .test,"dr"
- .rva func
-
.section .hybmp$x,"yi"
.symidx "#func"
.symidx entry_thunk
.word 1
+#--- ref-arm64ec.s
+ .section .test,"dr"
+ .rva func
+ .rva "#func"
+
#--- drectve.s
.section .drectve, "yn"
.ascii " -arm64xsameaddress:func"
diff --git a/lld/test/COFF/delayimports.test b/lld/test/COFF/delayimports.test
index f410eef..ed074f4 100644
--- a/lld/test/COFF/delayimports.test
+++ b/lld/test/COFF/delayimports.test
@@ -10,7 +10,7 @@ IMPORT-NEXT: Name: std64.dll
IMPORT-NEXT: Attributes: 0x1
IMPORT-NEXT: ModuleHandle: 0x3018
IMPORT-NEXT: ImportAddressTable: 0x3020
-IMPORT-NEXT: ImportNameTable: 0x2050
+IMPORT-NEXT: ImportNameTable: 0x2048
IMPORT-NEXT: BoundDelayImportTable: 0x0
IMPORT-NEXT: UnloadDelayImportTable: 0x0
IMPORT-NEXT: Import {
@@ -44,22 +44,18 @@ BASEREL-NEXT: }
UNWIND: UnwindInformation [
UNWIND-NEXT: RuntimeFunction {
UNWIND-NEXT: StartAddress: (0x14000108A)
-UNWIND-NEXT: EndAddress: (0x1400010DD)
+UNWIND-NEXT: EndAddress: (0x140001101)
UNWIND-NEXT: UnwindInfoAddress: (0x140002000)
UNWIND-NEXT: UnwindInfo {
UNWIND-NEXT: Version: 1
UNWIND-NEXT: Flags [ (0x0)
UNWIND-NEXT: ]
-UNWIND-NEXT: PrologSize: 10
+UNWIND-NEXT: PrologSize: 24
UNWIND-NEXT: FrameRegister: -
UNWIND-NEXT: FrameOffset: -
-UNWIND-NEXT: UnwindCodeCount: 5
+UNWIND-NEXT: UnwindCodeCount: 1
UNWIND-NEXT: UnwindCodes [
-UNWIND-NEXT: 0x0A: ALLOC_SMALL size=72
-UNWIND-NEXT: 0x06: ALLOC_SMALL size=8
-UNWIND-NEXT: 0x04: ALLOC_SMALL size=8
-UNWIND-NEXT: 0x02: ALLOC_SMALL size=8
-UNWIND-NEXT: 0x01: ALLOC_SMALL size=8
+UNWIND-NEXT: 0x18: ALLOC_SMALL size=104
UNWIND-NEXT: ]
UNWIND-NEXT: }
UNWIND-NEXT: }
diff --git a/lld/test/COFF/delayimporttables.yaml b/lld/test/COFF/delayimporttables.yaml
index cf54c0a..ff66812 100644
--- a/lld/test/COFF/delayimporttables.yaml
+++ b/lld/test/COFF/delayimporttables.yaml
@@ -15,7 +15,7 @@
# CHECK-NEXT: Attributes: 0x1
# CHECK-NEXT: ModuleHandle: 0x3000
# CHECK-NEXT: ImportAddressTable: 0x3010
-# CHECK-NEXT: ImportNameTable: 0x2070
+# CHECK-NEXT: ImportNameTable: 0x2068
# CHECK-NEXT: BoundDelayImportTable: 0x0
# CHECK-NEXT: UnloadDelayImportTable: 0x0
# CHECK-NEXT: Import {
@@ -32,16 +32,16 @@
# CHECK-NEXT: Attributes: 0x1
# CHECK-NEXT: ModuleHandle: 0x3008
# CHECK-NEXT: ImportAddressTable: 0x3028
-# CHECK-NEXT: ImportNameTable: 0x2088
+# CHECK-NEXT: ImportNameTable: 0x2080
# CHECK-NEXT: BoundDelayImportTable: 0x0
# CHECK-NEXT: UnloadDelayImportTable: 0x0
# CHECK-NEXT: Import {
# CHECK-NEXT: Symbol: left (0)
-# CHECK-NEXT: Address: 0x1400010B8
+# CHECK-NEXT: Address: 0x1400010DC
# CHECK-NEXT: }
# CHECK-NEXT: Import {
# CHECK-NEXT: Symbol: right (0)
-# CHECK-NEXT: Address: 0x1400010C4
+# CHECK-NEXT: Address: 0x1400010E8
# CHECK-NEXT: }
# CHECK-NEXT: }
diff --git a/lld/test/COFF/embed-bitcode.test b/lld/test/COFF/embed-bitcode.test
new file mode 100644
index 0000000..10f88c5
--- /dev/null
+++ b/lld/test/COFF/embed-bitcode.test
@@ -0,0 +1,30 @@
+# RUN: yaml2obj %s -o %t.obj
+# RUN: lld-link /entry:main /subsystem:console /out:%t.exe %t.obj
+# RUN: llvm-readobj -S %t.exe | FileCheck %s
+
+# CHECK-NOT: Name: .llvmbc
+# CHECK-NOT: Name: .llvmcmd
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ SectionData: "C3"
+ - Name: .llvmbc
+ Characteristics: [ IMAGE_SCN_MEM_DISCARDABLE ]
+ SectionData: "4243C0DE"
+ - Name: .llvmcmd
+ Characteristics: [ IMAGE_SCN_MEM_DISCARDABLE ]
+ SectionData: "2D63633100"
+
+symbols:
+ - Name: main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/lld/test/COFF/giats.s b/lld/test/COFF/giats.s
index f870429..c044210 100644
--- a/lld/test/COFF/giats.s
+++ b/lld/test/COFF/giats.s
@@ -37,14 +37,14 @@
# DELAY-CHECK: ImageBase: 0x140000000
# DELAY-CHECK: LoadConfig [
-# DELAY-CHECK: GuardCFFunctionTable: 0x140002124
+# DELAY-CHECK: GuardCFFunctionTable: 0x14000211C
# DELAY-CHECK: GuardCFFunctionCount: 2
# DELAY-CHECK: GuardFlags [ (0x10500)
# DELAY-CHECK: CF_FUNCTION_TABLE_PRESENT (0x400)
# DELAY-CHECK: CF_INSTRUMENTED (0x100)
# DELAY-CHECK: CF_LONGJUMP_TABLE_PRESENT (0x10000)
# DELAY-CHECK: ]
-# DELAY-CHECK: GuardAddressTakenIatEntryTable: 0x14000212C
+# DELAY-CHECK: GuardAddressTakenIatEntryTable: 0x140002124
# DELAY-CHECK: GuardAddressTakenIatEntryCount: 1
# DELAY-CHECK: ]
# DELAY-CHECK: GuardFidTable [
diff --git a/lld/test/COFF/pdb-empty-sec.s b/lld/test/COFF/pdb-empty-sec.s
new file mode 100644
index 0000000..0d61447
--- /dev/null
+++ b/lld/test/COFF/pdb-empty-sec.s
@@ -0,0 +1,19 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-windows %s -o %t.obj
+// RUN: lld-link -dll -noentry -debug %t.obj -out:%t.dll
+// RUN: llvm-pdbutil dump -publics %t.pdb | FileCheck %s
+
+// CHECK: Records
+// CHECK-NEXT: 0 | S_PUB32 [size = 20] `func`
+// CHECK-NEXT: flags = none, addr = 0001:0000
+// CHECK-NEXT: 20 | S_PUB32 [size = 20] `sym`
+// CHECK-NEXT: flags = none, addr = 0000:0000
+
+ .globl sym
+ .data
+sym:
+ .text
+ .globl func
+func:
+ ret
diff --git a/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
index a417d89..a33f866 100644
--- a/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
+++ b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
@@ -1,22 +1,23 @@
# REQUIRES: loongarch
+# RUN: rm -rf %t && split-file %s %t && cd %t
-# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax %s -o %t.32.o
-# RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax %s -o %t.64.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax a.s -o a.32.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax a.s -o a.64.o
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.32.o -o %t.32
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.64.o -o %t.64
-# RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck --check-prefixes=RELAX %s
-# RUN: llvm-objdump -td --no-show-raw-insn %t.64 | FileCheck --check-prefixes=RELAX %s
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 a.32.o -o a.32
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 a.64.o -o a.64
+# RUN: llvm-objdump -td --no-show-raw-insn a.32 | FileCheck --check-prefixes=RELAX %s
+# RUN: llvm-objdump -td --no-show-raw-insn a.64 | FileCheck --check-prefixes=RELAX %s
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.32.o -shared -o %t.32s
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.64.o -shared -o %t.64s
-# RUN: llvm-objdump -td --no-show-raw-insn %t.32s | FileCheck --check-prefixes=RELAX %s
-# RUN: llvm-objdump -td --no-show-raw-insn %t.64s | FileCheck --check-prefixes=RELAX %s
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 a.32.o -shared -o a.32s
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 a.64.o -shared -o a.64s
+# RUN: llvm-objdump -td --no-show-raw-insn a.32s | FileCheck --check-prefixes=RELAX %s
+# RUN: llvm-objdump -td --no-show-raw-insn a.64s | FileCheck --check-prefixes=RELAX %s
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 %t.32.o -o %t.32o
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 %t.64.o -o %t.64o
-# RUN: llvm-objdump -td --no-show-raw-insn %t.32o | FileCheck --check-prefixes=NORELAX32 %s
-# RUN: llvm-objdump -td --no-show-raw-insn %t.64o | FileCheck --check-prefixes=NORELAX64 %s
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 a.32.o -o a.32o
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 a.64.o -o a.64o
+# RUN: llvm-objdump -td --no-show-raw-insn a.32o | FileCheck --check-prefixes=NORELAX32 %s
+# RUN: llvm-objdump -td --no-show-raw-insn a.64o | FileCheck --check-prefixes=NORELAX64 %s
# RELAX-LABEL: <_start>:
## offset = 0x14000 - 0x10000 = 4096<<2
@@ -49,6 +50,25 @@
# NORELAX64-NEXT: pcalau12i $a0, 1024
# NORELAX64-NEXT: ld.d $a0, $a0, 8
+
+## GOT references with non-zero addends. No relaxation.
+# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax nonzero.s -o nonzero.32.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax nonzero.s -o nonzero.64.o
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 nonzero.32.o -o nonzero.32
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 nonzero.64.o -o nonzero.64
+# RUN: llvm-objdump -td --no-show-raw-insn nonzero.32 | FileCheck --check-prefixes=NONZERO32 %s
+# RUN: llvm-objdump -td --no-show-raw-insn nonzero.64 | FileCheck --check-prefixes=NONZERO64 %s
+
+# NONZERO32-LABEL: <_start>:
+# NONZERO32-NEXT: 10000: pcalau12i $a0, 4
+# NONZERO32-NEXT: ld.w $a0, $a0, 8
+
+# NONZERO64-LABEL: <_start>:
+# NONZERO64-NEXT: 10000: pcalau12i $a0, 4
+# NONZERO64-NEXT: ld.d $a0, $a0, 12
+
+
+#--- a.s
.section .text
.global _start
_start:
@@ -60,3 +80,14 @@ _start:
.section .data
sym:
.zero 4
+
+
+#--- nonzero.s
+.section .text
+.global _start
+_start:
+ la.got $a0, sym+4
+
+.section .data
+sym:
+ .zero 4