brintos

brintos / llvm-project-archived public Read only

0
0
Text · 17.8 KiB · 9fe7489 Raw
533 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9//  This file contains both code to deal with invoking "external" functions, but10//  also contains code that implements "exported" external functions.11//12//  There are currently two mechanisms for handling external functions in the13//  Interpreter.  The first is to implement lle_* wrapper functions that are14//  specific to well-known library functions which manually translate the15//  arguments from GenericValues and make the call.  If such a wrapper does16//  not exist, and libffi is available, then the Interpreter will attempt to17//  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 libffi25#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 <vector>45 46#ifdef HAVE_FFI_CALL47#ifdef HAVE_FFI_H48#include <ffi.h>49#define USE_LIBFFI50#elif HAVE_FFI_FFI_H51#include <ffi/ffi.h>52#define USE_LIBFFI53#endif54#endif55 56using namespace llvm;57 58namespace {59 60typedef GenericValue (*ExFunc)(FunctionType *, ArrayRef<GenericValue>);61typedef void (*RawFunc)();62 63struct Functions {64  sys::Mutex Lock;65  std::map<const Function *, ExFunc> ExportedFunctions;66  std::map<std::string, ExFunc> FuncNames;67#ifdef USE_LIBFFI68  std::map<const Function *, RawFunc> RawFunctions;69#endif70};71 72Functions &getFunctions() {73  static Functions F;74  return F;75}76 77} // anonymous namespace78 79static Interpreter *TheInterpreter;80 81static char getTypeID(Type *Ty) {82  switch (Ty->getTypeID()) {83  case Type::VoidTyID:    return 'V';84  case Type::IntegerTyID:85    switch (cast<IntegerType>(Ty)->getBitWidth()) {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    }93  case Type::FloatTyID:   return 'F';94  case Type::DoubleTyID:  return 'D';95  case Type::PointerTyID: return 'P';96  case Type::FunctionTyID:return 'M';97  case Type::StructTyID:  return 'T';98  case Type::ArrayTyID:   return 'A';99  default: return 'U';100  }101}102 103// Try to find address of external function given a Function object.104// Please note, that interpreter doesn't know how to assemble a105// real call in general case (this is JIT job), that's why it assumes,106// that all external functions has the same (and pretty "general") signature.107// The typical example of such functions are "lle_X_" ones.108static ExFunc lookupFunction(const Function *F) {109  // Function not found, look it up... start by figuring out what the110  // composite function name should be.111  std::string ExtName = "lle_";112  FunctionType *FT = F->getFunctionType();113  ExtName += getTypeID(FT->getReturnType());114  for (Type *T : FT->params())115    ExtName += getTypeID(T);116  ExtName += ("_" + F->getName()).str();117 118  auto &Fns = getFunctions();119  sys::ScopedLock Writer(Fns.Lock);120  ExFunc FnPtr = Fns.FuncNames[ExtName];121  if (!FnPtr)122    FnPtr = Fns.FuncNames[("lle_X_" + F->getName()).str()];123  if (!FnPtr)  // Try calling a generic function... if it exists...124    FnPtr = (ExFunc)(intptr_t)sys::DynamicLibrary::SearchForAddressOfSymbol(125        ("lle_X_" + F->getName()).str());126  if (FnPtr)127    Fns.ExportedFunctions.insert(std::make_pair(F, FnPtr)); // Cache for later128  return FnPtr;129}130 131#ifdef USE_LIBFFI132static ffi_type *ffiTypeFor(Type *Ty) {133  switch (Ty->getTypeID()) {134    case Type::VoidTyID: return &ffi_type_void;135    case Type::IntegerTyID:136      switch (cast<IntegerType>(Ty)->getBitWidth()) {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      }142      llvm_unreachable("Unhandled integer type bitwidth");143    case Type::FloatTyID:   return &ffi_type_float;144    case Type::DoubleTyID:  return &ffi_type_double;145    case Type::PointerTyID: return &ffi_type_pointer;146    default: break;147  }148  // TODO: Support other types such as StructTyID, ArrayTyID, OpaqueTyID, etc.149  report_fatal_error("Type could not be mapped for use with libffi.");150  return NULL;151}152 153static void *ffiValueFor(Type *Ty, const GenericValue &AV,154                         void *ArgDataPtr) {155  switch (Ty->getTypeID()) {156    case Type::IntegerTyID:157      switch (cast<IntegerType>(Ty)->getBitWidth()) {158        case 8: {159          int8_t *I8Ptr = (int8_t *) ArgDataPtr;160          *I8Ptr = (int8_t) AV.IntVal.getZExtValue();161          return ArgDataPtr;162        }163        case 16: {164          int16_t *I16Ptr = (int16_t *) ArgDataPtr;165          *I16Ptr = (int16_t) AV.IntVal.getZExtValue();166          return ArgDataPtr;167        }168        case 32: {169          int32_t *I32Ptr = (int32_t *) ArgDataPtr;170          *I32Ptr = (int32_t) AV.IntVal.getZExtValue();171          return ArgDataPtr;172        }173        case 64: {174          int64_t *I64Ptr = (int64_t *) ArgDataPtr;175          *I64Ptr = (int64_t) AV.IntVal.getZExtValue();176          return ArgDataPtr;177        }178      }179      llvm_unreachable("Unhandled integer type bitwidth");180    case Type::FloatTyID: {181      float *FloatPtr = (float *) ArgDataPtr;182      *FloatPtr = AV.FloatVal;183      return ArgDataPtr;184    }185    case Type::DoubleTyID: {186      double *DoublePtr = (double *) ArgDataPtr;187      *DoublePtr = AV.DoubleVal;188      return ArgDataPtr;189    }190    case Type::PointerTyID: {191      void **PtrPtr = (void **) ArgDataPtr;192      *PtrPtr = GVTOP(AV);193      return ArgDataPtr;194    }195    default: break;196  }197  // TODO: Support other types such as StructTyID, ArrayTyID, OpaqueTyID, etc.198  report_fatal_error("Type value could not be mapped for use with libffi.");199  return NULL;200}201 202static bool ffiInvoke(RawFunc Fn, Function *F, ArrayRef<GenericValue> ArgVals,203                      const DataLayout &TD, GenericValue &Result) {204  ffi_cif cif;205  FunctionType *FTy = F->getFunctionType();206  const unsigned NumArgs = F->arg_size();207 208  // TODO: We don't have type information about the remaining arguments, because209  // this information is never passed into ExecutionEngine::runFunction().210  if (ArgVals.size() > NumArgs && F->isVarArg()) {211    report_fatal_error("Calling external var arg function '" + F->getName()212                      + "' is not supported by the Interpreter.");213  }214 215  unsigned ArgBytes = 0;216 217  std::vector<ffi_type*> args(NumArgs);218  for (Function::const_arg_iterator A = F->arg_begin(), E = F->arg_end();219       A != E; ++A) {220    const unsigned ArgNo = A->getArgNo();221    Type *ArgTy = FTy->getParamType(ArgNo);222    args[ArgNo] = ffiTypeFor(ArgTy);223    ArgBytes += TD.getTypeStoreSize(ArgTy);224  }225 226  SmallVector<uint8_t, 128> ArgData;227  ArgData.resize(ArgBytes);228  uint8_t *ArgDataPtr = ArgData.data();229  SmallVector<void*, 16> values(NumArgs);230  for (Function::const_arg_iterator A = F->arg_begin(), E = F->arg_end();231       A != E; ++A) {232    const unsigned ArgNo = A->getArgNo();233    Type *ArgTy = FTy->getParamType(ArgNo);234    values[ArgNo] = ffiValueFor(ArgTy, ArgVals[ArgNo], ArgDataPtr);235    ArgDataPtr += TD.getTypeStoreSize(ArgTy);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) {243    SmallVector<uint8_t, 128> ret;244    if (RetTy->getTypeID() != Type::VoidTyID)245      ret.resize(TD.getTypeStoreSize(RetTy));246    ffi_call(&cif, Fn, ret.data(), values.data());247    switch (RetTy->getTypeID()) {248      case Type::IntegerTyID:249        switch (cast<IntegerType>(RetTy)->getBitWidth()) {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;256      case Type::FloatTyID:   Result.FloatVal   = *(float *) ret.data(); break;257      case Type::DoubleTyID:  Result.DoubleVal  = *(double*) ret.data(); break;258      case Type::PointerTyID: Result.PointerVal = *(void **) ret.data(); break;259      default: break;260    }261    return true;262  }263 264  return false;265}266#endif // USE_LIBFFI267 268GenericValue Interpreter::callExternalFunction(Function *F,269                                               ArrayRef<GenericValue> ArgVals) {270  TheInterpreter = this;271 272  auto &Fns = getFunctions();273  std::unique_lock<sys::Mutex> Guard(Fns.Lock);274 275  // Do a lookup to see if the function is in our cache... this should just be a276  // deferred annotation!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_LIBFFI286  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)290      sys::DynamicLibrary::SearchForAddressOfSymbol(std::string(F->getName()));291    if (!RawFn)292      RawFn = (RawFunc)(intptr_t)getPointerToGlobalIfAvailable(F);293    if (RawFn != 0)294      Fns.RawFunctions.insert(std::make_pair(F, RawFn)); // Cache for later295  } else {296    RawFn = RF->second;297  }298 299  Guard.unlock();300 301  GenericValue Result;302  if (RawFn != 0 && ffiInvoke(RawFn, F, ArgVals, getDataLayout(), Result))303    return Result;304#endif // USE_LIBFFI305 306  if (F->getName() == "__main")307    errs() << "Tried to execute an unknown external function: "308      << *F->getType() << " __main\n";309  else310    report_fatal_error("Tried to execute an unknown external function: " +311                       F->getName());312#ifndef USE_LIBFFI313  errs() << "Recompiling LLVM with --enable-libffi might help.\n";314#endif315  return GenericValue();316}317 318//===----------------------------------------------------------------------===//319//  Functions "exported" to the running application...320//321 322// void atexit(Function*)323static GenericValue lle_X_atexit(FunctionType *FT,324                                 ArrayRef<GenericValue> Args) {325  assert(Args.size() == 1);326  TheInterpreter->addAtExitHandler((Function*)GVTOP(Args[0]));327  GenericValue GV;328  GV.IntVal = 0;329  return GV;330}331 332// void exit(int)333static GenericValue lle_X_exit(FunctionType *FT, ArrayRef<GenericValue> Args) {334  TheInterpreter->exitCalled(Args[0]);335  return GenericValue();336}337 338// void abort(void)339static GenericValue lle_X_abort(FunctionType *FT, ArrayRef<GenericValue> Args) {340  //FIXME: should we report or raise here?341  //report_fatal_error("Interpreted program raised SIGABRT");342  raise (SIGABRT);343  return GenericValue();344}345 346// Silence warnings about sprintf. (See also347// https://github.com/llvm/llvm-project/issues/58086)348#if defined(__clang__)349#pragma clang diagnostic push350#pragma clang diagnostic ignored "-Wdeprecated-declarations"351#endif352// int sprintf(char *, const char *, ...) - a very rough implementation to make353// output useful.354static GenericValue lle_X_sprintf(FunctionType *FT,355                                  ArrayRef<GenericValue> Args) {356  char *OutputBuffer = (char *)GVTOP(Args[0]);357  const char *FmtStr = (const char *)GVTOP(Args[1]);358  unsigned ArgNo = 2;359 360  // printf should return # chars printed.  This is completely incorrect, but361  // close enough for now.362  GenericValue GV;363  GV.IntVal = APInt(32, strlen(FmtStr));364  while (true) {365    switch (*FmtStr) {366    case 0: return GV;             // Null terminator...367    default:                       // Normal nonspecial character368      sprintf(OutputBuffer++, "%c", *FmtStr++);369      break;370    case '\\': {                   // Handle escape codes371      sprintf(OutputBuffer, "%c%c", *FmtStr, *(FmtStr+1));372      FmtStr += 2; OutputBuffer += 2;373      break;374    }375    case '%': {                    // Handle format specifiers376      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' &&382             Last != 'o' && Last != 'x' && Last != 'X' && Last != 'e' &&383             Last != 'E' && Last != 'g' && Last != 'G' && Last != 'f' &&384             Last != 'p' && Last != 's' && Last != '%') {385        if (Last == 'l' || Last == 'L') HowLong++;  // Keep track of l's386        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            // Make sure we use %lld with a 64 bit argument because we might be404            // compiling LLI on a 32 bit compiler.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        } else412          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);425      memcpy(OutputBuffer, Buffer, Len + 1);426      OutputBuffer += Len;427      }428      break;429    }430  }431  return GV;432}433#if defined(__clang__)434#pragma clang diagnostic pop435#endif436 437// int printf(const char *, ...) - a very rough implementation to make output438// useful.439static GenericValue lle_X_printf(FunctionType *FT,440                                 ArrayRef<GenericValue> Args) {441  char Buffer[10000];442  std::vector<GenericValue> NewArgs;443  NewArgs.push_back(PTOGV((void*)&Buffer[0]));444  llvm::append_range(NewArgs, Args);445  GenericValue GV = lle_X_sprintf(FT, NewArgs);446  outs() << Buffer;447  return GV;448}449 450// int sscanf(const char *format, ...);451static GenericValue lle_X_sscanf(FunctionType *FT,452                                 ArrayRef<GenericValue> args) {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)457    Args[i] = (char*)GVTOP(args[i]);458 459  GenericValue GV;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// int scanf(const char *format, ...);466static GenericValue lle_X_scanf(FunctionType *FT, ArrayRef<GenericValue> args) {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)471    Args[i] = (char*)GVTOP(args[i]);472 473  GenericValue GV;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// int fprintf(FILE *, const char *, ...) - a very rough implementation to make480// output useful.481static GenericValue lle_X_fprintf(FunctionType *FT,482                                  ArrayRef<GenericValue> Args) {483  assert(Args.size() >= 2);484  char Buffer[10000];485  std::vector<GenericValue> NewArgs;486  NewArgs.push_back(PTOGV(Buffer));487  llvm::append_range(NewArgs, llvm::drop_begin(Args));488  GenericValue GV = lle_X_sprintf(FT, NewArgs);489 490  fputs(Buffer, (FILE *) GVTOP(Args[0]));491  return GV;492}493 494static GenericValue lle_X_memset(FunctionType *FT,495                                 ArrayRef<GenericValue> Args) {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  // llvm.memset.* returns void, lle_X_* returns GenericValue,500  // so here we return GenericValue with IntVal set to zero501  GenericValue GV;502  GV.IntVal = 0;503  return GV;504}505 506static GenericValue lle_X_memcpy(FunctionType *FT,507                                 ArrayRef<GenericValue> Args) {508  memcpy(GVTOP(Args[0]), GVTOP(Args[1]),509         (size_t)(Args[2].IntVal.getLimitedValue()));510 511  // llvm.memcpy* returns void, lle_X_* returns GenericValue,512  // so here we return GenericValue with IntVal set to zero513  GenericValue GV;514  GV.IntVal = 0;515  return GV;516}517 518void Interpreter::initializeExternalFunctions() {519  auto &Fns = getFunctions();520  sys::ScopedLock Writer(Fns.Lock);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;526  Fns.FuncNames["lle_X_sprintf"]      = lle_X_sprintf;527  Fns.FuncNames["lle_X_sscanf"]       = lle_X_sscanf;528  Fns.FuncNames["lle_X_scanf"]        = lle_X_scanf;529  Fns.FuncNames["lle_X_fprintf"]      = lle_X_fprintf;530  Fns.FuncNames["lle_X_memset"]       = lle_X_memset;531  Fns.FuncNames["lle_X_memcpy"]       = lle_X_memcpy;532}533