digitalmars.D.learn - Thunking problems with arch issues
- Hiemlick Hiemlicker (115/115) Jul 01 2016 The following code works on dmd x64. Fails on dmd x32 and ldc
- rikki cattermole (8/8) Jul 01 2016 Couple of things could be happening.
- Hiemlick Hiemlicker (15/24) Jul 02 2016 Where? I rewrote the code to use size_t and same problem. If
The following code works on dmd x64. Fails on dmd x32 and ldc x64. The problem is the passed variable. import std.stdio; version (Windows) { import core.sys.windows.windows; void makeExecutable(ubyte[] code) { DWORD old; VirtualProtect(code.ptr, code.length, PAGE_EXECUTE_READWRITE, &old); } } else version (linux) { import core.sys.posix.sys.mman; import core.sys.posix.unistd; static if (!is(typeof(&mprotect))) extern(C) int mprotect(void*, size_t, int); void makeExecutable(ubyte[] code) { auto pageSize = sysconf(_SC_PAGE_SIZE); auto address = ((cast(size_t)code.ptr) & ~(pageSize-1)); int pageCount = (address/pageSize == (address+code.length)/pageSize) ? 1 : 2; mprotect(cast(void*)address, pageSize * pageCount, PROT_READ | PROT_WRITE | PROT_EXEC); } } else static assert(0, "TODO"); R function(A) delegate2function(R, A...)(R delegate(A) d) { enum size_t TEMPLATE1 = cast(size_t)0x01234567_01234567; enum size_t TEMPLATE2 = cast(size_t)0x89ABCDEF_89ABCDEF; static R functionTemplate(A args) { R delegate(A) d; d.ptr = cast(typeof(d.ptr ))TEMPLATE1; d.funcptr = cast(typeof(d.funcptr))TEMPLATE2; return d(args); } static void functionTemplateEnd() {} static void replaceWord(ubyte[] a, size_t from, size_t to) { foreach (i; 0..a.length - size_t.sizeof + 1) { auto p = cast(size_t*)(a.ptr + i); if (*p == from) { *p = to; return; } } assert(0); } auto templateStart = cast(ubyte*)&functionTemplate; auto templateEnd = cast(ubyte*)&functionTemplateEnd; auto templateBytes = templateStart[0 .. templateEnd - templateStart]; // must allocate type with pointers, otherwise GC won't scan it auto functionWords = new void*[(templateBytes.length / (void*).sizeof) + 3]; // store context in word-aligned boundary, so the GC can find it functionWords[0] = d.ptr; functionWords[1] = d.funcptr; functionWords = functionWords[2..$]; auto functionBytes = (cast(ubyte[])functionWords)[0..templateBytes.length]; functionBytes[] = templateBytes[]; replaceWord(functionBytes, TEMPLATE1, cast(size_t)d.ptr ); replaceWord(functionBytes, TEMPLATE2, cast(size_t)d.funcptr); makeExecutable(functionBytes); return cast(typeof(return)) functionBytes.ptr; } public struct sExtThread(T) { uint Id = 0; HANDLE Handle; alias callbackType = extern (Windows) uint function(void*); public void Create(uint delegate(T) c, T param, bool suspended = false, uint stackSize = 16000) { Handle = CreateThread(cast(SECURITY_ATTRIBUTES*)null, stackSize, cast(callbackType)delegate2function(c), cast(void*)¶m, (suspended) ? CREATE_SUSPENDED : 0, &Id); } } void main() { import std.stdio; string q = "WTFSDFA"; sExtThread!string t; t.Create((p) { writeln(q); writeln(p); return 1; }, "ASDFASDF"); getchar(); } p is invalid. Obviously isn't not necessary to pass p but still, somethings wrong. I stole the delegate2function from Vladimir "The Propeller" Panteleev! Thanks Vlad! It doesn't seem to be a problem with x86 since LDC x64 has the same problem(or writes junk I guess). Could be an issue with delegate2function but it's a bit over my head.
Jul 01 2016
Couple of things could be happening. 1) Alignments are off, aligning of data really really matters when dealing with executable code. 2) For Windows only. Don't forget to call FlushInstructionCache. Before executing. https://msdn.microsoft.com/en-us/library/windows/desktop/ms679350(v=vs.85).aspx 3) Don't use new to get your executable memory, nope nope nope. Use things like VirtualAlloc as malloc doesn't work right see the first point.
Jul 01 2016
On Saturday, 2 July 2016 at 01:51:03 UTC, rikki cattermole wrote:Couple of things could be happening. 1) Alignments are off, aligning of data really really mattersWhere? I rewrote the code to use size_t and same problem. If alignments were off chances are it wouldn't exhibit the issues in the way it does(work fine for 64 and not 86, not for ldc).when dealing with executable code. 2) For Windows only. Don't forget to call FlushInstructionCache. Before executing. https://msdn.microsoft.com/en-us/library/windows/desktop/ms679350(v=vs.85).aspxTried, didn't work.3) Don't use new to get your executable memory, nope nope nope. Use things like VirtualAlloc as malloc doesn't work right see the first point.Well.. I see these as general statements that don't actually address the real problem in the code. I rewrote the code and it has the same problem. I see no reason why it shouldn't work. It does not manipulate the code, and new seems to allocate aligned(if not it would work some of the time and fail others). It specifically has the problem when used as a windows callback. I guess it has to do with the calling convention. Here is the complete test code: https://dpaste.dzfl.pl/d8cea3b39d0d
Jul 02 2016