[lld] r342962 - [COFF] Add support for creating range extension thunks for ARM
Martin Storsjo via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 25 03:59:29 PDT 2018
Author: mstorsjo
Date: Tue Sep 25 03:59:29 2018
New Revision: 342962
URL: http://llvm.org/viewvc/llvm-project?rev=342962&view=rev
Log:
[COFF] Add support for creating range extension thunks for ARM
This is a feature that MS link.exe lacks; it currently errors out on
such relocations, just like lld did before.
This allows linking clang.exe for ARM - practically, any image over
16 MB will likely run into the issue.
Differential Revision: https://reviews.llvm.org/D52156
Added:
lld/trunk/test/COFF/arm-thumb-thunks-multipass.s
lld/trunk/test/COFF/arm-thumb-thunks.s
Removed:
lld/trunk/test/COFF/Inputs/far-arm-thumb-abs.s
lld/trunk/test/COFF/Inputs/far-arm-thumb-abs20.s
lld/trunk/test/COFF/arm-thumb-branch-error.s
Modified:
lld/trunk/COFF/Chunks.cpp
lld/trunk/COFF/Chunks.h
lld/trunk/COFF/MapFile.cpp
lld/trunk/COFF/PDB.cpp
lld/trunk/COFF/Writer.cpp
lld/trunk/COFF/Writer.h
lld/trunk/test/COFF/arm-thumb-branch20-error.s
Modified: lld/trunk/COFF/Chunks.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Chunks.cpp?rev=342962&r1=342961&r2=342962&view=diff
==============================================================================
--- lld/trunk/COFF/Chunks.cpp (original)
+++ lld/trunk/COFF/Chunks.cpp Tue Sep 25 03:59:29 2018
@@ -44,6 +44,22 @@ SectionChunk::SectionChunk(ObjFile *F, c
Live = !Config->DoGC || !isCOMDAT();
}
+// Initialize the RelocTargets vector, to allow redirecting certain relocations
+// to a thunk instead of the actual symbol the relocation's symbol table index
+// indicates.
+void SectionChunk::readRelocTargets() {
+ assert(RelocTargets.empty());
+ RelocTargets.reserve(Relocs.size());
+ for (const coff_relocation &Rel : Relocs)
+ RelocTargets.push_back(File->getSymbol(Rel.SymbolTableIndex));
+}
+
+// Reset RelocTargets to their original targets before thunks were added.
+void SectionChunk::resetRelocTargets() {
+ for (size_t I = 0, E = Relocs.size(); I < E; ++I)
+ RelocTargets[I] = File->getSymbol(Relocs[I].SymbolTableIndex);
+}
+
static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); }
static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); }
static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); }
@@ -309,7 +325,9 @@ void SectionChunk::writeTo(uint8_t *Buf)
// Apply relocations.
size_t InputSize = getSize();
- for (const coff_relocation &Rel : Relocs) {
+ for (size_t I = 0, E = Relocs.size(); I < E; I++) {
+ const coff_relocation &Rel = Relocs[I];
+
// Check for an invalid relocation offset. This check isn't perfect, because
// we don't have the relocation size, which is only known after checking the
// machine and relocation type. As a result, a relocation may overwrite the
@@ -321,8 +339,9 @@ void SectionChunk::writeTo(uint8_t *Buf)
uint8_t *Off = Buf + OutputSectionOff + Rel.VirtualAddress;
- auto *Sym =
- dyn_cast_or_null<Defined>(File->getSymbol(Rel.SymbolTableIndex));
+ // Use the potentially remapped Symbol instead of the one that the
+ // relocation points to.
+ auto *Sym = dyn_cast_or_null<Defined>(RelocTargets[I]);
if (!Sym) {
if (isCodeView() || isDWARF())
continue;
@@ -410,11 +429,14 @@ static uint8_t getBaserelType(const coff
// fixed by the loader if load-time relocation is needed.
// Only called when base relocation is enabled.
void SectionChunk::getBaserels(std::vector<Baserel> *Res) {
- for (const coff_relocation &Rel : Relocs) {
+ for (size_t I = 0, E = Relocs.size(); I < E; I++) {
+ const coff_relocation &Rel = Relocs[I];
uint8_t Ty = getBaserelType(Rel);
if (Ty == IMAGE_REL_BASED_ABSOLUTE)
continue;
- Symbol *Target = File->getSymbol(Rel.SymbolTableIndex);
+ // Use the potentially remapped Symbol instead of the one that the
+ // relocation points to.
+ Symbol *Target = RelocTargets[I];
if (!Target || isa<DefinedAbsolute>(Target))
continue;
Res->emplace_back(RVA + Rel.VirtualAddress, Ty);
@@ -618,6 +640,25 @@ void ImportThunkChunkARM64::writeTo(uint
applyArm64Ldr(Buf + OutputSectionOff + 4, Off);
}
+// A Thumb2, PIC, non-interworking range extension thunk.
+const uint8_t ArmThunk[] = {
+ 0x40, 0xf2, 0x00, 0x0c, // P: movw ip,:lower16:S - (P + (L1-P) + 4)
+ 0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P) + 4)
+ 0xe7, 0x44, // L1: add pc, ip
+};
+
+size_t RangeExtensionThunk::getSize() const {
+ assert(Config->Machine == ARMNT);
+ return sizeof(ArmThunk);
+}
+
+void RangeExtensionThunk::writeTo(uint8_t *Buf) const {
+ assert(Config->Machine == ARMNT);
+ uint64_t Offset = Target->getRVA() - RVA - 12;
+ memcpy(Buf + OutputSectionOff, ArmThunk, sizeof(ArmThunk));
+ applyMOV32T(Buf + OutputSectionOff, uint32_t(Offset));
+}
+
void LocalImportChunk::getBaserels(std::vector<Baserel> *Res) {
Res->emplace_back(getRVA());
}
@@ -757,10 +798,13 @@ void MergeChunk::addSection(SectionChunk
}
void MergeChunk::finalizeContents() {
- for (SectionChunk *C : Sections)
- if (C->Live)
- Builder.add(toStringRef(C->getContents()));
- Builder.finalize();
+ if (!Finalized) {
+ for (SectionChunk *C : Sections)
+ if (C->Live)
+ Builder.add(toStringRef(C->getContents()));
+ Builder.finalize();
+ Finalized = true;
+ }
for (SectionChunk *C : Sections) {
if (!C->Live)
Modified: lld/trunk/COFF/Chunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Chunks.h?rev=342962&r1=342961&r2=342962&view=diff
==============================================================================
--- lld/trunk/COFF/Chunks.h (original)
+++ lld/trunk/COFF/Chunks.h Tue Sep 25 03:59:29 2018
@@ -64,6 +64,13 @@ public:
// before calling this function.
virtual void writeTo(uint8_t *Buf) const {}
+ // Called by the writer once before assigning addresses and writing
+ // the output.
+ virtual void readRelocTargets() {}
+
+ // Called if restarting thunk addition.
+ virtual void resetRelocTargets() {}
+
// Called by the writer after an RVA is assigned, but before calling
// getSize().
virtual void finalizeContents() {}
@@ -145,6 +152,8 @@ public:
SectionChunk(ObjFile *File, const coff_section *Header);
static bool classof(const Chunk *C) { return C->kind() == SectionKind; }
+ void readRelocTargets() override;
+ void resetRelocTargets() override;
size_t getSize() const override { return Header->SizeOfRawData; }
ArrayRef<uint8_t> getContents() const;
void writeTo(uint8_t *Buf) const override;
@@ -217,6 +226,10 @@ public:
// Used by the garbage collector.
bool Live;
+ // When inserting a thunk, we need to adjust a relocation to point to
+ // the thunk instead of the actual original target Symbol.
+ std::vector<Symbol *> RelocTargets;
+
private:
StringRef SectionName;
std::vector<SectionChunk *> AssocChildren;
@@ -251,6 +264,7 @@ public:
private:
llvm::StringTableBuilder Builder;
+ bool Finalized = false;
};
// A chunk for common symbols. Common chunks don't have actual data.
@@ -338,6 +352,15 @@ private:
Defined *ImpSymbol;
};
+class RangeExtensionThunk : public Chunk {
+public:
+ explicit RangeExtensionThunk(Defined *T) : Target(T) {}
+ size_t getSize() const override;
+ void writeTo(uint8_t *Buf) const override;
+
+ Defined *Target;
+};
+
// Windows-specific.
// See comments for DefinedLocalImport class.
class LocalImportChunk : public Chunk {
Modified: lld/trunk/COFF/MapFile.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/MapFile.cpp?rev=342962&r1=342961&r2=342962&view=diff
==============================================================================
--- lld/trunk/COFF/MapFile.cpp (original)
+++ lld/trunk/COFF/MapFile.cpp Tue Sep 25 03:59:29 2018
@@ -110,7 +110,7 @@ void coff::writeMapFile(ArrayRef<OutputS
writeHeader(OS, Sec->getRVA(), Sec->getVirtualSize(), /*Align=*/PageSize);
OS << Sec->Name << '\n';
- for (Chunk *C : Sec->getChunks()) {
+ for (Chunk *C : Sec->Chunks) {
auto *SC = dyn_cast<SectionChunk>(C);
if (!SC)
continue;
Modified: lld/trunk/COFF/PDB.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/PDB.cpp?rev=342962&r1=342961&r2=342962&view=diff
==============================================================================
--- lld/trunk/COFF/PDB.cpp (original)
+++ lld/trunk/COFF/PDB.cpp Tue Sep 25 03:59:29 2018
@@ -839,6 +839,7 @@ static ArrayRef<uint8_t> relocateDebugCh
uint8_t *Buffer = Alloc.Allocate<uint8_t>(DebugChunk.getSize());
assert(DebugChunk.OutputSectionOff == 0 &&
"debug sections should not be in output sections");
+ DebugChunk.readRelocTargets();
DebugChunk.writeTo(Buffer);
return makeArrayRef(Buffer, DebugChunk.getSize());
}
@@ -1290,7 +1291,7 @@ void PDBLinker::addSections(ArrayRef<Out
// Add section contributions. They must be ordered by ascending RVA.
for (OutputSection *OS : OutputSections) {
addLinkerModuleSectionSymbol(LinkerModule, *OS, Alloc);
- for (Chunk *C : OS->getChunks()) {
+ for (Chunk *C : OS->Chunks) {
pdb::SectionContrib SC =
createSectionContrib(C, LinkerModule.getModuleIndex());
Builder.getDbiBuilder().addSectionContrib(SC);
Modified: lld/trunk/COFF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Writer.cpp?rev=342962&r1=342961&r2=342962&view=diff
==============================================================================
--- lld/trunk/COFF/Writer.cpp (original)
+++ lld/trunk/COFF/Writer.cpp Tue Sep 25 03:59:29 2018
@@ -172,7 +172,9 @@ private:
std::map<std::pair<StringRef, uint32_t>, std::vector<Chunk *>> &Map);
void createExportTable();
void mergeSections();
+ void readRelocTargets();
void assignAddresses();
+ void finalizeAddresses();
void removeEmptySections();
void createSymbolAndStringTable();
void openFile(StringRef OutputPath);
@@ -299,6 +301,193 @@ void OutputSection::writeHeaderTo(uint8_
} // namespace coff
} // namespace lld
+// Check whether the target address S is in range from a relocation
+// of type RelType at address P.
+static bool isInRange(uint16_t RelType, uint64_t S, uint64_t P, int Margin) {
+ assert(Config->Machine == ARMNT);
+ int64_t Diff = AbsoluteDifference(S, P + 4) + Margin;
+ switch (RelType) {
+ case IMAGE_REL_ARM_BRANCH20T:
+ return isInt<21>(Diff);
+ case IMAGE_REL_ARM_BRANCH24T:
+ case IMAGE_REL_ARM_BLX23T:
+ return isInt<25>(Diff);
+ default:
+ return true;
+ }
+}
+
+// Return the last thunk for the given target if it is in range,
+// or create a new one.
+static std::pair<Defined *, bool>
+getThunk(DenseMap<uint64_t, Defined *> &LastThunks, Defined *Target, uint64_t P,
+ uint16_t Type, int Margin) {
+ Defined *&LastThunk = LastThunks[Target->getRVA()];
+ if (LastThunk && isInRange(Type, LastThunk->getRVA(), P, Margin))
+ return {LastThunk, false};
+ RangeExtensionThunk *C = make<RangeExtensionThunk>(Target);
+ Defined *D = make<DefinedSynthetic>("", C);
+ LastThunk = D;
+ return {D, true};
+}
+
+// This checks all relocations, and for any relocation which isn't in range
+// it adds a thunk after the section chunk that contains the relocation.
+// If the latest thunk for the specific target is in range, that is used
+// instead of creating a new thunk. All range checks are done with the
+// specified margin, to make sure that relocations that originally are in
+// range, but only barely, also get thunks - in case other added thunks makes
+// the target go out of range.
+//
+// After adding thunks, we verify that all relocations are in range (with
+// no extra margin requirements). If this failed, we restart (throwing away
+// the previously created thunks) and retry with a wider margin.
+static bool createThunks(std::vector<Chunk *> &Chunks, int Margin) {
+ bool AddressesChanged = false;
+ DenseMap<uint64_t, Defined *> LastThunks;
+ size_t ThunksSize = 0;
+ // Recheck Chunks.size() each iteration, since we can insert more
+ // elements into it.
+ for (size_t I = 0; I != Chunks.size(); ++I) {
+ SectionChunk *SC = dyn_cast_or_null<SectionChunk>(Chunks[I]);
+ if (!SC)
+ continue;
+ size_t ThunkInsertionSpot = I + 1;
+
+ // Try to get a good enough estimate of where new thunks will be placed.
+ // Offset this by the size of the new thunks added so far, to make the
+ // estimate slightly better.
+ size_t ThunkInsertionRVA = SC->getRVA() + SC->getSize() + ThunksSize;
+ for (size_t J = 0, E = SC->Relocs.size(); J < E; ++J) {
+ const coff_relocation &Rel = SC->Relocs[J];
+ Symbol *&RelocTarget = SC->RelocTargets[J];
+
+ // The estimate of the source address P should be pretty accurate,
+ // but we don't know whether the target Symbol address should be
+ // offset by ThunkSize or not (or by some of ThunksSize but not all of
+ // it), giving us some uncertainty once we have added one thunk.
+ uint64_t P = SC->getRVA() + Rel.VirtualAddress + ThunksSize;
+
+ Defined *Sym = dyn_cast_or_null<Defined>(RelocTarget);
+ if (!Sym)
+ continue;
+
+ uint64_t S = Sym->getRVA();
+
+ if (isInRange(Rel.Type, S, P, Margin))
+ continue;
+
+ // If the target isn't in range, hook it up to an existing or new
+ // thunk.
+ Defined *Thunk;
+ bool WasNew;
+ std::tie(Thunk, WasNew) = getThunk(LastThunks, Sym, P, Rel.Type, Margin);
+ if (WasNew) {
+ Chunk *ThunkChunk = Thunk->getChunk();
+ ThunkChunk->setRVA(
+ ThunkInsertionRVA); // Estimate of where it will be located.
+ Chunks.insert(Chunks.begin() + ThunkInsertionSpot, ThunkChunk);
+ ThunkInsertionSpot++;
+ ThunksSize += ThunkChunk->getSize();
+ ThunkInsertionRVA += ThunkChunk->getSize();
+ AddressesChanged = true;
+ }
+ RelocTarget = Thunk;
+ }
+ }
+ return AddressesChanged;
+}
+
+// Verify that all relocations are in range, with no extra margin requirements.
+static bool verifyRanges(const std::vector<Chunk *> Chunks) {
+ for (Chunk *C : Chunks) {
+ SectionChunk *SC = dyn_cast_or_null<SectionChunk>(C);
+ if (!SC)
+ continue;
+
+ for (size_t J = 0, E = SC->Relocs.size(); J < E; ++J) {
+ const coff_relocation &Rel = SC->Relocs[J];
+ Symbol *RelocTarget = SC->RelocTargets[J];
+
+ Defined *Sym = dyn_cast_or_null<Defined>(RelocTarget);
+ if (!Sym)
+ continue;
+
+ uint64_t P = SC->getRVA() + Rel.VirtualAddress;
+ uint64_t S = Sym->getRVA();
+
+ if (!isInRange(Rel.Type, S, P, 0))
+ return false;
+ }
+ }
+ return true;
+}
+
+// Assign addresses and add thunks if necessary.
+void Writer::finalizeAddresses() {
+ assignAddresses();
+ if (Config->Machine != ARMNT)
+ return;
+
+ size_t OrigNumChunks = 0;
+ for (OutputSection *Sec : OutputSections) {
+ Sec->OrigChunks = Sec->Chunks;
+ OrigNumChunks += Sec->Chunks.size();
+ }
+
+ int Pass = 0;
+ int Margin = 1024 * 100;
+ while (true) {
+ // First check whether we need thunks at all, or if the previous pass of
+ // adding them turned out ok.
+ bool RangesOk = true;
+ size_t NumChunks = 0;
+ for (OutputSection *Sec : OutputSections) {
+ if (!verifyRanges(Sec->Chunks)) {
+ RangesOk = false;
+ break;
+ }
+ NumChunks += Sec->Chunks.size();
+ }
+ if (RangesOk) {
+ if (Pass > 0)
+ log("Added " + Twine(NumChunks - OrigNumChunks) + " thunks with " +
+ "margin " + Twine(Margin) + " in " + Twine(Pass) + " passes");
+ return;
+ }
+
+ if (Pass >= 10)
+ fatal("adding thunks hasn't converged after " + Twine(Pass) + " passes");
+
+ if (Pass > 0) {
+ // If the previous pass didn't work out, reset everything back to the
+ // original conditions before retrying with a wider margin. This should
+ // ideally never happen under real circumstances.
+ for (OutputSection *Sec : OutputSections) {
+ Sec->Chunks = Sec->OrigChunks;
+ for (Chunk *C : Sec->Chunks)
+ C->resetRelocTargets();
+ }
+ Margin *= 2;
+ }
+
+ // Try adding thunks everywhere where it is needed, with a margin
+ // to avoid things going out of range due to the added thunks.
+ bool AddressesChanged = false;
+ for (OutputSection *Sec : OutputSections)
+ AddressesChanged |= createThunks(Sec->Chunks, Margin);
+ // If the verification above thought we needed thunks, we should have
+ // added some.
+ assert(AddressesChanged);
+
+ // Recalculate the layout for the whole image (and verify the ranges at
+ // the start of the next round).
+ assignAddresses();
+
+ Pass++;
+ }
+}
+
// The main function of the writer.
void Writer::run() {
ScopedTimer T1(CodeLayoutTimer);
@@ -309,7 +498,8 @@ void Writer::run() {
appendImportThunks();
createExportTable();
mergeSections();
- assignAddresses();
+ readRelocTargets();
+ finalizeAddresses();
removeEmptySections();
setSectionPermissions();
createSymbolAndStringTable();
@@ -796,9 +986,9 @@ void Writer::createSymbolAndStringTable(
}
void Writer::mergeSections() {
- if (!PdataSec->getChunks().empty()) {
- FirstPdata = PdataSec->getChunks().front();
- LastPdata = PdataSec->getChunks().back();
+ if (!PdataSec->Chunks.empty()) {
+ FirstPdata = PdataSec->Chunks.front();
+ LastPdata = PdataSec->Chunks.back();
}
for (auto &P : Config->Merge) {
@@ -826,6 +1016,13 @@ void Writer::mergeSections() {
}
}
+// Visits all sections to initialize their relocation targets.
+void Writer::readRelocTargets() {
+ for (OutputSection *Sec : OutputSections)
+ for_each(parallel::par, Sec->Chunks.begin(), Sec->Chunks.end(),
+ [&](Chunk *C) { C->readRelocTargets(); });
+}
+
// Visits all sections to assign incremental, non-overlapping RVAs and
// file offsets.
void Writer::assignAddresses() {
@@ -843,7 +1040,7 @@ void Writer::assignAddresses() {
addBaserels();
uint64_t RawSize = 0, VirtualSize = 0;
Sec->Header.VirtualAddress = RVA;
- for (Chunk *C : Sec->getChunks()) {
+ for (Chunk *C : Sec->Chunks) {
VirtualSize = alignTo(VirtualSize, C->Alignment);
C->setRVA(RVA + VirtualSize);
C->OutputSectionOff = VirtualSize;
@@ -1315,7 +1512,7 @@ void Writer::writeSections() {
// ADD instructions).
if (Sec->Header.Characteristics & IMAGE_SCN_CNT_CODE)
memset(SecBuf, 0xCC, Sec->getRawSize());
- for_each(parallel::par, Sec->getChunks().begin(), Sec->getChunks().end(),
+ for_each(parallel::par, Sec->Chunks.begin(), Sec->Chunks.end(),
[&](Chunk *C) { C->writeTo(SecBuf); });
}
}
@@ -1399,12 +1596,13 @@ uint32_t Writer::getSizeOfInitializedDat
void Writer::addBaserels() {
if (!Config->Relocatable)
return;
+ RelocSec->Chunks.clear();
std::vector<Baserel> V;
for (OutputSection *Sec : OutputSections) {
if (Sec->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
continue;
// Collect all locations for base relocations.
- for (Chunk *C : Sec->getChunks())
+ for (Chunk *C : Sec->Chunks)
C->getBaserels(&V);
// Add the addresses to .reloc section.
if (!V.empty())
Modified: lld/trunk/COFF/Writer.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Writer.h?rev=342962&r1=342961&r2=342962&view=diff
==============================================================================
--- lld/trunk/COFF/Writer.h (original)
+++ lld/trunk/COFF/Writer.h Tue Sep 25 03:59:29 2018
@@ -36,7 +36,6 @@ public:
void addChunk(Chunk *C);
void insertChunkAtStart(Chunk *C);
void merge(OutputSection *Other);
- ArrayRef<Chunk *> getChunks() { return Chunks; }
void addPermissions(uint32_t C);
void setPermissions(uint32_t C);
uint64_t getRVA() { return Header.VirtualAddress; }
@@ -63,9 +62,11 @@ public:
llvm::StringRef Name;
llvm::object::coff_section Header = {};
+ std::vector<Chunk *> Chunks;
+ std::vector<Chunk *> OrigChunks;
+
private:
uint32_t StringTableOff = 0;
- std::vector<Chunk *> Chunks;
};
}
Removed: lld/trunk/test/COFF/Inputs/far-arm-thumb-abs.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/Inputs/far-arm-thumb-abs.s?rev=342961&view=auto
==============================================================================
--- lld/trunk/test/COFF/Inputs/far-arm-thumb-abs.s (original)
+++ lld/trunk/test/COFF/Inputs/far-arm-thumb-abs.s (removed)
@@ -1,2 +0,0 @@
-.global too_far1
-too_far1 = 0x1401004
Removed: lld/trunk/test/COFF/Inputs/far-arm-thumb-abs20.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/Inputs/far-arm-thumb-abs20.s?rev=342961&view=auto
==============================================================================
--- lld/trunk/test/COFF/Inputs/far-arm-thumb-abs20.s (original)
+++ lld/trunk/test/COFF/Inputs/far-arm-thumb-abs20.s (removed)
@@ -1,2 +0,0 @@
-.global too_far20
-too_far20 = 0x501004
Removed: lld/trunk/test/COFF/arm-thumb-branch-error.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/arm-thumb-branch-error.s?rev=342961&view=auto
==============================================================================
--- lld/trunk/test/COFF/arm-thumb-branch-error.s (original)
+++ lld/trunk/test/COFF/arm-thumb-branch-error.s (removed)
@@ -1,10 +0,0 @@
-// RUN: llvm-mc -filetype=obj -triple=thumbv7a-windows-gnu %s -o %t
-// RUN: llvm-mc -filetype=obj -triple=thumbv7a-windows-gnu %S/Inputs/far-arm-thumb-abs.s -o %tfar
-// RUN: not lld-link -entry:_start -subsystem:console %t %tfar -out:%t2 2>&1 | FileCheck %s
-// REQUIRES: arm
- .syntax unified
- .globl _start
-_start:
- bl too_far1
-
-// CHECK: relocation out of range
Modified: lld/trunk/test/COFF/arm-thumb-branch20-error.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/arm-thumb-branch20-error.s?rev=342962&r1=342961&r2=342962&view=diff
==============================================================================
--- lld/trunk/test/COFF/arm-thumb-branch20-error.s (original)
+++ lld/trunk/test/COFF/arm-thumb-branch20-error.s Tue Sep 25 03:59:29 2018
@@ -1,10 +1,16 @@
// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=thumbv7a-windows-gnu %s -o %t.obj
-// RUN: llvm-mc -filetype=obj -triple=thumbv7a-windows-gnu %S/Inputs/far-arm-thumb-abs20.s -o %t.far.obj
-// RUN: not lld-link -entry:_start -subsystem:console %t.obj %t.far.obj -out:%t.exe 2>&1 | FileCheck %s
+// RUN: not lld-link -entry:_start -subsystem:console %t.obj -out:%t.exe 2>&1 | FileCheck %s
.syntax unified
.globl _start
_start:
bne too_far20
+ .space 0x100000
+ .section .text$a, "xr"
+too_far20:
+ bx lr
-// CHECK: relocation out of range
+// When trying to add a thunk at the end of the section, the thunk itself
+// will be too far away, so this won't converge.
+
+// CHECK: adding thunks hasn't converged
Added: lld/trunk/test/COFF/arm-thumb-thunks-multipass.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/arm-thumb-thunks-multipass.s?rev=342962&view=auto
==============================================================================
--- lld/trunk/test/COFF/arm-thumb-thunks-multipass.s (added)
+++ lld/trunk/test/COFF/arm-thumb-thunks-multipass.s Tue Sep 25 03:59:29 2018
@@ -0,0 +1,70 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=thumbv7-windows %s -o %t.obj
+// RUN: lld-link -entry:main -subsystem:console %t.obj -out:%t.exe -verbose 2>&1 | FileCheck -check-prefix=VERBOSE %s
+// RUN: llvm-objdump -d %t.exe -start-address=0x403000 -stop-address=0x403008 | FileCheck -check-prefix=FUNC01 %s
+// RUN: llvm-objdump -d %t.exe -start-address=0x404ffa -stop-address=0x405012 | FileCheck -check-prefix=FUNC01-THUNKS %s
+
+// VERBOSE: Added {{.*}} thunks with margin 204800 in 2 passes
+
+ .syntax unified
+ .globl main
+ .text
+main:
+ b func01
+ bx lr
+
+.irp i, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15, 16, 17, 18
+ .section .text$\i\()a, "xr"
+ .balign 8192
+func\i:
+ bne far_func\i
+ bne func_within_margin\i
+ // Originally, the first section is less than 8192 bytes large, and the
+ // second one follows almost directly. After adding one thunk after
+ // the first section, the second one will move forward by 8192 bytes
+ // due to the alignment.
+ .space 8192 - 8 - 4
+
+ .section .text$\i\()b, "xr"
+ .balign 8192
+align\i:
+ nop
+.endr
+
+ .section .text$999, "xr"
+tail:
+ .space 0x100000 - 100*1024 - 18*8192*2
+ // Initially, these symbols are within range from all the sections above,
+ // even when taking the initial margin into account. After adding thunks
+ // to all the sections above, some of these are also out of range, forcing
+ // running a second pass.
+.irp i, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15, 16, 17, 18
+func_within_margin\i:
+ nop
+.endr
+ .space 0x100000
+
+ // These are always out of range.
+.irp i, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15, 16, 17, 18
+far_func\i:
+ nop
+.endr
+ bx lr
+
+// FUNC01: 403000: 41 f0 fc 87 bne.w #8184 <.text+0x3ffc>
+// FUNC01: 403004: 41 f0 ff 87 bne.w #8190 <.text+0x4006>
+
+// Check that we only have two thunks here, even if we created the first
+// thunk twice (once in the first pass, then thrown away and recreated
+// in the second pass).
+
+// FUNC01-THUNKS: 404ffa: 00 00 movs r0, r0
+// The instruction above is padding from the .space
+// FUNC01-THUNKS: 404ffc: 47 f2 1e 0c movw r12, #28702
+// FUNC01-THUNKS: 405000: c0 f2 20 0c movt r12, #32
+// FUNC01-THUNKS: 405004: e7 44 add pc, r12
+// FUNC01-THUNKS: 405006: 46 f6 f0 7c movw r12, #28656
+// FUNC01-THUNKS: 40500a: c0 f2 10 0c movt r12, #16
+// FUNC01-THUNKS: 40500e: e7 44 add pc, r12
+// The instruction below is padding from the .balign
+// FUNC01-THUNKS: 405010: cc cc ldm r4!, {r2, r3, r6, r7}
Added: lld/trunk/test/COFF/arm-thumb-thunks.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/arm-thumb-thunks.s?rev=342962&view=auto
==============================================================================
--- lld/trunk/test/COFF/arm-thumb-thunks.s (added)
+++ lld/trunk/test/COFF/arm-thumb-thunks.s Tue Sep 25 03:59:29 2018
@@ -0,0 +1,75 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=thumbv7-windows %s -o %t.obj
+// RUN: lld-link -entry:main -subsystem:console %t.obj -out:%t.exe -verbose 2>&1 | FileCheck -check-prefix=VERBOSE %s
+// RUN: llvm-objdump -d %t.exe -start-address=0x401000 -stop-address=0x401022 | FileCheck -check-prefix=MAIN %s
+// RUN: llvm-objdump -d %t.exe -start-address=0x501022 -stop-address=0x501032 | FileCheck -check-prefix=FUNC1 %s
+// RUN: llvm-objdump -d %t.exe -start-address=0x601032 | FileCheck -check-prefix=FUNC2 %s
+
+// VERBOSE: Added 3 thunks with margin {{.*}} in 1 passes
+
+ .syntax unified
+ .globl main
+ .globl func1
+ .text
+main:
+ bne func1
+ bne func2
+ // This should reuse the same thunk as func1 above
+ bne func1_alias
+ bx lr
+ .section .text$a, "xr"
+ .space 0x100000
+ .section .text$b, "xr"
+func1:
+func1_alias:
+ // This shouldn't reuse the func2 thunk from above, since it is out
+ // of range.
+ bne func2
+ bx lr
+ .section .text$c, "xr"
+ .space 0x100000
+ .section .text$d, "xr"
+func2:
+// Test using string tail merging. This is irrelevant to the thunking itself,
+// but running multiple passes of assignAddresses() calls finalizeAddresses()
+// multiple times; check that MergeChunk handles this correctly.
+ movw r0, :lower16:"??_C at string1"
+ movt r0, :upper16:"??_C at string1"
+ movw r1, :lower16:"??_C at string2"
+ movt r1, :upper16:"??_C at string2"
+ bx lr
+
+ .section .rdata,"dr",discard,"??_C at string1"
+ .globl "??_C at string1"
+"??_C at string1":
+ .asciz "foobar"
+ .section .rdata,"dr",discard,"??_C at string2"
+ .globl "??_C at string2"
+"??_C at string2":
+ .asciz "bar"
+
+// MAIN: 401000: 40 f0 05 80 bne.w #10 <.text+0xe>
+// MAIN: 401004: 40 f0 08 80 bne.w #16 <.text+0x18>
+// MAIN: 401008: 40 f0 01 80 bne.w #2 <.text+0xe>
+// MAIN: 40100c: 70 47 bx lr
+// func1 thunk
+// MAIN: 40100e: 40 f2 08 0c movw r12, #8
+// MAIN: 401012: c0 f2 10 0c movt r12, #16
+// MAIN: 401016: e7 44 add pc, r12
+// func2 thunk
+// MAIN: 401018: 40 f2 0e 0c movw r12, #14
+// MAIN: 40101c: c0 f2 20 0c movt r12, #32
+// MAIN: 401020: e7 44 add pc, r12
+
+// FUNC1: 501022: 40 f0 01 80 bne.w #2 <.text+0x100028>
+// FUNC1: 501026: 70 47 bx lr
+// func2 thunk
+// FUNC1: 501028: 4f f6 fe 7c movw r12, #65534
+// FUNC1: 50102c: c0 f2 0f 0c movt r12, #15
+// FUNC1: 501030: e7 44 add pc, r12
+
+// FUNC2: 601032: 42 f2 00 00 movw r0, #8192
+// FUNC2: 601036: c0 f2 60 00 movt r0, #96
+// FUNC2: 60103a: 42 f2 03 01 movw r1, #8195
+// FUNC2: 60103e: c0 f2 60 01 movt r1, #96
+// FUNC2: 601042: 70 47 bx lr
More information about the llvm-commits
mailing list