Workaround for platforms lacking crt_destructor (#13364)

Workaround for platforms lacking crt_destructor

Signed-off-by: Iain Buclaw <ibuclaw@users.noreply.github.com>
Signed-off-by: Razvan Nitu <RazvanN7@users.noreply.github.com>
Merged-on-behalf-of: Razvan Nitu <RazvanN7@users.noreply.github.com>
This commit is contained in:
Max Haughton 2021-12-15 12:26:45 +00:00 committed by GitHub
parent dba01aec93
commit 93108bb9ea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 102 additions and 5 deletions

View file

@ -82,6 +82,22 @@ task:
<< : *COMMON_STEPS_TEMPLATE
# Mac
task:
name: macOS 12.x x64, $TASK_NAME_SUFFIX
osx_instance:
image: monterey-xcode
timeout_in: 60m
environment:
OS_NAME: darwin
# override Cirrus default OS (`darwin`)
OS: osx
# 12 CPU cores and 24 GB of memory are available
N: 12
matrix:
- TASK_NAME_SUFFIX: DMD (latest)
- TASK_NAME_SUFFIX: DMD (coverage)
<< : *COVERAGE_ENVIRONMENT_TEMPLATE
<< : *COMMON_STEPS_TEMPLATE
task:
name: macOS 11.x x64, $TASK_NAME_SUFFIX
osx_instance:

View file

@ -238,6 +238,7 @@ Symbol *getRtlsym(RTLSYM i)
case RTLSYM.C__ASSERT_FAIL: symbolz(ps,FLfunc,FREGSAVED,"__assert_fail", SFLexit, t); break;
case RTLSYM.C__ASSERT_RTN: symbolz(ps,FLfunc,FREGSAVED,"__assert_rtn", SFLexit, t); break;
case RTLSYM.CXA_ATEXIT: symbolz(ps,FLfunc,FREGSAVED,"__cxa_atexit", 0, t); break;
default:
assert(0);
}

View file

@ -169,7 +169,9 @@ enum RTLSYM
C_ASSERT,
C__ASSERT,
C__ASSERT_FAIL,
C__ASSERT_RTN
C__ASSERT_RTN,
CXA_ATEXIT
}
extern (C++):

View file

@ -5031,18 +5031,21 @@ struct TargetC final
Gcc_Clang = 3u,
};
bool crtDestructorsSupported;
uint8_t longsize;
uint8_t long_doublesize;
uint8_t wchar_tsize;
Runtime runtime;
BitFieldStyle bitFieldStyle;
TargetC() :
crtDestructorsSupported(true),
longsize(),
long_doublesize(),
wchar_tsize()
{
}
TargetC(uint8_t longsize, uint8_t long_doublesize = 0u, uint8_t wchar_tsize = 0u, Runtime runtime = (Runtime)0u, BitFieldStyle bitFieldStyle = (BitFieldStyle)0u) :
TargetC(bool crtDestructorsSupported, uint8_t longsize = 0u, uint8_t long_doublesize = 0u, uint8_t wchar_tsize = 0u, Runtime runtime = (Runtime)0u, BitFieldStyle bitFieldStyle = (BitFieldStyle)0u) :
crtDestructorsSupported(crtDestructorsSupported),
longsize(longsize),
long_doublesize(long_doublesize),
wchar_tsize(wchar_tsize),
@ -7821,7 +7824,7 @@ public:
RealProperties()
{
}
Target(OS os, uint8_t osMajor = 0u, uint8_t ptrsize = 0u, uint8_t realsize = 0u, uint8_t realpad = 0u, uint8_t realalignsize = 0u, uint8_t classinfosize = 0u, uint64_t maxStaticDataSize = 0LLU, TargetC c = TargetC(0u, 0u, 0u, (TargetC::Runtime)0u, (TargetC::BitFieldStyle)0u), TargetCPP cpp = TargetCPP(false, false, false, false, (TargetCPP::Runtime)0u), TargetObjC objc = TargetObjC(false), _d_dynamicArray< const char > architectureName = {}, CPU cpu = (CPU)11u, bool is64bit = true, bool isLP64 = false, _d_dynamicArray< const char > obj_ext = {}, _d_dynamicArray< const char > lib_ext = {}, _d_dynamicArray< const char > dll_ext = {}, bool run_noext = false, bool mscoff = false, FPTypeProperties<float > FloatProperties = FPTypeProperties<float >(NAN, NAN, NAN, NAN, NAN, 0LL, 0LL, 0LL, 0LL, 0LL, 0LL), FPTypeProperties<double > DoubleProperties = FPTypeProperties<double >(NAN, NAN, NAN, NAN, NAN, 0LL, 0LL, 0LL, 0LL, 0LL, 0LL), FPTypeProperties<_d_real > RealProperties = FPTypeProperties<_d_real >(NAN, NAN, NAN, NAN, NAN, 0LL, 0LL, 0LL, 0LL, 0LL, 0LL)) :
Target(OS os, uint8_t osMajor = 0u, uint8_t ptrsize = 0u, uint8_t realsize = 0u, uint8_t realpad = 0u, uint8_t realalignsize = 0u, uint8_t classinfosize = 0u, uint64_t maxStaticDataSize = 0LLU, TargetC c = TargetC(true, 0u, 0u, 0u, (TargetC::Runtime)0u, (TargetC::BitFieldStyle)0u), TargetCPP cpp = TargetCPP(false, false, false, false, (TargetCPP::Runtime)0u), TargetObjC objc = TargetObjC(false), _d_dynamicArray< const char > architectureName = {}, CPU cpu = (CPU)11u, bool is64bit = true, bool isLP64 = false, _d_dynamicArray< const char > obj_ext = {}, _d_dynamicArray< const char > lib_ext = {}, _d_dynamicArray< const char > dll_ext = {}, bool run_noext = false, bool mscoff = false, FPTypeProperties<float > FloatProperties = FPTypeProperties<float >(NAN, NAN, NAN, NAN, NAN, 0LL, 0LL, 0LL, 0LL, 0LL, 0LL), FPTypeProperties<double > DoubleProperties = FPTypeProperties<double >(NAN, NAN, NAN, NAN, NAN, 0LL, 0LL, 0LL, 0LL, 0LL, 0LL), FPTypeProperties<_d_real > RealProperties = FPTypeProperties<_d_real >(NAN, NAN, NAN, NAN, NAN, 0LL, 0LL, 0LL, 0LL, 0LL, 0LL)) :
os(os),
osMajor(osMajor),
ptrsize(ptrsize),

