Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit 15f2421

Browse files
committed
Support merging of EH tables across DLLs
1 parent 2429fb8 commit 15f2421

File tree

2 files changed

+120
-8
lines changed

2 files changed

+120
-8
lines changed

src/rt/dmain2.d

+94-5
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ version (CRuntime_Microsoft)
8989
extern(C) void init_msvc();
9090
}
9191

92+
version(Win64)
93+
import rt.deh_win64_posix;
94+
9295
/***********************************
9396
* These are a temporary means of providing a GC hook for DLL use. They may be
9497
* replaced with some other similar functionality later.
@@ -102,6 +105,10 @@ extern (C)
102105
alias void* function() gcGetFn;
103106
alias void function(void*) gcSetFn;
104107
alias void function() gcClrFn;
108+
109+
// for exception handling, at least until druntime.dll actually works.
110+
alias void function(const(FuncTable)[]*) ehSetFn;
111+
alias const(FuncTable)[] function() ehGetFn;
105112
}
106113

107114
version (Windows)
@@ -112,12 +119,12 @@ version (Windows)
112119
* opaque handle to the DLL if successfully loaded
113120
* null if failure
114121
*/
115-
extern (C) void* rt_loadLibrary(const char* name)
122+
export extern (C) void* rt_loadLibrary(const char* name)
116123
{
117124
return initLibrary(.LoadLibraryA(name));
118125
}
119126

120-
extern (C) void* rt_loadLibraryW(const WCHAR* name)
127+
export extern (C) void* rt_loadLibraryW(const WCHAR* name)
121128
{
122129
return initLibrary(.LoadLibraryW(name));
123130
}
@@ -126,13 +133,58 @@ version (Windows)
126133
{
127134
// BUG: LoadLibrary() call calls rt_init(), which fails if proxy is not set!
128135
// (What? LoadLibrary() is a Windows API call, it shouldn't call rt_init().)
136+
// FYI LoadLibrary calls DllMain. DllMain calls rt_init.
129137
if (mod is null)
130138
return mod;
131139
gcSetFn gcSet = cast(gcSetFn) GetProcAddress(mod, "gc_setProxy");
132140
if (gcSet !is null)
133141
{ // BUG: Set proxy, but too late
134142
gcSet(gc_getProxy());
135143
}
144+
145+
import rt.sections_win64;
146+
147+
ehGetFn ehGet = cast(ehGetFn) GetProcAddress(mod, "_d_innerEhTable");
148+
ehSetFn ehSet = cast(ehSetFn) GetProcAddress(mod, "_d_setEhTablePointer");
149+
150+
typeof(ehGet()) libraryEh;
151+
if (ehGet)
152+
{
153+
libraryEh = ehGet();
154+
if (ehTablesGlobal is null)
155+
{
156+
// first time: copy the local table into it as well as
157+
// the new library
158+
auto local = _d_innerEhTable();
159+
auto len = libraryEh.length + local.length;
160+
auto ptr = cast(FuncTable*) malloc(typeof(ehTablesGlobal[0]).sizeof * len);
161+
ptr[0 .. local.length] = cast(FuncTable[]) local[];
162+
ptr[local.length .. local.length + libraryEh.length] = cast(FuncTable[]) libraryEh[];
163+
ehTablesGlobal = ptr[0 .. len];
164+
}
165+
else
166+
{
167+
// otherwise we need to realloc it to append the library table
168+
auto ptr = ehTablesGlobal.ptr;
169+
ptr = cast(FuncTable*) realloc(cast(void*) ptr,
170+
typeof(ehTablesGlobal[0]).sizeof * (ehTablesGlobal.length + libraryEh.length));
171+
if (ptr is null)
172+
abort();
173+
auto orig = ehTablesGlobal.length;
174+
cast(FuncTable[]) ptr[orig .. orig + libraryEh.length] = cast(FuncTable[]) libraryEh[];
175+
ehTablesGlobal = ptr[0 .. orig + libraryEh.length];
176+
}
177+
178+
// set the local pointer
179+
_d_setEhTablePointer(&ehTablesGlobal);
180+
181+
if (ehSet)
182+
{
183+
// and set the remote table too so throwing from the dll also sees the whole thing
184+
ehSet(&ehTablesGlobal);
185+
}
186+
}
187+
136188
return mod;
137189
}
138190

