[LLD][COFF] Implement /filealign parameter

Patch by Stefan Schmidt.

This adds the /filealign parameter to lld, which allows to specify the
section alignment in the output file (as it does on Microsoft's
link.exe).

This is required to be able to load dynamically linked libraries on the
original Xbox, where the debugger monitor expects the section alignment
in the file to be the same as in memory.

llvm-svn: 361634
This commit is contained in:
Rui Ueyama 2019-05-24 12:42:36 +00:00
parent 8362cbe13b
commit 74de6203ef
5 changed files with 65 additions and 6 deletions

View File

@ -180,6 +180,7 @@ struct Configuration {
std::string MapFile;
uint64_t ImageBase = -1;
uint64_t FileAlign = 512;
uint64_t StackReserve = 1024 * 1024;
uint64_t StackCommit = 4096;
uint64_t HeapReserve = 1024 * 1024;

View File

@ -1197,6 +1197,13 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
if (auto *Arg = Args.getLastArg(OPT_base))
parseNumbers(Arg->getValue(), &Config->ImageBase);
// Handle /filealign
if (auto *Arg = Args.getLastArg(OPT_filealign)) {
parseNumbers(Arg->getValue(), &Config->FileAlign);
if (!isPowerOf2_64(Config->FileAlign))
error("/filealign: not a power of two: " + Twine(Config->FileAlign));
}
// Handle /stack
if (auto *Arg = Args.getLastArg(OPT_stack))
parseNumbers(Arg->getValue(), &Config->StackReserve, &Config->StackCommit);

View File

@ -32,6 +32,7 @@ def errorlimit : P<"errorlimit",
def export : P<"export", "Export a function">;
// No help text because /failifmismatch is not intended to be used by the user.
def failifmismatch : P<"failifmismatch", "">;
def filealign : P<"filealign", "Section alignment in the output file">;
def functionpadmin : F<"functionpadmin">;
def functionpadmin_opt : P<"functionpadmin", "Prepares an image for hotpatching">;
def guard : P<"guard", "Control flow guard">;

View File

@ -73,7 +73,6 @@ static unsigned char DOSProgram[] = {
static_assert(sizeof(DOSProgram) % 8 == 0,
"DOSProgram size must be multiple of 8");
static const int SectorSize = 512;
static const int DOSStubSize = sizeof(dos_header) + sizeof(DOSProgram);
static_assert(DOSStubSize % 8 == 0, "DOSStub size must be multiple of 8");
@ -1100,7 +1099,7 @@ void Writer::createSymbolAndStringTable() {
PointerToSymbolTable = FileOff;
FileOff += OutputSymtab.size() * sizeof(coff_symbol16);
FileOff += 4 + Strtab.size();
FileSize = alignTo(FileOff, SectorSize);
FileSize = alignTo(FileOff, Config->FileAlign);
}
void Writer::mergeSections() {
@ -1142,7 +1141,7 @@ void Writer::assignAddresses() {
sizeof(coff_section) * OutputSections.size();
SizeOfHeaders +=
Config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header);
SizeOfHeaders = alignTo(SizeOfHeaders, SectorSize);
SizeOfHeaders = alignTo(SizeOfHeaders, Config->FileAlign);
uint64_t RVA = PageSize; // The first page is kept unmapped.
FileSize = SizeOfHeaders;
@ -1167,7 +1166,7 @@ void Writer::assignAddresses() {
C->setRVA(RVA + VirtualSize);
VirtualSize += C->getSize();
if (C->hasData())
RawSize = alignTo(VirtualSize, SectorSize);
RawSize = alignTo(VirtualSize, Config->FileAlign);
}
if (VirtualSize > UINT32_MAX)
error("section larger than 4 GiB: " + Sec->Name);
@ -1176,7 +1175,7 @@ void Writer::assignAddresses() {
if (RawSize != 0)
Sec->Header.PointerToRawData = FileSize;
RVA += alignTo(VirtualSize, PageSize);
FileSize += alignTo(RawSize, SectorSize);
FileSize += alignTo(RawSize, Config->FileAlign);
}
SizeOfImage = alignTo(RVA, PageSize);
@ -1248,7 +1247,7 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
PE->ImageBase = Config->ImageBase;
PE->SectionAlignment = PageSize;
PE->FileAlignment = SectorSize;
PE->FileAlignment = Config->FileAlign;
PE->MajorImageVersion = Config->MajorImageVersion;
PE->MinorImageVersion = Config->MinorImageVersion;
PE->MajorOperatingSystemVersion = Config->MajorOSVersion;

View File

@ -0,0 +1,51 @@
# RUN: yaml2obj < %s > %t.obj
# RUN: lld-link /out:%t.exe /entry:main %t.obj
# RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=DEFAULT-HEADER %s
# DEFAULT-HEADER: FileAlignment: 512
# RUN: lld-link /out:%t.exe /entry:main %t.obj /filealign:4096
# RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=FILEALIGN-HEADER %s
# FILEALIGN-HEADER: FileAlignment: 4096
--- !COFF
header:
Machine: IMAGE_FILE_MACHINE_AMD64
Characteristics: []
sections:
- Name: .text
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
Alignment: 4096
SectionData: 0000000000000000
Relocations:
- VirtualAddress: 0
SymbolName: __ImageBase
Type: IMAGE_REL_AMD64_ADDR64
symbols:
- Name: .text
Value: 0
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
SectionDefinition:
Length: 8
NumberOfRelocations: 1
NumberOfLinenumbers: 0
CheckSum: 0
Number: 0
- Name: main
Value: 0
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
- Name: __ImageBase
Value: 0
SectionNumber: 0
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
...