So, it looks like what has happened is that newer OSs (ie >= Vista) set
the page protect to PAGE_EXECUTE_WRITECOPY when doing a LoadLibrary.
This is a (relatively) new flag and apparently Mingw still assumes the
old values are always in use.
There are 3 places in pseudo-reloc.c that do comparisons of b.Protect to
PAGE_EXECUTE_READWRITE. I believe all three should also check for
PAGE_EXECUTE_WRITECOPY.
It also looks like a minor perf improvement in __write_memory is
possible by adding an #else for that VirtualQuery / VirtualProtect stuff:
static void
__write_memory (void *addr, const void *src, size_t len)
{
if (!len)
return;
#ifdef __MINGW64_VERSION_MAJOR
/* Mark the section writable once, and unset it in
* restore_modified_sections. */
mark_section_writable ((LPVOID) addr);
#else/* __MINGW64_VERSION_MAJOR */
MEMORY_BASIC_INFORMATION b;
DWORD oldprot = 0;
int call_unprotect = 0;
if (!VirtualQuery (addr, &b, sizeof(b)))
{
__report_error (" VirtualQuery failed for %d bytes at address %p",
(int) sizeof(b), addr);
}
/* Temporarily allow write access to read-only protected memory. */
if (b.Protect != PAGE_EXECUTE_READWRITE && b.Protect !=
PAGE_READWRITE && b.Protect != PAGE_EXECUTE_WRITECOPY)
{
call_unprotect = 1;
VirtualProtect (b.BaseAddress, b.RegionSize, PAGE_EXECUTE_READWRITE,
&oldprot);
}
#endif /* __MINGW64_VERSION_MAJOR */
/* write the data. */
memcpy (addr, src, len);
#ifndef __MINGW64_VERSION_MAJOR
/* Restore original protection. */
if (call_unprotect && b.Protect != PAGE_EXECUTE_READWRITE &&
b.Protect != PAGE_READWRITE && b.Protect != PAGE_EXECUTE_WRITECOPY)
VirtualProtect (b.BaseAddress, b.RegionSize, oldprot, &oldprot);
#endif /* __MINGW64_VERSION_MAJOR */
}
If setting the protection in mark_section_writable was unsuccessful
(unlikely as that is), trying to set it again here is not likely to help.
NB: I haven't tried this, but you have the setup to test it anyway.
Also, this code snippet only fixes 2 of the 3 places that use
PAGE_EXECUTE_WRITECOPY. Remember to change the comparison in
mark_section_writable() as well.
FWIW,
dw
On 8/15/2014 8:17 PM, Vadim Chugunov wrote:
Okay, I was wrong about __MINGW64_VERSION_MAJOR: it *was* defined.
What apparently happens is that the VirtualQuery() call that follows
mark_section_writable(), returns page protection status of 0x80
(PAGE_EXECUTE_WRITECOPY), which is unexpected by the relocator code,
so it falls back to calling VirtualProtect() per relocation entry.
I am not entirely sure how this situation comes about, but here you go...
On Fri, Aug 15, 2014 at 1:01 AM, Vadim Chugunov <[email protected]
<mailto:[email protected]>> wrote:
Hi,
I am trying to figure out the cause of a slow application startup,
and the evidence I have so far, points to mingw's
_pei386_runtime_relocator() routine as the culprit. When I start
my app under debugger, I see this function calling
VirtualProtect() about a zillion times in a row.
Looking at the source, I see that __pei386_runtime_relocator() is
supposed to change memory protection just once per executable
section, but only if __MINGW64_VERSION_MAJOR is defined at
compilation time. Otherwise, it reverts to changing protection
once per relocation entry, for compatibility (?).
Unfortunately, I don't see any headers included by pseudo-reloc.c
that would define this symbol. And, indeed, the behavior I am
seeing at runtime indicates that if was not defined...
Am I reading this right?
Thanks!
Vadim
(mingw version = i686-4.9.0-win32-dwarf-rt_v3-rev2)
------------------------------------------------------------------------------
_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
------------------------------------------------------------------------------
_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public