Skip to content

Conversation

folkertdev
Copy link
Contributor

@folkertdev folkertdev commented Jun 21, 2025

tracking issue: #82232
split out from: #140261

Request for Stabilization

Summary

The -Cmin-function-alignment=<align> flag specifies the minimum alignment of functions for which code is generated.
The align value must be a power of 2, other values are rejected.

Note that -Zbuild-std (or similar) is required to apply this minimum alignment to standard library functions.
By default, these functions come precompiled and their alignments won't respect the min-function-alignment flag.

This flag is equivalent to:

  • -fmin-function-alignment for GCC
  • -falign-functions for Clang

The specified alignment is a minimum. A higher alignment can be specified for specific functions by annotating the function with a #[align(<align>)] attribute.
The attribute's value is ignored when it is lower than the value passed to min-function-alignment.

There are two additional edge cases for this flag:

  • targets have a minimum alignment for functions (e.g. on x86_64 the lowest that LLVM generates is 16 bytes).
    A min-function-alignment value lower than the target's minimum has no effect.
  • the maximum alignment supported by this flag is 8192. Trying to set a higher value results in an error.

Testing

History

The -Zmin-function-alignment flag was requested by rust-for-linux #128830. It will be used soon (see #t-compiler/help > ✔ Alignment for function addresses).

Miri supports function alignment since #140072. In const-eval there is no way to observe the address of a function pointer, so no special attention is needed there (see #t-compiler/const-eval > function address alignment).

