My x86-64 lld executable is 2KiB smaller. .eh_frame writing gets faster as there
were lots of divisions.
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");
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");
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 {
// 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);
}
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;
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();
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);
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") {
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());
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; }));
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);
}
}
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();
}
}
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();
}
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;
(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
// 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;
};
}
// 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).
// 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.
// 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;
}
}
}
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
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);
}
}
# 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
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