LLVM: lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

24#include "llvm/Config/config.h"

35#include

36#include

37#include

38#include

39#include

40#include

41#include

42#include

43#include

44#include

45

46#ifdef HAVE_FFI_CALL

47#ifdef HAVE_FFI_H

48#include <ffi.h>

49#define USE_LIBFFI

50#elif HAVE_FFI_FFI_H

51#include <ffi/ffi.h>

52#define USE_LIBFFI

53#endif

54#endif

55

56using namespace llvm;

57

58namespace {

59

61typedef void (*RawFunc)();

62

63struct Functions {

65 std::map<const Function *, ExFunc> ExportedFunctions;

66 std::map<std::string, ExFunc> FuncNames;

67#ifdef USE_LIBFFI

68 std::map<const Function *, RawFunc> RawFunctions;

69#endif

70};

71

72Functions &getFunctions() {

73 static Functions F;

74 return F;

75}

76

77}

78

80

82 switch (Ty->getTypeID()) {

86 case 1: return 'o';

87 case 8: return 'B';

88 case 16: return 'S';

89 case 32: return 'I';

90 case 64: return 'L';

91 default: return 'N';

92 }

99 default: return 'U';

100 }

101}

102

103

104

105

106

107

109

110

111 std::string ExtName = "lle_";

113 ExtName += getTypeID(FT->getReturnType());

114 for (Type *T : FT->params())

116 ExtName += ("_" + F->getName()).str();

117

118 auto &Fns = getFunctions();

120 ExFunc FnPtr = Fns.FuncNames[ExtName];

121 if (!FnPtr)

122 FnPtr = Fns.FuncNames[("lle_X_" + F->getName()).str()];

123 if (!FnPtr)

125 ("lle_X_" + F->getName()).str());

126 if (FnPtr)

127 Fns.ExportedFunctions.insert(std::make_pair(F, FnPtr));

128 return FnPtr;

129}

130

131#ifdef USE_LIBFFI

132static ffi_type *ffiTypeFor(Type *Ty) {

133 switch (Ty->getTypeID()) {

137 case 8: return &ffi_type_sint8;

138 case 16: return &ffi_type_sint16;

139 case 32: return &ffi_type_sint32;

140 case 64: return &ffi_type_sint64;

141 }

146 default: break;

147 }

148

150 return NULL;

151}

152

154 void *ArgDataPtr) {

155 switch (Ty->getTypeID()) {

158 case 8: {

159 int8_t *I8Ptr = (int8_t *) ArgDataPtr;

161 return ArgDataPtr;

162 }

163 case 16: {

164 int16_t *I16Ptr = (int16_t *) ArgDataPtr;

166 return ArgDataPtr;

167 }

168 case 32: {

169 int32_t *I32Ptr = (int32_t *) ArgDataPtr;

171 return ArgDataPtr;

172 }

173 case 64: {

174 int64_t *I64Ptr = (int64_t *) ArgDataPtr;

176 return ArgDataPtr;

177 }

178 }

181 float *FloatPtr = (float *) ArgDataPtr;

183 return ArgDataPtr;

184 }

186 double *DoublePtr = (double *) ArgDataPtr;

188 return ArgDataPtr;

189 }

191 void **PtrPtr = (void **) ArgDataPtr;

192 *PtrPtr = GVTOP(AV);

193 return ArgDataPtr;

194 }

195 default: break;

196 }

197

198 report_fatal_error("Type value could not be mapped for use with libffi.");

199 return NULL;

200}

201

204 ffi_cif cif;

206 const unsigned NumArgs = F->arg_size();

207

208

209

210 if (ArgVals.size() > NumArgs && F->isVarArg()) {

212 + "' is not supported by the Interpreter.");

213 }

214

215 unsigned ArgBytes = 0;

216

217 std::vector<ffi_type*> args(NumArgs);

219 A != E; ++A) {

220 const unsigned ArgNo = A->getArgNo();

221 Type *ArgTy = FTy->getParamType(ArgNo);

222 args[ArgNo] = ffiTypeFor(ArgTy);

224 }

225