Originally, the maximum allowed alignment was 1 << 29, because this is the highest value the LLVM API accepts. However, on COFF the highest supported alignment is only 8192 (see #142638). Practically speaking, that seems more than sufficient for all known use cases. So for simplicity, for now, we limit the alignment to 8192. The value can be increased on platforms that support it if the need arises.


r? @workingjubilee

the first commit can be split out if that is more convenient.

@rustbot rustbot added A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jun 21, 2025
@rustbot
Copy link
Collaborator

rustbot commented Jun 21, 2025

Some changes occurred to the CTFE machinery

cc @RalfJung, @oli-obk, @lcnr

Some changes occurred to the CTFE / Miri interpreter

cc @rust-lang/miri

Some changes occurred in compiler/rustc_codegen_cranelift

cc @bjorn3

Some changes occurred in compiler/rustc_codegen_ssa

cc @WaffleLapkin

The Miri subtree was changed

cc @rust-lang/miri

// alignment that works on all target platforms. COFF does not support higher alignments.
if bytes > 8192 {
return false;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should it be limited on all platforms? Can't we error when the alignment exceeds the maximum that the actual target we are compiling for supports? Maybe someone genuinely needs to align to 16k on ELF for whatever reason?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, so as we've discovered, alignment is just a mess between clang and llvm. For instance -falign-function only goes up to 1 << 16, although you can manually align a function to a much higher alignment.

For 8192, we know it'll work everywhere, and the logic for when to accept/reject an alignment value is clear.

This flag aligns all functions to the minimum, so I have a hard time seeing a realistic scenario where aligning all functions to 16k is a reasonable thing to do (the limit on individual functions will be handled separately).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I think the options are:

  1. Limit to 8192 on all platforms, it's consistent and unlikely to cause issues. The limit can be safely raised in the future if a need arises
  2. Follow clang and allow 1 << 16, except when the target object format is COFF, then the limit is 8192.
  3. Accept what llvm accepts: allow 1 << 29, except when the target object format is COFF, then the limit is 8192.

I've picked the most conservative one (again, with the option to relax the limits if the need ever arises), but if there is consensus now on one of the other options that's also fine.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is my understanding that on Linux kernels we still nominally support, overaligning beyond the page size, typically 4096, is not going to work properly, so it is arguable that even 8192 is too high.

Copy link
Member

@jieyouxu jieyouxu Jun 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO for the long term, hard-coding to 8192 across all platforms seem like a mistake -- especially because then, does this become part of the language or even more problematic, become part of (compiler/language) stability guarantees?

EDIT: or rather, what is a suitable upper bound in this case in terms of stability guarantees? As in, if we stabilize n=8192 as a universal upper bound, if we find out some platform cannot handle that in the future?

// the alignment from a `#[align(<n>)]` is used if it specifies a higher alignment.
let fn_align = self.tcx.codegen_fn_attrs(instance.def_id()).alignment;
let global_align = self.tcx.sess.opts.unstable_opts.min_function_alignment;
let global_align = self.tcx.sess.opts.cg.min_function_alignment;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(orthogonal to this PR)
it is not great that the logic for merging the per-fn alignment and the global alignment needs to be repeated in each backend.

Maybe codegen_fn_attrs should just take min_function_alignment into account?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact, using sess.opts in the interpreter is at best iffy since it means the interpreter can behave differently in different crates in the same crate graph which can cause unsoundness...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that function pointers can be odd even when -Cmin-function-alignment is 2 (see here), I don't think it makes sense for the interpreter to do anything with min_function_alignment.

@traviscross
Copy link
Contributor

@rustbot labels +T-lang

If the idea with this is that passing -Cmin-function-alignment represents a language-level guarantee, e.g. that a naked function could validly rely on this minimum alignment holding when this flag is passed to prove the soundness of its operations -- that from a language spec standpoint, this is equivalent to marking each function with #[align(..)] -- then I'd suggest that a dual FCP with lang here is proper.

cc @rust-lang/lang

@rustbot rustbot added the T-lang Relevant to the language team label Jun 22, 2025
@folkertdev
Copy link
Contributor Author

Yeah that sounds right. There is also a bunch of overlap with rfc 3806.

Specifically, it contains a section that attempts to define what alignment values are accepted. #[align] and -Cmin-function-alignment should accept/reject the same values.

@traviscross
Copy link
Contributor

@rust-lang/spec: What thoughts do we have about how to handle compiler flags that affect the language definition?

cc @RalfJung

@traviscross traviscross added needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. S-waiting-on-team DEPRECATED: Use the team-based variants `S-waiting-on-t-lang`, `S-waiting-on-t-compiler`, ... S-waiting-on-documentation Status: Waiting on approved PRs to documentation before merging labels Jun 22, 2025
@traviscross
Copy link
Contributor

traviscross commented Jun 22, 2025

Here's a question. Since this does have language-level effect, might this be better expressed as a crate-level attribute?

If there's a good reason, given the use case, for this to be a compiler flag instead, probably it'd be good to describe that in some detail.

@ojeda
Copy link
Contributor

ojeda commented Jun 22, 2025

If it can then be applied via --crate-attr similarly, then that should be fine for our use case.

jhpratt added a commit to jhpratt/rust that referenced this pull request Jun 22, 2025
…-alignment, r=workingjubilee

centralize `-Zmin-function-alignment` logic

tracking issue: rust-lang#82232
discussed in: rust-lang#142824 (comment)

Apply the `-Zmin-function-alignment` value to the alignment field of the function attributes when those are created, so that individual backends don't need to consider it.

The one exception right now is cranelift, because it can't yet set the alignment for individual functions, but it can (and does) set the global minimum function alignment.

cc `@RalfJung` I think this is an improvement regardless, is there anything else that should be done for miri?
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Jun 23, 2025
…-alignment, r=workingjubilee

centralize `-Zmin-function-alignment` logic

tracking issue: rust-lang#82232
discussed in: rust-lang#142824 (comment)

Apply the `-Zmin-function-alignment` value to the alignment field of the function attributes when those are created, so that individual backends don't need to consider it.

The one exception right now is cranelift, because it can't yet set the alignment for individual functions, but it can (and does) set the global minimum function alignment.

cc ``@RalfJung`` I think this is an improvement regardless, is there anything else that should be done for miri?
@workingjubilee
Copy link
Member

Huh. That could be... interesting to work with, since it would logically apply only to entities that originate from that crate, right?

@workingjubilee
Copy link
Member

workingjubilee commented Jun 23, 2025

@folkertdev Do any of our tests verify that if you

  • use this option on the functions described in a crate
  • one is generic or from a trait or otherwise non-instantiated
  • you instantiate that function in another crate without this flag

Then the resulting function is instantiated with the correct alignment? Where "correct" is... well, pick an answer, I guess?

rust-timer added a commit that referenced this pull request Jun 23, 2025
Rollup merge of #142854 - folkertdev:centralize-min-function-alignment, r=workingjubilee

centralize `-Zmin-function-alignment` logic

tracking issue: #82232
discussed in: #142824 (comment)

Apply the `-Zmin-function-alignment` value to the alignment field of the function attributes when those are created, so that individual backends don't need to consider it.

The one exception right now is cranelift, because it can't yet set the alignment for individual functions, but it can (and does) set the global minimum function alignment.

cc ``@RalfJung`` I think this is an improvement regardless, is there anything else that should be done for miri?
@bors
Copy link
Collaborator

bors commented Jun 23, 2025

☔ The latest upstream changes (presumably #142901) made this pull request unmergeable. Please resolve the merge conflicts.

@folkertdev
Copy link
Contributor Author

@workingjubilee we don't, currently. I think the expected answer is clear though, because -Zmin-function-alignment is applied to all compiled crates, not just the top-level one?

I'm not sure how that would work with #![min_function_alignment = N], because then library crates could set the value as well? So far I've been thinking of this option as similar to -Ctarget-cpu or -Ctarget-feature: they are not properties of a crate but of the compilation as a whole.

What thoughts do we have about how to handle compiler flags that affect the language definition?

Is setting and then relying on the alignment fundamentally different from -Ctarget-feature=+avx2 and then asserting in the program that avx2 is available?

@traviscross
Copy link
Contributor

traviscross commented Jun 23, 2025

Is setting and then relying on the alignment fundamentally different from -Ctarget-feature=+avx2 and then asserting in the program that avx2 is available?

It's about whether we like this as a safety argument:

/// SAFETY: The pointee must be a 32-byte aligned function.  It's OK
/// for the low-order bits of the function pointer itself to be
/// non-zero, e.g., if they're used for controlling the processor
/// mode.
unsafe fn f(x: fn()) { todo!() }
fn g() {
    let p = g as fn();
    // SAFETY: We compiled with `-Cmin-function-alignment=32`.
    unsafe { f(p) };
}

For avx2, I'd expect that the safety argument would be made by use of cfg(target_feature = ".."), if is_x86_feature_detected!("avx2") { .. }, etc., rather than by using the argument that it was compiled with -Ctarget-feature=+avx2 in the proof.

@jieyouxu
Copy link
Member

they are not properties of a crate but of the compilation as a whole.

Wait so, does this need to be handled like Target Modifiers?

@jieyouxu
Copy link
Member

Actually, let my try to use rustbot's concern functionality to make the existing discussions/concerns more explicit.

@jieyouxu
Copy link
Member

@rustbot concern per-target-vs-universal-max-alignment

Why should it be limited on all platforms? Can't we error when the alignment exceeds the maximum that the actual target we are compiling for supports? Maybe someone genuinely needs to align to 16k on ELF for whatever reason?

@rustbot rustbot added the S-waiting-on-concerns Status: Awaiting concerns to be addressed by the author label Jun 29, 2025
@jieyouxu
Copy link
Member

@rustbot concern hint-vs-language-guarantee-can-be-relied-upon-for-soundness

We should figure out if this is a hint or a language guarantee -- can this be relied upon for soundness?

@jieyouxu
Copy link
Member

@rustbot concern applicability-current-crate-or-whole-crate-graph

Looks like the current direction is "for the whole crate graph" (potentially "enforced" via Target Modifiers mechanism), but just noting a concern to make sure this is what we explicitly decide to go with.

@jieyouxu
Copy link
Member

@rustbot concern carve-out-interface-and-behavioral-stability-guarantees

See #142824 (comment)

@folkertdev
Copy link
Contributor Author

I suppose in theory if -Zbuild-std becomes stabilized this might be less of an issue.

My understanding is that target modifiers effectively require -Zbuild-std. From the RFC:

https://github.com/rust-lang/rfcs/blob/master/text/3716-target-modifiers.md#guide-level-explanation

The requirement that all CUs agree includes stdlib crates (core, alloc, std), so using these flags usually requires that you compile your own standard library with -Zbuild-std or by directly invoking rustc. That said, some flags (e.g., -Cpanic) have mechanisms to avoid this requirement.


I also have another question: would -Cmin-function-alignment (whether hint form, or in some theoretical guarantee form) apply to extern functions? I guess why I'm asking is more for the "if this is intended to become a language guarantee", that can code also assume extern functions follow this min alignment?

You mean foreign functions here right (so, declared in an extern "abi" {} block)? Making that assumption would mean that linking to any foreign function that is not appropriately aligned would be UB.

Such a guarantee/requirement would be really restrictive, especially for the performance use-case. I guess RfL does control it's build process sufficiently to guarantee that external C code also follows the alignment, but in general that seems unlikely?

On the other hand, from the outside it's not really clear whether a symbol is a foreign function, or a vanilla rust function.

@jieyouxu
Copy link
Member

jieyouxu commented Jun 29, 2025

Yeah, I'm assuming that this flag wouldn't apply to extern functions as a hint or guarantee (I don't really see how it meaningfully can). Or rather, if for whatever reason the intended use case is a language guarantee, then in any case reasoning about min alignment of extern functions seems like "well, the burden of ensuring that said extern fns do have the min alignment falls upon the user, if the user wishes to rely upon that for soundness". I'm asking in case there are... interesting or really weird interactions.

@rustbot resolve interaction-with-extern-functions

(Ignore this, this is purely my skill issue)
@rustbot resolve resolve interaction-with-extern-functions

@folkertdev
Copy link
Contributor Author

Well an implication is that you can't, for an arbitrary function pointer, assume that it is well-aligned, because it may be an extern function

@folkertdev
Copy link
Contributor Author

the PR for making -Zmin-function-alignment a target modifier is up at #143323

@traviscross traviscross added I-lang-radar Items that are on lang's radar and will need eventual work or consideration. and removed I-lang-nominated Nominated for discussion during a lang team meeting. P-lang-drag-3 Lang team prioritization drag level 3.https://rust-lang.zulipchat.com/#narrow/channel/410516-t-lang. labels Jul 2, 2025
@Jules-Bertholet
Copy link
Contributor

As discovered in #143206 (comment), it looks like LLVM completely ignores function alignment specifications on WASM.

@RalfJung
Copy link
Member

RalfJung commented Jul 3, 2025

As discovered in #143206 (comment), it looks like LLVM completely ignores function alignment specifications on WASM.

That's tracked at #143368 now and yeah I assume it also affects this flag.

@RalfJung
Copy link
Member

RalfJung commented Jul 3, 2025

@rustbot concern wasm

@RalfJung
Copy link
Member

RalfJung commented Jul 3, 2025

@rustbot concern resolve-interaction-with-fn-ptrs

It seems like this does not actually interact with function pointers in any reasonable way, and in particular does not guarantee anything about the integral value of function pointers (see here).

That means this is entirely unobservable in the language itself, i.e. in pure Rust programs. It can only possibly be exploited by inline asm code that observes the layout of the generated machine code. We should make sure this is suitably documented as it is extremely surprising.

@bors
Copy link
Collaborator

bors commented Jul 7, 2025

☔ The latest upstream changes (presumably #143556) made this pull request unmergeable. Please resolve the merge conflicts.

@RalfJung
Copy link
Member

RalfJung commented Aug 1, 2025

#144661 also relates to this -- const-eval prematurely considered function alignment as a property observable via function pointers, leading to nonsense behavior (arguably that could even be an unsoundness).

@workingjubilee workingjubilee added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 10, 2025
@workingjubilee
Copy link
Member

@folkertdev Please feel free to ping me about this if you need review/guidance/ideas on addressing these concerns and to of course rustbot-ready it when it is indeed ready. I am just whittling down my queue.

@folkertdev
Copy link
Contributor Author

@rustbot blocked

this is effectively blocked on #143323, which in turn needs some sort of decision on the alignment guarantees and limitations (e.g. what to do on targets where the maximum alignment is lower than what LLVM tells us is allowed).

@rustbot rustbot added S-blocked Status: Blocked on something else such as an RFC or other implementation work. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Sep 11, 2025
@Dylan-DPC Dylan-DPC removed S-waiting-on-team DEPRECATED: Use the team-based variants `S-waiting-on-t-lang`, `S-waiting-on-t-compiler`, ... I-lang-radar Items that are on lang's radar and will need eventual work or consideration. labels Sep 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-attributes Area: Attributes (`#[…]`, `#![…]`) A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. S-blocked Status: Blocked on something else such as an RFC or other implementation work. S-waiting-on-concerns Status: Awaiting concerns to be addressed by the author S-waiting-on-documentation Status: Waiting on approved PRs to documentation before merging T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team
Projects
None yet
Development

Successfully merging this pull request may close these issues.