COFF: Handle base relocation as a tuple of relocation type and RVA. NFC.
On x64 and x86, we use only one base relocation type, so we handled
base relocations just as a list of RVAs. That doesn't work well for
ARM becuase we have to handle two types of base relocations on ARM.
This patch changes the type of base relocation from uint32_t to
{reltype, uint32_t} to make it easy to port this code to ARM.
llvm-svn: 243197
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index 93ac540..b7d0dd1 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -115,12 +115,16 @@
Child->Root = false;
}
-static bool isAbs(const coff_relocation &Rel) {
+static uint8_t getBaserelType(const coff_relocation &Rel) {
switch (Config->MachineType) {
case IMAGE_FILE_MACHINE_AMD64:
- return Rel.Type == IMAGE_REL_AMD64_ADDR64;
+ if (Rel.Type == IMAGE_REL_AMD64_ADDR64)
+ return IMAGE_REL_BASED_DIR64;
+ return IMAGE_REL_BASED_ABSOLUTE;
case IMAGE_FILE_MACHINE_I386:
- return Rel.Type == IMAGE_REL_I386_DIR32;
+ if (Rel.Type == IMAGE_REL_I386_DIR32)
+ return IMAGE_REL_BASED_HIGHLOW;
+ return IMAGE_REL_BASED_ABSOLUTE;
default:
llvm_unreachable("unknown machine type");
}
@@ -130,14 +134,15 @@
// Collect all locations that contain absolute addresses, which need to be
// fixed by the loader if load-time relocation is needed.
// Only called when base relocation is enabled.
-void SectionChunk::getBaserels(std::vector<uint32_t> *Res) {
+void SectionChunk::getBaserels(std::vector<Baserel> *Res) {
for (const coff_relocation &Rel : Relocs) {
- if (!isAbs(Rel))
+ uint8_t Ty = getBaserelType(Rel);
+ if (Ty == IMAGE_REL_BASED_ABSOLUTE)
continue;
SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex)->repl();
if (isa<DefinedAbsolute>(Body))
continue;
- Res->push_back(RVA + Rel.VirtualAddress);
+ Res->emplace_back(RVA + Rel.VirtualAddress, Ty);
}
}
@@ -258,8 +263,8 @@
write32le(Buf + FileOff + 2, ImpSymbol->getRVA() - RVA - getSize());
}
-void ImportThunkChunkX86::getBaserels(std::vector<uint32_t> *Res) {
- Res->push_back(getRVA() + 2);
+void ImportThunkChunkX86::getBaserels(std::vector<Baserel> *Res) {
+ Res->emplace_back(getRVA() + 2);
}
void ImportThunkChunkX86::writeTo(uint8_t *Buf) {
@@ -268,8 +273,8 @@
write32le(Buf + FileOff + 2, ImpSymbol->getRVA() + Config->ImageBase);
}
-void LocalImportChunk::getBaserels(std::vector<uint32_t> *Res) {
- Res->push_back(getRVA());
+void LocalImportChunk::getBaserels(std::vector<Baserel> *Res) {
+ Res->emplace_back(getRVA());
}
size_t LocalImportChunk::getSize() const {
@@ -294,7 +299,7 @@
// Windows-specific.
// This class represents a block in .reloc section.
-BaserelChunk::BaserelChunk(uint32_t Page, uint32_t *Begin, uint32_t *End) {
+BaserelChunk::BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End) {
// Block header consists of 4 byte page RVA and 4 byte block size.
// Each entry is 2 byte. Last entry may be padding.
Data.resize(RoundUpToAlignment((End - Begin) * 2 + 8, 4));
@@ -302,17 +307,8 @@
write32le(P, Page);
write32le(P + 4, Data.size());
P += 8;
- for (uint32_t *I = Begin; I != End; ++I) {
- switch (Config->MachineType) {
- case AMD64:
- write16le(P, (IMAGE_REL_BASED_DIR64 << 12) | (*I - Page));
- break;
- case I386:
- write16le(P, (IMAGE_REL_BASED_HIGHLOW << 12) | (*I - Page));
- break;
- default:
- llvm_unreachable("unsupported machine type");
- }
+ for (Baserel *I = Begin; I != End; ++I) {
+ write16le(P, (I->Type << 12) | (I->RVA - Page));
P += 2;
}
}
@@ -321,5 +317,16 @@
memcpy(Buf + FileOff, Data.data(), Data.size());
}
+uint8_t Baserel::getDefaultType() {
+ switch (Config->MachineType) {
+ case IMAGE_FILE_MACHINE_AMD64:
+ return IMAGE_REL_BASED_DIR64;
+ case IMAGE_FILE_MACHINE_I386:
+ return IMAGE_REL_BASED_HIGHLOW;
+ default:
+ llvm_unreachable("unknown machine type");
+ }
+}
+
} // namespace coff
} // namespace lld
diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h
index cf087af..e471699 100644
--- a/lld/COFF/Chunks.h
+++ b/lld/COFF/Chunks.h
@@ -29,9 +29,10 @@
using llvm::object::coff_section;
using llvm::sys::fs::file_magic;
+class Baserel;
class Defined;
-class DefinedRegular;
class DefinedImportData;
+class DefinedRegular;
class ObjectFile;
class OutputSection;
class SymbolBody;
@@ -83,7 +84,7 @@
// Windows-specific.
// Collect all locations that contain absolute addresses for base relocations.
- virtual void getBaserels(std::vector<uint32_t> *Res) {}
+ virtual void getBaserels(std::vector<Baserel> *Res) {}
// Returns a human-readable name of this chunk. Chunks are unnamed chunks of
// bytes, so this is used only for logging or debugging.
@@ -134,7 +135,7 @@
bool hasData() const override;
uint32_t getPermissions() const override;
StringRef getSectionName() const override { return SectionName; }
- void getBaserels(std::vector<uint32_t> *Res) override;
+ void getBaserels(std::vector<Baserel> *Res) override;
bool isCOMDAT() const;
void applyRelX64(uint8_t *Off, uint16_t Type, uint64_t S, uint64_t P);
void applyRelX86(uint8_t *Off, uint16_t Type, uint64_t S, uint64_t P);
@@ -244,7 +245,7 @@
public:
explicit ImportThunkChunkX86(Defined *S) : ImpSymbol(S) {}
size_t getSize() const override { return sizeof(ImportThunkX86); }
- void getBaserels(std::vector<uint32_t> *Res) override;
+ void getBaserels(std::vector<Baserel> *Res) override;
void writeTo(uint8_t *Buf) override;
private:
@@ -257,7 +258,7 @@
public:
explicit LocalImportChunk(Defined *S) : Sym(S) {}
size_t getSize() const override;
- void getBaserels(std::vector<uint32_t> *Res) override;
+ void getBaserels(std::vector<Baserel> *Res) override;
void writeTo(uint8_t *Buf) override;
private:
@@ -282,7 +283,7 @@
// See the PE/COFF spec 5.6 for details.
class BaserelChunk : public Chunk {
public:
- BaserelChunk(uint32_t Page, uint32_t *Begin, uint32_t *End);
+ BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End);
size_t getSize() const override { return Data.size(); }
void writeTo(uint8_t *Buf) override;
@@ -290,6 +291,16 @@
std::vector<uint8_t> Data;
};
+class Baserel {
+public:
+ Baserel(uint32_t V, uint8_t Ty) : RVA(V), Type(Ty) {}
+ explicit Baserel(uint32_t V) : Baserel(V, getDefaultType()) {}
+ uint8_t getDefaultType();
+
+ uint32_t RVA;
+ uint8_t Type;
+};
+
} // namespace coff
} // namespace lld
diff --git a/lld/COFF/DLL.cpp b/lld/COFF/DLL.cpp
index 9e1731d..09123bc 100644
--- a/lld/COFF/DLL.cpp
+++ b/lld/COFF/DLL.cpp
@@ -319,9 +319,9 @@
write32le(Buf + FileOff + 13, Helper->getRVA() - RVA - 17);
}
- void getBaserels(std::vector<uint32_t> *Res) override {
- Res->push_back(RVA + 3);
- Res->push_back(RVA + 8);
+ void getBaserels(std::vector<Baserel> *Res) override {
+ Res->emplace_back(RVA + 3);
+ Res->emplace_back(RVA + 8);
}
Defined *Imp = nullptr;
@@ -367,8 +367,8 @@
write64le(Buf + FileOff, Thunk->getRVA() + Config->ImageBase);
}
- void getBaserels(std::vector<uint32_t> *Res) override {
- Res->push_back(RVA);
+ void getBaserels(std::vector<Baserel> *Res) override {
+ Res->emplace_back(RVA);
}
Chunk *Thunk;
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 1245a21..405eb40 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -618,7 +618,7 @@
// Dest is .reloc section. Add contents to that section.
void Writer::addBaserels(OutputSection *Dest) {
- std::vector<uint32_t> V;
+ std::vector<Baserel> V;
for (OutputSection *Sec : OutputSections) {
if (Sec == Dest)
continue;
@@ -633,12 +633,12 @@
}
// Add addresses to .reloc section. Note that addresses are grouped by page.
-void Writer::addBaserelBlocks(OutputSection *Dest, std::vector<uint32_t> &V) {
+void Writer::addBaserelBlocks(OutputSection *Dest, std::vector<Baserel> &V) {
const uint32_t Mask = ~uint32_t(PageSize - 1);
- uint32_t Page = V[0] & Mask;
+ uint32_t Page = V[0].RVA & Mask;
size_t I = 0, J = 1;
for (size_t E = V.size(); J < E; ++J) {
- uint32_t P = V[J] & Mask;
+ uint32_t P = V[J].RVA & Mask;
if (P == Page)
continue;
BaserelChunk *Buf = BAlloc.Allocate();
diff --git a/lld/COFF/Writer.h b/lld/COFF/Writer.h
index 5af6b3d..1e370d6 100644
--- a/lld/COFF/Writer.h
+++ b/lld/COFF/Writer.h
@@ -100,7 +100,7 @@
OutputSection *findSection(StringRef Name);
OutputSection *createSection(StringRef Name);
void addBaserels(OutputSection *Dest);
- void addBaserelBlocks(OutputSection *Dest, std::vector<uint32_t> &V);
+ void addBaserelBlocks(OutputSection *Dest, std::vector<Baserel> &V);
uint32_t getSizeOfInitializedData();
std::map<StringRef, std::vector<DefinedImportData *>> binImports();