Skip to content
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

[CFI][annotation] Leave alone function pointers in function annotations #80173

Merged
merged 8 commits into from
Feb 9, 2024

Conversation

yozhu
Copy link
Contributor

@yozhu yozhu commented Jan 31, 2024

Function annotation, as part of llvm.metadata, is for the function itself and doesn't apply to its corresponding jump table entry, so with CFI we shouldn't replace function pointer in function annotation with pointer to its corresponding jump table entry.

Function annotation, as part of llvm.metadata, is for the function itself
and doesn't apply to its corresponding jump table entry, so with CFI we
shouldn't replace function pointer in function annotation with pointer to
its corresponding jump table entry.
@llvmbot
Copy link
Collaborator

llvmbot commented Jan 31, 2024

@llvm/pr-subscribers-backend-aarch64

@llvm/pr-subscribers-llvm-transforms

Author: None (yozhu)

Changes

Function annotation, as part of llvm.metadata, is for the function itself and doesn't apply to its corresponding jump table entry, so with CFI we shouldn't replace function pointer in function annotation with pointer to its corresponding jump table entry.


Full diff: https://github.com/llvm/llvm-project/pull/80173.diff

1 Files Affected:

  • (modified) llvm/lib/Transforms/IPO/LowerTypeTests.cpp (+29-1)
