Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp
35271 views
1
//===-- ExternalFunctions.cpp - Implement External Functions --------------===//
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
// This file contains both code to deal with invoking "external" functions, but
10
// also contains code that implements "exported" external functions.
11
//
12
// There are currently two mechanisms for handling external functions in the
13
// Interpreter. The first is to implement lle_* wrapper functions that are
14
// specific to well-known library functions which manually translate the
15
// arguments from GenericValues and make the call. If such a wrapper does
16
// not exist, and libffi is available, then the Interpreter will attempt to
17
// invoke the function using libffi, after finding its address.
18
//
19
//===----------------------------------------------------------------------===//
20
21
#include "Interpreter.h"
22
#include "llvm/ADT/APInt.h"
23
#include "llvm/ADT/ArrayRef.h"
24
#include "llvm/Config/config.h" // Detect libffi
25
#include "llvm/ExecutionEngine/GenericValue.h"
26
#include "llvm/IR/DataLayout.h"
27
#include "llvm/IR/DerivedTypes.h"
28
#include "llvm/IR/Function.h"
29
#include "llvm/IR/Type.h"
30
#include "llvm/Support/Casting.h"
31
#include "llvm/Support/DynamicLibrary.h"
32
#include "llvm/Support/ErrorHandling.h"
33
#include "llvm/Support/Mutex.h"
34
#include "llvm/Support/raw_ostream.h"
35
#include <cassert>
36
#include <cmath>
37
#include <csignal>
38
#include <cstdint>
39
#include <cstdio>
40
#include <cstring>
41
#include <map>
42
#include <mutex>
43
#include <string>
44
#include <utility>
45
#include <vector>
46
47
#ifdef HAVE_FFI_CALL
48
#ifdef HAVE_FFI_H
49
#include <ffi.h>
50
#define USE_LIBFFI
51
#elif HAVE_FFI_FFI_H
52
#include <ffi/ffi.h>
53
#define USE_LIBFFI
54
#endif
55
#endif
56
57
using namespace llvm;
58
59
namespace {
60
61
typedef GenericValue (*ExFunc)(FunctionType *, ArrayRef<GenericValue>);
62
typedef void (*RawFunc)();
63
64
struct Functions {
65
sys::Mutex Lock;
66
std::map<const Function *, ExFunc> ExportedFunctions;
67
std::map<std::string, ExFunc> FuncNames;
68
#ifdef USE_LIBFFI
69
std::map<const Function *, RawFunc> RawFunctions;
70
#endif
71
};
72
73
Functions &getFunctions() {
74
static Functions F;
75
return F;
76
}
77
78
} // anonymous namespace
79
80
static Interpreter *TheInterpreter;
81
82
static char getTypeID(Type *Ty) {
83
switch (Ty->getTypeID()) {
84
case Type::VoidTyID: return 'V';
85
case Type::IntegerTyID:
86
switch (cast<IntegerType>(Ty)->getBitWidth()) {
87
case 1: return 'o';
88
case 8: return 'B';
89
case 16: return 'S';
90
case 32: return 'I';
91
case 64: return 'L';
92
default: return 'N';
93
}
94
case Type::FloatTyID: return 'F';
95
case Type::DoubleTyID: return 'D';
96
case Type::PointerTyID: return 'P';
97
case Type::FunctionTyID:return 'M';
98
case Type::StructTyID: return 'T';
99
case Type::ArrayTyID: return 'A';
100
default: return 'U';
101
}
102
}
103
104
// Try to find address of external function given a Function object.
105
// Please note, that interpreter doesn't know how to assemble a
106
// real call in general case (this is JIT job), that's why it assumes,
107
// that all external functions has the same (and pretty "general") signature.
108
// The typical example of such functions are "lle_X_" ones.
109
static ExFunc lookupFunction(const Function *F) {
110
// Function not found, look it up... start by figuring out what the
111
// composite function name should be.
112
std::string ExtName = "lle_";
113
FunctionType *FT = F->getFunctionType();
114
ExtName += getTypeID(FT->getReturnType());
115
for (Type *T : FT->params())
116
ExtName += getTypeID(T);
117
ExtName += ("_" + F->getName()).str();
118
119
auto &Fns = getFunctions();
120
sys::ScopedLock Writer(Fns.Lock);
121
ExFunc FnPtr = Fns.FuncNames[ExtName];
122
if (!FnPtr)
123
FnPtr = Fns.FuncNames[("lle_X_" + F->getName()).str()];
124
if (!FnPtr) // Try calling a generic function... if it exists...
125
FnPtr = (ExFunc)(intptr_t)sys::DynamicLibrary::SearchForAddressOfSymbol(
126
("lle_X_" + F->getName()).str());
127
if (FnPtr)
128
Fns.ExportedFunctions.insert(std::make_pair(F, FnPtr)); // Cache for later
129
return FnPtr;
130
}
131
132
#ifdef USE_LIBFFI
133
static ffi_type *ffiTypeFor(Type *Ty) {
134
switch (Ty->getTypeID()) {
135
case Type::VoidTyID: return &ffi_type_void;
136
case Type::IntegerTyID:
137
switch (cast<IntegerType>(Ty)->getBitWidth()) {
138
case 8: return &ffi_type_sint8;
139
case 16: return &ffi_type_sint16;
140
case 32: return &ffi_type_sint32;
141
case 64: return &ffi_type_sint64;
142
}
143
llvm_unreachable("Unhandled integer type bitwidth");
144
case Type::FloatTyID: return &ffi_type_float;
145
case Type::DoubleTyID: return &ffi_type_double;
146
case Type::PointerTyID: return &ffi_type_pointer;
147
default: break;
148
}
149
// TODO: Support other types such as StructTyID, ArrayTyID, OpaqueTyID, etc.
150
report_fatal_error("Type could not be mapped for use with libffi.");
151
return NULL;
152
}
153
154
static void *ffiValueFor(Type *Ty, const GenericValue &AV,
155
void *ArgDataPtr) {
156
switch (Ty->getTypeID()) {
157
case Type::IntegerTyID:
158
switch (cast<IntegerType>(Ty)->getBitWidth()) {
159
case 8: {
160
int8_t *I8Ptr = (int8_t *) ArgDataPtr;
161
*I8Ptr = (int8_t) AV.IntVal.getZExtValue();
162
return ArgDataPtr;
163
}
164
case 16: {
165
int16_t *I16Ptr = (int16_t *) ArgDataPtr;
166
*I16Ptr = (int16_t) AV.IntVal.getZExtValue();
167
return ArgDataPtr;
168
}
169
case 32: {
170
int32_t *I32Ptr = (int32_t *) ArgDataPtr;
171
*I32Ptr = (int32_t) AV.IntVal.getZExtValue();
172
return ArgDataPtr;
173
}
174
case 64: {
175
int64_t *I64Ptr = (int64_t *) ArgDataPtr;
176
*I64Ptr = (int64_t) AV.IntVal.getZExtValue();
177
return ArgDataPtr;
178
}
179
}
180
llvm_unreachable("Unhandled integer type bitwidth");
181
case Type::FloatTyID: {
182
float *FloatPtr = (float *) ArgDataPtr;
183
*FloatPtr = AV.FloatVal;
184
return ArgDataPtr;
185
}
186
case Type::DoubleTyID: {
187
double *DoublePtr = (double *) ArgDataPtr;
188
*DoublePtr = AV.DoubleVal;
189
return ArgDataPtr;
190
}
191
case Type::PointerTyID: {
192
void **PtrPtr = (void **) ArgDataPtr;
193
*PtrPtr = GVTOP(AV);
194
return ArgDataPtr;
195
}
196
default: break;
197
}
198
// TODO: Support other types such as StructTyID, ArrayTyID, OpaqueTyID, etc.
199
report_fatal_error("Type value could not be mapped for use with libffi.");
200
return NULL;
201
}
202
203
static bool ffiInvoke(RawFunc Fn, Function *F, ArrayRef<GenericValue> ArgVals,
204
const DataLayout &TD, GenericValue &Result) {
205
ffi_cif cif;
206
FunctionType *FTy = F->getFunctionType();
207
const unsigned NumArgs = F->arg_size();
208
209
// TODO: We don't have type information about the remaining arguments, because
210
// this information is never passed into ExecutionEngine::runFunction().
211
if (ArgVals.size() > NumArgs && F->isVarArg()) {
212
report_fatal_error("Calling external var arg function '" + F->getName()
213
+ "' is not supported by the Interpreter.");
214
}
215
216
unsigned ArgBytes = 0;
217
218
std::vector<ffi_type*> args(NumArgs);
219
for (Function::const_arg_iterator A = F->arg_begin(), E = F->arg_end();
220
A != E; ++A) {
221
const unsigned ArgNo = A->getArgNo();
222
Type *ArgTy = FTy->getParamType(ArgNo);
223
args[ArgNo] = ffiTypeFor(ArgTy);
224
ArgBytes += TD.getTypeStoreSize(ArgTy);
225
}
226
227
SmallVector<uint8_t, 128> ArgData;
228
ArgData.resize(ArgBytes);
229
uint8_t *ArgDataPtr = ArgData.data();
230
SmallVector<void*, 16> values(NumArgs);
231
for (Function::const_arg_iterator A = F->arg_begin(), E = F->arg_end();
232
A != E; ++A) {
233
const unsigned ArgNo = A->getArgNo();
234
Type *ArgTy = FTy->getParamType(ArgNo);
235
values[ArgNo] = ffiValueFor(ArgTy, ArgVals[ArgNo], ArgDataPtr);
236
ArgDataPtr += TD.getTypeStoreSize(ArgTy);
237
}
238
239
Type *RetTy = FTy->getReturnType();
240
ffi_type *rtype = ffiTypeFor(RetTy);
241
242
if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, NumArgs, rtype, args.data()) ==
243
FFI_OK) {
244
SmallVector<uint8_t, 128> ret;
245
if (RetTy->getTypeID() != Type::VoidTyID)
246
ret.resize(TD.getTypeStoreSize(RetTy));
247
ffi_call(&cif, Fn, ret.data(), values.data());
248
switch (RetTy->getTypeID()) {
249
case Type::IntegerTyID:
250
switch (cast<IntegerType>(RetTy)->getBitWidth()) {
251
case 8: Result.IntVal = APInt(8 , *(int8_t *) ret.data()); break;
252
case 16: Result.IntVal = APInt(16, *(int16_t*) ret.data()); break;
253
case 32: Result.IntVal = APInt(32, *(int32_t*) ret.data()); break;
254
case 64: Result.IntVal = APInt(64, *(int64_t*) ret.data()); break;
255
}
256
break;
257
case Type::FloatTyID: Result.FloatVal = *(float *) ret.data(); break;
258
case Type::DoubleTyID: Result.DoubleVal = *(double*) ret.data(); break;
259
case Type::PointerTyID: Result.PointerVal = *(void **) ret.data(); break;
260
default: break;
261
}
262
return true;
263
}
264
265
return false;
266
}
267
#endif // USE_LIBFFI
268
269
GenericValue Interpreter::callExternalFunction(Function *F,
270
ArrayRef<GenericValue> ArgVals) {
271
TheInterpreter = this;
272
273
auto &Fns = getFunctions();
274
std::unique_lock<sys::Mutex> Guard(Fns.Lock);
275
276
// Do a lookup to see if the function is in our cache... this should just be a
277
// deferred annotation!
278
std::map<const Function *, ExFunc>::iterator FI =
279
Fns.ExportedFunctions.find(F);
280
if (ExFunc Fn = (FI == Fns.ExportedFunctions.end()) ? lookupFunction(F)
281
: FI->second) {
282
Guard.unlock();
283
return Fn(F->getFunctionType(), ArgVals);
284
}
285
286
#ifdef USE_LIBFFI
287
std::map<const Function *, RawFunc>::iterator RF = Fns.RawFunctions.find(F);
288
RawFunc RawFn;
289
if (RF == Fns.RawFunctions.end()) {
290
RawFn = (RawFunc)(intptr_t)
291
sys::DynamicLibrary::SearchForAddressOfSymbol(std::string(F->getName()));
292
if (!RawFn)
293
RawFn = (RawFunc)(intptr_t)getPointerToGlobalIfAvailable(F);
294
if (RawFn != 0)
295
Fns.RawFunctions.insert(std::make_pair(F, RawFn)); // Cache for later
296
} else {
297
RawFn = RF->second;
298
}
299
300
Guard.unlock();
301
302
GenericValue Result;
303
if (RawFn != 0 && ffiInvoke(RawFn, F, ArgVals, getDataLayout(), Result))
304
return Result;
305
#endif // USE_LIBFFI
306
307
if (F->getName() == "__main")
308
errs() << "Tried to execute an unknown external function: "
309
<< *F->getType() << " __main\n";
310
else
311
report_fatal_error("Tried to execute an unknown external function: " +
312
F->getName());
313
#ifndef USE_LIBFFI
314
errs() << "Recompiling LLVM with --enable-libffi might help.\n";
315
#endif
316
return GenericValue();
317
}
318
319
//===----------------------------------------------------------------------===//
320
// Functions "exported" to the running application...
321
//
322
323
// void atexit(Function*)
324
static GenericValue lle_X_atexit(FunctionType *FT,
325
ArrayRef<GenericValue> Args) {
326
assert(Args.size() == 1);
327
TheInterpreter->addAtExitHandler((Function*)GVTOP(Args[0]));
328
GenericValue GV;
329
GV.IntVal = 0;
330
return GV;
331
}
332
333
// void exit(int)
334
static GenericValue lle_X_exit(FunctionType *FT, ArrayRef<GenericValue> Args) {
335
TheInterpreter->exitCalled(Args[0]);
336
return GenericValue();
337
}
338
339
// void abort(void)
340
static GenericValue lle_X_abort(FunctionType *FT, ArrayRef<GenericValue> Args) {
341
//FIXME: should we report or raise here?
342
//report_fatal_error("Interpreted program raised SIGABRT");
343
raise (SIGABRT);
344
return GenericValue();
345
}
346
347
// Silence warnings about sprintf. (See also
348
// https://github.com/llvm/llvm-project/issues/58086)
349
#if defined(__clang__)
350
#pragma clang diagnostic push
351
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
352
#endif
353
// int sprintf(char *, const char *, ...) - a very rough implementation to make
354
// output useful.
355
static GenericValue lle_X_sprintf(FunctionType *FT,
356
ArrayRef<GenericValue> Args) {
357
char *OutputBuffer = (char *)GVTOP(Args[0]);
358
const char *FmtStr = (const char *)GVTOP(Args[1]);
359
unsigned ArgNo = 2;
360
361
// printf should return # chars printed. This is completely incorrect, but
362
// close enough for now.
363
GenericValue GV;
364
GV.IntVal = APInt(32, strlen(FmtStr));
365
while (true) {
366
switch (*FmtStr) {
367
case 0: return GV; // Null terminator...
368
default: // Normal nonspecial character
369
sprintf(OutputBuffer++, "%c", *FmtStr++);
370
break;
371
case '\\': { // Handle escape codes
372
sprintf(OutputBuffer, "%c%c", *FmtStr, *(FmtStr+1));
373
FmtStr += 2; OutputBuffer += 2;
374
break;
375
}
376
case '%': { // Handle format specifiers
377
char FmtBuf[100] = "", Buffer[1000] = "";
378
char *FB = FmtBuf;
379
*FB++ = *FmtStr++;
380
char Last = *FB++ = *FmtStr++;
381
unsigned HowLong = 0;
382
while (Last != 'c' && Last != 'd' && Last != 'i' && Last != 'u' &&
383
Last != 'o' && Last != 'x' && Last != 'X' && Last != 'e' &&
384
Last != 'E' && Last != 'g' && Last != 'G' && Last != 'f' &&
385
Last != 'p' && Last != 's' && Last != '%') {
386
if (Last == 'l' || Last == 'L') HowLong++; // Keep track of l's
387
Last = *FB++ = *FmtStr++;
388
}
389
*FB = 0;
390
391
switch (Last) {
392
case '%':
393
memcpy(Buffer, "%", 2); break;
394
case 'c':
395
sprintf(Buffer, FmtBuf, uint32_t(Args[ArgNo++].IntVal.getZExtValue()));
396
break;
397
case 'd': case 'i':
398
case 'u': case 'o':
399
case 'x': case 'X':
400
if (HowLong >= 1) {
401
if (HowLong == 1 &&
402
TheInterpreter->getDataLayout().getPointerSizeInBits() == 64 &&
403
sizeof(long) < sizeof(int64_t)) {
404
// Make sure we use %lld with a 64 bit argument because we might be
405
// compiling LLI on a 32 bit compiler.
406
unsigned Size = strlen(FmtBuf);
407
FmtBuf[Size] = FmtBuf[Size-1];
408
FmtBuf[Size+1] = 0;
409
FmtBuf[Size-1] = 'l';
410
}
411
sprintf(Buffer, FmtBuf, Args[ArgNo++].IntVal.getZExtValue());
412
} else
413
sprintf(Buffer, FmtBuf,uint32_t(Args[ArgNo++].IntVal.getZExtValue()));
414
break;
415
case 'e': case 'E': case 'g': case 'G': case 'f':
416
sprintf(Buffer, FmtBuf, Args[ArgNo++].DoubleVal); break;
417
case 'p':
418
sprintf(Buffer, FmtBuf, (void*)GVTOP(Args[ArgNo++])); break;
419
case 's':
420
sprintf(Buffer, FmtBuf, (char*)GVTOP(Args[ArgNo++])); break;
421
default:
422
errs() << "<unknown printf code '" << *FmtStr << "'!>";
423
ArgNo++; break;
424
}
425
size_t Len = strlen(Buffer);
426
memcpy(OutputBuffer, Buffer, Len + 1);
427
OutputBuffer += Len;
428
}
429
break;
430
}
431
}
432
return GV;
433
}
434
#if defined(__clang__)
435
#pragma clang diagnostic pop
436
#endif
437
438
// int printf(const char *, ...) - a very rough implementation to make output
439
// useful.
440
static GenericValue lle_X_printf(FunctionType *FT,
441
ArrayRef<GenericValue> Args) {
442
char Buffer[10000];
443
std::vector<GenericValue> NewArgs;
444
NewArgs.push_back(PTOGV((void*)&Buffer[0]));
445
llvm::append_range(NewArgs, Args);
446
GenericValue GV = lle_X_sprintf(FT, NewArgs);
447
outs() << Buffer;
448
return GV;
449
}
450
451
// int sscanf(const char *format, ...);
452
static GenericValue lle_X_sscanf(FunctionType *FT,
453
ArrayRef<GenericValue> args) {
454
assert(args.size() < 10 && "Only handle up to 10 args to sscanf right now!");
455
456
char *Args[10];
457
for (unsigned i = 0; i < args.size(); ++i)
458
Args[i] = (char*)GVTOP(args[i]);
459
460
GenericValue GV;
461
GV.IntVal = APInt(32, sscanf(Args[0], Args[1], Args[2], Args[3], Args[4],
462
Args[5], Args[6], Args[7], Args[8], Args[9]));
463
return GV;
464
}
465
466
// int scanf(const char *format, ...);
467
static GenericValue lle_X_scanf(FunctionType *FT, ArrayRef<GenericValue> args) {
468
assert(args.size() < 10 && "Only handle up to 10 args to scanf right now!");
469
470
char *Args[10];
471
for (unsigned i = 0; i < args.size(); ++i)
472
Args[i] = (char*)GVTOP(args[i]);
473
474
GenericValue GV;
475
GV.IntVal = APInt(32, scanf( Args[0], Args[1], Args[2], Args[3], Args[4],
476
Args[5], Args[6], Args[7], Args[8], Args[9]));
477
return GV;
478
}
479
480
// int fprintf(FILE *, const char *, ...) - a very rough implementation to make
481
// output useful.
482
static GenericValue lle_X_fprintf(FunctionType *FT,
483
ArrayRef<GenericValue> Args) {
484
assert(Args.size() >= 2);
485
char Buffer[10000];
486
std::vector<GenericValue> NewArgs;
487
NewArgs.push_back(PTOGV(Buffer));
488
NewArgs.insert(NewArgs.end(), Args.begin()+1, Args.end());
489
GenericValue GV = lle_X_sprintf(FT, NewArgs);
490
491
fputs(Buffer, (FILE *) GVTOP(Args[0]));
492
return GV;
493
}
494
495
static GenericValue lle_X_memset(FunctionType *FT,
496
ArrayRef<GenericValue> Args) {
497
int val = (int)Args[1].IntVal.getSExtValue();
498
size_t len = (size_t)Args[2].IntVal.getZExtValue();
499
memset((void *)GVTOP(Args[0]), val, len);
500
// llvm.memset.* returns void, lle_X_* returns GenericValue,
501
// so here we return GenericValue with IntVal set to zero
502
GenericValue GV;
503
GV.IntVal = 0;
504
return GV;
505
}
506
507
static GenericValue lle_X_memcpy(FunctionType *FT,
508
ArrayRef<GenericValue> Args) {
509
memcpy(GVTOP(Args[0]), GVTOP(Args[1]),
510
(size_t)(Args[2].IntVal.getLimitedValue()));
511
512
// llvm.memcpy* returns void, lle_X_* returns GenericValue,
513
// so here we return GenericValue with IntVal set to zero
514
GenericValue GV;
515
GV.IntVal = 0;
516
return GV;
517
}
518
519
void Interpreter::initializeExternalFunctions() {
520
auto &Fns = getFunctions();
521
sys::ScopedLock Writer(Fns.Lock);
522
Fns.FuncNames["lle_X_atexit"] = lle_X_atexit;
523
Fns.FuncNames["lle_X_exit"] = lle_X_exit;
524
Fns.FuncNames["lle_X_abort"] = lle_X_abort;
525
526
Fns.FuncNames["lle_X_printf"] = lle_X_printf;
527
Fns.FuncNames["lle_X_sprintf"] = lle_X_sprintf;
528
Fns.FuncNames["lle_X_sscanf"] = lle_X_sscanf;
529
Fns.FuncNames["lle_X_scanf"] = lle_X_scanf;
530
Fns.FuncNames["lle_X_fprintf"] = lle_X_fprintf;
531
Fns.FuncNames["lle_X_memset"] = lle_X_memset;
532
Fns.FuncNames["lle_X_memcpy"] = lle_X_memcpy;
533
}
534
535