llvm::Function* createPrintf(CodeGenContext& context) { std::vector<llvm::Type *> printf_arg_types; printf_arg_types.push_back(llvm::Type::getInt8PtrTy(llvm::getGlobalContext())); auto printf_type = llvm::FunctionType::get(llvm::Type::getInt32Ty(getGlobalContext()), printf_arg_types, true); auto func = llvm::Function::Create(printf_type, llvm::Function::ExternalLinkage, llvm::Twine("printf"), context.module); func->setCallingConv(llvm::CallingConv::C); return func; }
// Iterate over the list of external functions and insert them as // global functions. static void InitExternalCode(NativeModulePtr natMod, llvm::Module *M) { for (auto e : natMod->getExtCalls()) { auto conv = e->getCallingConvention(); auto argCount = e->getNumArgs(); auto symName = e->getSymbolName(); auto funcSign = e->getFunctionSignature(); // Create the function if it is not already there. auto &C = M->getContext(); auto F = M->getFunction(symName); if (F) { continue; } if (ExternalCodeRef::McsemaCall == conv) { // normal mcsema function prototypes F = llvm::dyn_cast<llvm::Function>(M->getOrInsertFunction( ArchNameMcSemaCall(symName), LiftedFunctionType())); ArchSetCallingConv(M, F); F->setLinkage(llvm::GlobalValue::ExternalLinkage); continue; } std::vector<llvm::Type *> arguments; llvm::Type *returnType = nullptr; // Create arguments. const auto Arch = SystemArch(M); const auto OS = SystemOS(M); for (auto i = 0; i < argCount; i++) { if (_X86_64_ == Arch) { if (llvm::Triple::Win32 == OS) { if (funcSign.c_str()[i] == 'F') { arguments.push_back(llvm::Type::getDoubleTy(C)); } else { arguments.push_back(llvm::Type::getInt64Ty(C)); } } else if (llvm::Triple::Linux == OS) { arguments.push_back(llvm::Type::getInt64Ty(C)); } else { TASSERT(false, "Unknown OS Type!"); } } else { arguments.push_back(llvm::Type::getInt32Ty(C)); } } //create function type switch (e->getReturnType()) { case ExternalCodeRef::NoReturn: case ExternalCodeRef::VoidTy: returnType = llvm::Type::getVoidTy(C); break; case ExternalCodeRef::Unknown: case ExternalCodeRef::IntTy: if (natMod->is64Bit()) { returnType = llvm::Type::getInt64Ty(C); } else { returnType = llvm::Type::getInt32Ty(C); } break; default: throw TErr( __LINE__, __FILE__, "Encountered an unknown return type while translating function"); } auto FTy = llvm::FunctionType::get(returnType, arguments, false); if (e->isWeak()) { F = llvm::Function::Create(FTy, llvm::GlobalValue::ExternalWeakLinkage, symName, M); } else { F = llvm::Function::Create(FTy, llvm::GlobalValue::ExternalLinkage, symName, M); } if (e->getReturnType() == ExternalCodeRef::NoReturn) { F->setDoesNotReturn(); } //set calling convention if (natMod->is64Bit()) { ArchSetCallingConv(M, F); } else { F->setCallingConv(getLLVMCC(conv)); } } }
// Wrap `F` in a function that will transition from lifted code into native // code, where `F` is an external reference to a native function. llvm::Function *ArchAddExitPointDriver(llvm::Function *F) { std::stringstream ss; auto M = F->getParent(); const auto OS = SystemOS(M); if(llvm::Triple::Win32 == OS) { ss << "mcsema_" << F->getName().str(); } else { ss << "_" << F->getName().str(); } auto &C = M->getContext(); auto name = ss.str(); auto W = M->getFunction(name); if (W) { return W; } W = llvm::Function::Create(F->getFunctionType(), F->getLinkage(), name, M); W->setCallingConv(F->getCallingConv()); W->addFnAttr(llvm::Attribute::NoInline); W->addFnAttr(llvm::Attribute::Naked); const auto Arch = SystemArch(M); if (llvm::Triple::Linux == OS) { if (_X86_64_ == Arch) { LinuxAddPushJumpStub(M, F, W, "__mcsema_detach_call"); } else { switch (F->getCallingConv()) { case llvm::CallingConv::C: LinuxAddPushJumpStub(M, F, W, "__mcsema_detach_call_cdecl"); break; case llvm::CallingConv::X86_StdCall: LinuxAddPushJumpStub(M, F, W, "__mcsema_detach_call_stdcall"); break; case llvm::CallingConv::X86_FastCall: LinuxAddPushJumpStub(M, F, W, "__mcsema_detach_call_fastcall"); break; default: TASSERT(false, "Unsupported Calling Convention for 32-bit Linux"); break; } } } else if (llvm::Triple::Win32 == OS) { if (_X86_64_ == Arch) { WindowsAddPushJumpStub(true, M, F, W, "__mcsema_detach_call"); } else { switch (F->getCallingConv()) { case llvm::CallingConv::C: WindowsAddPushJumpStub(true, M, F, W, "__mcsema_detach_call_cdecl"); break; case llvm::CallingConv::X86_StdCall: WindowsAddPushJumpStub(true, M, F, W, "__mcsema_detach_call_stdcall"); break; case llvm::CallingConv::X86_FastCall: WindowsAddPushJumpStub(true, M, F, W, "__mcsema_detach_call_fastcall"); break; default: TASSERT(false, "Unsupported Calling Convention for 32-bit Windows"); break; } } } else { TASSERT(false, "Unsupported OS for exit point driver."); } if (F->doesNotReturn()) { W->setDoesNotReturn(); } return W; }