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
This commit is contained in:
Rui Ueyama
2015-07-25 01:44:32 +00:00
parent 922b702bf9
commit 3afd5bfd7b
5 changed files with 56 additions and 38 deletions

View File

@@ -115,12 +115,16 @@ void SectionChunk::addAssociative(SectionChunk *Child) {
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 @@ static bool isAbs(const coff_relocation &Rel) {
// 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 @@ void ImportThunkChunkX64::writeTo(uint8_t *Buf) {
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 @@ void ImportThunkChunkX86::writeTo(uint8_t *Buf) {
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 @@ void SEHTableChunk::writeTo(uint8_t *Buf) {
// 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 @@ BaserelChunk::BaserelChunk(uint32_t Page, uint32_t *Begin, uint32_t *End) {
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 @@ void BaserelChunk::writeTo(uint8_t *Buf) {
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

View File

@@ -29,9 +29,10 @@ using llvm::object::coff_relocation;
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 @@ public:
// 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 @@ public:
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 @@ class ImportThunkChunkX86 : public Chunk {
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 @@ class LocalImportChunk : public Chunk {
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 @@ private:
// 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 @@ private:
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

View File

@@ -319,9 +319,9 @@ public:
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 @@ public:
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;

View File

@@ -618,7 +618,7 @@ OutputSection *Writer::createSection(StringRef Name) {
// 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 @@ void Writer::addBaserels(OutputSection *Dest) {
}
// 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();

View File

@@ -100,7 +100,7 @@ private:
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();