-
Notifications
You must be signed in to change notification settings - Fork 15.2k
MC: Add directive for specifying a section's preferred alignment. #150151
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
base: users/pcc/spr/main.mc-add-elf-section-and-directive-for-specifying-a-sections-preferred-alignment
Are you sure you want to change the base?
Conversation
Created using spr 1.3.6-beta.1
@llvm/pr-subscribers-llvm-binary-utilities @llvm/pr-subscribers-mc Author: Peter Collingbourne (pcc) ChangesThe new The new asm directive: .prefalign n specifies that the preferred alignment of the current section is Full diff: https://github.com/llvm/llvm-project/pull/150151.diff 13 Files Affected:
diff --git a/llvm/docs/Extensions.rst b/llvm/docs/Extensions.rst
index d8fb87b6998ad..e6b2db0745623 100644
--- a/llvm/docs/Extensions.rst
+++ b/llvm/docs/Extensions.rst
@@ -601,6 +601,28 @@ sees fit (generally the section that would provide the best locality).
.. _CFI jump table: https://clang.llvm.org/docs/ControlFlowIntegrityDesign.html#forward-edge-cfi-for-indirect-function-calls
+``SHT_LLVM_MIN_ADDRALIGN`` Section (minimum section alignment)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+This section 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.
+
+.. code-block:: gas
+
+ .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.
+
CodeView-Dependent
------------------
diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h
index e4f82ad96a084..95600f39153d4 100644
--- a/llvm/include/llvm/BinaryFormat/ELF.h
+++ b/llvm/include/llvm/BinaryFormat/ELF.h
@@ -1160,6 +1160,7 @@ enum : unsigned {
SHT_LLVM_LTO = 0x6fff4c0c, // .llvm.lto for fat LTO.
SHT_LLVM_JT_SIZES = 0x6fff4c0d, // LLVM jump tables sizes.
SHT_LLVM_CFI_JUMP_TABLE = 0x6fff4c0e, // LLVM CFI jump table.
+ SHT_LLVM_MIN_ADDRALIGN = 0x6fff4c0f, // Minimum alignment specification.
// Android's experimental support for SHT_RELR sections.
// https://android.googlesource.com/platform/bionic/+/b7feec74547f84559a1467aca02708ff61346d2a/libc/include/elf.h#512
SHT_ANDROID_RELR = 0x6fffff00, // Relocation entries; only offsets.
diff --git a/llvm/include/llvm/MC/MCObjectStreamer.h b/llvm/include/llvm/MC/MCObjectStreamer.h
index 319e131999d48..27de57f2ccd91 100644
--- a/llvm/include/llvm/MC/MCObjectStreamer.h
+++ b/llvm/include/llvm/MC/MCObjectStreamer.h
@@ -113,6 +113,7 @@ class MCObjectStreamer : public MCStreamer {
unsigned MaxBytesToEmit = 0) override;
void emitCodeAlignment(Align ByteAlignment, const MCSubtargetInfo *STI,
unsigned MaxBytesToEmit = 0) override;
+ void emitPrefAlign(Align Alignment) override;
void emitValueToOffset(const MCExpr *Offset, unsigned char Value,
SMLoc Loc) override;
void emitDwarfLocDirective(unsigned FileNo, unsigned Line, unsigned Column,
diff --git a/llvm/include/llvm/MC/MCSection.h b/llvm/include/llvm/MC/MCSection.h
index 313071ec75033..61ae6dff4d146 100644
--- a/llvm/include/llvm/MC/MCSection.h
+++ b/llvm/include/llvm/MC/MCSection.h
@@ -82,6 +82,7 @@ class LLVM_ABI MCSection {
MCSymbol *End = nullptr;
/// The alignment requirement of this section.
Align Alignment;
+ MaybeAlign PreferredAlignment;
/// The section index in the assemblers section list.
unsigned Ordinal = 0;
@@ -147,6 +148,17 @@ class LLVM_ABI MCSection {
Alignment = MinAlignment;
}
+ Align getPreferredAlignment() const {
+ if (!PreferredAlignment || Alignment > *PreferredAlignment)
+ return Alignment;
+ return *PreferredAlignment;
+ }
+
+ void ensurePreferredAlignment(Align PrefAlign) {
+ if (!PreferredAlignment || PrefAlign > *PreferredAlignment)
+ PreferredAlignment = PrefAlign;
+ }
+
unsigned getOrdinal() const { return Ordinal; }
void setOrdinal(unsigned Value) { Ordinal = Value; }
diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h
index 4b91dbc794682..e7947657e1356 100644
--- a/llvm/include/llvm/MC/MCStreamer.h
+++ b/llvm/include/llvm/MC/MCStreamer.h
@@ -832,6 +832,8 @@ class LLVM_ABI MCStreamer {
virtual void emitCodeAlignment(Align Alignment, const MCSubtargetInfo *STI,
unsigned MaxBytesToEmit = 0);
+ virtual void emitPrefAlign(Align A);
+
/// Emit some number of copies of \p Value until the byte offset \p
/// Offset is reached.
///
diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp
index 9f52b3e3e85c0..7709cf56ffd32 100644
--- a/llvm/lib/MC/ELFObjectWriter.cpp
+++ b/llvm/lib/MC/ELFObjectWriter.cpp
@@ -926,10 +926,10 @@ void ELFWriter::writeSectionHeader(uint32_t GroupSymbolIndex, uint64_t Offset,
sh_link = Sym->getSection().getOrdinal();
}
- writeSectionHeaderEntry(StrTabBuilder.getOffset(Section.getName()),
- Section.getType(), Section.getFlags(), 0, Offset,
- Size, sh_link, sh_info, Section.getAlign(),
- Section.getEntrySize());
+ writeSectionHeaderEntry(
+ StrTabBuilder.getOffset(Section.getName()), Section.getType(),
+ Section.getFlags(), 0, Offset, Size, sh_link, sh_info,
+ Section.getPreferredAlignment(), Section.getEntrySize());
}
void ELFWriter::writeSectionHeaders() {
@@ -1062,6 +1062,15 @@ uint64_t ELFWriter::writeObject() {
Relocations.push_back(RelSection);
}
+ if (Sec.getPreferredAlignment() != Sec.getAlign()) {
+ MCSectionELF *MinAlign = Ctx.getELFSection(
+ ".llvm.minalign", ELF::SHT_LLVM_MIN_ADDRALIGN,
+ ELF::SHF_EXCLUDE | ELF::SHF_LINK_ORDER, 0, "", false, 0,
+ cast<MCSymbolELF>(Section.getBeginSymbol()));
+ MinAlign->setOrdinal(addToSectionTable(MinAlign));
+ MinAlign->setAlignment(Sec.getAlign());
+ }
+
if (GroupIdxEntry) {
auto &Members = Groups[GroupMap[*GroupIdxEntry]];
Members.second.push_back(Section.getOrdinal());
diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp
index 67c53e01a6111..4d53607400a27 100644
--- a/llvm/lib/MC/MCAsmStreamer.cpp
+++ b/llvm/lib/MC/MCAsmStreamer.cpp
@@ -275,6 +275,7 @@ class MCAsmStreamer final : public MCStreamer {
void emitCodeAlignment(Align Alignment, const MCSubtargetInfo *STI,
unsigned MaxBytesToEmit = 0) override;
+ void emitPrefAlign(Align Alignment) override;
void emitValueToOffset(const MCExpr *Offset,
unsigned char Value,
@@ -1540,6 +1541,11 @@ void MCAsmStreamer::emitCodeAlignment(Align Alignment,
emitAlignmentDirective(Alignment.value(), std::nullopt, 1, MaxBytesToEmit);
}
+void MCAsmStreamer::emitPrefAlign(Align Alignment) {
+ OS << ".prefalign " << Alignment.value();
+ EmitEOL();
+}
+
void MCAsmStreamer::emitValueToOffset(const MCExpr *Offset,
unsigned char Value,
SMLoc Loc) {
diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp
index d5b8f22463894..e860f6c61c5f7 100644
--- a/llvm/lib/MC/MCObjectStreamer.cpp
+++ b/llvm/lib/MC/MCObjectStreamer.cpp
@@ -567,6 +567,10 @@ void MCObjectStreamer::emitCodeAlignment(Align Alignment,
}
}
+void MCObjectStreamer::emitPrefAlign(Align Alignment) {
+ getCurrentSectionOnly()->ensurePreferredAlignment(Alignment);
+}
+
void MCObjectStreamer::emitValueToOffset(const MCExpr *Offset,
unsigned char Value,
SMLoc Loc) {
diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp
index 77bf84364c5a3..2e85c08852c15 100644
--- a/llvm/lib/MC/MCParser/AsmParser.cpp
+++ b/llvm/lib/MC/MCParser/AsmParser.cpp
@@ -418,6 +418,7 @@ class AsmParser : public MCAsmParser {
DK_P2ALIGN,
DK_P2ALIGNW,
DK_P2ALIGNL,
+ DK_PREFALIGN,
DK_ORG,
DK_FILL,
DK_ENDR,
@@ -565,6 +566,7 @@ class AsmParser : public MCAsmParser {
bool parseDirectiveOrg(); // ".org"
// ".align{,32}", ".p2align{,w,l}"
bool parseDirectiveAlign(bool IsPow2, uint8_t ValueSize);
+ bool parseDirectivePrefAlign();
// ".file", ".line", ".loc", ".loc_label", ".stabs"
bool parseDirectiveFile(SMLoc DirectiveLoc);
@@ -2000,6 +2002,8 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info,
return parseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/2);
case DK_P2ALIGNL:
return parseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/4);
+ case DK_PREFALIGN:
+ return parseDirectivePrefAlign();
case DK_ORG:
return parseDirectiveOrg();
case DK_FILL:
@@ -3426,6 +3430,21 @@ bool AsmParser::parseDirectiveAlign(bool IsPow2, uint8_t ValueSize) {
return ReturnVal;
}
+bool AsmParser::parseDirectivePrefAlign() {
+ SMLoc AlignmentLoc = getLexer().getLoc();
+ int64_t Alignment;
+ if (checkForValidSection() || parseAbsoluteExpression(Alignment))
+ return true;
+ if (parseEOL())
+ return true;
+
+ if (!isPowerOf2_64(Alignment))
+ return Error(AlignmentLoc, "alignment must be a power of 2");
+ getStreamer().emitPrefAlign(Align(Alignment));
+
+ return false;
+}
+
/// parseDirectiveFile
/// ::= .file filename
/// ::= .file number [directory] filename [md5 checksum] [source source-text]
@@ -5377,6 +5396,7 @@ void AsmParser::initializeDirectiveKindMap() {
DirectiveKindMap[".p2align"] = DK_P2ALIGN;
DirectiveKindMap[".p2alignw"] = DK_P2ALIGNW;
DirectiveKindMap[".p2alignl"] = DK_P2ALIGNL;
+ DirectiveKindMap[".prefalign"] = DK_PREFALIGN;
DirectiveKindMap[".org"] = DK_ORG;
DirectiveKindMap[".fill"] = DK_FILL;
DirectiveKindMap[".zero"] = DK_ZERO;
diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp
index c3ecf8fc717f5..eeca414da580d 100644
--- a/llvm/lib/MC/MCStreamer.cpp
+++ b/llvm/lib/MC/MCStreamer.cpp
@@ -1329,6 +1329,7 @@ void MCStreamer::emitFill(const MCExpr &NumBytes, uint64_t Value, SMLoc Loc) {}
void MCStreamer::emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr,
SMLoc Loc) {}
void MCStreamer::emitValueToAlignment(Align, int64_t, uint8_t, unsigned) {}
+void MCStreamer::emitPrefAlign(Align A) {}
void MCStreamer::emitCodeAlignment(Align Alignment, const MCSubtargetInfo *STI,
unsigned MaxBytesToEmit) {}
void MCStreamer::emitValueToOffset(const MCExpr *Offset, unsigned char Value,
diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp
index 788c6020a7f99..ab23a0b1f25b9 100644
--- a/llvm/lib/Object/ELF.cpp
+++ b/llvm/lib/Object/ELF.cpp
@@ -322,6 +322,7 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) {
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_LTO);
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_JT_SIZES)
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_CFI_JUMP_TABLE)
+ STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_MIN_ADDRALIGN)
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_SFRAME);
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES);
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_HASH);
diff --git a/llvm/test/MC/ELF/prefalign-errors.s b/llvm/test/MC/ELF/prefalign-errors.s
new file mode 100644
index 0000000000000..363638f9bcb1e
--- /dev/null
+++ b/llvm/test/MC/ELF/prefalign-errors.s
@@ -0,0 +1,5 @@
+// RUN: not llvm-mc -filetype=asm -triple x86_64-pc-linux-gnu %s -o - 2>&1 | FileCheck %s
+
+.section .text.f1,"ax",@progbits
+// CHECK: error: alignment must be a power of 2
+.prefalign 3
diff --git a/llvm/test/MC/ELF/prefalign.s b/llvm/test/MC/ELF/prefalign.s
new file mode 100644
index 0000000000000..f3537029b23c1
--- /dev/null
+++ b/llvm/test/MC/ELF/prefalign.s
@@ -0,0 +1,47 @@
+// RUN: llvm-mc -filetype=asm -triple x86_64-pc-linux-gnu %s -o - | FileCheck --check-prefix=ASM %s
+// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | llvm-readelf -SW - | FileCheck --check-prefix=OBJ %s
+
+// Minimum alignment = preferred alignment, no SHT_LLVM_MIN_ADDRALIGN needed.
+// ASM: .section .text.f1
+// ASM: .p2align 2
+// ASM: .prefalign 4
+// OBJ: .text.f1
+// OBJ-NOT: .llvm.minalign
+.section .text.f1,"ax",@progbits
+.p2align 2
+.prefalign 4
+
+// Minimum alignment < preferred alignment, SHT_LLVM_MIN_ADDRALIGN emitted.
+// ASM: .section .text.f2
+// ASM: .p2align 2
+// ASM: .prefalign 8
+// OBJ: [ 4] .text.f2 PROGBITS 0000000000000000 000040 000000 00 AX 0 0 8
+// OBJ: [ 5] .llvm.minalign LLVM_MIN_ADDRALIGN 0000000000000000 000000 000000 00 LE 4 0 4
+.section .text.f2,"ax",@progbits
+.p2align 2
+.prefalign 8
+
+// Minimum alignment > preferred alignment, preferred alignment rounded up to
+// minimum alignment. No SHT_LLVM_MIN_ADDRALIGN emitted.
+// ASM: .section .text.f3
+// ASM: .p2align 3
+// ASM: .prefalign 4
+// OBJ: .text.f3
+// OBJ-NOT: .llvm.minalign
+.section .text.f3,"ax",@progbits
+.p2align 3
+.prefalign 4
+
+// Maximum of all .prefalign directives written to object file.
+// ASM: .section .text.f4
+// ASM: .p2align 2
+// ASM: .prefalign 8
+// ASM: .prefalign 16
+// ASM: .prefalign 8
+// OBJ: [ 7] .text.f4 PROGBITS 0000000000000000 000040 000000 00 AX 0 0 16
+// OBJ: [ 8] .llvm.minalign LLVM_MIN_ADDRALIGN 0000000000000000 000000 000000 00 LE 7 0 4
+.section .text.f4,"ax",@progbits
+.p2align 2
+.prefalign 8
+.prefalign 16
+.prefalign 8
|
You can test this locally with the following command:git-clang-format --diff origin/main HEAD --extensions h,cpp -- llvm/include/llvm/MC/MCAsmInfo.h llvm/include/llvm/MC/MCObjectStreamer.h llvm/include/llvm/MC/MCSection.h llvm/include/llvm/MC/MCStreamer.h llvm/lib/MC/ELFObjectWriter.cpp llvm/lib/MC/MCAsmInfoELF.cpp llvm/lib/MC/MCAsmStreamer.cpp llvm/lib/MC/MCObjectStreamer.cpp llvm/lib/MC/MCParser/AsmParser.cpp llvm/lib/MC/MCSection.cpp llvm/lib/MC/MCStreamer.cpp
View the diff from clang-format here.diff --git a/llvm/include/llvm/MC/MCSection.h b/llvm/include/llvm/MC/MCSection.h
index 38b512f31..0fac76b8a 100644
--- a/llvm/include/llvm/MC/MCSection.h
+++ b/llvm/include/llvm/MC/MCSection.h
@@ -623,7 +623,7 @@ public:
}
Align getAlignmentForObjectFile(uint64_t Size) const;
-
+
unsigned getOrdinal() const { return Ordinal; }
void setOrdinal(unsigned Value) { Ordinal = Value; }
diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h
index 0cc42f099..cb7fd5410 100644
--- a/llvm/include/llvm/MC/MCStreamer.h
+++ b/llvm/include/llvm/MC/MCStreamer.h
@@ -840,7 +840,7 @@ public:
unsigned MaxBytesToEmit = 0);
virtual void emitPrefAlign(Align A);
-
+
/// Emit some number of copies of \p Value until the byte offset \p
/// Offset is reached.
///
|
There are some discussions on a codegen patch #149444 that I did not follow. Could you summarize the motivation in this patch's description? |
Ping, any thoughts on this approach? |
Created using spr 1.3.6-beta.1
Ping |
Ping |
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 minimumalignment.
Sections whose size is larger than the preferred alignment are aligned
to the preferred alignment. If the size of a section with a preferred
alignment is between the minimum alignment and the preferred alignment,
the section alignment is the smallest power of 2 >= the section size.
Part of this RFC:
https://discourse.llvm.org/t/rfc-enhancing-function-alignment-attributes/88019