Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -136,7 +136,8 @@ uint16_t EMachine = llvm::ELF::EM_NONE; uint64_t EntryAddr = 0; uint64_t ImageBase; - uint64_t ZStackSize = -1; + uint64_t MaxPageSize; + uint64_t ZStackSize; unsigned LtoJobs; unsigned LtoO; unsigned Optimize; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -264,15 +264,20 @@ return false; } -static Optional -getZOptionValue(opt::InputArgList &Args, StringRef Key) { +static uint64_t +getZOptionValue(opt::InputArgList &Args, StringRef Key, uint64_t Default) { for (auto *Arg : Args.filtered(OPT_z)) { StringRef Value = Arg->getValue(); size_t Pos = Value.find("="); - if (Pos != StringRef::npos && Key == Value.substr(0, Pos)) - return Value.substr(Pos + 1); + if (Pos != StringRef::npos && Key == Value.substr(0, Pos)) { + Value = Value.substr(Pos + 1); + uint64_t Result; + if (Value.getAsInteger(0, Result)) + error("invalid " + Key + ": " + Value); + return Result; + } } - return None; + return Default; } void LinkerDriver::main(ArrayRef ArgsArr) { @@ -492,9 +497,7 @@ if (!Config->Relocatable) Config->Strip = getStripOption(Args); - if (Optional Value = getZOptionValue(Args, "stack-size")) - if (Value->getAsInteger(0, Config->ZStackSize)) - error("invalid stack size: " + *Value); + Config->ZStackSize = getZOptionValue(Args, "stack-size", -1); // Config->Pic is true if we are generating position-independent code. Config->Pic = Config->Pie || Config->Shared; @@ -657,6 +660,16 @@ Config->ImageBase = Config->Pic ? 0 : Target->DefaultImageBase; } + // Initialize Config->MaxPageSize. The default value is defined by + // the target, but it can be overriden using the option. + Config->MaxPageSize = + getZOptionValue(Args, "max-page-size", Target->MaxPageSize); + if (!isPowerOf2_64(Config->MaxPageSize)) + error("max-page-size: value isn't a power of 2"); + + if (Config->MaxPageSize != Target->MaxPageSize) + Target->PageSize = Config->MaxPageSize; + // Add all files to the symbol table. After this, the symbol table // contains all known names except a few linker-synthesized symbols. for (InputFile *F : Files) Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -1472,7 +1472,7 @@ if (S == "COMMONPAGESIZE") return Target->PageSize; if (S == "MAXPAGESIZE") - return Target->MaxPageSize; + return Config->MaxPageSize; error("unknown constant: " + S); return 0; } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1154,7 +1154,7 @@ for (OutputSectionBase *Sec : OutputSections) { uintX_t Alignment = Sec->getAlignment(); if (Sec->PageAlign) - Alignment = std::max(Alignment, Target->MaxPageSize); + Alignment = std::max(Alignment, Config->MaxPageSize); auto I = Config->SectionStartMap.find(Sec->getName()); if (I != Config->SectionStartMap.end()) @@ -1182,14 +1182,14 @@ static uintX_t getFileAlignment(uintX_t Off, OutputSectionBase *Sec) { uintX_t Alignment = Sec->getAlignment(); if (Sec->PageAlign) - Alignment = std::max(Alignment, Target->MaxPageSize); + Alignment = std::max(Alignment, Config->MaxPageSize); Off = alignTo(Off, Alignment); // Relocatable output does not have program headers // and does not need any other offset adjusting. if (Config->Relocatable || !(Sec->getFlags() & SHF_ALLOC)) return Off; - return alignTo(Off, Target->MaxPageSize, Sec->getVA()); + return alignTo(Off, Config->MaxPageSize, Sec->getVA()); } template @@ -1241,7 +1241,7 @@ H.p_vaddr = First->getVA(); } if (H.p_type == PT_LOAD) - H.p_align = Target->MaxPageSize; + H.p_align = Config->MaxPageSize; else if (H.p_type == PT_GNU_RELRO) H.p_align = 1; Index: test/ELF/linkerscript/page-size.s =================================================================== --- /dev/null +++ test/ELF/linkerscript/page-size.s @@ -0,0 +1,68 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t + +# RUN: ld.lld -z max-page-size=0x4000 %t -o %t2 +# RUN: llvm-readobj -program-headers %t2 | FileCheck %s + +# CHECK: ProgramHeaders [ +# CHECK: ProgramHeader { +# CHECK: Type: PT_LOAD +# CHECK-NEXT: Offset: 0x0 +# CHECK-NEXT: VirtualAddress: 0x10000 +# CHECK-NEXT: PhysicalAddress: 0x10000 +# CHECK-NEXT: FileSize: 344 +# CHECK-NEXT: MemSize: 344 +# CHECK-NEXT: Flags [ +# CHECK-NEXT: PF_R +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 16384 +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD +# CHECK-NEXT: Offset: 0x4000 +# CHECK-NEXT: VirtualAddress: 0x14000 +# CHECK-NEXT: PhysicalAddress: 0x14000 +# CHECK-NEXT: FileSize: 1 +# CHECK-NEXT: MemSize: 1 +# CHECK-NEXT: Flags [ +# CHECK-NEXT: PF_R +# CHECK-NEXT: PF_X +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 16384 +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD +# CHECK-NEXT: Offset: 0x8000 +# CHECK-NEXT: VirtualAddress: 0x18000 +# CHECK-NEXT: PhysicalAddress: 0x18000 +# CHECK-NEXT: FileSize: 8 +# CHECK-NEXT: MemSize: 8 +# CHECK-NEXT: Flags [ +# CHECK-NEXT: PF_R +# CHECK-NEXT: PF_W +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 16384 +# CHECK-NEXT: } + +# RUN: echo "SECTIONS { \ +# RUN: symbol = CONSTANT(MAXPAGESIZE); \ +# RUN: }" > %t.script +# RUN: ld.lld -z max-page-size=0x4000 -o %t1 --script %t.script %t +# RUN: llvm-objdump -t %t1 | FileCheck -check-prefix CHECK-SCRIPT %s + +# CHECK-SCRIPT: 0000000000004000 *ABS* 00000000 symbol + +# RUN: not ld.lld -z max-page-size=0x1001 -o %t1 --script %t.script %t 2>&1 \ +# RUN: | FileCheck -check-prefix=ERR1 %s +# ERR1: max-page-size: value isn't a power of 2 + +# RUN: not ld.lld -z max-page-size=-0x1000 -o %t1 --script %t.script %t 2>&1 \ +# RUN: | FileCheck -check-prefix=ERR2 %s +# ERR2: invalid max-page-size: -0x1000 + +.global _start +_start: + nop + +.section .a, "aw" +.quad 0