227 ArgData.resize(ArgBytes);

231 A != E; ++A) {

232 const unsigned ArgNo = A->getArgNo();

233 Type *ArgTy = FTy->getParamType(ArgNo);

234 values[ArgNo] = ffiValueFor(ArgTy, ArgVals[ArgNo], ArgDataPtr);

236 }

237

238 Type *RetTy = FTy->getReturnType();

239 ffi_type *rtype = ffiTypeFor(RetTy);

240

241 if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, NumArgs, rtype, args.data()) ==

242 FFI_OK) {

246 ffi_call(&cif, Fn, ret.data(), values.data());

250 case 8: Result.IntVal = APInt(8 , *(int8_t *) ret.data()); break;

251 case 16: Result.IntVal = APInt(16, *(int16_t*) ret.data()); break;

252 case 32: Result.IntVal = APInt(32, *(int32_t*) ret.data()); break;

253 case 64: Result.IntVal = APInt(64, *(int64_t*) ret.data()); break;

254 }

255 break;

259 default: break;

260 }

261 return true;

262 }

263

264 return false;

265}

266#endif

267

271

272 auto &Fns = getFunctions();

273 std::unique_locksys::Mutex Guard(Fns.Lock);

274

275

276

277 std::map<const Function *, ExFunc>::iterator FI =

278 Fns.ExportedFunctions.find(F);

279 if (ExFunc Fn = (FI == Fns.ExportedFunctions.end()) ? lookupFunction(F)

280 : FI->second) {

281 Guard.unlock();

282 return Fn(F->getFunctionType(), ArgVals);

283 }

284

285#ifdef USE_LIBFFI

286 std::map<const Function *, RawFunc>::iterator RF = Fns.RawFunctions.find(F);

287 RawFunc RawFn;

288 if (RF == Fns.RawFunctions.end()) {

289 RawFn = (RawFunc)(intptr_t)

291 if (!RawFn)

293 if (RawFn != 0)

294 Fns.RawFunctions.insert(std::make_pair(F, RawFn));

295 } else {

296 RawFn = RF->second;

297 }

298

299 Guard.unlock();

300

302 if (RawFn != 0 && ffiInvoke(RawFn, F, ArgVals, getDataLayout(), Result))

303 return Result;

304#endif

305

306 if (F->getName() == "__main")

307 errs() << "Tried to execute an unknown external function: "

308 << *F->getType() << " __main\n";

309 else

310 report_fatal_error("Tried to execute an unknown external function: " +

311 F->getName());

312#ifndef USE_LIBFFI

313 errs() << "Recompiling LLVM with --enable-libffi might help.\n";

314#endif

316}

317

318

319

320

321

322

325 assert(Args.size() == 1);

329 return GV;

330}

331

332

337

338

340

341

342 raise (SIGABRT);

344}

345

346

347

348#if defined(__clang__)

349#pragma clang diagnostic push

350#pragma clang diagnostic ignored "-Wdeprecated-declarations"

351#endif

352

353

357 const char *FmtStr = (const char *)GVTOP(Args[1]);

358 unsigned ArgNo = 2;

359

360

361