diff --git a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp
index 733f290b1bc93..f6630019eaec6 100644
--- a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp
+++ b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp
@@ -470,6 +470,9 @@ class LowerTypeTestsModule {
 
   Function *WeakInitializerFn = nullptr;
 
+  GlobalVariable *GlobalAnnotation;
+  std::set<void *> FunctionAnnotations;
+
   bool shouldExportConstantsAsAbsoluteSymbols();
   uint8_t *exportTypeId(StringRef TypeId, const TypeIdLowering &TIL);
   TypeIdLowering importTypeId(StringRef TypeId);
@@ -531,6 +534,10 @@ class LowerTypeTestsModule {
   /// replace each use, which is a direct function call.
   void replaceDirectCalls(Value *Old, Value *New);
 
+  bool isFunctionAnnotation(void *GV) {
+    return FunctionAnnotations.count(GV) != 0;
+  }
+
 public:
   LowerTypeTestsModule(Module &M, ModuleAnalysisManager &AM,
                        ModuleSummaryIndex *ExportSummary,
@@ -1377,8 +1384,11 @@ void LowerTypeTestsModule::replaceWeakDeclarationWithJumpTablePtr(
   // (all?) targets. Switch to a runtime initializer.
   SmallSetVector<GlobalVariable *, 8> GlobalVarUsers;
   findGlobalVariableUsersOf(F, GlobalVarUsers);
-  for (auto *GV : GlobalVarUsers)
+  for (auto *GV : GlobalVarUsers) {
+    if (GV == GlobalAnnotation)
+      continue;
     moveInitializerToModuleConstructor(GV);
+  }
 
   // Can not RAUW F with an expression that uses F. Replace with a temporary
   // placeholder first.
@@ -1392,6 +1402,10 @@ void LowerTypeTestsModule::replaceWeakDeclarationWithJumpTablePtr(
   // Don't use range based loop, because use list will be modified.
   while (!PlaceholderFn->use_empty()) {
     Use &U = *PlaceholderFn->use_begin();
+    if (isFunctionAnnotation(U.getUser())) {
+      U.set(F);
+      continue;
+    }
     auto *InsertPt = dyn_cast<Instruction>(U.getUser());
     assert(InsertPt && "Non-instruction users should have been eliminated");
     auto *PN = dyn_cast<PHINode>(InsertPt);
@@ -1837,6 +1851,16 @@ LowerTypeTestsModule::LowerTypeTestsModule(
   }
   OS = TargetTriple.getOS();
   ObjectFormat = TargetTriple.getObjectFormat();
+
+  // Function annotation describes or applies to function itself, and
+  // shouldn't be associated with jump table thunk generated for CFI.
+  GlobalAnnotation = M.getGlobalVariable("llvm.global.annotations");
+  auto *C = dyn_cast_or_null<Constant>(GlobalAnnotation);
+  if (C && C->getNumOperands() == 1) {
+    C = cast<Constant>(C->getOperand(0));
+    for (auto &Op : C->operands())
+      FunctionAnnotations.insert(Op.get());
+  }
 }
 
 bool LowerTypeTestsModule::runForTesting(Module &M, ModuleAnalysisManager &AM) {
@@ -1900,6 +1924,10 @@ void LowerTypeTestsModule::replaceCfiUses(Function *Old, Value *New,
     if (isDirectCall(U) && (Old->isDSOLocal() || !IsJumpTableCanonical))
       continue;
 
+    // Skip function annotation
+    if (isFunctionAnnotation(U.getUser()))
+      continue;
+
     // Must handle Constants specially, we cannot call replaceUsesOfWith on a
     // constant because they are uniqued.
     if (auto *C = dyn_cast<Constant>(U.getUser())) {

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

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

Missing tests.

llvm/lib/Transforms/IPO/LowerTypeTests.cpp Outdated Show resolved Hide resolved
llvm/lib/Transforms/IPO/LowerTypeTests.cpp Outdated Show resolved Hide resolved
llvm/lib/Transforms/IPO/LowerTypeTests.cpp Outdated Show resolved Hide resolved
llvm/lib/Transforms/IPO/LowerTypeTests.cpp Outdated Show resolved Hide resolved
llvm/lib/Transforms/IPO/LowerTypeTests.cpp Outdated Show resolved Hide resolved
llvm/lib/Transforms/IPO/LowerTypeTests.cpp Outdated Show resolved Hide resolved
llvm/lib/Transforms/IPO/LowerTypeTests.cpp Outdated Show resolved Hide resolved
llvm/test/CodeGen/AArch64/cfi-annotation.test Outdated Show resolved Hide resolved
@yozhu yozhu requested a review from nikic February 1, 2024 21:52
Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

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

Implementation looks fine, the test needs more work.

llvm/lib/Transforms/IPO/LowerTypeTests.cpp Outdated Show resolved Hide resolved
llvm/test/CodeGen/AArch64/cfi-annotation.ll Outdated Show resolved Hide resolved
llvm/test/CodeGen/AArch64/cfi-annotation.ll Outdated Show resolved Hide resolved
@yozhu yozhu requested a review from nikic February 2, 2024 18:36
@yozhu
Copy link
Contributor Author

yozhu commented Feb 6, 2024

CC @nikic: thanks for all the comments so far. Any other feedback? If the latest version looks good to you, could you approve it?

llvm/test/CodeGen/AArch64/cfi-annotation.ll Outdated Show resolved Hide resolved
llvm/test/CodeGen/AArch64/cfi-annotation.ll Outdated Show resolved Hide resolved
llvm/test/CodeGen/AArch64/cfi-annotation.ll Outdated Show resolved Hide resolved
llvm/test/CodeGen/AArch64/cfi-annotation.ll Outdated Show resolved Hide resolved
@yozhu yozhu requested a review from nikic February 6, 2024 17:52
@yozhu
Copy link
Contributor Author

yozhu commented Feb 7, 2024

CC: @nikic Unnecessary things have been removed from the test ..

@@ -0,0 +1,46 @@
; RUN: opt -passes=lowertypetests %s -o %t.o
Copy link
Contributor

Choose a reason for hiding this comment

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

After your last update, the test will also pass without your changes. I believe the issue is that you dropped the !2 = !{i32 4, !"CFI Canonical Jump Tables", i32 0} metadata, which is necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The issue turns out to be that I dropped attribute and type specifications:

  • With the following the problem will reproduce:

define i32 @bar(i32 noundef %0) #0 !type !8 !type !9 {

  • And with the following the problem doesn't reproduce:

define i32 @bar(i32 noundef %0) {

#0, !8 and !9 are defined as:

attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+fp-armv8,+neon,+v8a,-fmv" }
 60 !8 = !{i64 0, !"_ZTSFiiE"}
 61 !9 = !{i64 0, !"_ZTSFiiE.generalized"}

Also it appears that the test code can't be made too simple because otherwise indirect call target will be easy to figure out by optimizations and then CFI has nowhere to apply.

llvm/test/Transforms/LowerTypeTests/cfi-annotation.ll Outdated Show resolved Hide resolved
@yozhu yozhu requested a review from nikic February 8, 2024 18:55
@yozhu
Copy link
Contributor Author

yozhu commented Feb 9, 2024

CC @nikic on the updated test .. could we please get this wrapped up this week? Thanks.

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

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

LGTM

@yozhu
Copy link
Contributor Author

yozhu commented Feb 9, 2024

LGTM

Thanks for all your feedback and comments! Much appreciated!

@yozhu yozhu merged commit c7a0db1 into llvm:main Feb 9, 2024
3 of 4 checks passed
yozhu added a commit to yozhu/llvm-project that referenced this pull request Feb 13, 2024
…ns (llvm#80173)

Function annotation, as part of llvm.metadata, is for the function
itself and doesn't apply to its corresponding jump table entry, so with
CFI we shouldn't replace function pointer in function annotation with
pointer to its corresponding jump table entry.

(cherry picked from commit c7a0db1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants