mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-04-29 22:50:53 +03:00
Add pragma(LDC_extern_weak) for symbols with (ELF-style) weak linkage.
For now, this is only an internal feature to be used in the implementation of rt.sections_linux.
This commit is contained in:
parent
36e9465b7a
commit
fc7acc48fc
7 changed files with 78 additions and 5 deletions
|
@ -24,6 +24,10 @@
|
|||
#include "declaration.h"
|
||||
#include "utf.h"
|
||||
|
||||
#if IN_LLVM
|
||||
#include "gen/pragma.h"
|
||||
#endif
|
||||
|
||||
#define LOG 0
|
||||
|
||||
int RealEquals(real_t x1, real_t x2);
|
||||
|
@ -68,6 +72,13 @@ int NullExp::isConst()
|
|||
|
||||
int SymOffExp::isConst()
|
||||
{
|
||||
#if IN_LLVM
|
||||
// We don't statically know anything about the address of a weak symbol
|
||||
// if there is no offset. With an offset, we can at least say that it is
|
||||
// non-zero.
|
||||
if (var->llvmInternal == LLVMextern_weak && !offset)
|
||||
return 0;
|
||||
#endif
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,10 @@
|
|||
#include "doc.h"
|
||||
#include "aav.h"
|
||||
|
||||
#if IN_LLVM
|
||||
#include "gen/pragma.h"
|
||||
#endif
|
||||
|
||||
bool isArrayOpValid(Expression *e);
|
||||
#if IN_DMD
|
||||
Expression *createTypeInfoArray(Scope *sc, Expression *args[], size_t dim);
|
||||
|
@ -5608,6 +5612,14 @@ Expression *SymOffExp::semantic(Scope *sc)
|
|||
|
||||
int SymOffExp::isBool(int result)
|
||||
{
|
||||
#if IN_LLVM
|
||||
// For a weak symbol, we only statically know that it is non-null if the
|
||||
// offset is non-zero.
|
||||
if (var->llvmInternal == LLVMextern_weak)
|
||||
{
|
||||
return result && offset != 0;
|
||||
}
|
||||
#endif
|
||||
return result ? true : false;
|
||||
}
|
||||
|
||||
|
|
|
@ -292,6 +292,7 @@ Msgtable msgtable[] =
|
|||
{ "LDC_atomic_rmw" },
|
||||
{ "LDC_global_crt_ctor" },
|
||||
{ "LDC_global_crt_dtor" },
|
||||
{ "LDC_extern_weak" },
|
||||
#endif
|
||||
|
||||
// For special functions
|
||||
|
|
|
@ -1055,12 +1055,17 @@ void DtoResolveVariable(VarDeclaration* vd)
|
|||
// vd->ir.irGlobal->value!), and in case we also do an initializer
|
||||
// with a different type later, swap it out and replace any existing
|
||||
// uses with bitcasts to the previous type.
|
||||
//
|
||||
|
||||
// We always start out with external linkage; any other type is set
|
||||
// when actually defining it in VarDeclaration::codegen.
|
||||
llvm::GlobalValue::LinkageTypes linkage = llvm::GlobalValue::ExternalLinkage;
|
||||
if (vd->llvmInternal == LLVMextern_weak) {
|
||||
linkage = llvm::GlobalValue::ExternalWeakLinkage;
|
||||
}
|
||||
|
||||
llvm::GlobalVariable* gvar = getOrCreateGlobal(vd->loc, *gIR->module,
|
||||
i1ToI8(DtoType(vd->type)), isLLConst, llvm::GlobalValue::ExternalLinkage,
|
||||
0, llName, vd->isThreadlocal());
|
||||
i1ToI8(DtoType(vd->type)), isLLConst, linkage, 0, llName,
|
||||
vd->isThreadlocal());
|
||||
vd->ir.irGlobal->value = gvar;
|
||||
|
||||
// Set the alignment (it is important not to use type->alignsize because
|
||||
|
|
|
@ -287,6 +287,17 @@ Pragma DtoGetPragma(Scope *sc, PragmaDeclaration *decl, std::string &arg1str)
|
|||
return LLVMinline_ir;
|
||||
}
|
||||
|
||||
// pragma(LDC_extern_weak) { vardecl(s) }
|
||||
else if (ident == Id::LDC_extern_weak)
|
||||
{
|
||||
if (args && args->dim > 0)
|
||||
{
|
||||
error(Loc(), "takes no parameters");
|
||||
fatal();
|
||||
}
|
||||
return LLVMextern_weak;
|
||||
}
|
||||
|
||||
return LLVMnone;
|
||||
}
|
||||
|
||||
|
@ -511,6 +522,38 @@ void DtoCheckPragma(PragmaDeclaration *decl, Dsymbol *s,
|
|||
}
|
||||
break;
|
||||
|
||||
case LLVMextern_weak:
|
||||
if (VarDeclaration* vd = s->isVarDeclaration())
|
||||
{
|
||||
if (!vd->isDataseg() || !(vd->storage_class & STCextern)) {
|
||||
error(s->loc, "'%s' requires storage class 'extern'",
|
||||
ident->toChars());
|
||||
fatal();
|
||||
}
|
||||
|
||||
// It seems like the interaction between weak symbols and thread-local
|
||||
// storage is not well-defined (the address of an undefined weak TLS
|
||||
// symbol is non-zero on the ELF static TLS model on Linux x86_64).
|
||||
// Thus, just disallow this altogether.
|
||||
if (vd->isThreadlocal()) {
|
||||
error(s->loc, "'%s' cannot be applied to thread-local variable '%s'",
|
||||
ident->toChars(), vd->toPrettyChars());
|
||||
fatal();
|
||||
}
|
||||
vd->llvmInternal = llvm_internal;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Currently, things like "pragma(LDC_extern_weak) extern int foo;"
|
||||
// fail because 'extern' creates an intermediate
|
||||
// StorageClassDeclaration. This might eventually be fixed by making
|
||||
// extern_weak a proper storage class.
|
||||
error(s->loc, "the '%s' pragma can only be specified directly on "
|
||||
"variable declarations for now", ident->toChars());
|
||||
fatal();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
warning(s->loc,
|
||||
"the LDC specific pragma '%s' is not yet implemented, ignoring",
|
||||
|
|
|
@ -44,7 +44,8 @@ enum Pragma
|
|||
LLVMbitop_bt,
|
||||
LLVMbitop_btc,
|
||||
LLVMbitop_btr,
|
||||
LLVMbitop_bts
|
||||
LLVMbitop_bts,
|
||||
LLVMextern_weak
|
||||
};
|
||||
|
||||
Pragma DtoGetPragma(Scope *sc, PragmaDeclaration *decl, std::string &arg1str);
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit c81979c297785fd53735300767f22e95312b0d80
|
||||
Subproject commit d19b2ef57b27cc8b430d940e1beda0eb9ba8153d
|
Loading…
Add table
Add a link
Reference in a new issue