364 while (true) {

365 switch (*FmtStr) {

366 case 0: return GV;

367 default:

369 break;

370 case '\\': {

371 sprintf(OutputBuffer, "%c%c", *FmtStr, *(FmtStr+1));

373 break;

374 }

375 case '%': {

376 char FmtBuf[100] = "", Buffer[1000] = "";

377 char *FB = FmtBuf;

378 *FB++ = *FmtStr++;

379 char Last = *FB++ = *FmtStr++;

380 unsigned HowLong = 0;

381 while (Last != 'c' && Last != 'd' && Last != 'i' && Last != 'u' &&

385 if (Last == 'l' || Last == 'L') HowLong++;

386 Last = *FB++ = *FmtStr++;

387 }

388 *FB = 0;

389

390 switch (Last) {

391 case '%':

392 memcpy(Buffer, "%", 2); break;

393 case 'c':

394 sprintf(Buffer, FmtBuf, uint32_t(Args[ArgNo++].IntVal.getZExtValue()));

395 break;

396 case 'd': case 'i':

397 case 'u': case 'o':

398 case 'x': case 'X':

399 if (HowLong >= 1) {

400 if (HowLong == 1 &&

401 TheInterpreter->getDataLayout().getPointerSizeInBits() == 64 &&

402 sizeof(long) < sizeof(int64_t)) {

403

404

405 unsigned Size = strlen(FmtBuf);

406 FmtBuf[Size] = FmtBuf[Size-1];

407 FmtBuf[Size+1] = 0;

408 FmtBuf[Size-1] = 'l';

409 }

410 sprintf(Buffer, FmtBuf, Args[ArgNo++].IntVal.getZExtValue());

411 } else

412 sprintf(Buffer, FmtBuf,uint32_t(Args[ArgNo++].IntVal.getZExtValue()));

413 break;

414 case 'e': case 'E': case 'g': case 'G': case 'f':

415 sprintf(Buffer, FmtBuf, Args[ArgNo++].DoubleVal); break;

416 case 'p':

417 sprintf(Buffer, FmtBuf, (void*)GVTOP(Args[ArgNo++])); break;

418 case 's':

419 sprintf(Buffer, FmtBuf, (char*)GVTOP(Args[ArgNo++])); break;

420 default:

421 errs() << "<unknown printf code '" << *FmtStr << "'!>";

422 ArgNo++; break;

423 }

424 size_t Len = strlen(Buffer);

427 }

428 break;

429 }

430 }

431 return GV;

432}

433#if defined(__clang__)

434#pragma clang diagnostic pop

435#endif

436

437

438

441 char Buffer[10000];

442 std::vector NewArgs;

443 NewArgs.push_back(PTOGV((void*)&Buffer[0]));

446 outs() << Buffer;

447 return GV;

448}

449

450

453 assert(args.size() < 10 && "Only handle up to 10 args to sscanf right now!");

454

455 char *Args[10];

456 for (unsigned i = 0; i < args.size(); ++i)

458

460 GV.IntVal = APInt(32, sscanf(Args[0], Args[1], Args[2], Args[3], Args[4],

461 Args[5], Args[6], Args[7], Args[8], Args[9]));

462 return GV;

463}

464

465

467 assert(args.size() < 10 && "Only handle up to 10 args to scanf right now!");

468

469 char *Args[10];

470 for (unsigned i = 0; i < args.size(); ++i)

472

474 GV.IntVal = APInt(32, scanf( Args[0], Args[1], Args[2], Args[3], Args[4],

475 Args[5], Args[6], Args[7], Args[8], Args[9]));

476 return GV;

477}

478

479

480

483 assert(Args.size() >= 2);

484 char Buffer[10000];

485 std::vector NewArgs;

486 NewArgs.push_back(PTOGV(Buffer));

489

490 fputs(Buffer, (FILE *) GVTOP(Args[0]));

491 return GV;

492}

493

496 int val = (int)Args[1].IntVal.getSExtValue();

497 size_t len = (size_t)Args[2].IntVal.getZExtValue();

498 memset((void *)GVTOP(Args[0]), val, len);

499

500

503 return GV;

504}

505

508 memcpy(GVTOP(Args[0]), GVTOP(Args[1]),

509 (size_t)(Args[2].IntVal.getLimitedValue()));

510

511

512

515 return GV;

516}

517

518void Interpreter::initializeExternalFunctions() {

519 auto &Fns = getFunctions();

521 Fns.FuncNames["lle_X_atexit"] = lle_X_atexit;

522 Fns.FuncNames["lle_X_exit"] = lle_X_exit;

523 Fns.FuncNames["lle_X_abort"] = lle_X_abort;

524

525 Fns.FuncNames["lle_X_printf"] = lle_X_printf;

527 Fns.FuncNames["lle_X_sscanf"] = lle_X_sscanf;

528 Fns.FuncNames["lle_X_scanf"] = lle_X_scanf;

530 Fns.FuncNames["lle_X_memset"] = lle_X_memset;

531 Fns.FuncNames["lle_X_memcpy"] = lle_X_memcpy;

532}

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

