mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-03 08:30:47 +03:00
Fix ABI on Win32.
We can't simply use the C calling convention, as the D(MD) ABI is callee-pop, and this is hardcoded in naked functions with stack parameters. The \1 "trick" is normally used to avoid prefixes added by LLVM; on the 3.2 release, a patch is needed to make it work for the @<n> stdcall suffixes as well.
This commit is contained in:
parent
e05a5c6f22
commit
2d3de4a3d4
4 changed files with 65 additions and 28 deletions
|
@ -36,8 +36,6 @@ struct X86TargetABI : TargetABI
|
|||
return llvm::CallingConv::C;
|
||||
case LINKd:
|
||||
case LINKdefault:
|
||||
return global.params.targetTriple.isOSWindows() ?
|
||||
llvm::CallingConv::C : llvm::CallingConv::X86_StdCall;
|
||||
case LINKpascal:
|
||||
case LINKwindows:
|
||||
return llvm::CallingConv::X86_StdCall;
|
||||
|
@ -46,6 +44,30 @@ struct X86TargetABI : TargetABI
|
|||
}
|
||||
}
|
||||
|
||||
std::string mangleForLLVM(llvm::StringRef name, LINK l)
|
||||
{
|
||||
switch (l)
|
||||
{
|
||||
case LINKc:
|
||||
case LINKcpp:
|
||||
case LINKintrinsic:
|
||||
case LINKpascal:
|
||||
case LINKwindows:
|
||||
return name;
|
||||
case LINKd:
|
||||
case LINKdefault:
|
||||
if (global.params.targetTriple.isOSWindows())
|
||||
{
|
||||
// Prepend a 0x1 byte to keep LLVM from adding the usual
|
||||
// "@<paramsize>" stdcall suffix.
|
||||
return ("\1_" + name).str();
|
||||
}
|
||||
return name;
|
||||
default:
|
||||
llvm_unreachable("Unhandled D linkage type.");
|
||||
}
|
||||
}
|
||||
|
||||
bool returnInArg(TypeFunction* tf)
|
||||
{
|
||||
#if DMDV2
|
||||
|
|
10
gen/abi.h
10
gen/abi.h
|
@ -60,7 +60,15 @@ struct TargetABI
|
|||
|
||||
/// Returns the LLVM calling convention to be used for the given D linkage
|
||||
/// type on the target.
|
||||
virtual llvm::CallingConv::ID callingConv(enum LINK l) = 0;
|
||||
virtual llvm::CallingConv::ID callingConv(LINK l) = 0;
|
||||
|
||||
/// Applies any rewrites that might be required to accurately reproduce the
|
||||
/// passed function name on LLVM given a specific calling convention.
|
||||
///
|
||||
/// Using this function at a stage where the name could be user-visible is
|
||||
/// almost certainly a mistake; it is intended to e.g. prepend '\1' where
|
||||
/// disabling the LLVM-internal name mangling/postprocessing is required.
|
||||
virtual std::string mangleForLLVM(llvm::StringRef name, LINK l) { return name; }
|
||||
|
||||
/// Called if a new function type is resolved
|
||||
virtual void newFunctionType(TypeFunction* tf) {}
|
||||
|
|
|
@ -741,48 +741,52 @@ void DtoDeclareFunction(FuncDeclaration* fdecl)
|
|||
fdecl->ir.irFunc = new IrFunction(fdecl);
|
||||
}
|
||||
|
||||
// mangled name
|
||||
const char* mangled_name;
|
||||
if (fdecl->llvmInternal == LLVMintrinsic)
|
||||
mangled_name = fdecl->intrinsicName.c_str();
|
||||
else
|
||||
mangled_name = fdecl->mangle();
|
||||
|
||||
LLFunction* vafunc = 0;
|
||||
if (fdecl->isVaIntrinsic())
|
||||
vafunc = DtoDeclareVaFunction(fdecl);
|
||||
|
||||
// calling convention
|
||||
LINK link = f->linkage;
|
||||
if (vafunc || fdecl->llvmInternal == LLVMintrinsic
|
||||
#if DMDV2
|
||||
// DMD treats _Dmain as having C calling convention and this has been
|
||||
// hardcoded into druntime, even if the frontend type has D linkage.
|
||||
// See Bugzilla issue 9028.
|
||||
|| fdecl->isMain()
|
||||
#endif
|
||||
)
|
||||
{
|
||||
link = LINKc;
|
||||
}
|
||||
|
||||
// mangled name
|
||||
std::string mangledName;
|
||||
if (fdecl->llvmInternal == LLVMintrinsic)
|
||||
mangledName = fdecl->intrinsicName;
|
||||
else
|
||||
mangledName = fdecl->mangle();
|
||||
mangledName = gABI->mangleForLLVM(mangledName, link);
|
||||
|
||||
// construct function
|
||||
LLFunctionType* functype = DtoFunctionType(fdecl);
|
||||
LLFunction* func = vafunc ? vafunc : gIR->module->getFunction(mangled_name);
|
||||
LLFunction* func = vafunc ? vafunc : gIR->module->getFunction(mangledName);
|
||||
if (!func) {
|
||||
if(fdecl->llvmInternal == LLVMinline_ir)
|
||||
func = DtoInlineIRFunction(fdecl);
|
||||
else
|
||||
func = LLFunction::Create(functype, DtoLinkage(fdecl), mangled_name, gIR->module);
|
||||
func = LLFunction::Create(functype, DtoLinkage(fdecl), mangledName, gIR->module);
|
||||
} else if (func->getFunctionType() != functype) {
|
||||
error(fdecl->loc, "Function type does not match previously declared function with the same mangled name: %s", fdecl->mangle());
|
||||
}
|
||||
|
||||
func->setCallingConv(gABI->callingConv(link));
|
||||
|
||||
if (Logger::enabled())
|
||||
Logger::cout() << "func = " << *func << std::endl;
|
||||
|
||||
// add func to IRFunc
|
||||
fdecl->ir.irFunc->func = func;
|
||||
|
||||
// calling convention
|
||||
if (!vafunc && fdecl->llvmInternal != LLVMintrinsic
|
||||
#if DMDV2
|
||||
// DMD treats _Dmain as having C calling convention and this has been
|
||||
// hardcoded into druntime, even if the frontend type has D linkage.
|
||||
// See Bugzilla issue 9028.
|
||||
&& !fdecl->isMain()
|
||||
#endif
|
||||
)
|
||||
func->setCallingConv(gABI->callingConv(f->linkage));
|
||||
else // fall back to C, it should be the right thing to do
|
||||
func->setCallingConv(llvm::CallingConv::C);
|
||||
|
||||
// parameter attributes
|
||||
if (!fdecl->isIntrinsic()) {
|
||||
set_param_attrs(f, func, fdecl);
|
||||
|
|
|
@ -74,15 +74,18 @@ static llvm::Function* build_module_function(const std::string &name, const std:
|
|||
|
||||
std::vector<LLType*> argsTy;
|
||||
LLFunctionType* fnTy = LLFunctionType::get(LLType::getVoidTy(gIR->context()),argsTy,false);
|
||||
assert(gIR->module->getFunction(name) == NULL);
|
||||
llvm::Function* fn = llvm::Function::Create(fnTy, llvm::GlobalValue::InternalLinkage, name, gIR->module);
|
||||
|
||||
std::string const symbolName = gABI->mangleForLLVM(name, LINKd);
|
||||
assert(gIR->module->getFunction(symbolName) == NULL);
|
||||
llvm::Function* fn = llvm::Function::Create(fnTy,
|
||||
llvm::GlobalValue::InternalLinkage, symbolName, gIR->module);
|
||||
fn->setCallingConv(gABI->callingConv(LINKd));
|
||||
|
||||
llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "entry", fn);
|
||||
IRBuilder<> builder(bb);
|
||||
|
||||
// debug info
|
||||
DtoDwarfSubProgramInternal(name.c_str(), name.c_str());
|
||||
DtoDwarfSubProgramInternal(name.c_str(), symbolName.c_str());
|
||||
|
||||
// Call ctor's
|
||||
typedef std::list<FuncDeclaration*>::const_iterator FuncIterator;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue