Skip to content

ELF: Add --preferred-function-alignment option. #149448

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: users/pcc/spr/main.elf-add-preferred-function-alignment-flag
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions lld/ELF/Arch/X86_64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,9 @@ void X86_64::relaxCFIJumpTables() const {
sec->file, sec->name, sec->type, sec->flags, sec->entsize,
sec->entsize,
sec->contentMaybeDecompress().slice(begin, end - begin));
// Ensure that --preferred-function-alignment does not mess with the
// placement of this section.
slice->retainAlignment = true;
for (const Relocation &r : ArrayRef<Relocation>(rbegin, rend)) {
slice->relocations.push_back(
Relocation{r.expr, r.type, r.offset - begin, r.addend, r.sym});
Expand Down Expand Up @@ -421,6 +424,9 @@ void X86_64::relaxCFIJumpTables() const {
// table. First add a slice for the unmodified jump table entries
// before this one.
addSectionSlice(begin, cur, rbegin, rcur);
// Ensure that --preferred-function-alignment does not mess with the
// placement of this section.
target->retainAlignment = true;
// Add the target to our replacement list, and set the target's
// replacement list to the empty list. This removes it from its
// original position and adds it here, as well as causing
Expand All @@ -441,6 +447,7 @@ void X86_64::relaxCFIJumpTables() const {
// jump table where it is and keep the last entry.
if (lastSec) {
addSectionSlice(begin, cur, rbegin, rcur);
lastSec->retainAlignment = true;
replacements.push_back(lastSec);
sectionReplacements[sec] = {};
sectionReplacements[lastSec] = replacements;
Expand Down
1 change: 1 addition & 0 deletions lld/ELF/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ struct Config {
bool optRemarksWithHotness;
bool picThunk;
bool pie;
std::optional<uint64_t> preferredFunctionAlignment;
bool printGcSections;
bool printIcfSections;
bool printMemoryUsage;
Expand Down
3 changes: 3 additions & 0 deletions lld/ELF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1508,6 +1508,9 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
if (auto *arg = args.getLastArg(OPT_package_metadata))
parsePackageMetadata(ctx, *arg);
ctx.arg.pie = args.hasFlag(OPT_pie, OPT_no_pie, false);
if (args.hasArg(OPT_preferred_function_alignment))
ctx.arg.preferredFunctionAlignment =
args::getInteger(args, OPT_preferred_function_alignment, 0);
ctx.arg.printIcfSections =
args.hasFlag(OPT_print_icf_sections, OPT_no_print_icf_sections, false);
ctx.arg.printGcSections =
Expand Down
2 changes: 1 addition & 1 deletion lld/ELF/InputSection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ InputSectionBase::InputSectionBase(InputFile *file, StringRef name,
Kind sectionKind)
: SectionBase(sectionKind, file, name, type, flags, link, info, addralign,
entsize),
bss(0), decodedCrel(0), keepUnique(0), nopFiller(0),
bss(0), decodedCrel(0), keepUnique(0), nopFiller(0), retainAlignment(0),
content_(data.data()), size(data.size()) {
// In order to reduce memory allocation, we assume that mergeable
// sections are smaller than 4 GiB, which is not an unreasonable
Expand Down
5 changes: 5 additions & 0 deletions lld/ELF/InputSection.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,11 @@ class InputSectionBase : public SectionBase {
LLVM_PREFERRED_TYPE(bool)
uint8_t nopFiller : 1;

// If true, --preferred-function-alignment has no effect on this section.
// Set by the CFI jump table relaxation pass.
LLVM_PREFERRED_TYPE(bool)
uint8_t retainAlignment : 1;

mutable bool compressed = false;

// Input sections are part of an output section. Special sections
Expand Down
3 changes: 3 additions & 0 deletions lld/ELF/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,9 @@ def pop_state: F<"pop-state">,
def push_state: F<"push-state">,
HelpText<"Save the current state of --as-needed, -static and --whole-archive">;

def preferred_function_alignment: JJ<"preferred-function-alignment=">,
HelpText<"Align functions to the given alignment if possible">;

def print_map: F<"print-map">,
HelpText<"Print a link map to the standard output">;

Expand Down
17 changes: 17 additions & 0 deletions lld/ELF/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1499,6 +1499,20 @@ static void randomizeSectionPadding(Ctx &ctx) {
}
}

static void applyPreferredFunctionAlignment(Ctx &ctx) {
if (!ctx.arg.preferredFunctionAlignment)
return;
SmallVector<InputSection *, 0> storage;
for (OutputSection *osec : ctx.outputSections) {
if (!(osec->flags & SHF_EXECINSTR))
continue;
for (InputSection *sec : getInputSections(*osec, storage))
if (!isa<SyntheticSection>(sec) && !sec->retainAlignment)
sec->addralign = std::max<uint32_t>(
sec->addralign, *ctx.arg.preferredFunctionAlignment);
}
}

// We need to generate and finalize the content that depends on the address of
// InputSections. As the generation of the content may also alter InputSection
// addresses we must converge to a fixed point. We do that here. See the comment
Expand Down Expand Up @@ -1530,6 +1544,9 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {

ctx.target->relaxCFIJumpTables();

if (ctx.arg.preferredFunctionAlignment)
applyPreferredFunctionAlignment(ctx);

uint32_t pass = 0, assignPasses = 0;
for (;;) {
bool changed = ctx.target->needsThunks
Expand Down
7 changes: 7 additions & 0 deletions lld/docs/ld.lld.1
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,13 @@ Currently the same as yes.
Don't use.
.El

.It Fl -preferred-function-alignment Ns = Ns Ar align
Specify the preferred function alignment. This flag increases the
alignment of all user-provided executable (SHF_EXECINSTR) sections to the
specified value unless retaining the original alignment is beneficial
for performance reasons. For example, when using LLVM's control flow
integrity feature, functions may retain their original alignment if
necessary in order to move them into the jump table.
.It Fl -print-gc-sections
List removed unused sections.
.It Fl -print-icf-sections
Expand Down
15 changes: 15 additions & 0 deletions lld/test/ELF/preferred-function-alignment.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
// RUN: ld.lld --preferred-function-alignment=32 -o %t %t.o
// RUN: llvm-nm -n %t | FileCheck %s

// CHECK: 0000000000201120 t f1
.section .text.f1,"ax",@progbits
f1:
ret

// CHECK: 0000000000201140 t f2
.section .text.f2,"ax",@progbits
f2:
ret

2 changes: 2 additions & 0 deletions lld/test/ELF/x86_64-relax-jump-tables.s
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
// RUN: ld.lld %t.o -shared -o %t
// RUN: llvm-objdump -d --show-all-symbols %t | FileCheck %s
// RUN: ld.lld %t.o -shared -o %t32 --preferred-function-alignment=32
// RUN: llvm-objdump -d --show-all-symbols %t32 | FileCheck %s

// Mostly positive cases, except for f2.
.section .text.jt1,"ax",@llvm_cfi_jump_table,8
Expand Down
Loading