@@ -144,8 +196,39 @@ version (Windows)
144196
* 1 succeeded
145197
* 0 some failure happened
146198
*/
147-
extern (C) int rt_unloadLibrary(void* ptr)
199+
export extern (C) int rt_unloadLibrary(void* ptr)
148200
{
201+
// should this logic just be done in the dll's DllMain instead?
202+
203+
// need to clear the DLL's table out of the global list, so first that
204+
// means fetching the dll's table...
205+
ehGetFn ehGet = cast(ehGetFn) GetProcAddress(ptr, "_d_innerEhTable");
206+
if (ehGetFn)
207+
{
208+
auto dllTables = ehGetFn();
209+
import rt.sections_win64;
210+
//__gshared package(rt) const(FuncTable)[] ehTablesGlobal;
211+
212+
loop: foreach (entry; dllTables)
213+
{
214+
foreach (idx, ge; ehTablesGlobal)
215+
{
216+
if (ge == entry)
217+
{
218+
import core.stdc.string;
219+
// assumes continuous append! If you ever sort the loading code or something
220+
// be sure to fix this too.
221+
memmove(&ehTablesGlobal[idx], &ehTablesGlobal[idx + dllTables.length], typeof(ge).sizeof * (ehTablesGlobal.length - (idx + dllTables.length)));
222+
ehTablesGlobal = ehTablesGlobal[idx + dllTables.length .. $];
223+
// could realloc it down to the new size, but I suspect it will be useful
224+
// again in the future anyway so might as well let the realloc on load reuse
225+
// space if needed and also simplify this part of the code a little.
226+
break loop;
227+
}
228+
}
229+
}
230+
}
231+
149232
gcClrFn gcClr = cast(gcClrFn) GetProcAddress(ptr, "gc_clrProxy");
150233
if (gcClr !is null)
151234
gcClr();
@@ -179,7 +262,7 @@ shared size_t _initCount;
179262
* If a C program wishes to call D code, and there's no D main(), then it
180263
* must call rt_init() and rt_term().
181264
*/
182-
extern (C) int rt_init()
265+
export extern (C) int rt_init()
183266
{
184267
/* @@BUG 11380 @@ Need to synchronize rt_init/rt_term calls for
185268
version (Shared) druntime, because multiple C threads might
@@ -191,6 +274,12 @@ extern (C) int rt_init()
191274
version (CRuntime_Microsoft)
192275
init_msvc();
193276

277+
version(Win64)
278+
{{
279+
import rt.sections_win64;
280+
loadDefaultEhTables();
281+
}}
282+
194283
_d_monitor_staticctor();
195284
_d_critical_init();
196285

@@ -321,7 +410,7 @@ private alias extern(C) int function(char[][] args) MainFunc;
321410
* runs embedded unittests and then runs the given D main() function,
322411
* optionally catching and printing any unhandled exceptions.
323412
*/
324-
extern (C) int _d_run_main(int argc, char** argv, MainFunc mainFunc)
413+
export extern (C) int _d_run_main(int argc, char** argv, MainFunc mainFunc)
325414
{
326415
// Set up _cArgs and array of D char[] slices, then forward to _d_run_main2
327416

src/rt/sections_win64.d

+26-3
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,7 @@ struct SectionGroup
4444
version (Win64)
4545
@property immutable(FuncTable)[] ehTables() const nothrow @nogc
4646
{
47-
auto pbeg = cast(immutable(FuncTable)*)&_deh_beg;
48-
auto pend = cast(immutable(FuncTable)*)&_deh_end;
49-
return pbeg[0 .. pend - pbeg];
47+
return cast(typeof(return)) *ehTablesFull;
5048
}
5149

5250
@property inout(void[])[] gcRanges() inout nothrow @nogc
@@ -218,6 +216,31 @@ do
218216
return cast(immutable)result;
219217
}
220218

219+
// Used for EH table merging across DLL boundaries
220+
221+
__gshared const(FuncTable)[]* ehTablesFull; // this is the proxy throw actually uses. may point to local or global
222+
__gshared const(FuncTable)[] ehTablesLocal; // never changed, just the local module's things
223+
224+
// this is only valid if we are an exe, it contains the concatenation of the exe and all loaded dlls
225+
__gshared package(rt) const(FuncTable)[] ehTablesGlobal;
226+
227+
package(rt) void loadDefaultEhTables() {
228+
ehTablesLocal = _d_innerEhTable();
229+
ehTablesFull = &ehTablesLocal;
230+
}
231+
232+
extern(C) export void _d_setEhTablePointer(const(FuncTable)[]* ptr) {
233+
ehTablesFull = ptr;
234+
}
235+
236+
extern(C) export const(FuncTable)[] _d_innerEhTable() {
237+
auto pbeg = cast(const(FuncTable)*)&_deh_beg;
238+
auto pend = cast(const(FuncTable)*)&_deh_end;
239+
return pbeg[0 .. pend - pbeg];
240+
}
241+
242+
// finished
243+
221244
extern(C)
222245
{
223246
/* Symbols created by the compiler/linker and inserted into the

0 commit comments

Comments
 (0)