1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
|
//===- RewritePNaClLibraryCalls.cpp - PNaCl library calls to intrinsics ---===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass replaces calls to known library functions with calls to intrinsics
// that are part of the PNaCl stable bitcode ABI.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/NaCl.h"
using namespace llvm;
namespace {
class RewritePNaClLibraryCalls : public ModulePass {
public:
static char ID;
RewritePNaClLibraryCalls() :
ModulePass(ID), TheModule(NULL) {
// This is a module pass because it may have to introduce
// intrinsic declarations into the module and modify a global function.
initializeRewritePNaClLibraryCallsPass(*PassRegistry::getPassRegistry());
}
virtual bool runOnModule(Module &M);
private:
/// Rewrites the given \p Call of setjmp to a direct intrinsic call.
void rewriteSetjmpCall(CallInst *Call);
/// Rewrites the given \p Call of longjmp to a direct intrinsic call.
void rewriteLongjmpCall(CallInst *Call);
/// Populates the body of longjmp as a wrapper of the intrinsic call.
/// Should only be called once. Modifies the given \p LongjmpFunc.
void populateLongjmpWrapper(Function *LongjmpFunc);
/// Sanity check that the types of these functions are what we expect them
/// to be.
void sanityCheckSetjmpFunc(Function *SetjmpFunc);
void sanityCheckLongjmpFunc(Function *LongjmpFunc);
/// The module this pass runs on.
Module *TheModule;
};
}
char RewritePNaClLibraryCalls::ID = 0;
INITIALIZE_PASS(RewritePNaClLibraryCalls, "rewrite-pnacl-library-calls",
"Rewrite PNaCl library calls to stable intrinsics",
false, false)
bool RewritePNaClLibraryCalls::runOnModule(Module &M) {
TheModule = &M;
bool Changed = false;
// Iterate over all uses of the setjmp, if it exists in the module with
// external linkage. If it exists but the linkage is not external, this may
// come from code that defines its own function named setjmp and doesn't
// include <setjmp.h>. In such a case we leave the code as it is.
//
// The calls are replaced with intrinsics. All other uses of setjmp are
// disallowed (taking the address of setjmp is disallowed in C and C++).
Function *SetjmpFunc = TheModule->getFunction("setjmp");
if (SetjmpFunc && SetjmpFunc->hasExternalLinkage()) {
sanityCheckSetjmpFunc(SetjmpFunc);
for (Value::use_iterator UI = SetjmpFunc->use_begin(),
UE = SetjmpFunc->use_end(); UI != UE;) {
Value *Use = *UI++;
if (CallInst *Call = dyn_cast<CallInst>(Use)) {
rewriteSetjmpCall(Call);
Changed = true;
} else {
report_fatal_error("Taking the address of setjmp is invalid");
}
}
}
// For longjmp things are a little more complicated, since longjmp's address
// can be taken. Therefore, longjmp can appear in a variety of Uses. The
// common case is still a direct call and we want that to be as efficient as
// possible, so we rewrite it into a direct intrinsic call. If there are other
// uses, the actual body of longjmp is populated with a wrapper that calls
// the intrinsic.
Function *LongjmpFunc = TheModule->getFunction("longjmp");
if (LongjmpFunc && LongjmpFunc->hasExternalLinkage()) {
sanityCheckLongjmpFunc(LongjmpFunc);
for (Value::use_iterator UI = LongjmpFunc->use_begin(),
UE = LongjmpFunc->use_end(); UI != UE;) {
Value *Use = *UI++;
if (CallInst *Call = dyn_cast<CallInst>(Use)) {
rewriteLongjmpCall(Call);
Changed = true;
}
}
// If additional uses remain, these aren't calls; populate the wrapper.
if (!LongjmpFunc->use_empty()) {
populateLongjmpWrapper(LongjmpFunc);
Changed = true;
}
}
return Changed;
}
void RewritePNaClLibraryCalls::rewriteSetjmpCall(CallInst *Call) {
// Find the intrinsic function.
Function *NaClSetjmpFunc = Intrinsic::getDeclaration(TheModule,
Intrinsic::nacl_setjmp);
// Cast the jmp_buf argument to the type NaClSetjmpCall expects.
Type *PtrTy = NaClSetjmpFunc->getFunctionType()->getParamType(0);
BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy,
"jmp_buf_i8", Call);
const DebugLoc &DLoc = Call->getDebugLoc();
JmpBufCast->setDebugLoc(DLoc);
// Emit the updated call.
SmallVector<Value *, 1> Args;
Args.push_back(JmpBufCast);
CallInst *NaClSetjmpCall = CallInst::Create(NaClSetjmpFunc, Args, "", Call);
NaClSetjmpCall->setDebugLoc(DLoc);
NaClSetjmpCall->takeName(Call);
// Replace the original call.
Call->replaceAllUsesWith(NaClSetjmpCall);
Call->eraseFromParent();
}
void RewritePNaClLibraryCalls::sanityCheckLongjmpFunc(Function *LongjmpFunc) {
FunctionType *FTy = LongjmpFunc->getFunctionType();
if (!(FTy->getNumParams() == 2 &&
FTy->getReturnType()->isVoidTy() &&
FTy->getParamType(0)->isPointerTy() &&
FTy->getParamType(1)->isIntegerTy())) {
report_fatal_error("Wrong signature of longjmp");
}
}
void RewritePNaClLibraryCalls::sanityCheckSetjmpFunc(Function *SetjmpFunc) {
FunctionType *FTy = SetjmpFunc->getFunctionType();
if (!(FTy->getNumParams() == 1 &&
FTy->getReturnType()->isIntegerTy() &&
FTy->getParamType(0)->isPointerTy())) {
report_fatal_error("Wrong signature of setjmp");
}
}
void RewritePNaClLibraryCalls::rewriteLongjmpCall(CallInst *Call) {
// Find the intrinsic function.
Function *NaClLongjmpFunc = Intrinsic::getDeclaration(
TheModule, Intrinsic::nacl_longjmp);
// Cast the jmp_buf argument to the type NaClLongjmpCall expects.
Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0);
BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy,
"jmp_buf_i8", Call);
const DebugLoc &DLoc = Call->getDebugLoc();
JmpBufCast->setDebugLoc(DLoc);
// Emit the call.
SmallVector<Value *, 2> Args;
Args.push_back(JmpBufCast);
Args.push_back(Call->getArgOperand(1));
CallInst *NaClLongjmpCall = CallInst::Create(NaClLongjmpFunc, Args, "", Call);
NaClLongjmpCall->setDebugLoc(DLoc);
// No takeName here since longjmp is a void call that does not get assigned to
// a value.
// Remove the original call. There's no need for RAUW because longjmp
// returns void.
Call->eraseFromParent();
}
void RewritePNaClLibraryCalls::populateLongjmpWrapper(Function *LongjmpFunc) {
assert(LongjmpFunc->size() == 0 &&
"Expected to be called when longjmp has an empty body");
// Populate longjmp with code.
LLVMContext &Context = TheModule->getContext();
BasicBlock *BB = BasicBlock::Create(Context, "entry", LongjmpFunc);
Function::arg_iterator LongjmpArgs = LongjmpFunc->arg_begin();
Value *EnvArg = LongjmpArgs++;
EnvArg->setName("env");
Value *ValArg = LongjmpArgs++;
ValArg->setName("val");
// Find the intrinsic function.
Function *NaClLongjmpFunc = Intrinsic::getDeclaration(
TheModule, Intrinsic::nacl_longjmp);
// Cast the jmp_buf argument to the type NaClLongjmpCall expects.
Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0);
BitCastInst *JmpBufCast = new BitCastInst(EnvArg, PtrTy, "jmp_buf_i8", BB);
// Emit the call.
SmallVector<Value *, 2> Args;
Args.push_back(JmpBufCast);
Args.push_back(ValArg);
CallInst::Create(NaClLongjmpFunc, Args, "", BB);
// Insert an unreachable instruction to terminate this function since longjmp
// does not return.
new UnreachableInst(Context, BB);
// Finally, set the linkage to internal
LongjmpFunc->setLinkage(Function::InternalLinkage);
}
ModulePass *llvm::createRewritePNaClLibraryCallsPass() {
return new RewritePNaClLibraryCalls();
}
|