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:
David Nadlinger 2014-07-10 00:01:55 +02:00
parent 36e9465b7a
commit fc7acc48fc
7 changed files with 78 additions and 5 deletions

View file

@ -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;
}

View file

@ -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;
}

View file

@ -292,6 +292,7 @@ Msgtable msgtable[] =
{ "LDC_atomic_rmw" },
{ "LDC_global_crt_ctor" },
{ "LDC_global_crt_dtor" },
{ "LDC_extern_weak" },
#endif
// For special functions

View file

@ -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

View file

@ -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",

View file

@ -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