LLVM 24.0.0git
BPFFuncTable.cpp
Go to the documentation of this file.
1//===-- BPFFuncTable.cpp - Call functions through a table -----------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// A program that keeps its data in arena keeps pointers to functions there too:
10// vtables, closures, Box<dyn Trait>. Arena is shared with user space, so what
11// is loaded from it is a number and the kernel does not let callx take it.
12//
13// Make the pointer to a function a number to begin with: the index of the
14// function in a table that is read-only data.
15// &f index of f
16// (*p)(...) __bpf_func_table[min(p - first, cnt - 1) + first](...)
17// The functions of one type are next to each other in the table: 'first' and
18// 'cnt' are those of the type of the call. A number that is not an index of
19// such function calls the last one of them. That is not what the program
20// meant, but it is a function that takes what the call passes.
21//
22// The kernel knows the pointers to functions in read-only data. A load at
23// an offset that is not constant is fine as long as there is such a pointer at
24// every offset it can be at. So callx gets a pointer to a function again and
25// there is nothing for a loader or the kernel to do.
26//
27// 0 is not an index, so that null stays null. When there is one function of
28// the type the call is direct. When there is none it is a trap.
29//
30// A function that is passed to a helper or to a kfunc stays a function, also
31// when it is one of several: cond ? cb1 : cb2.
32//
33// All functions whose address is taken have to be in the module and static.
34//
35//===----------------------------------------------------------------------===//
36
37#include "BPF.h"
38#include "llvm/ADT/MapVector.h"
39#include "llvm/ADT/SetVector.h"
40#include "llvm/IR/Constants.h"
42#include "llvm/IR/IRBuilder.h"
45#include "llvm/IR/Module.h"
46#include "llvm/Pass.h"
48
49using namespace llvm;
50
51#define DEBUG_TYPE "bpf-func-table"
52
53namespace {
54
55/// The functions of one type: where they start in the table.
56struct FuncRange {
57 uint64_t First = 0;
59};
60
61} // namespace
62
63/// The address of a function in another section is the address of a program,
64/// e.g. in struct_ops.
65static bool isInText(const Function &F) {
66 return !F.isDeclaration() && !F.hasSection();
67}
68
69/// A callback: bpf_loop(), bpf_timer_set_callback() and co. The kernel calls
70/// it and wants the function. A helper is a number, a kfunc a declaration.
71static bool isCallbackUse(const Use &U, SmallPtrSetImpl<const User *> &Seen) {
72 const User *Usr = U.getUser();
73
74 // cond ? cb1 : cb2, as long as nothing else is done with the result. A call
75 // of it goes through the table and wants an index.
77 return !Seen.insert(Usr).second || all_of(Usr->uses(), [&](const Use &U) {
78 return isCallbackUse(U, Seen);
79 });
80
81 const auto *CB = dyn_cast<CallBase>(Usr);
82 if (!CB || CB->isCallee(&U))
83 return false;
84 const Value *Callee = CB->getCalledOperand()->stripPointerCasts();
85 const auto *F = dyn_cast<Function>(Callee);
86 return F ? F->isDeclaration() && !F->isIntrinsic() : isa<Constant>(Callee);
87}
88
89/// The use is the address of the function as a value.
90static bool isAddressUse(const Use &U) {
91 const User *Usr = U.getUser();
92 const auto *CB = dyn_cast<CallBase>(Usr);
94
95 if ((CB && CB->isCallee(&U)) || isCallbackUse(U, Seen))
96 return false;
97 // Personality, prefix and prologue data, aliases.
99 Usr);
100}
101
102static void replaceAddress(Function &F, Constant *Index) {
104
105 for (Use &U : make_early_inc_range(F.uses())) {
106 if (!isAddressUse(U))
107 continue;
108 // Constants are uniqued: the operand cannot be set.
109 auto *C = dyn_cast<Constant>(U.getUser());
110 if (C && !isa<GlobalValue>(C))
111 Constants.insert(C);
112 else
113 U.set(Index);
114 }
115 for (Constant *C : Constants)
116 C->handleOperandChange(&F, Index);
117}
118
119static bool runFuncTable(Module &M) {
120 LLVMContext &C = M.getContext();
121 const DataLayout &DL = M.getDataLayout();
122 Type *I64 = Type::getInt64Ty(C);
126 SmallVector<GlobalValue *, 4> Used, CompilerUsed;
128
129 // They hold functions, not their addresses.
130 if (GlobalVariable *GV = collectUsedGlobalVariables(M, Used, false))
131 GV->eraseFromParent();
132 if (GlobalVariable *GV = collectUsedGlobalVariables(M, CompilerUsed, true))
133 GV->eraseFromParent();
134 bool Changed = !Used.empty() || !CompilerUsed.empty();
135
136 for (Function &F : M) {
137 if (isInText(F) && any_of(F.uses(), isAddressUse)) {
138 // callx takes static functions only. An address that is left as it is
139 // would be an index out of range: a call of another function.
140 if (!F.hasLocalLinkage())
142 F, "BPF func-table cannot take the address of a function that is "
143 "not static"));
144 Types[F.getFunctionType()].Funcs.push_back(&F);
145 }
146 for (Instruction &I : instructions(F)) {
147 auto *CB = dyn_cast<CallBase>(&I);
148 // A constant is a function or the number of a helper.
149 if (CB && !CB->isInlineAsm() && !isa<Constant>(CB->getCalledOperand()))
150 Calls.push_back(CB);
151 }
152 }
153
154 Table.push_back(ConstantPointerNull::get(Ptr));
155 for (auto &[FTy, R] : Types) {
156 R.First = Table.size();
157 for (Function *F : R.Funcs) {
159 ConstantInt::get(I64, Table.size()), Ptr));
160 Table.push_back(F);
161 }
162 }
163
164 appendToUsed(M, Used);
165 appendToCompilerUsed(M, CompilerUsed);
166 if (Calls.empty() && Types.empty())
167 return Changed;
168
169 ArrayType *TableTy = ArrayType::get(Ptr, Table.size());
170 GlobalVariable *GV = nullptr;
171
172 for (CallBase *CB : Calls) {
173 const FuncRange &R = Types.lookup(CB->getFunctionType());
174 uint64_t Cnt = R.Funcs.size();
175
176 // Nothing to call. The kernel rejects the trap if it is reachable. A call
177 // of null alone is undefined behaviour: what leads to nothing else is
178 // removed with it, the exit of a loop for example.
179 if (!Cnt) {
180 IRBuilder<>(CB).CreateIntrinsic(Intrinsic::trap, {});
181 CB->setCalledOperand(ConstantPointerNull::get(Ptr));
182 continue;
183 }
184 if (Cnt == 1) {
185 CB->setCalledOperand(R.Funcs[0]);
186 continue;
187 }
188 if (!GV)
189 GV = new GlobalVariable(M, TableTy, true, GlobalValue::InternalLinkage,
190 ConstantArray::get(TableTy, Table),
191 "__bpf_func_table");
192
193 IRBuilder<> B(CB);
194 Value *Idx = B.CreatePtrToInt(CB->getCalledOperand(), I64);
195 Idx = B.CreateSub(Idx, ConstantInt::get(I64, R.First));
196 Idx = B.CreateBinaryIntrinsic(Intrinsic::umin, Idx,
197 ConstantInt::get(I64, Cnt - 1));
199 GV, ConstantInt::get(I64, R.First * DL.getPointerSize()));
200 Value *Slot = B.CreateInBoundsGEP(Ptr, First, Idx);
201 CB->setCalledOperand(B.CreateLoad(Ptr, Slot));
202 }
203 return true;
204}
205
206namespace {
207
208struct BPFFuncTableLegacy : public ModulePass {
209 static char ID;
210 BPFFuncTableLegacy() : ModulePass(ID) {}
211 StringRef getPassName() const override { return "BPF Function Table"; }
212 bool runOnModule(Module &M) override { return runFuncTable(M); }
213};
214
215} // namespace
216
217char BPFFuncTableLegacy::ID = 0;
218
219INITIALIZE_PASS(BPFFuncTableLegacy, DEBUG_TYPE, "BPF Function Table", false,
220 false)
221
222ModulePass *llvm::createBPFFuncTablePass() { return new BPFFuncTableLegacy(); }
223
uint64_t uint64_t
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
static bool isInText(const Function &F)
The address of a function in another section is the address of a program, e.g.
static bool runFuncTable(Module &M)
static bool isCallbackUse(const Use &U, SmallPtrSetImpl< const User * > &Seen)
A callback: bpf_loop(), bpf_timer_set_callback() and co.
static void replaceAddress(Function &F, Constant *Index)
static bool isAddressUse(const Use &U)
The use is the address of the function as a value.
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
#define DEBUG_TYPE
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
This file implements a map that provides insertion order iteration.
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
This file implements a set that has insertion order iteration characteristics.
static LLVM_ABI ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
static LLVM_ABI Constant * get(ArrayType *T, ArrayRef< Constant * > V)
static LLVM_ABI Constant * getIntToPtr(Constant *C, Type *Ty, bool OnlyIfReduced=false)
static LLVM_SUPPRESS_DEPRECATED_DECLARATIONS_POP Constant * getInBoundsPtrAdd(Constant *Ptr, Constant *Offset)
Create a getelementptr inbounds i8, ptr, offset constant expression.
Definition Constants.h:1550
static LLVM_ABI ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
This is an important base class in LLVM.
Definition Constant.h:44
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
Diagnostic information for unsupported feature in backend.
@ InternalLinkage
Rename collisions when linking (static functions).
Definition GlobalValue.h:60
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2909
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:76
This class implements a map that also provides access to all stored values in a deterministic order.
Definition MapVector.h:38
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition Pass.h:253
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
static PointerType * getUnqual(LLVMContext &C)
This constructs an opaque pointer to an object in the default address space (address space zero).
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
A SetVector that performs no allocations if smaller than a certain size.
Definition SetVector.h:345
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
static LLVM_ABI IntegerType * getInt64Ty(LLVMContext &C)
Definition Type.cpp:300
A Use represents the edge between a Value definition and its users.
Definition Use.h:35
LLVM Value Representation.
Definition Value.h:75
iterator_range< use_iterator > uses()
Definition Value.h:382
This is an optimization pass for GlobalISel generic memory operations.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1755
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:649
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1762
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
Definition ModRef.h:74
LLVM_ABI void appendToCompilerUsed(Module &M, ArrayRef< GlobalValue * > Values)
Adds global values to the llvm.compiler.used list.
ModulePass * createBPFFuncTablePass()
LLVM_ABI void appendToUsed(Module &M, ArrayRef< GlobalValue * > Values)
Adds global values to the llvm.used list.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
LLVM_ABI GlobalVariable * collectUsedGlobalVariables(const Module &M, SmallVectorImpl< GlobalValue * > &Vec, bool CompilerUsed)
Given "llvm.used" or "llvm.compiler.used" as a global name, collect the initializer elements of that ...
Definition Module.cpp:966