This file implements a class to represent arbitrary precision integral constant values and operations...

static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")

static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")

static ExFunc lookupFunction(const Function *F)

Definition ExternalFunctions.cpp:108

static Interpreter * TheInterpreter

Definition ExternalFunctions.cpp:79

static GenericValue lle_X_memset(FunctionType *FT, ArrayRef< GenericValue > Args)

Definition ExternalFunctions.cpp:494

static char getTypeID(Type *Ty)

Definition ExternalFunctions.cpp:81

static GenericValue lle_X_fprintf(FunctionType *FT, ArrayRef< GenericValue > Args)

Definition ExternalFunctions.cpp:481

static GenericValue lle_X_scanf(FunctionType *FT, ArrayRef< GenericValue > args)

Definition ExternalFunctions.cpp:466

static GenericValue lle_X_printf(FunctionType *FT, ArrayRef< GenericValue > Args)

Definition ExternalFunctions.cpp:439

static GenericValue lle_X_memcpy(FunctionType *FT, ArrayRef< GenericValue > Args)

Definition ExternalFunctions.cpp:506

static GenericValue lle_X_atexit(FunctionType *FT, ArrayRef< GenericValue > Args)

Definition ExternalFunctions.cpp:323

static GenericValue lle_X_sscanf(FunctionType *FT, ArrayRef< GenericValue > args)

Definition ExternalFunctions.cpp:451

static GenericValue lle_X_abort(FunctionType *FT, ArrayRef< GenericValue > Args)

Definition ExternalFunctions.cpp:339

static GenericValue lle_X_exit(FunctionType *FT, ArrayRef< GenericValue > Args)

Definition ExternalFunctions.cpp:333

static GenericValue lle_X_sprintf(FunctionType *FT, ArrayRef< GenericValue > Args)

Definition ExternalFunctions.cpp:354

static unsigned getBitWidth(Type *Ty, const DataLayout &DL)

Returns the bitwidth of the given scalar or pointer type.

Class for arbitrary precision integers.

uint64_t getZExtValue() const

Get zero extended value.

ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...

size_t size() const

size - Get the array size.

A parsed version of the target data layout string in and methods for querying it.

TypeSize getTypeStoreSize(Type *Ty) const

Returns the maximum number of bytes that may be overwritten by storing the specified type.

const DataLayout & getDataLayout() const

void * getPointerToGlobalIfAvailable(StringRef S)

getPointerToGlobalIfAvailable - This returns the address of the specified global value if it is has a...

const Argument * const_arg_iterator

GenericValue callExternalFunction(Function *F, ArrayRef< GenericValue > ArgVals)

Definition ExternalFunctions.cpp:268

pointer data()

Return a pointer to the vector's buffer, even if empty().

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.

@ VoidTyID

type with no size

@ FloatTyID

32-bit floating point type

@ IntegerTyID

Arbitrary bit width integers.

@ DoubleTyID

64-bit floating point type

TypeID getTypeID() const

Return the type id for the type.

static LLVM_ABI void * SearchForAddressOfSymbol(const char *symbolName)

This function will search through all previously loaded dynamic libraries for the symbol symbolName.

#define llvm_unreachable(msg)

Marks that the current location is not supposed to be reachable.

ValuesClass values(OptsTy... Options)

Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...

SmartMutex< false > Mutex

Mutex - A standard, always enforced mutex.

SmartScopedLock< false > ScopedLock

This is an optimization pass for GlobalISel generic memory operations.

auto drop_begin(T &&RangeOrContainer, size_t N=1)

Return a range covering RangeOrContainer with the first N elements excluded.

LLVM_ABI raw_fd_ostream & outs()

This returns a reference to a raw_fd_ostream for standard output.

void append_range(Container &C, Range &&R)

Wrapper function to append range R to container C.

GenericValue PTOGV(void *P)

LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)

LLVM_ABI raw_fd_ostream & errs()

This returns a reference to a raw_ostream for standard error.

void * GVTOP(const GenericValue &GV)

decltype(auto) cast(const From &Val)

cast - Return the argument parameter cast to the specified type.