View file

@ -1170,8 +1170,75 @@ void FuncDeclaration_toObjFile(FuncDeclaration fd, bool multiobj)
if (fd.isCrtCtorDtor & 1)
objmod.setModuleCtorDtor(s, true);
if (fd.isCrtCtorDtor & 2)
objmod.setModuleCtorDtor(s, false);
{
//See TargetC.initialize
if(target.c.crtDestructorsSupported)
{
objmod.setModuleCtorDtor(s, false);
} else
{
/*
https://issues.dlang.org/show_bug.cgi?id=22520
Apple radar: https://openradar.appspot.com/FB9733712
Apple deprecated the mechanism used to implement `crt_destructor`
on MacOS Monterey. This works around that by generating a new function
(crt_destructor_thunk_NNN, run as a constructor) which registers
the destructor-to-be using __cxa_atexit()
This workaround may need a further look at when it comes to
shared library support, however there is no bridge for
that spilt milk to flow under yet.
This relies on the Itanium ABI so is portable to any
platform it, if needed.
*/
__gshared uint nthDestructor = 0;
char* buf = cast(char*) calloc(50, 1);
assert(buf);
const ret = snprintf(buf, 100, "_dmd_crt_destructor_thunk.%u", nthDestructor++);
assert(ret >= 0 && ret < 100, "snprintf either failed or overran buffer");
//Function symbol
auto newConstructor = symbol_calloc(buf);
//Build type
newConstructor.Stype = type_function(TYnfunc, [], false, type_alloc(TYvoid));
//Tell it it's supposed to be a C function. Does it do anything? Not sure.
type_setmangle(&newConstructor.Stype, mTYman_c);
symbol_func(newConstructor);
//Global SC for now.
newConstructor.Sclass = SCstatic;
func_t* funcState = newConstructor.Sfunc;
//Init start block
funcState.Fstartblock = block_calloc();
block* startBlk = funcState.Fstartblock;
//Make that block run __cxa_atexit(&func);
auto atexitSym = getRtlsym(RTLSYM.CXA_ATEXIT);
Symbol* dso_handle = symbol_calloc("__dso_handle");
dso_handle.Stype = type_fake(TYint);
//Try to get MacOS _ prefix-ism right.
type_setmangle(&dso_handle.Stype, mTYman_c);
dso_handle.Sfl = FLextern;
dso_handle.Sclass = SCextern;
dso_handle.Stype.Tcount++;
auto handlePtr = el_ptr(dso_handle);
//Build parameter pack - __cxa_atexit(&func, null, null)
auto paramPack = el_params(handlePtr, el_long(TYnptr, 0), el_ptr(s), null);
auto exec = el_bin(OPcall, TYvoid, el_var(atexitSym), paramPack);
block_appendexp(startBlk, exec); //payload
startBlk.BC = BCgoto;
auto next = block_calloc();
startBlk.appendSucc(next);
startBlk.Bnext = next;
next.BC = BCret;
//Emit in binary
writefunc(newConstructor);
//Mark as a CONSTRUCTOR because our thunk implements the destructor
objmod.setModuleCtorDtor(newConstructor, true);
}
}
foreach (sd; *irs.deferToObj)
{

View file

@ -1192,7 +1192,7 @@ struct TargetC
/// https://docs.microsoft.com/en-us/cpp/cpp/cpp-bit-fields?view=msvc-160
Gcc_Clang, /// gcc and clang
}
bool crtDestructorsSupported = true; /// Not all platforms support crt_destructor
ubyte longsize; /// size of a C `long` or `unsigned long` type
ubyte long_doublesize; /// size of a C `long double`
ubyte wchar_tsize; /// size of a C `wchar_t` type
@ -1245,6 +1245,13 @@ struct TargetC
bitFieldStyle = BitFieldStyle.Gcc_Clang;
else
assert(0);
/*
MacOS Monterey (12) does not support C runtime destructors.
*/
if (os == Target.OS.OSX)
{
crtDestructorsSupported = false;
}
}
void addRuntimePredefinedGlobalIdent() const

View file

@ -70,6 +70,7 @@ struct TargetC
Gcc_Clang, // gcc and clang
};
uint8_t crtDestructorsSupported; // Not all platforms support crt_destructor
uint8_t longsize; // size of a C 'long' or 'unsigned long' type
uint8_t long_doublesize; // size of a C 'long double'
uint8_t wchar_tsize; // size of a C 'wchar_t' type