Skip to content

Commit

Permalink
[ELF] Optimize some non-constant alignTo with alignToPowerOf2. NFC
Browse files Browse the repository at this point in the history
My x86-64 lld executable is 2KiB smaller. .eh_frame writing gets faster as there
were lots of divisions.
  • Loading branch information
MaskRay committed Jul 24, 2022
1 parent 81f0f5a commit 85cfd91
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 32 deletions.
8 changes: 6 additions & 2 deletions lld/ELF/Driver.cpp
Expand Up @@ -1691,8 +1691,10 @@ void LinkerDriver::inferMachineType() {
static uint64_t getMaxPageSize(opt::InputArgList &args) {
uint64_t val = args::getZOptionValue(args, OPT_z, "max-page-size",
target->defaultMaxPageSize);
if (!isPowerOf2_64(val))
if (!isPowerOf2_64(val)) {
error("max-page-size: value isn't a power of 2");
return target->defaultMaxPageSize;
}
if (config->nmagic || config->omagic) {
if (val != target->defaultMaxPageSize)
warn("-z max-page-size set, but paging disabled by omagic or nmagic");
Expand All @@ -1706,8 +1708,10 @@ static uint64_t getMaxPageSize(opt::InputArgList &args) {
static uint64_t getCommonPageSize(opt::InputArgList &args) {
uint64_t val = args::getZOptionValue(args, OPT_z, "common-page-size",
target->defaultCommonPageSize);
if (!isPowerOf2_64(val))
if (!isPowerOf2_64(val)) {
error("common-page-size: value isn't a power of 2");
return target->defaultCommonPageSize;
}
if (config->nmagic || config->omagic) {
if (val != target->defaultCommonPageSize)
warn("-z common-page-size set, but paging disabled by omagic or nmagic");
Expand Down
12 changes: 6 additions & 6 deletions lld/ELF/LinkerScript.cpp
Expand Up @@ -112,9 +112,9 @@ static StringRef getOutputSectionName(const InputSectionBase *s) {

uint64_t ExprValue::getValue() const {
if (sec)
return alignTo(sec->getOutputSection()->addr + sec->getOffset(val),
alignment);
return alignTo(val, alignment);
return alignToPowerOf2(sec->getOutputSection()->addr + sec->getOffset(val),
alignment);
return alignToPowerOf2(val, alignment);
}

uint64_t ExprValue::getSecAddr() const {
Expand Down Expand Up @@ -989,7 +989,7 @@ void LinkerScript::assignOffsets(OutputSection *sec) {
// sec->alignment is the max of ALIGN and the maximum of input
// section alignments.
const uint64_t pos = dot;
dot = alignTo(dot, sec->alignment);
dot = alignToPowerOf2(dot, sec->alignment);
sec->addr = dot;
expandMemoryRegions(dot - pos);
}
Expand All @@ -1003,7 +1003,7 @@ void LinkerScript::assignOffsets(OutputSection *sec) {
if (sec->lmaExpr) {
ctx->lmaOffset = sec->lmaExpr().getValue() - dot;
} else if (MemoryRegion *mr = sec->lmaRegion) {
uint64_t lmaStart = alignTo(mr->curPos, sec->alignment);
uint64_t lmaStart = alignToPowerOf2(mr->curPos, sec->alignment);
if (mr->curPos < lmaStart)
expandMemoryRegion(mr, lmaStart - mr->curPos, sec->name);
ctx->lmaOffset = lmaStart - dot;
Expand Down Expand Up @@ -1046,7 +1046,7 @@ void LinkerScript::assignOffsets(OutputSection *sec) {
for (InputSection *isec : cast<InputSectionDescription>(cmd)->sections) {
assert(isec->getParent() == sec);
const uint64_t pos = dot;
dot = alignTo(dot, isec->alignment);
dot = alignToPowerOf2(dot, isec->alignment);
isec->outSecOff = dot - sec->addr;
dot += isec->getSize();

Expand Down
7 changes: 4 additions & 3 deletions lld/ELF/ScriptParser.cpp
Expand Up @@ -1392,7 +1392,7 @@ Expr ScriptParser::readPrimary() {
Expr e = readExpr();
if (consume(")")) {
e = checkAlignment(e, location);
return [=] { return alignTo(script->getDot(), e().getValue()); };
return [=] { return alignToPowerOf2(script->getDot(), e().getValue()); };
}
expect(",");
Expr e2 = checkAlignment(readExpr(), location);
Expand Down Expand Up @@ -1423,7 +1423,8 @@ Expr ScriptParser::readPrimary() {
expect(")");
seenDataAlign = true;
return [=] {
return alignTo(script->getDot(), std::max((uint64_t)1, e().getValue()));
uint64_t align = std::max(uint64_t(1), e().getValue());
return (script->getDot() + align - 1) & -align;
};
}
if (tok == "DATA_SEGMENT_END") {
Expand All @@ -1443,7 +1444,7 @@ Expr ScriptParser::readPrimary() {
expect(")");
seenRelroEnd = true;
Expr e = getPageSize();
return [=] { return alignTo(script->getDot(), e().getValue()); };
return [=] { return alignToPowerOf2(script->getDot(), e().getValue()); };
}
if (tok == "DEFINED") {
StringRef name = unquote(readParenLiteral());
Expand Down
12 changes: 6 additions & 6 deletions lld/ELF/SyntheticSections.cpp
Expand Up @@ -498,7 +498,7 @@ void EhFrameSection::iterateFDEWithLSDA(
static void writeCieFde(uint8_t *buf, ArrayRef<uint8_t> d) {
memcpy(buf, d.data(), d.size());

size_t aligned = alignTo(d.size(), config->wordsize);
size_t aligned = alignToPowerOf2(d.size(), config->wordsize);
assert(std::all_of(buf + d.size(), buf + aligned,
[](uint8_t c) { return c == 0; }));

Expand Down Expand Up @@ -533,11 +533,11 @@ void EhFrameSection::finalizeContents() {
size_t off = 0;
for (CieRecord *rec : cieRecords) {
rec->cie->outputOff = off;
off += alignTo(rec->cie->size, config->wordsize);
off += alignToPowerOf2(rec->cie->size, config->wordsize);

for (EhSectionPiece *fde : rec->fdes) {
fde->outputOff = off;
off += alignTo(fde->size, config->wordsize);
off += alignToPowerOf2(fde->size, config->wordsize);
}
}

Expand Down Expand Up @@ -919,7 +919,7 @@ void MipsGotSection::build() {
for (SectionCommand *cmd : os->commands) {
if (auto *isd = dyn_cast<InputSectionDescription>(cmd))
for (InputSection *isec : isd->sections) {
uint64_t off = alignTo(secSize, isec->alignment);
uint64_t off = alignToPowerOf2(secSize, isec->alignment);
secSize = off + isec->getSize();
}
}
Expand Down Expand Up @@ -3330,7 +3330,7 @@ void MergeNoTailSection::finalizeContents() {
for (size_t i = 0; i < numShards; ++i) {
shards[i].finalizeInOrder();
if (shards[i].getSize() > 0)
off = alignTo(off, alignment);
off = alignToPowerOf2(off, alignment);
shardOffsets[i] = off;
off += shards[i].getSize();
}
Expand Down Expand Up @@ -3612,7 +3612,7 @@ InputSection *ThunkSection::getTargetInputSection() const {
bool ThunkSection::assignOffsets() {
uint64_t off = 0;
for (Thunk *t : thunks) {
off = alignTo(off, t->alignment);
off = alignToPowerOf2(off, t->alignment);
t->setOffset(off);
uint32_t size = t->size();
t->getThunkTargetSym()->size = size;
Expand Down
30 changes: 16 additions & 14 deletions lld/ELF/Writer.cpp
Expand Up @@ -2483,7 +2483,7 @@ template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
(prev->p_flags & PF_X) != (p->p_flags & PF_X)) ||
cmd->type == SHT_LLVM_PART_EHDR)
cmd->addrExpr = [] {
return alignTo(script->getDot(), config->maxPageSize);
return alignToPowerOf2(script->getDot(), config->maxPageSize);
};
// PT_TLS is at the start of the first RW PT_LOAD. If `p` includes PT_TLS,
// it must be the RW. Align to p_align(PT_TLS) to make sure
Expand All @@ -2500,13 +2500,13 @@ template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
// blocks correctly. We need to keep the workaround for a while.
else if (Out::tlsPhdr && Out::tlsPhdr->firstSec == p->firstSec)
cmd->addrExpr = [] {
return alignTo(script->getDot(), config->maxPageSize) +
alignTo(script->getDot() % config->maxPageSize,
Out::tlsPhdr->p_align);
return alignToPowerOf2(script->getDot(), config->maxPageSize) +
alignToPowerOf2(script->getDot() % config->maxPageSize,
Out::tlsPhdr->p_align);
};
else
cmd->addrExpr = [] {
return alignTo(script->getDot(), config->maxPageSize) +
return alignToPowerOf2(script->getDot(), config->maxPageSize) +
script->getDot() % config->maxPageSize;
};
}
Expand Down Expand Up @@ -2540,7 +2540,7 @@ static uint64_t computeFileOffset(OutputSection *os, uint64_t off) {

// If the section is not in a PT_LOAD, we just have to align it.
if (!os->ptLoad)
return alignTo(off, os->alignment);
return alignToPowerOf2(off, os->alignment);

// If two sections share the same PT_LOAD the file offset is calculated
// using this formula: Off2 = Off1 + (VA2 - VA1).
Expand Down Expand Up @@ -2599,15 +2599,15 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
// following section to avoid loading non-segments parts of the file.
if (config->zSeparate != SeparateSegmentKind::None && lastRX &&
lastRX->lastSec == sec)
off = alignTo(off, config->maxPageSize);
off = alignToPowerOf2(off, config->maxPageSize);
}
for (OutputSection *osec : outputSections)
if (!(osec->flags & SHF_ALLOC)) {
osec->offset = alignTo(off, osec->alignment);
osec->offset = alignToPowerOf2(off, osec->alignment);
off = osec->offset + osec->size;
}

sectionHeaderOff = alignTo(off, config->wordsize);
sectionHeaderOff = alignToPowerOf2(off, config->wordsize);
fileSize = sectionHeaderOff + (outputSections.size() + 1) * sizeof(Elf_Shdr);

// Our logic assumes that sections have rising VA within the same segment.
Expand Down Expand Up @@ -2659,8 +2659,9 @@ template <class ELFT> void Writer<ELFT>::setPhdrs(Partition &part) {
// musl/glibc ld.so rounds the size down, so we need to round up
// to protect the last page. This is a no-op on FreeBSD which always
// rounds up.
p->p_memsz = alignTo(p->p_offset + p->p_memsz, config->commonPageSize) -
p->p_offset;
p->p_memsz =
alignToPowerOf2(p->p_offset + p->p_memsz, config->commonPageSize) -
p->p_offset;
}
}
}
Expand Down Expand Up @@ -2880,8 +2881,9 @@ template <class ELFT> void Writer<ELFT>::writeTrapInstr() {
if (p->p_type == PT_LOAD && (p->p_flags & PF_X))
fillTrap(Out::bufferStart +
alignDown(p->firstSec->offset + p->p_filesz, 4),
Out::bufferStart + alignTo(p->firstSec->offset + p->p_filesz,
config->maxPageSize));
Out::bufferStart +
alignToPowerOf2(p->firstSec->offset + p->p_filesz,
config->maxPageSize));

// Round up the file size of the last segment to the page boundary iff it is
// an executable segment to ensure that other tools don't accidentally
Expand All @@ -2893,7 +2895,7 @@ template <class ELFT> void Writer<ELFT>::writeTrapInstr() {

if (last && (last->p_flags & PF_X))
last->p_memsz = last->p_filesz =
alignTo(last->p_filesz, config->maxPageSize);
alignToPowerOf2(last->p_filesz, config->maxPageSize);
}
}

Expand Down
2 changes: 1 addition & 1 deletion lld/test/ELF/linkerscript/operators.test
Expand Up @@ -100,7 +100,7 @@ SECTIONS {
# CHECK-NEXT: 0000000000000009 A precedence2
# CHECK-NEXT: 0000000000001000 A maxpagesize
# CHECK-NEXT: 0000000000001000 A commonpagesize
# CHECK-NEXT: 000000000000ffff A datasegmentalign
# CHECK-NEXT: 0000000000010000 A datasegmentalign
# CHECK-NEXT: 000000000000fff0 A datasegmentalign2
# CHECK-NEXT: 000000000000ffe0 T minus_rel
# CHECK-NEXT: 000000000000fff0 A minus_abs
Expand Down
6 changes: 6 additions & 0 deletions llvm/include/llvm/Support/MathExtras.h
Expand Up @@ -747,6 +747,12 @@ inline uint64_t alignTo(uint64_t Value, uint64_t Align) {
return (Value + Align - 1) / Align * Align;
}

inline uint64_t alignToPowerOf2(uint64_t Value, uint64_t Align) {
assert(Align != 0 && (Align & Align - 1) == 0 &&
"Align must be a power of 2");
return (Value + Align - 1) & -Align;
}

/// If non-zero \p Skew is specified, the return value will be a minimal integer
/// that is greater than or equal to \p Size and equal to \p A * N + \p Skew for
/// some integer N. If \p Skew is larger than \p A, its value is adjusted to '\p
Expand Down

0 comments on commit 85cfd91

Please sign in to comment.