diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -51,6 +51,12 @@ dynamic_lookup, }; +struct SectionAlign { + llvm::StringRef segName; + llvm::StringRef sectName; + uint32_t align; +}; + struct SegmentProtection { llvm::StringRef name; uint32_t maxProt; @@ -115,8 +121,9 @@ std::vector runtimePaths; std::vector astPaths; std::vector explicitUndefineds; - // There are typically very few custom segmentProtections, so use a vector - // instead of a map. + // There are typically few custom sectionAlignments or segmentProtections, + // so use a vector instead of a map. + std::vector sectionAlignments; std::vector segmentProtections; llvm::DenseMap priorities; diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -751,6 +751,30 @@ return prot; } +static std::vector parseSectAlign(const opt::InputArgList &args) { + std::vector sectAligns; + for (const Arg *arg : args.filtered(OPT_sectalign)) { + StringRef segName = arg->getValue(0); + StringRef sectName = arg->getValue(1); + StringRef alignStr = arg->getValue(2); + if (alignStr.startswith("0x") || alignStr.startswith("0X")) + alignStr = alignStr.drop_front(2); + uint32_t align; + if (alignStr.getAsInteger(16, align)) { + error("-sectalign: failed to parse '" + StringRef(arg->getValue(2)) + + "' as number"); + continue; + } + if (!isPowerOf2_32(align)) { + error("-sectalign: '" + StringRef(arg->getValue(2)) + + "' (in base 16) not a power of two"); + continue; + } + sectAligns.push_back({segName, sectName, align}); + } + return sectAligns; +} + static bool dataConstDefault(const InputArgList &args) { switch (config->outputType) { case MH_EXECUTE: @@ -1039,6 +1063,8 @@ validName(arg->getValue(1)); } + config->sectionAlignments = parseSectAlign(args); + for (const Arg *arg : args.filtered(OPT_segprot)) { StringRef segName = arg->getValue(0); uint32_t maxProt = parseProtection(arg->getValue(1)); diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td --- a/lld/MachO/Options.td +++ b/lld/MachO/Options.td @@ -778,7 +778,6 @@ def sectalign : MultiArg<["-"], "sectalign", 3>, MetaVarName<"
">, HelpText<"Align
within to hex power-of-2 ">, - Flags<[HelpHidden]>, Group; def stack_addr : Separate<["-"], "stack_addr">, MetaVarName<"
">, diff --git a/lld/MachO/OutputSegment.cpp b/lld/MachO/OutputSegment.cpp --- a/lld/MachO/OutputSegment.cpp +++ b/lld/MachO/OutputSegment.cpp @@ -52,6 +52,10 @@ void OutputSegment::addOutputSection(OutputSection *osec) { osec->parent = this; sections.push_back(osec); + + for (const SectionAlign §Align : config->sectionAlignments) + if (sectAlign.segName == name && sectAlign.sectName == osec->name) + osec->align = sectAlign.align; } static DenseMap nameToOutputSegment; diff --git a/lld/test/MachO/sectalign.s b/lld/test/MachO/sectalign.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/sectalign.s @@ -0,0 +1,42 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o + +# RUN: not %lld -dylib -o %t %t.o -sectalign __TEXT __text asdf 2>&1 \ +# RUN: | FileCheck --check-prefix=NONUM -DNUM=asdf %s +# RUN: not %lld -dylib -o %t %t.o -sectalign __TEXT __text 0x0X4 2>&1 \ +# RUN: | FileCheck --check-prefix=NONUM -DNUM=0x0X4 %s +# NONUM: error: -sectalign: failed to parse '[[NUM]]' as number + +# RUN: not %lld -dylib -o %t %t.o -sectalign __TEXT __text 16 2>&1 \ +# RUN: | FileCheck --check-prefix=NOPOW -DNUM=16 %s +# RUN: not %lld -dylib -o %t %t.o -sectalign __TEXT __text 0x16 2>&1 \ +# RUN: | FileCheck --check-prefix=NOPOW -DNUM=0x16 %s +# RUN: not %lld -dylib -o %t %t.o -sectalign __TEXT __text 0 2>&1 \ +# RUN: | FileCheck --check-prefix=NOPOW -DNUM=0 %s +# NOPOW: error: -sectalign: '[[NUM]]' (in base 16) not a power of two + +## __DATA_CONST tests that the flag applies to names after section renaming. +# RUN: %lld -dylib -o %t %t.o -sectalign __TEXT __text 20 \ +# RUN: -sectalign __DATA_CONST __const 0x40 +# RUN: llvm-readobj --section-headers %t \ +# RUN: | FileCheck -DSECT=__text -DSEG=__TEXT -DALIGN=5 %s +# RUN: llvm-readobj --section-headers %t \ +# RUN: | FileCheck -DSECT=__const -DSEG=__DATA_CONST -DALIGN=6 %s + +# RUN: %lld -dylib -o %t %t.o -rename_section __TEXT __text __TxT __foo \ +# RUN: -sectalign __TxT __foo 0x40 +# RUN: llvm-readobj --section-headers %t \ +# RUN: | FileCheck -DSECT=__foo -DSEG=__TxT -DALIGN=6 %s + +# CHECK: Name: [[SECT]] +# CHECK-NEXT: Segment: [[SEG]] +# CHECK-NEXT: Address: +# CHECK-NEXT: Size: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Alignment: [[ALIGN]] + +.section __TEXT,__text +.space 1 + +.section __DATA,__const +.space 1