COFF: Create output sections early. NFCI.
With this, all output sections are created in one place. This will make it simpler to implement merging of builtin sections. Differential Revision: https://reviews.llvm.org/D45349 llvm-svn: 329370
This commit is contained in:
parent
f108d57f9b
commit
f2c0f39b91
|
@ -163,14 +163,13 @@ private:
|
|||
void createSymbolAndStringTable();
|
||||
void openFile(StringRef OutputPath);
|
||||
template <typename PEHeaderTy> void writeHeader();
|
||||
void createSEHTable(OutputSection *RData);
|
||||
void createGuardCFTables(OutputSection *RData);
|
||||
void createGLJmpTable(OutputSection *RData);
|
||||
void createSEHTable();
|
||||
void createGuardCFTables();
|
||||
void markSymbolsForRVATable(ObjFile *File,
|
||||
ArrayRef<SectionChunk *> SymIdxChunks,
|
||||
SymbolRVASet &TableSymbols);
|
||||
void maybeAddRVATable(OutputSection *RData, SymbolRVASet TableSymbols,
|
||||
StringRef TableSym, StringRef CountSym);
|
||||
void maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym,
|
||||
StringRef CountSym);
|
||||
void setSectionPermissions();
|
||||
void writeSections();
|
||||
void writeBuildId();
|
||||
|
@ -180,9 +179,8 @@ private:
|
|||
size_t addEntryToStringTable(StringRef Str);
|
||||
|
||||
OutputSection *findSection(StringRef Name);
|
||||
OutputSection *createSection(StringRef Name);
|
||||
void addBaserels(OutputSection *Dest);
|
||||
void addBaserelBlocks(OutputSection *Dest, std::vector<Baserel> &V);
|
||||
void addBaserels();
|
||||
void addBaserelBlocks(std::vector<Baserel> &V);
|
||||
|
||||
uint32_t getSizeOfInitializedData();
|
||||
std::map<StringRef, std::vector<DefinedImportData *>> binImports();
|
||||
|
@ -207,6 +205,16 @@ private:
|
|||
uint32_t PointerToSymbolTable = 0;
|
||||
uint64_t SizeOfImage;
|
||||
uint64_t SizeOfHeaders;
|
||||
|
||||
OutputSection *TextSec;
|
||||
OutputSection *RdataSec;
|
||||
OutputSection *DataSec;
|
||||
OutputSection *PdataSec;
|
||||
OutputSection *IdataSec;
|
||||
OutputSection *EdataSec;
|
||||
OutputSection *DidatSec;
|
||||
OutputSection *RsrcSec;
|
||||
OutputSection *RelocSec;
|
||||
};
|
||||
} // anonymous namespace
|
||||
|
||||
|
@ -318,8 +326,6 @@ void Writer::run() {
|
|||
createMiscChunks();
|
||||
createImportTables();
|
||||
createExportTable();
|
||||
if (Config->Relocatable)
|
||||
createSection(".reloc");
|
||||
assignAddresses();
|
||||
removeEmptySections();
|
||||
setSectionPermissions();
|
||||
|
@ -386,7 +392,37 @@ static void sortBySectionOrder(std::vector<Chunk *> &Chunks) {
|
|||
|
||||
// Create output section objects and add them to OutputSections.
|
||||
void Writer::createSections() {
|
||||
// First, bin chunks by name.
|
||||
// First, create the builtin sections.
|
||||
const uint32_t DATA = IMAGE_SCN_CNT_INITIALIZED_DATA;
|
||||
const uint32_t BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA;
|
||||
const uint32_t CODE = IMAGE_SCN_CNT_CODE;
|
||||
const uint32_t DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE;
|
||||
const uint32_t R = IMAGE_SCN_MEM_READ;
|
||||
const uint32_t W = IMAGE_SCN_MEM_WRITE;
|
||||
const uint32_t X = IMAGE_SCN_MEM_EXECUTE;
|
||||
|
||||
SmallDenseMap<StringRef, OutputSection *> Sections;
|
||||
auto CreateSection = [&](StringRef Name, uint32_t Perms) {
|
||||
auto Sec = make<OutputSection>(Name);
|
||||
Sec->addPermissions(Perms);
|
||||
OutputSections.push_back(Sec);
|
||||
Sections[Name] = Sec;
|
||||
return Sec;
|
||||
};
|
||||
|
||||
// Try to match the section order used by link.exe.
|
||||
TextSec = CreateSection(".text", CODE | R | X);
|
||||
CreateSection(".bss", BSS | R | W);
|
||||
RdataSec = CreateSection(".rdata", DATA | R);
|
||||
DataSec = CreateSection(".data", DATA | R | W);
|
||||
PdataSec = CreateSection(".pdata", DATA | R);
|
||||
IdataSec = CreateSection(".idata", DATA | R);
|
||||
EdataSec = CreateSection(".edata", DATA | R);
|
||||
DidatSec = CreateSection(".didat", DATA | R);
|
||||
RsrcSec = CreateSection(".rsrc", DATA | R);
|
||||
RelocSec = CreateSection(".reloc", DATA | DISCARDABLE | R);
|
||||
|
||||
// Then bin chunks by name.
|
||||
std::map<StringRef, std::vector<Chunk *>> Map;
|
||||
for (Chunk *C : Symtab->getChunks()) {
|
||||
auto *SC = dyn_cast<SectionChunk>(C);
|
||||
|
@ -407,7 +443,6 @@ void Writer::createSections() {
|
|||
// '$' and all following characters in input section names are
|
||||
// discarded when determining output section. So, .text$foo
|
||||
// contributes to .text, for example. See PE/COFF spec 3.2.
|
||||
SmallDenseMap<StringRef, OutputSection *> Sections;
|
||||
for (auto Pair : Map) {
|
||||
StringRef Name = getOutputSection(Pair.first);
|
||||
OutputSection *&Sec = Sections[Name];
|
||||
|
@ -421,18 +456,38 @@ void Writer::createSections() {
|
|||
Sec->addPermissions(C->getPermissions());
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, move some output sections to the end.
|
||||
auto SectionOrder = [&](OutputSection *S) {
|
||||
// .reloc should come last of all since it refers to RVAs of data in the
|
||||
// previous sections.
|
||||
if (S == RelocSec)
|
||||
return 3;
|
||||
// Move DISCARDABLE (or non-memory-mapped) sections to the end of file because
|
||||
// the loader cannot handle holes.
|
||||
if (S->getPermissions() & IMAGE_SCN_MEM_DISCARDABLE)
|
||||
return 2;
|
||||
// .rsrc should come at the end of the non-discardable sections because its
|
||||
// size may change by the Win32 UpdateResources() function, causing
|
||||
// subsequent sections to move (see https://crbug.com/827082).
|
||||
if (S == RsrcSec)
|
||||
return 1;
|
||||
return 0;
|
||||
};
|
||||
std::stable_sort(OutputSections.begin(), OutputSections.end(),
|
||||
[&](OutputSection *S, OutputSection *T) {
|
||||
return SectionOrder(S) < SectionOrder(T);
|
||||
});
|
||||
}
|
||||
|
||||
void Writer::createMiscChunks() {
|
||||
OutputSection *RData = createSection(".rdata");
|
||||
|
||||
for (auto &P : MergeChunk::Instances)
|
||||
RData->addChunk(P.second);
|
||||
RdataSec->addChunk(P.second);
|
||||
|
||||
// Create thunks for locally-dllimported symbols.
|
||||
if (!Symtab->LocalImportChunks.empty()) {
|
||||
for (Chunk *C : Symtab->LocalImportChunks)
|
||||
RData->addChunk(C);
|
||||
RdataSec->addChunk(C);
|
||||
}
|
||||
|
||||
// Create Debug Information Chunks
|
||||
|
@ -447,18 +502,18 @@ void Writer::createMiscChunks() {
|
|||
BuildId = CVChunk;
|
||||
DebugRecords.push_back(CVChunk);
|
||||
|
||||
RData->addChunk(DebugDirectory);
|
||||
RdataSec->addChunk(DebugDirectory);
|
||||
for (Chunk *C : DebugRecords)
|
||||
RData->addChunk(C);
|
||||
RdataSec->addChunk(C);
|
||||
}
|
||||
|
||||
// Create SEH table. x86-only.
|
||||
if (Config->Machine == I386)
|
||||
createSEHTable(RData);
|
||||
createSEHTable();
|
||||
|
||||
// Create /guard:cf tables if requested.
|
||||
if (Config->GuardCF != GuardCFLevel::Off)
|
||||
createGuardCFTables(RData);
|
||||
createGuardCFTables();
|
||||
}
|
||||
|
||||
// Create .idata section for the DLL-imported symbol table.
|
||||
|
@ -481,13 +536,12 @@ void Writer::createImportTables() {
|
|||
Config->DLLOrder[DLL] = Config->DLLOrder.size();
|
||||
}
|
||||
|
||||
OutputSection *Text = createSection(".text");
|
||||
for (ImportFile *File : ImportFile::Instances) {
|
||||
if (!File->Live)
|
||||
continue;
|
||||
|
||||
if (DefinedImportThunk *Thunk = File->ThunkSym)
|
||||
Text->addChunk(Thunk->getChunk());
|
||||
TextSec->addChunk(Thunk->getChunk());
|
||||
|
||||
if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) {
|
||||
if (!File->ThunkSym)
|
||||
|
@ -499,33 +553,27 @@ void Writer::createImportTables() {
|
|||
}
|
||||
}
|
||||
|
||||
if (!Idata.empty()) {
|
||||
OutputSection *Sec = createSection(".idata");
|
||||
if (!Idata.empty())
|
||||
for (Chunk *C : Idata.getChunks())
|
||||
Sec->addChunk(C);
|
||||
}
|
||||
IdataSec->addChunk(C);
|
||||
|
||||
if (!DelayIdata.empty()) {
|
||||
Defined *Helper = cast<Defined>(Config->DelayLoadHelper);
|
||||
DelayIdata.create(Helper);
|
||||
OutputSection *Sec = createSection(".didat");
|
||||
for (Chunk *C : DelayIdata.getChunks())
|
||||
Sec->addChunk(C);
|
||||
Sec = createSection(".data");
|
||||
DidatSec->addChunk(C);
|
||||
for (Chunk *C : DelayIdata.getDataChunks())
|
||||
Sec->addChunk(C);
|
||||
Sec = createSection(".text");
|
||||
DataSec->addChunk(C);
|
||||
for (Chunk *C : DelayIdata.getCodeChunks())
|
||||
Sec->addChunk(C);
|
||||
TextSec->addChunk(C);
|
||||
}
|
||||
}
|
||||
|
||||
void Writer::createExportTable() {
|
||||
if (Config->Exports.empty())
|
||||
return;
|
||||
OutputSection *Sec = createSection(".edata");
|
||||
for (Chunk *C : Edata.Chunks)
|
||||
Sec->addChunk(C);
|
||||
EdataSec->addChunk(C);
|
||||
}
|
||||
|
||||
// The Windows loader doesn't seem to like empty sections,
|
||||
|
@ -644,29 +692,6 @@ void Writer::createSymbolAndStringTable() {
|
|||
FileSize = alignTo(FileOff, SectorSize);
|
||||
}
|
||||
|
||||
static int sectionIndex(OutputSection *S) {
|
||||
// Move DISCARDABLE (or non-memory-mapped) sections to the end of file because
|
||||
// the loader cannot handle holes.
|
||||
if (S->getPermissions() & IMAGE_SCN_MEM_DISCARDABLE)
|
||||
return 101;
|
||||
|
||||
// Try to match the section order used by link.exe. In particular, it's
|
||||
// important that .reloc comes last since it refers to RVA's of data in
|
||||
// the previous sections. .rsrc should come late because its size may
|
||||
// change by the Win32 UpdateResources() function, causing subsequent
|
||||
// sections to move (see https://crbug.com/827082).
|
||||
return StringSwitch<int>(S->Name)
|
||||
.Case(".text", 1)
|
||||
.Case(".bss", 2)
|
||||
.Case(".rdata", 3)
|
||||
.Case(".data", 4)
|
||||
.Case(".pdata", 5)
|
||||
.Case(".idata", 6)
|
||||
.Case(".rsrc", 99)
|
||||
.Case(".reloc", 100)
|
||||
.Default(50); // Default to somewhere in the middle.
|
||||
}
|
||||
|
||||
// Visits all sections to assign incremental, non-overlapping RVAs and
|
||||
// file offsets.
|
||||
void Writer::assignAddresses() {
|
||||
|
@ -679,15 +704,9 @@ void Writer::assignAddresses() {
|
|||
uint64_t RVA = PageSize; // The first page is kept unmapped.
|
||||
FileSize = SizeOfHeaders;
|
||||
|
||||
// Reorder the sections.
|
||||
std::stable_sort(OutputSections.begin(), OutputSections.end(),
|
||||
[](OutputSection *S, OutputSection *T) {
|
||||
return sectionIndex(S) < sectionIndex(T);
|
||||
});
|
||||
|
||||
for (OutputSection *Sec : OutputSections) {
|
||||
if (Sec->Name == ".reloc")
|
||||
addBaserels(Sec);
|
||||
if (Sec == RelocSec)
|
||||
addBaserels();
|
||||
uint64_t RawSize = 0, VirtualSize = 0;
|
||||
Sec->Header.VirtualAddress = RVA;
|
||||
for (Chunk *C : Sec->getChunks()) {
|
||||
|
@ -810,18 +829,18 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
|
|||
if (Config->TerminalServerAware)
|
||||
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE;
|
||||
PE->NumberOfRvaAndSize = NumberfOfDataDirectory;
|
||||
if (OutputSection *Text = findSection(".text")) {
|
||||
PE->BaseOfCode = Text->getRVA();
|
||||
PE->SizeOfCode = Text->getRawSize();
|
||||
if (TextSec->getVirtualSize()) {
|
||||
PE->BaseOfCode = TextSec->getRVA();
|
||||
PE->SizeOfCode = TextSec->getRawSize();
|
||||
}
|
||||
PE->SizeOfInitializedData = getSizeOfInitializedData();
|
||||
|
||||
// Write data directory
|
||||
auto *Dir = reinterpret_cast<data_directory *>(Buf);
|
||||
Buf += sizeof(*Dir) * NumberfOfDataDirectory;
|
||||
if (OutputSection *Sec = findSection(".edata")) {
|
||||
Dir[EXPORT_TABLE].RelativeVirtualAddress = Sec->getRVA();
|
||||
Dir[EXPORT_TABLE].Size = Sec->getVirtualSize();
|
||||
if (EdataSec->getVirtualSize()) {
|
||||
Dir[EXPORT_TABLE].RelativeVirtualAddress = EdataSec->getRVA();
|
||||
Dir[EXPORT_TABLE].Size = EdataSec->getVirtualSize();
|
||||
}
|
||||
if (!Idata.empty()) {
|
||||
Dir[IMPORT_TABLE].RelativeVirtualAddress = Idata.getDirRVA();
|
||||
|
@ -829,17 +848,17 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
|
|||
Dir[IAT].RelativeVirtualAddress = Idata.getIATRVA();
|
||||
Dir[IAT].Size = Idata.getIATSize();
|
||||
}
|
||||
if (OutputSection *Sec = findSection(".rsrc")) {
|
||||
Dir[RESOURCE_TABLE].RelativeVirtualAddress = Sec->getRVA();
|
||||
Dir[RESOURCE_TABLE].Size = Sec->getVirtualSize();
|
||||
if (RsrcSec->getVirtualSize()) {
|
||||
Dir[RESOURCE_TABLE].RelativeVirtualAddress = RsrcSec->getRVA();
|
||||
Dir[RESOURCE_TABLE].Size = RsrcSec->getVirtualSize();
|
||||
}
|
||||
if (OutputSection *Sec = findSection(".pdata")) {
|
||||
Dir[EXCEPTION_TABLE].RelativeVirtualAddress = Sec->getRVA();
|
||||
Dir[EXCEPTION_TABLE].Size = Sec->getVirtualSize();
|
||||
if (PdataSec->getVirtualSize()) {
|
||||
Dir[EXCEPTION_TABLE].RelativeVirtualAddress = PdataSec->getRVA();
|
||||
Dir[EXCEPTION_TABLE].Size = PdataSec->getVirtualSize();
|
||||
}
|
||||
if (OutputSection *Sec = findSection(".reloc")) {
|
||||
Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = Sec->getRVA();
|
||||
Dir[BASE_RELOCATION_TABLE].Size = Sec->getVirtualSize();
|
||||
if (RelocSec->getVirtualSize()) {
|
||||
Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = RelocSec->getRVA();
|
||||
Dir[BASE_RELOCATION_TABLE].Size = RelocSec->getVirtualSize();
|
||||
}
|
||||
if (Symbol *Sym = Symtab->findUnderscore("_tls_used")) {
|
||||
if (Defined *B = dyn_cast<Defined>(Sym)) {
|
||||
|
@ -908,7 +927,7 @@ void Writer::openFile(StringRef Path) {
|
|||
"failed to open " + Path);
|
||||
}
|
||||
|
||||
void Writer::createSEHTable(OutputSection *RData) {
|
||||
void Writer::createSEHTable() {
|
||||
SymbolRVASet Handlers;
|
||||
for (ObjFile *File : ObjFile::Instances) {
|
||||
// FIXME: We should error here instead of earlier unless /safeseh:no was
|
||||
|
@ -919,7 +938,7 @@ void Writer::createSEHTable(OutputSection *RData) {
|
|||
markSymbolsForRVATable(File, File->getSXDataChunks(), Handlers);
|
||||
}
|
||||
|
||||
maybeAddRVATable(RData, std::move(Handlers), "__safe_se_handler_table",
|
||||
maybeAddRVATable(std::move(Handlers), "__safe_se_handler_table",
|
||||
"__safe_se_handler_count");
|
||||
}
|
||||
|
||||
|
@ -964,7 +983,7 @@ static void markSymbolsWithRelocations(ObjFile *File,
|
|||
// Create the guard function id table. This is a table of RVAs of all
|
||||
// address-taken functions. It is sorted and uniqued, just like the safe SEH
|
||||
// table.
|
||||
void Writer::createGuardCFTables(OutputSection *RData) {
|
||||
void Writer::createGuardCFTables() {
|
||||
SymbolRVASet AddressTakenSyms;
|
||||
SymbolRVASet LongJmpTargets;
|
||||
for (ObjFile *File : ObjFile::Instances) {
|
||||
|
@ -985,12 +1004,12 @@ void Writer::createGuardCFTables(OutputSection *RData) {
|
|||
if (Config->Entry)
|
||||
addSymbolToRVASet(AddressTakenSyms, cast<Defined>(Config->Entry));
|
||||
|
||||
maybeAddRVATable(RData, std::move(AddressTakenSyms), "__guard_fids_table",
|
||||
maybeAddRVATable(std::move(AddressTakenSyms), "__guard_fids_table",
|
||||
"__guard_fids_count");
|
||||
|
||||
// Add the longjmp target table unless the user told us not to.
|
||||
if (Config->GuardCF == GuardCFLevel::Full)
|
||||
maybeAddRVATable(RData, std::move(LongJmpTargets), "__guard_longjmp_table",
|
||||
maybeAddRVATable(std::move(LongJmpTargets), "__guard_longjmp_table",
|
||||
"__guard_longjmp_count");
|
||||
|
||||
// Set __guard_flags, which will be used in the load config to indicate that
|
||||
|
@ -1047,14 +1066,13 @@ void Writer::markSymbolsForRVATable(ObjFile *File,
|
|||
// Replace the absolute table symbol with a synthetic symbol pointing to
|
||||
// TableChunk so that we can emit base relocations for it and resolve section
|
||||
// relative relocations.
|
||||
void Writer::maybeAddRVATable(OutputSection *RData,
|
||||
SymbolRVASet TableSymbols,
|
||||
StringRef TableSym, StringRef CountSym) {
|
||||
void Writer::maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym,
|
||||
StringRef CountSym) {
|
||||
if (TableSymbols.empty())
|
||||
return;
|
||||
|
||||
RVATableChunk *TableChunk = make<RVATableChunk>(std::move(TableSymbols));
|
||||
RData->addChunk(TableChunk);
|
||||
RdataSec->addChunk(TableChunk);
|
||||
|
||||
Symbol *T = Symtab->findUnderscore(TableSym);
|
||||
Symbol *C = Symtab->findUnderscore(CountSym);
|
||||
|
@ -1141,12 +1159,11 @@ void Writer::writeBuildId() {
|
|||
|
||||
// Sort .pdata section contents according to PE/COFF spec 5.5.
|
||||
void Writer::sortExceptionTable() {
|
||||
OutputSection *Sec = findSection(".pdata");
|
||||
if (!Sec)
|
||||
if (PdataSec->getVirtualSize() == 0)
|
||||
return;
|
||||
// We assume .pdata contains function table entries only.
|
||||
uint8_t *Begin = Buffer->getBufferStart() + Sec->getFileOff();
|
||||
uint8_t *End = Begin + Sec->getVirtualSize();
|
||||
uint8_t *Begin = Buffer->getBufferStart() + PdataSec->getFileOff();
|
||||
uint8_t *End = Begin + PdataSec->getVirtualSize();
|
||||
if (Config->Machine == AMD64) {
|
||||
struct Entry { ulittle32_t Begin, End, Unwind; };
|
||||
sort(parallel::par, (Entry *)Begin, (Entry *)End,
|
||||
|
@ -1177,50 +1194,26 @@ uint32_t Writer::getSizeOfInitializedData() {
|
|||
return Res;
|
||||
}
|
||||
|
||||
// Returns an existing section or create a new one if not found.
|
||||
OutputSection *Writer::createSection(StringRef Name) {
|
||||
if (auto *Sec = findSection(Name))
|
||||
return Sec;
|
||||
const auto DATA = IMAGE_SCN_CNT_INITIALIZED_DATA;
|
||||
const auto BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA;
|
||||
const auto CODE = IMAGE_SCN_CNT_CODE;
|
||||
const auto DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE;
|
||||
const auto R = IMAGE_SCN_MEM_READ;
|
||||
const auto W = IMAGE_SCN_MEM_WRITE;
|
||||
const auto X = IMAGE_SCN_MEM_EXECUTE;
|
||||
uint32_t Perms = StringSwitch<uint32_t>(Name)
|
||||
.Case(".bss", BSS | R | W)
|
||||
.Case(".data", DATA | R | W)
|
||||
.Cases(".didat", ".edata", ".idata", ".rdata", DATA | R)
|
||||
.Case(".reloc", DATA | DISCARDABLE | R)
|
||||
.Case(".text", CODE | R | X)
|
||||
.Default(0);
|
||||
if (!Perms)
|
||||
llvm_unreachable("unknown section name");
|
||||
auto Sec = make<OutputSection>(Name);
|
||||
Sec->addPermissions(Perms);
|
||||
OutputSections.push_back(Sec);
|
||||
return Sec;
|
||||
}
|
||||
|
||||
// Dest is .reloc section. Add contents to that section.
|
||||
void Writer::addBaserels(OutputSection *Dest) {
|
||||
// Add base relocations to .reloc section.
|
||||
void Writer::addBaserels() {
|
||||
if (!Config->Relocatable)
|
||||
return;
|
||||
std::vector<Baserel> V;
|
||||
for (OutputSection *Sec : OutputSections) {
|
||||
if (Sec == Dest)
|
||||
if (Sec == RelocSec)
|
||||
continue;
|
||||
// Collect all locations for base relocations.
|
||||
for (Chunk *C : Sec->getChunks())
|
||||
C->getBaserels(&V);
|
||||
// Add the addresses to .reloc section.
|
||||
if (!V.empty())
|
||||
addBaserelBlocks(Dest, V);
|
||||
addBaserelBlocks(V);
|
||||
V.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Add addresses to .reloc section. Note that addresses are grouped by page.
|
||||
void Writer::addBaserelBlocks(OutputSection *Dest, std::vector<Baserel> &V) {
|
||||
void Writer::addBaserelBlocks(std::vector<Baserel> &V) {
|
||||
const uint32_t Mask = ~uint32_t(PageSize - 1);
|
||||
uint32_t Page = V[0].RVA & Mask;
|
||||
size_t I = 0, J = 1;
|
||||
|
@ -1228,11 +1221,11 @@ void Writer::addBaserelBlocks(OutputSection *Dest, std::vector<Baserel> &V) {
|
|||
uint32_t P = V[J].RVA & Mask;
|
||||
if (P == Page)
|
||||
continue;
|
||||
Dest->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
|
||||
RelocSec->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
|
||||
I = J;
|
||||
Page = P;
|
||||
}
|
||||
if (I == J)
|
||||
return;
|
||||
Dest->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
|
||||
RelocSec->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue