Skip to content

Commit

Permalink
Support the min of module flags when linking, use for AArch64 BTI/PAC…
Browse files Browse the repository at this point in the history
…-RET

LTO objects might compiled with different `mbranch-protection` flags which will cause an error in the linker.
Such a setup is allowed in the normal build with this change that is possible.

Reviewed By: pcc

Differential Revision: https://reviews.llvm.org/D123493
  • Loading branch information
DanielKristofKiss committed Apr 13, 2022
1 parent e500062 commit b0343a3
Show file tree
Hide file tree
Showing 56 changed files with 294 additions and 160 deletions.
13 changes: 8 additions & 5 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -729,7 +729,10 @@ void CodeGenModule::Release() {
// attributes, but we use module metadata to emit build attributes. This is
// needed for LTO, where the function attributes are inside bitcode
// serialised into a global variable by the time build attributes are
// emitted, so we can't access them.
// emitted, so we can't access them. LTO objects could be compiled with
// different flags therefore module flags are set to "Min" behavior to achieve
// the same end result of the normal build where e.g BTI is off if any object
// doesn't support it.
if (Context.getTargetInfo().hasFeature("ptrauth") &&
LangOpts.getSignReturnAddressScope() !=
LangOptions::SignReturnAddressScopeKind::None)
Expand All @@ -743,16 +746,16 @@ void CodeGenModule::Release() {
Arch == llvm::Triple::arm || Arch == llvm::Triple::armeb ||
Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::aarch64_32 ||
Arch == llvm::Triple::aarch64_be) {
getModule().addModuleFlag(llvm::Module::Error, "branch-target-enforcement",
getModule().addModuleFlag(llvm::Module::Min, "branch-target-enforcement",
LangOpts.BranchTargetEnforcement);

getModule().addModuleFlag(llvm::Module::Error, "sign-return-address",
getModule().addModuleFlag(llvm::Module::Min, "sign-return-address",
LangOpts.hasSignReturnAddress());

getModule().addModuleFlag(llvm::Module::Error, "sign-return-address-all",
getModule().addModuleFlag(llvm::Module::Min, "sign-return-address-all",
LangOpts.isSignReturnAddressScopeAll());

getModule().addModuleFlag(llvm::Module::Error,
getModule().addModuleFlag(llvm::Module::Min,
"sign-return-address-with-bkey",
!LangOpts.isSignReturnAddressWithAKey());
}
Expand Down
46 changes: 23 additions & 23 deletions clang/test/CodeGen/aarch64-sign-return-address.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,28 @@

// Check module attributes

// NONE: !{i32 1, !"branch-target-enforcement", i32 0}
// ALL: !{i32 1, !"branch-target-enforcement", i32 0}
// PART: !{i32 1, !"branch-target-enforcement", i32 0}
// BTE: !{i32 1, !"branch-target-enforcement", i32 1}
// B-KEY: !{i32 1, !"branch-target-enforcement", i32 0}

// NONE: !{i32 1, !"sign-return-address", i32 0}
// ALL: !{i32 1, !"sign-return-address", i32 1}
// PART: !{i32 1, !"sign-return-address", i32 1}
// BTE: !{i32 1, !"sign-return-address", i32 0}
// B-KEY: !{i32 1, !"sign-return-address", i32 1}

// NONE: !{i32 1, !"sign-return-address-all", i32 0}
// ALL: !{i32 1, !"sign-return-address-all", i32 1}
// PART: !{i32 1, !"sign-return-address-all", i32 0}
// BTE: !{i32 1, !"sign-return-address-all", i32 0}
// B-KEY: !{i32 1, !"sign-return-address-all", i32 0}

// NONE: !{i32 1, !"sign-return-address-with-bkey", i32 0}
// ALL: !{i32 1, !"sign-return-address-with-bkey", i32 0}
// PART: !{i32 1, !"sign-return-address-with-bkey", i32 0}
// BTE: !{i32 1, !"sign-return-address-with-bkey", i32 0}
// B-KEY: !{i32 1, !"sign-return-address-with-bkey", i32 1}
// NONE: !{i32 8, !"branch-target-enforcement", i32 0}
// ALL: !{i32 8, !"branch-target-enforcement", i32 0}
// PART: !{i32 8, !"branch-target-enforcement", i32 0}
// BTE: !{i32 8, !"branch-target-enforcement", i32 1}
// B-KEY: !{i32 8, !"branch-target-enforcement", i32 0}

// NONE: !{i32 8, !"sign-return-address", i32 0}
// ALL: !{i32 8, !"sign-return-address", i32 1}
// PART: !{i32 8, !"sign-return-address", i32 1}
// BTE: !{i32 8, !"sign-return-address", i32 0}
// B-KEY: !{i32 8, !"sign-return-address", i32 1}

// NONE: !{i32 8, !"sign-return-address-all", i32 0}
// ALL: !{i32 8, !"sign-return-address-all", i32 1}
// PART: !{i32 8, !"sign-return-address-all", i32 0}
// BTE: !{i32 8, !"sign-return-address-all", i32 0}
// B-KEY: !{i32 8, !"sign-return-address-all", i32 0}

// NONE: !{i32 8, !"sign-return-address-with-bkey", i32 0}
// ALL: !{i32 8, !"sign-return-address-with-bkey", i32 0}
// PART: !{i32 8, !"sign-return-address-with-bkey", i32 0}
// BTE: !{i32 8, !"sign-return-address-with-bkey", i32 0}
// B-KEY: !{i32 8, !"sign-return-address-with-bkey", i32 1}

void foo() {}
28 changes: 14 additions & 14 deletions clang/test/CodeGen/arm-branch-protection-attr-2.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,19 @@

// Check module attributes

// NONE: !{i32 1, !"branch-target-enforcement", i32 0}
// PART: !{i32 1, !"branch-target-enforcement", i32 0}
// ALL: !{i32 1, !"branch-target-enforcement", i32 0}
// BTE: !{i32 1, !"branch-target-enforcement", i32 1}

// NONE: !{i32 1, !"sign-return-address", i32 0}
// PART: !{i32 1, !"sign-return-address", i32 1}
// ALL: !{i32 1, !"sign-return-address", i32 1}
// BTE: !{i32 1, !"sign-return-address", i32 0}

// NONE: !{i32 1, !"sign-return-address-all", i32 0}
// PART: !{i32 1, !"sign-return-address-all", i32 0}
// ALL: !{i32 1, !"sign-return-address-all", i32 1}
// BTE: !{i32 1, !"sign-return-address-all", i32 0}
// NONE: !{i32 8, !"branch-target-enforcement", i32 0}
// PART: !{i32 8, !"branch-target-enforcement", i32 0}
// ALL: !{i32 8, !"branch-target-enforcement", i32 0}
// BTE: !{i32 8, !"branch-target-enforcement", i32 1}

// NONE: !{i32 8, !"sign-return-address", i32 0}
// PART: !{i32 8, !"sign-return-address", i32 1}
// ALL: !{i32 8, !"sign-return-address", i32 1}
// BTE: !{i32 8, !"sign-return-address", i32 0}

// NONE: !{i32 8, !"sign-return-address-all", i32 0}
// PART: !{i32 8, !"sign-return-address-all", i32 0}
// ALL: !{i32 8, !"sign-return-address-all", i32 1}
// BTE: !{i32 8, !"sign-return-address-all", i32 0}

void foo() {}
2 changes: 1 addition & 1 deletion clang/test/Frontend/arm-ignore-branch-protection-option.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ __attribute__((target("arch=cortex-m0"))) void f() {}
// CHECK-NOT: attributes { {{.*}} "branch-target-enforcement"

/// Check that there are branch protection module attributes despite the warning.
// CHECK: !{i32 1, !"branch-target-enforcement", i32 1}
// CHECK: !{i32 8, !"branch-target-enforcement", i32 1}
5 changes: 4 additions & 1 deletion llvm/include/llvm/IR/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,12 @@ class LLVM_EXTERNAL_VISIBILITY Module {
/// Takes the max of the two values, which are required to be integers.
Max = 7,

/// Takes the min of the two values, which are required to be integers.
Min = 8,

// Markers:
ModFlagBehaviorFirstVal = Error,
ModFlagBehaviorLastVal = Max
ModFlagBehaviorLastVal = Min
};

/// Checks if Metadata represents a valid ModFlagBehavior, and stores the
Expand Down
18 changes: 18 additions & 0 deletions llvm/lib/IR/AutoUpgrade.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4388,6 +4388,24 @@ bool llvm::UpgradeModuleFlags(Module &M) {
}
}
}

// Upgrade branch protection and return address signing module flags. The
// module flag behavior for these fields were Error and now they are Min.
if (ID->getString() == "branch-target-enforcement" ||
ID->getString().startswith("sign-return-address")) {
if (auto *Behavior =
mdconst::dyn_extract_or_null<ConstantInt>(Op->getOperand(0))) {
if (Behavior->getLimitedValue() == Module::Error) {
Type *Int32Ty = Type::getInt32Ty(M.getContext());
Metadata *Ops[3] = {
ConstantAsMetadata::get(ConstantInt::get(Int32Ty, Module::Min)),
Op->getOperand(1), Op->getOperand(2)};
ModFlags->setOperand(I, MDNode::get(M.getContext(), Ops));
Changed = true;
}
}
}

// Upgrade Objective-C Image Info Section. Removed the whitespce in the
// section name so that llvm-lto will not complain about mismatching
// module flags that is functionally the same.
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/IR/Verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1623,6 +1623,13 @@ Verifier::visitModuleFlag(const MDNode *Op,
// These behavior types accept any value.
break;

case Module::Min: {
Check(mdconst::dyn_extract_or_null<ConstantInt>(Op->getOperand(2)),
"invalid value for 'min' module flag (expected constant integer)",
Op->getOperand(2));
break;
}

case Module::Max: {
Check(mdconst::dyn_extract_or_null<ConstantInt>(Op->getOperand(2)),
"invalid value for 'max' module flag (expected constant integer)",
Expand Down
29 changes: 28 additions & 1 deletion llvm/lib/Linker/IRMover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Triple.h"
#include "llvm/IR/AutoUpgrade.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DiagnosticPrinter.h"
Expand Down Expand Up @@ -1256,6 +1257,9 @@ Error IRLinker::linkModuleFlagsMetadata() {
if (!SrcModFlags)
return Error::success();

// Check for module flag for updates before do anything.
UpgradeModuleFlags(*SrcM);

// If the destination module doesn't have module flags yet, then just copy
// over the source module's flags.
NamedMDNode *DstModFlags = DstM.getOrInsertModuleFlagsMetadata();
Expand Down Expand Up @@ -1338,11 +1342,15 @@ Error IRLinker::linkModuleFlagsMetadata() {

// Diagnose inconsistent merge behavior types.
if (SrcBehaviorValue != DstBehaviorValue) {
bool MinAndWarn = (SrcBehaviorValue == Module::Min &&
DstBehaviorValue == Module::Warning) ||
(DstBehaviorValue == Module::Min &&
SrcBehaviorValue == Module::Warning);
bool MaxAndWarn = (SrcBehaviorValue == Module::Max &&
DstBehaviorValue == Module::Warning) ||
(DstBehaviorValue == Module::Max &&
SrcBehaviorValue == Module::Warning);
if (!MaxAndWarn)
if (!(MaxAndWarn || MinAndWarn))
return stringErr("linking module flags '" + ID->getString() +
"': IDs have conflicting behaviors in '" +
SrcM->getModuleIdentifier() + "' and '" +
Expand Down Expand Up @@ -1371,6 +1379,25 @@ Error IRLinker::linkModuleFlagsMetadata() {
emitWarning(Str);
}

// Choose the minimum if either source or destination request Min behavior.
if (DstBehaviorValue == Module::Min || SrcBehaviorValue == Module::Min) {
ConstantInt *DstValue =
mdconst::extract<ConstantInt>(DstOp->getOperand(2));
ConstantInt *SrcValue =
mdconst::extract<ConstantInt>(SrcOp->getOperand(2));

// The resulting flag should have a Min behavior, and contain the minimum
// value from between the source and destination values.
Metadata *FlagOps[] = {
(DstBehaviorValue != Module::Min ? SrcOp : DstOp)->getOperand(0), ID,
(SrcValue->getZExtValue() < DstValue->getZExtValue() ? SrcOp : DstOp)
->getOperand(2)};
MDNode *Flag = MDNode::get(DstM.getContext(), FlagOps);
DstModFlags->setOperand(DstIndex, Flag);
Flags[ID].first = Flag;
continue;
}

// Choose the maximum if either source or destination request Max behavior.
if (DstBehaviorValue == Module::Max || SrcBehaviorValue == Module::Max) {
ConstantInt *DstValue =
Expand Down
16 changes: 16 additions & 0 deletions llvm/test/Bitcode/upgrade-branch-protection.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
;; Test that module flags "branch-target-enforcement" and "sign-return-address" can be upgraded to
;; are upgraded from Error to Min.

; RUN: llvm-as %s -o - | llvm-dis - | FileCheck %s

!llvm.module.flags = !{!0, !1, !2, !3}

!0 = !{i32 1, !"branch-target-enforcement", i32 1}
!1 = !{i32 1, !"sign-return-address", i32 1}
!2 = !{i32 1, !"sign-return-address-all", i32 1}
!3 = !{i32 1, !"sign-return-address-with-bkey", i32 1}

;CHECK: !0 = !{i32 8, !"branch-target-enforcement", i32 1}
;CHECK: !1 = !{i32 8, !"sign-return-address", i32 1}
;CHECK: !2 = !{i32 8, !"sign-return-address-all", i32 1}
;CHECK: !3 = !{i32 8, !"sign-return-address-with-bkey", i32 1}
8 changes: 4 additions & 4 deletions llvm/test/CodeGen/AArch64/debug-info-sve-dbg-declare.mir
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,10 @@
!3 = !{i32 7, !"Dwarf Version", i32 4}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = !{i32 1, !"wchar_size", i32 4}
!6 = !{i32 1, !"branch-target-enforcement", i32 0}
!7 = !{i32 1, !"sign-return-address", i32 0}
!8 = !{i32 1, !"sign-return-address-all", i32 0}
!9 = !{i32 1, !"sign-return-address-with-bkey", i32 0}
!6 = !{i32 8, !"branch-target-enforcement", i32 0}
!7 = !{i32 8, !"sign-return-address", i32 0}
!8 = !{i32 8, !"sign-return-address-all", i32 0}
!9 = !{i32 8, !"sign-return-address-with-bkey", i32 0}
!10 = !{!"clang version 12.0.0 (https:/llvm/llvm-project.git b19275ba870a06c5ef0428af6264ffd28c7cde9e)"}
!11 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 4, type: !12, scopeLine: 4, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
!12 = !DISubroutineType(types: !13)
Expand Down
8 changes: 4 additions & 4 deletions llvm/test/CodeGen/AArch64/live-debugvalues-sve.mir
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,10 @@
!3 = !{i32 7, !"Dwarf Version", i32 4}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = !{i32 1, !"wchar_size", i32 4}
!6 = !{i32 1, !"branch-target-enforcement", i32 0}
!7 = !{i32 1, !"sign-return-address", i32 0}
!8 = !{i32 1, !"sign-return-address-all", i32 0}
!9 = !{i32 1, !"sign-return-address-with-bkey", i32 0}
!6 = !{i32 8, !"branch-target-enforcement", i32 0}
!7 = !{i32 8, !"sign-return-address", i32 0}
!8 = !{i32 8, !"sign-return-address-all", i32 0}
!9 = !{i32 8, !"sign-return-address-with-bkey", i32 0}
!10 = !{!"clang version 12.0.0 (https:/llvm/llvm-project.git b19275ba870a06c5ef0428af6264ffd28c7cde9e)"}
!11 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 6, type: !12, scopeLine: 6, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !26)
!12 = !DISubroutineType(types: !13)
Expand Down
8 changes: 4 additions & 4 deletions llvm/test/CodeGen/AArch64/memsize-remarks.ll
Original file line number Diff line number Diff line change
Expand Up @@ -328,10 +328,10 @@ attributes #4 = { nounwind }
!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 12, i32 0]}
!1 = !{i32 2, !"Debug Info Version", i32 3}
!2 = !{i32 1, !"wchar_size", i32 4}
!3 = !{i32 1, !"branch-target-enforcement", i32 0}
!4 = !{i32 1, !"sign-return-address", i32 0}
!5 = !{i32 1, !"sign-return-address-all", i32 0}
!6 = !{i32 1, !"sign-return-address-with-bkey", i32 0}
!3 = !{i32 8, !"branch-target-enforcement", i32 0}
!4 = !{i32 8, !"sign-return-address", i32 0}
!5 = !{i32 8, !"sign-return-address-all", i32 0}
!6 = !{i32 8, !"sign-return-address-with-bkey", i32 0}
!7 = !{i32 7, !"PIC Level", i32 2}
!8 = !{i32 7, !"uwtable", i32 1}
!9 = !{i32 7, !"frame-pointer", i32 1}
Expand Down
8 changes: 4 additions & 4 deletions llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-0.ll
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ attributes #0 = { "branch-target-enforcement"="true" }

!llvm.module.flags = !{!0, !1, !2, !3}

!0 = !{i32 1, !"branch-target-enforcement", i32 1}
!1 = !{i32 1, !"sign-return-address", i32 1}
!2 = !{i32 1, !"sign-return-address-all", i32 0}
!3 = !{i32 1, !"sign-return-address-with-bkey", i32 0}
!0 = !{i32 8, !"branch-target-enforcement", i32 1}
!1 = !{i32 8, !"sign-return-address", i32 1}
!2 = !{i32 8, !"sign-return-address-all", i32 0}
!3 = !{i32 8, !"sign-return-address-with-bkey", i32 0}

; Both attributes present in a file with no functions.
; ASM: .word 3221225472
Expand Down
8 changes: 4 additions & 4 deletions llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-1.ll
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ entry:

!llvm.module.flags = !{!0, !1, !2, !3}

!0 = !{i32 1, !"branch-target-enforcement", i32 1}
!1 = !{i32 1, !"sign-return-address", i32 0}
!2 = !{i32 1, !"sign-return-address-all", i32 0}
!3 = !{i32 1, !"sign-return-address-with-bkey", i32 0}
!0 = !{i32 8, !"branch-target-enforcement", i32 1}
!1 = !{i32 8, !"sign-return-address", i32 0}
!2 = !{i32 8, !"sign-return-address-all", i32 0}
!3 = !{i32 8, !"sign-return-address-with-bkey", i32 0}

; BTI attribute present
; ASM: .word 3221225472
Expand Down
8 changes: 4 additions & 4 deletions llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-2.ll
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ entry:

!llvm.module.flags = !{!0, !1, !2, !3}

!0 = !{i32 1, !"branch-target-enforcement", i32 0}
!1 = !{i32 1, !"sign-return-address", i32 1}
!2 = !{i32 1, !"sign-return-address-all", i32 0}
!3 = !{i32 1, !"sign-return-address-with-bkey", i32 0}
!0 = !{i32 8, !"branch-target-enforcement", i32 0}
!1 = !{i32 8, !"sign-return-address", i32 1}
!2 = !{i32 8, !"sign-return-address-all", i32 0}
!3 = !{i32 8, !"sign-return-address-with-bkey", i32 0}

; PAC attribute present
; ASM: .word 3221225472
Expand Down
8 changes: 4 additions & 4 deletions llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-3.ll
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ entry:

!llvm.module.flags = !{!0, !1, !2, !3}

!0 = !{i32 1, !"branch-target-enforcement", i32 1}
!1 = !{i32 1, !"sign-return-address", i32 1}
!2 = !{i32 1, !"sign-return-address-all", i32 0}
!3 = !{i32 1, !"sign-return-address-with-bkey", i32 0}
!0 = !{i32 8, !"branch-target-enforcement", i32 1}
!1 = !{i32 8, !"sign-return-address", i32 1}
!2 = !{i32 8, !"sign-return-address-all", i32 0}
!3 = !{i32 8, !"sign-return-address-with-bkey", i32 0}

; Both attribute present
; ASM: .word 3221225472
Expand Down
8 changes: 4 additions & 4 deletions llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-4.ll
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ attributes #1 = { "branch-target-enforcement"="true" }

!llvm.module.flags = !{!0, !1, !2, !3}

!0 = !{i32 1, !"branch-target-enforcement", i32 0}
!1 = !{i32 1, !"sign-return-address", i32 0}
!2 = !{i32 1, !"sign-return-address-all", i32 0}
!3 = !{i32 1, !"sign-return-address-with-bkey", i32 0}
!0 = !{i32 8, !"branch-target-enforcement", i32 0}
!1 = !{i32 8, !"sign-return-address", i32 0}
!2 = !{i32 8, !"sign-return-address-all", i32 0}
!3 = !{i32 8, !"sign-return-address-with-bkey", i32 0}

; Note is not emited if module has no properties
; ASM-NOT: .note.gnu.property
8 changes: 4 additions & 4 deletions llvm/test/CodeGen/AArch64/pacbti-llvm-generated-funcs-2.ll
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ attributes #2 = { nofree noinline norecurse nounwind writeonly }

!0 = !{i32 2, !"Debug Info Version", i32 3}
!1 = !{i32 1, !"wchar_size", i32 4}
!2 = !{i32 1, !"branch-target-enforcement", i32 0}
!3 = !{i32 1, !"sign-return-address", i32 1}
!4 = !{i32 1, !"sign-return-address-all", i32 1}
!5 = !{i32 1, !"sign-return-address-with-bkey", i32 1}
!2 = !{i32 8, !"branch-target-enforcement", i32 0}
!3 = !{i32 8, !"sign-return-address", i32 1}
!4 = !{i32 8, !"sign-return-address-all", i32 1}
!5 = !{i32 8, !"sign-return-address-with-bkey", i32 1}
Loading

0 comments on commit b0343a3

Please sign in to comment.