* pseudo-reloc.cc (auto_protect_for): New function.

(__write_memory): Call auto_protect_for to handle page protection.
	(do_pseudo_reloc): Call auto_protect_for to restore old page protection.
This commit is contained in:
Corinna Vinschen 2012-09-02 10:21:34 +00:00
parent 199a8245e0
commit 7dc5165954
2 changed files with 57 additions and 18 deletions

View File

@ -1,3 +1,10 @@
2012-09-02 Jin-woo Ye <jojelino@gmail.com>
Corinna Vinschen <corinna@vinschen.de>
* pseudo-reloc.cc (auto_protect_for): New function.
(__write_memory): Call auto_protect_for to handle page protection.
(do_pseudo_reloc): Call auto_protect_for to restore old page protection.
2012-08-26 Christopher Faylor <me.cygwin2012@cgf.cx> 2012-08-26 Christopher Faylor <me.cygwin2012@cgf.cx>
* pinfo.cc (pinfo::init): Remove assertion. * pinfo.cc (pinfo::init): Remove assertion.

View File

@ -126,6 +126,49 @@ __report_error (const char *msg, ...)
#endif #endif
} }
/*
* This function automatically sets addr as PAGE_EXECUTE_READWRITE
* by deciding whether VirtualQuery for the addr is actually needed.
* And it assumes that it is called in LdrpCallInitRoutine.
* Hence not thread safe.
*/
static void
auto_protect_for (void* addr)
{
static MEMORY_BASIC_INFORMATION mbi;
static bool state = false;
static DWORD oldprot;
if (!addr)
{
/* Restore original protection. */
if (!(mbi.Protect & (PAGE_EXECUTE_READWRITE | PAGE_READWRITE)))
VirtualProtect (mbi.BaseAddress, mbi.RegionSize, oldprot, &oldprot);
state = false;
return;
}
if (state)
{
/* We have valid region information. Are we still within this region?
If so, just leave. */
void *ptr = ((void*) ((ptrdiff_t) mbi.BaseAddress + mbi.RegionSize));
if (addr >= mbi.BaseAddress && addr < ptr)
return;
/* Otherwise, restore original protection and fall through to querying
and potentially changing next region. */
if (!(mbi.Protect & (PAGE_EXECUTE_READWRITE | PAGE_READWRITE)))
VirtualProtect (mbi.BaseAddress, mbi.RegionSize, oldprot, &oldprot);
}
else
state = true;
/* Query region and temporarily allow write access to read-only protected
memory. */
VirtualQuery (addr, &mbi, sizeof mbi);
if (!(mbi.Protect & (PAGE_EXECUTE_READWRITE | PAGE_READWRITE)))
VirtualProtect (mbi.BaseAddress, mbi.RegionSize,
PAGE_EXECUTE_READWRITE, &oldprot);
}
/* This function temporarily marks the page containing addr /* This function temporarily marks the page containing addr
* writable, before copying len bytes from *src to *addr, and * writable, before copying len bytes from *src to *addr, and
* then restores the original protection settings to the page. * then restores the original protection settings to the page.
@ -142,27 +185,12 @@ __report_error (const char *msg, ...)
static void static void
__write_memory (void *addr, const void *src, size_t len) __write_memory (void *addr, const void *src, size_t len)
{ {
MEMORY_BASIC_INFORMATION b;
DWORD oldprot;
if (!len) if (!len)
return; return;
/* Fix page protection for writing. */
if (!VirtualQuery (addr, &b, sizeof (b))) auto_protect_for (addr);
{
__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)
VirtualProtect (b.BaseAddress, b.RegionSize, PAGE_EXECUTE_READWRITE,
&oldprot);
/* write the data. */ /* write the data. */
memcpy (addr, src, len); memcpy (addr, src, len);
/* Restore original protection. */
if (b.Protect != PAGE_EXECUTE_READWRITE && b.Protect != PAGE_READWRITE)
VirtualProtect (b.BaseAddress, b.RegionSize, oldprot, &oldprot);
} }
#define RP_VERSION_V1 0 #define RP_VERSION_V1 0
@ -232,6 +260,8 @@ do_pseudo_reloc (void * start, void * end, void * base)
newval = (*((DWORD*) reloc_target)) + o->addend; newval = (*((DWORD*) reloc_target)) + o->addend;
__write_memory ((void *) reloc_target, &newval, sizeof (DWORD)); __write_memory ((void *) reloc_target, &newval, sizeof (DWORD));
} }
/* Restore original protection. */
auto_protect_for (NULL);
return; return;
} }
@ -322,7 +352,9 @@ do_pseudo_reloc (void * start, void * end, void * base)
break; break;
#endif #endif
} }
} }
/* Restore original protection. */
auto_protect_for (NULL);
} }
#ifdef __CYGWIN__ #ifdef __CYGWIN__