This RFC describes the proposed changes to ELF and the IR to support a notion of preferred alignment for GlobalObjects which is separate from the minimum alignment.
The initial use case is a recently proposed enhancement for CFI jump tables known as jump table relaxation. CFI jump table relaxation reduces the overhead of a CFI protected indirect call by inlining the function body into the jump table itself, as long as it is small enough. In order to achieve this, we must know the function’s minimum alignment as well as its preferred alignment. The purpose of using a preferred alignment larger than the minimum alignment is generally to enhance performance, but in the case of jump table relaxation we can expect it to be better for performance to inline the jump table entry (8 bytes on x86) than to obey the function’s preferred alignment (16 bytes on x86). Additionally, we must ensure that relaxing the jump table entry will not cause misbehavior at runtime, so we must obey the function’s minimum alignment and refrain from inlining the function body if it requires too much alignment.
IR
There is currently a single align field on GlobalObject. Prior to #149444 we have the following logic:
- If the align field is unset, a function’s alignment is the backend-determined minimum alignment if -Os or -Oz, otherwise the backend-determined preferred alignment.
- If the align field is set, the function’s alignment is the max of the align attribute and the alignment computed by (1).
The alignment via -falign-functions was ignored if it was less than the preferred alignment. This behavior was observed to be inconsistent with GCC. With #149444, step 2 was changed to “If the align field is set, the function’s alignment is the max of the align attribute and the minimum alignment”, bringing the behavior in line with GCC.
A new minalign field will be added to GlobalObject. This shall have type Align (instead of MaybeAlign) and will default to 1. For brevity (and to avoid churn), minalign will only be printed if it is not equal to 1.
As part of splitting up the attributes, the following is proposed as the logic for deciding a function’s alignment:
- A function’s minimum alignment is the max of the minalign attribute and backend-determined minimum alignment.
- A function’s preferred alignment is the align attribute if set, otherwise the backend-determined minimum alignment if -Os or -Oz, otherwise the backend-determined preferred alignment. Additionally, the preferred alignment shall be at least the minimum alignment.
The existing accessor names will be updated for clarity: GlobalObject::{getAlign,setAlignment} shall be renamed GlobalObject::{get,set}PreferredAlignment. The new accessors shall be named GlobalObject::{get,set}MinAlignment().
Clang will be updated to set minalign 2 on member functions instead of align 2. As a result, member functions will usually receive the preferred alignment, fixing the regression from #149444.
Object file (ELF)
To represent the preferred and minimum alignments in ELF, it is proposed to introduce a new SHT_LLVM_MIN_ADDRALIGN section, which is used to specify the minimum alignment of a section where that differs from its preferred alignment. Its sh_link field identifies the section whose alignment is
being specified, its sh_addralign field specifies the linked section’s minimum alignment and the sh_addralign field of the linked section’s section header specifies its preferred alignment. This section has the SHF_EXCLUDE flag so that it is stripped from the final executable or shared library, and the SHF_LINK_ORDER flag so that the sh_link field is updated by tools such as ld -r and objcopy. The contents of the section must be empty.
The new asm directive:
.prefalign n
specifies that the preferred alignment of the current section is determined by taking the maximum of n and the section’s minimum alignment, and causes an SHT_LLVM_MIN_ADDRALIGN section to be emitted if necessary.
The preferred alignment section is an opt-in feature. Because the initial anticipated use case (specifically CFI jump tables) requires LTO, it is expected that LTO clients (linkers) with support for the minimum alignment section will opt in via the API. For the same reason, there will not be a user facing (clang driver) flag for opting in for the time being. If preferred alignment is disabled (or unrepresentable, in the case of non-ELF object formats), the preferred alignment shall be stored as the only alignment in the object file, and CodeGen will emit .balign or .p2align instead of .prefalign.
The proposed ELF extension is backwards compatible with linkers that do not recognize the new section type. Linkers that do not support the section type will read the section’s sh_addralign field containing the preferred alignment and treat it as the minimum alignment, which will result in conservatively correct behavior, as the preferred alignment will always be at least as large as the minimum alignment.
The initial change to support the ELF extension is #150151. If this RFC is accepted, further changes will be developed to teach CodeGen to emit the new directive, and reimplement part of #147424 to read the new section.
The effect on -falign-functions
-falign-functions shall set both the preferred alignment and minimum alignment attributes, to maintain consistency with GCC.
To set the preferred function alignment on its own, a new flag is proposed, which shall be named -fpreferred-function-alignment.