Skip to content
This repository was archived by the owner on Feb 8, 2024. It is now read-only.

Commit e9535b4

Browse files
committed
Merge pull request #35 from rainers/ldc_msvc_x86
[WIP] support for building x86 with MSVC runtime
2 parents 8e13687 + 6ea47f1 commit e9535b4

File tree

5 files changed

+265
-22
lines changed

5 files changed

+265
-22
lines changed

src/core/cpuid.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -845,7 +845,7 @@ bool hasCPUID()
845845
return true;
846846
else version(LDC) {
847847
size_t flags;
848-
asm {
848+
asm @nogc nothrow {
849849
pushf;
850850
pop EAX;
851851
mov flags, EAX;

src/ldc/eh/common.d

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ extern(C) void fatalerror(in char* format, ...)
3030
// Reading DWARF data
3131
// ------------------------
3232

33-
version (Win64) {} else
33+
version (CRuntime_Microsoft) {} else
3434
{
3535
extern(C)
3636
{
@@ -195,15 +195,15 @@ ubyte* get_encoded_value(ubyte* addr, ref size_t res, ubyte encoding, void* cont
195195
res += cast(size_t)old_addr;
196196
break;
197197
case _DW_EH_Format.DW_EH_PE_funcrel:
198-
version(Win64) fatalerror("Not yet implemented."); else
198+
version(CRuntime_Microsoft) fatalerror("Not yet implemented."); else
199199
res += cast(size_t)_Unwind_GetRegionStart(context);
200200
break;
201201
case _DW_EH_Format.DW_EH_PE_textrel:
202-
version(Win64) fatalerror("Not yet implemented."); else
202+
version(CRuntime_Microsoft) fatalerror("Not yet implemented."); else
203203
res += cast(size_t)_Unwind_GetTextRelBase(context);
204204
break;
205205
case _DW_EH_Format.DW_EH_PE_datarel:
206-
version(Win64) fatalerror("Not yet implemented."); else
206+
version(CRuntime_Microsoft) fatalerror("Not yet implemented."); else
207207
res += cast(size_t)_Unwind_GetDataRelBase(context);
208208
break;
209209
default:
@@ -231,7 +231,7 @@ ptrdiff_t get_base_of_encoded_value(ubyte encoding, void* context)
231231
case DW_EH_PE_aligned:
232232
return 0;
233233

234-
version(Win64) {} else
234+
version(CRuntime_Microsoft) {} else
235235
{
236236
case DW_EH_PE_textrel:
237237
return _Unwind_GetTextRelBase (context);

src/ldc/eh/win32.d

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
/**
2+
* This module implements the runtime-part of LDC exceptions
3+
* on Windows win32.
4+
*/
5+
module ldc.eh.win32;
6+
7+
version(CRuntime_Microsoft):
8+
version(Win32):
9+
10+
import ldc.eh.common;
11+
import core.sys.windows.windows;
12+
import core.exception : onOutOfMemoryError;
13+
import core.stdc.stdlib : malloc;
14+
import core.stdc.string : memcpy;
15+
16+
// pointers are image relative for Win64 versions
17+
version(Win64)
18+
alias ImgPtr(T) = uint; // offset into image
19+
else
20+
alias ImgPtr(T) = T;
21+
22+
alias PMFN = ImgPtr!(void function(void*));
23+
24+
struct TypeDescriptor(int N)
25+
{
26+
version(_RTTI)
27+
const void * pVFTable; // Field overloaded by RTTI
28+
else
29+
uint hash; // Hash value computed from type's decorated name
30+
31+
void * spare; // reserved, possible for RTTI
32+
char[N+1] name; // variable size, zero terminated
33+
}
34+
35+
struct PMD
36+
{
37+
int mdisp; // Offset of intended data within base
38+
int pdisp; // Displacement to virtual base pointer
39+
int vdisp; // Index within vbTable to offset of base
40+
}
41+
42+
struct CatchableType
43+
{
44+
uint properties; // Catchable Type properties (Bit field)
45+
ImgPtr!(TypeDescriptor!1*) pType; // Pointer to TypeDescriptor
46+
PMD thisDisplacement; // Pointer to instance of catch type within thrown object.
47+
int sizeOrOffset; // Size of simple-type object or offset into buffer of 'this' pointer for catch object
48+
PMFN copyFunction; // Copy constructor or CC-closure
49+
}
50+
51+
enum CT_IsSimpleType = 0x00000001; // type is a simple type (includes pointers)
52+
enum CT_ByReferenceOnly = 0x00000002; // type must be caught by reference
53+
enum CT_HasVirtualBase = 0x00000004; // type is a class with virtual bases
54+
enum CT_IsWinRTHandle = 0x00000008; // type is a winrt handle
55+
enum CT_IsStdBadAlloc = 0x00000010; // type is a a std::bad_alloc
56+
57+
struct CatchableTypeArray
58+
{
59+
int nCatchableTypes;
60+
ImgPtr!(CatchableType*)[2] arrayOfCatchableTypes;
61+
}
62+
63+
struct _ThrowInfo
64+
{
65+
uint attributes; // Throw Info attributes (Bit field)
66+
PMFN pmfnUnwind; // Destructor to call when exception has been handled or aborted.
67+
PMFN pForwardCompat; // pointer to Forward compatibility frame handler
68+
ImgPtr!(CatchableTypeArray*) pCatchableTypeArray; // pointer to CatchableTypeArray
69+
}
70+
71+
enum TI_IsConst = 0x00000001; // thrown object has const qualifier
72+
enum TI_IsVolatile = 0x00000002; // thrown object has volatile qualifier
73+
enum TI_IsUnaligned = 0x00000004; // thrown object has unaligned qualifier
74+
enum TI_IsPure = 0x00000008; // object thrown from a pure module
75+
enum TI_IsWinRT = 0x00000010; // object thrown is a WinRT Exception
76+
77+
extern(Windows) void RaiseException(DWORD dwExceptionCode,
78+
DWORD dwExceptionFlags,
79+
DWORD nNumberOfArguments,
80+
ULONG_PTR* lpArguments);
81+
82+
__gshared TypeDescriptor!16 tdObject = { 0, null, "_D6object6Object\0" };
83+
__gshared TypeDescriptor!20 tdThrowable = { 0, null, "_D6object9Throwable\0" };
84+
__gshared TypeDescriptor!12 tdException = { 0, null, "_D9Exception\0" };
85+
version(none) {
86+
__gshared CatchableType ctThrowable = { CT_IsSimpleType, cast(TypeDescriptor!1*) &tdThrowable, { 0, -1, 0 }, 4, null };
87+
__gshared CatchableType ctException = { CT_IsSimpleType, cast(TypeDescriptor!1*) &tdException, { 0, -1, 0 }, 4, null };
88+
__gshared CatchableTypeArray ctArray = { 2, [ &ctThrowable, &ctException ] };
89+
__gshared _ThrowInfo objectThrowInfo = { 0, null, null, &ctArray };
90+
}
91+
92+
enum int STATUS_MSC_EXCEPTION = 0xe0000000 | ('m' << 16) | ('s' << 8) | ('c' << 0);
93+
94+
enum EXCEPTION_NONCONTINUABLE = 0x01;
95+
enum EXCEPTION_UNWINDING = 0x02;
96+
97+
enum EH_MAGIC_NUMBER1 = 0x19930520;
98+
99+
extern(C) void _d_throw_exception(Object e)
100+
{
101+
if (e is null)
102+
fatalerror("Cannot throw null exception");
103+
auto ti = typeid(e);
104+
if (ti is null)
105+
fatalerror("Cannot throw corrupt exception object with null classinfo");
106+
107+
ULONG_PTR[3] ExceptionInformation;
108+
ExceptionInformation[0] = EH_MAGIC_NUMBER1;
109+
ExceptionInformation[1] = cast(ULONG_PTR) cast(void*) &e;
110+
ExceptionInformation[2] = cast(ULONG_PTR) getThrowInfo(ti);
111+
112+
RaiseException(STATUS_MSC_EXCEPTION, EXCEPTION_NONCONTINUABLE, 3, ExceptionInformation.ptr);
113+
}
114+
115+
import rt.util.container.hashtab;
116+
import core.sync.mutex;
117+
118+
__gshared HashTab!(TypeInfo_Class, _ThrowInfo) throwInfoHashtab;
119+
__gshared HashTab!(TypeInfo_Class, CatchableType) catchableHashtab;
120+
__gshared Mutex throwInfoMutex;
121+
122+
// create and cache throwinfo for ti
123+
_ThrowInfo* getThrowInfo(TypeInfo_Class ti)
124+
{
125+
throwInfoMutex.lock();
126+
if (auto p = ti in throwInfoHashtab)
127+
{
128+
throwInfoMutex.unlock();
129+
return p;
130+
}
131+
132+
size_t classes = 0;
133+
for (TypeInfo_Class tic = ti; tic; tic = tic.base)
134+
classes++;
135+
136+
size_t sz = int.sizeof + classes * ImgPtr!(CatchableType*).sizeof;
137+
auto cta = cast(CatchableTypeArray*) malloc(sz);
138+
if (!cta)
139+
onOutOfMemoryError();
140+
cta.nCatchableTypes = classes;
141+
142+
size_t c = 0;
143+
for (TypeInfo_Class tic = ti; tic; tic = tic.base)
144+
cta.arrayOfCatchableTypes.ptr[c++] = getCatchableType(tic);
145+
146+
_ThrowInfo tinf = { 0, null, null, cta };
147+
throwInfoHashtab[ti] = tinf;
148+
auto pti = ti in throwInfoHashtab;
149+
throwInfoMutex.unlock();
150+
return pti;
151+
}
152+
153+
CatchableType* getCatchableType(TypeInfo_Class ti)
154+
{
155+
if (auto p = ti in catchableHashtab)
156+
return p;
157+
158+
static size_t mangledNameLength(string s)
159+
{
160+
size_t len = 2 + s.length; // "_D" + identifier + 1 digit per dot
161+
for (size_t q = 0; q < s.length; )
162+
{
163+
size_t p = q;
164+
while (p < s.length && s.ptr[p] != '.')
165+
p++;
166+
for (size_t r = p - q; r >= 10; r /= 10) // add digits for length >= 10
167+
len++;
168+
q = p + 1;
169+
}
170+
return len;
171+
}
172+
173+
static void mangleName(string s, char* buf)
174+
{
175+
*buf++ = '_';
176+
*buf++ = 'D';
177+
for (size_t q = 0; q < s.length; )
178+
{
179+
size_t p = q;
180+
while (p < s.length && s.ptr[p] != '.')
181+
p++;
182+
size_t digits = 10;
183+
size_t len = p - q;
184+
for ( ; len >= digits; digits *= 10) {}
185+
for (digits /= 10; digits > 1; digits /= 10)
186+
{
187+
size_t dig = len / digits;
188+
*buf++ = cast(char)('0' + dig);
189+
len -= dig * digits;
190+
}
191+
*buf++ = cast(char)('0' + len);
192+
memcpy(buf, s.ptr + q, p - q);
193+
buf += p - q;
194+
q = p + 1;
195+
}
196+
*buf = 0;
197+
}
198+
199+
size_t mangledLength = mangledNameLength(ti.name) + 1;
200+
size_t sz = TypeDescriptor!1.sizeof + mangledLength;
201+
auto td = cast(TypeDescriptor!1*) malloc(sz);
202+
if (!td)
203+
onOutOfMemoryError();
204+
205+
td.hash = 0;
206+
td.spare = null;
207+
mangleName(ti.name, td.name.ptr);
208+
209+
CatchableType ct = { CT_IsSimpleType, td, { 0, -1, 0 }, 4, null };
210+
catchableHashtab[ti] = ct;
211+
return ti in catchableHashtab;
212+
}
213+
214+
void msvc_eh_init()
215+
{
216+
throwInfoMutex = new Mutex;
217+
218+
// Exception has a special mangling that's not reflected in the name
219+
220+
CatchableType ctObject = { CT_IsSimpleType, cast(TypeDescriptor!1*) &tdObject, { 0, -1, 0 }, 4, null };
221+
catchableHashtab[typeid(Object)] = ctObject;
222+
CatchableType ctThrowable = { CT_IsSimpleType, cast(TypeDescriptor!1*) &tdThrowable, { 0, -1, 0 }, 4, null };
223+
catchableHashtab[typeid(Throwable)] = ctThrowable;
224+
CatchableType ctException = { CT_IsSimpleType, cast(TypeDescriptor!1*) &tdException, { 0, -1, 0 }, 4, null };
225+
catchableHashtab[typeid(Exception)] = ctException;
226+
}
227+
228+
shared static this()
229+
{
230+
// should be called from rt_init
231+
msvc_eh_init();
232+
}

src/rt/sections_ldc.d

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ private
9696
Section(SEG_DATA, SECT_COMMON)
9797
];
9898
}
99-
else version (Win64)
99+
else version (CRuntime_Microsoft)
100100
{
101101
extern extern (C) __gshared
102102
{
@@ -371,7 +371,7 @@ void initSections()
371371
}
372372
_dyld_register_func_for_add_image(&scanSections);
373373
}
374-
else version (Win64)
374+
else version (CRuntime_Microsoft)
375375
{
376376
pushRange(_data_start__, _data_end__);
377377
if (_bss_start__ != null)

src/rt/stdio_msvc.c

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,20 @@ int _set_output_format(int format); // VS2013-
3636
//extern const char* __acrt_iob_func;
3737
extern const char* _nullfunc = 0;
3838

39-
#pragma comment(linker, "/alternatename:__acrt_iob_func=_nullfunc")
40-
#pragma comment(linker, "/alternatename:__iob_func=_nullfunc")
41-
#pragma comment(linker, "/alternatename:_set_output_format=_nullfunc")
39+
#if defined _M_IX86
40+
#define C_PREFIX "_"
41+
#elif defined _M_X64 || defined _M_ARM || defined _M_ARM64
42+
#define C_PREFIX ""
43+
#else
44+
#error Unsupported architecture
45+
#endif
46+
47+
#define DECLARE_ALTERNATE_NAME(name, alternate_name) \
48+
__pragma(comment(linker, "/alternatename:" C_PREFIX #name "=" C_PREFIX #alternate_name))
49+
50+
DECLARE_ALTERNATE_NAME (__acrt_iob_func, _nullfunc);
51+
DECLARE_ALTERNATE_NAME (__iob_func, _nullfunc);
52+
DECLARE_ALTERNATE_NAME (_set_output_format, _nullfunc);
4253

4354
void init_msvc()
4455
{
@@ -65,25 +76,25 @@ void init_msvc()
6576
// VS2015+ provides C99-conformant (v)snprintf functions, so weakly
6677
// link to legacy _(v)snprintf (not C99-conformant!) for VS2013- only
6778

68-
#pragma comment(linker, "/alternatename:snprintf=_snprintf")
69-
#pragma comment(linker, "/alternatename:vsnprintf=_vsnprintf")
79+
DECLARE_ALTERNATE_NAME (snprintf, _snprintf);
80+
DECLARE_ALTERNATE_NAME (vsnprintf, _vsnprintf);
7081

7182
// VS2013- implements these functions as macros, VS2015+ provides symbols
7283

73-
#pragma comment(linker, "/alternatename:_fputc_nolock=_msvc_fputc_nolock")
74-
#pragma comment(linker, "/alternatename:_fgetc_nolock=_msvc_fgetc_nolock")
75-
#pragma comment(linker, "/alternatename:rewind=_msvc_rewind")
76-
#pragma comment(linker, "/alternatename:clearerr=_msvc_clearerr")
77-
#pragma comment(linker, "/alternatename:feof=_msvc_feof")
78-
#pragma comment(linker, "/alternatename:ferror=_msvc_ferror")
79-
#pragma comment(linker, "/alternatename:fileno=_msvc_fileno")
84+
DECLARE_ALTERNATE_NAME (_fputc_nolock, _msvc_fputc_nolock);
85+
DECLARE_ALTERNATE_NAME (_fgetc_nolock, _msvc_fgetc_nolock);
86+
DECLARE_ALTERNATE_NAME (rewind, _msvc_rewind);
87+
DECLARE_ALTERNATE_NAME (clearerr, _msvc_clearerr);
88+
DECLARE_ALTERNATE_NAME (feof, _msvc_feof);
89+
DECLARE_ALTERNATE_NAME (ferror, _msvc_ferror);
90+
DECLARE_ALTERNATE_NAME (fileno, _msvc_fileno);
8091

8192
// VS2013- helper functions
8293
int _filbuf(FILE* fp);
8394
int _flsbuf(int c, FILE* fp);
8495

85-
#pragma comment(linker, "/alternatename:_filbuf=_nullfunc")
86-
#pragma comment(linker, "/alternatename:_flsbuf=_nullfunc")
96+
DECLARE_ALTERNATE_NAME(_filbuf, _nullfunc);
97+
DECLARE_ALTERNATE_NAME(_flsbuf, _nullfunc);
8798

8899
int _msvc_fputc_nolock(int c, FILE* fp)
89100
{

0 commit comments

Comments
 (0)