diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h --- a/lld/COFF/Config.h +++ b/lld/COFF/Config.h @@ -180,6 +180,7 @@ 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; diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -1186,6 +1186,13 @@ 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); diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td --- a/lld/COFF/Options.td +++ b/lld/COFF/Options.td @@ -32,6 +32,7 @@ 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">; diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -73,7 +73,6 @@ 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"); @@ -1096,7 +1095,7 @@ PointerToSymbolTable = FileOff; FileOff += OutputSymtab.size() * sizeof(coff_symbol16); FileOff += 4 + Strtab.size(); - FileSize = alignTo(FileOff, SectorSize); + FileSize = alignTo(FileOff, Config->FileAlign); } void Writer::mergeSections() { @@ -1138,7 +1137,7 @@ 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; @@ -1164,7 +1163,7 @@ C->finalizeContents(); 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); @@ -1173,7 +1172,7 @@ if (RawSize != 0) Sec->Header.PointerToRawData = FileSize; RVA += alignTo(VirtualSize, PageSize); - FileSize += alignTo(RawSize, SectorSize); + FileSize += alignTo(RawSize, Config->FileAlign); } SizeOfImage = alignTo(RVA, PageSize); } @@ -1240,7 +1239,7 @@ 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; diff --git a/lld/test/COFF/filealign.test b/lld/test/COFF/filealign.test new file mode 100644 --- /dev/null +++ b/lld/test/COFF/filealign.test @@ -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 +...