LLVM 18.0.0git
AArch64GlobalsTagging.cpp
Go to the documentation of this file.
1//===- AArch64GlobalsTagging.cpp - Global tagging in IR -------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//===----------------------------------------------------------------------===//
10
11#include "AArch64.h"
13#include "llvm/IR/Attributes.h"
14#include "llvm/IR/Constants.h"
15#include "llvm/IR/GlobalValue.h"
17#include "llvm/IR/IRBuilder.h"
18#include "llvm/IR/Module.h"
19#include "llvm/Pass.h"
21
22#include <algorithm>
23#include <set>
24
25using namespace llvm;
26
27static const Align kTagGranuleSize = Align(16);
28
30 if (!G.isTagged())
31 return false;
32
33 assert(G.hasSanitizerMetadata() &&
34 "Missing sanitizer metadata, but symbol is apparently tagged.");
35 GlobalValue::SanitizerMetadata Meta = G.getSanitizerMetadata();
36
37 // For now, don't instrument constant data, as it'll be in .rodata anyway. It
38 // may be worth instrumenting these in future to stop them from being used as
39 // gadgets.
40 if (G.getName().startswith("llvm.") || G.isThreadLocal() || G.isConstant()) {
41 Meta.Memtag = false;
42 G.setSanitizerMetadata(Meta);
43 return false;
44 }
45
46 return true;
47}
48
49// Technically, due to ELF symbol interposition semantics, we can't change the
50// alignment or size of symbols. If we increase the alignment or size of a
51// symbol, the compiler may make optimisations based on this new alignment or
52// size. If the symbol is interposed, this optimisation could lead to
53// alignment-related or OOB read/write crashes.
54//
55// This is handled in the linker. When the linker sees multiple declarations of
56// a global variable, and some are tagged, and some are untagged, it resolves it
57// to be an untagged definition - but preserves the tag-granule-rounded size and
58// tag-granule-alignment. This should prevent these kind of crashes intra-DSO.
59// For cross-DSO, it's been a reasonable contract that if you're interposing a
60// sanitizer-instrumented global, then the interposer also needs to be
61// sanitizer-instrumented.
62//
63// FIXME: In theory, this can be fixed by splitting the size/alignment of
64// globals into two uses: an "output alignment" that's emitted to the ELF file,
65// and an "optimisation alignment" that's used for optimisation. Thus, we could
66// adjust the output alignment only, and still optimise based on the pessimistic
67// pre-tagging size/alignment.
69 Constant *Initializer = G->getInitializer();
70 uint64_t SizeInBytes =
71 M.getDataLayout().getTypeAllocSize(Initializer->getType());
72
73 uint64_t NewSize = alignTo(SizeInBytes, kTagGranuleSize);
74 if (SizeInBytes != NewSize) {
75 // Pad the initializer out to the next multiple of 16 bytes.
76 llvm::SmallVector<uint8_t> Init(NewSize - SizeInBytes, 0);
77 Constant *Padding = ConstantDataArray::get(M.getContext(), Init);
78 Initializer = ConstantStruct::getAnon({Initializer, Padding});
79 auto *NewGV = new GlobalVariable(
80 M, Initializer->getType(), G->isConstant(), G->getLinkage(),
81 Initializer, "", G, G->getThreadLocalMode(), G->getAddressSpace());
82 NewGV->copyAttributesFrom(G);
83 NewGV->setComdat(G->getComdat());
84 NewGV->copyMetadata(G, 0);
85
86 NewGV->takeName(G);
87 G->replaceAllUsesWith(NewGV);
88 G->eraseFromParent();
89 G = NewGV;
90 }
91
92 G->setAlignment(std::max(G->getAlign().valueOrOne(), kTagGranuleSize));
93
94 // Ensure that tagged globals don't get merged by ICF - as they should have
95 // different tags at runtime.
96 G->setUnnamedAddr(GlobalValue::UnnamedAddr::None);
97}
98
99namespace {
100class AArch64GlobalsTagging : public ModulePass {
101public:
102 static char ID;
103
104 explicit AArch64GlobalsTagging() : ModulePass(ID) {
106 }
107
108 bool runOnModule(Module &M) override;
109
110 StringRef getPassName() const override { return "AArch64 Globals Tagging"; }
111
112private:
113 std::set<GlobalVariable *> GlobalsToTag;
114};
115} // anonymous namespace
116
117char AArch64GlobalsTagging::ID = 0;
118
119bool AArch64GlobalsTagging::runOnModule(Module &M) {
120 // No mutating the globals in-place, or iterator invalidation occurs.
121 std::vector<GlobalVariable *> GlobalsToTag;
122 for (GlobalVariable &G : M.globals()) {
123 if (G.isDeclaration() || !shouldTagGlobal(G))
124 continue;
125 GlobalsToTag.push_back(&G);
126 }
127
128 for (GlobalVariable *G : GlobalsToTag) {
130 }
131
132 return true;
133}
134
135INITIALIZE_PASS_BEGIN(AArch64GlobalsTagging, "aarch64-globals-tagging",
136 "AArch64 Globals Tagging Pass", false, false)
137INITIALIZE_PASS_END(AArch64GlobalsTagging, "aarch64-globals-tagging",
138 "AArch64 Globals Tagging Pass", false, false)
139
141 return new AArch64GlobalsTagging();
142}
static bool shouldTagGlobal(GlobalVariable &G)
static void tagGlobalDefinition(Module &M, GlobalVariable *G)
static const Align kTagGranuleSize
aarch64 globals tagging
AArch64 Stack Tagging
This file contains the simple types necessary to represent the attributes associated with functions a...
This file contains the declarations for the subclasses of Constant, which represent the different fla...
dxil globals
#define G(x, y, z)
Definition: MD5.cpp:56
Module.h This file contains the declarations for the Module class.
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:59
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:52
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static Constant * get(LLVMContext &Context, ArrayRef< ElementTy > Elts)
get() constructor - Return a constant with array type with an element count and element type matching...
Definition: Constants.h:690
static Constant * getAnon(ArrayRef< Constant * > V, bool Packed=false)
Return an anonymous struct that has the specified elements.
Definition: Constants.h:461
This is an important base class in LLVM.
Definition: Constant.h:41
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition: Pass.h:251
virtual bool runOnModule(Module &M)=0
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
Pass interface - Implemented by all 'passes'.
Definition: Pass.h:94
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Definition: Pass.cpp:81
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
Type * getType() const
All values are typed, get the type of this value.
Definition: Value.h:255
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
void initializeAArch64GlobalsTaggingPass(PassRegistry &)
ModulePass * createAArch64GlobalsTaggingPass()
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition: Alignment.h:155
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39