2012-08-26 * pseudo-reloc.cc (auto_protect_for): Define. (__write_memory): Use auto_protect_for, add verbose message displaying the number of items. (_pei386_runtime_relocator):Add verbose message displaying time taken for pseudo-reloc. Index: winsup/cygwin/pseudo-reloc.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/pseudo-reloc.cc,v retrieving revision 1.10 diff -u -p -r1.10 pseudo-reloc.cc --- winsup/cygwin/pseudo-reloc.cc 16 Aug 2012 23:34:44 -0000 1.10 +++ winsup/cygwin/pseudo-reloc.cc 26 Aug 2012 01:47:13 -0000 @@ -125,7 +125,78 @@ __report_error (const char *msg, ...) abort (); #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 c[2]; + static int current = 0; + static int state = 0; + static DWORD oldprot; + if (addr == 0) + state = 2; + if (state == 0) + { + state = 1; +#if 0 + debug_printf("mark as initial %p", addr); +#endif + loop: + { + MEMORY_BASIC_INFORMATION * const b = &c[current]; + if (!VirtualQuery(addr, b, sizeof(MEMORY_BASIC_INFORMATION))) + { + __report_error(" VirtualQuery failed for %d bytes at address %p", + (int) sizeof(MEMORY_BASIC_INFORMATION), 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); + } + } + else if (state == 1) + { + MEMORY_BASIC_INFORMATION * const b = &c[current]; + void* ptr = ((void*) ((ptrdiff_t) b->BaseAddress + + (ptrdiff_t) b->RegionSize)); +#if 0 + debug_printf("reloc base %p bound %p", b->BaseAddress,ptr); +#endif + if ((addr >= b->BaseAddress) && addr < ptr) + { +#if 0 + debug_printf("mark as old %p", addr); +#endif + } + else + { +#if 0 + debug_printf("mark as new %p", addr); +#endif + /* Restore original protection. */ + if (b->Protect != PAGE_EXECUTE_READWRITE + && b->Protect != PAGE_READWRITE) + VirtualProtect(b->BaseAddress, b->RegionSize, oldprot, &oldprot); + current = (current + 1) % 2; + goto loop; + } + } + else if (state == 2) + { + MEMORY_BASIC_INFORMATION * const b = &c[current]; + if (b->Protect != PAGE_EXECUTE_READWRITE && b->Protect != PAGE_READWRITE) + VirtualProtect(b->BaseAddress, b->RegionSize, oldprot, &oldprot); + current = 0; + state = 0; + } +} /* This function temporarily marks the page containing addr * writable, before copying len bytes from *src to *addr, and * then restores the original protection settings to the page. @@ -142,27 +213,14 @@ __report_error (const char *msg, ...) static void __write_memory (void *addr, const void *src, size_t len) { - MEMORY_BASIC_INFORMATION b; - DWORD oldprot; - if (!len) return; - - 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) - VirtualProtect (b.BaseAddress, b.RegionSize, PAGE_EXECUTE_READWRITE, - &oldprot); + /* + * Hopefully it would eliminate unnecessary call to Virtual{Query,Protect}. + */ + auto_protect_for(addr); /* write the data. */ 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 @@ -222,8 +280,10 @@ do_pseudo_reloc (void * start, void * en /************************* * Handle v1 relocations * *************************/ - runtime_pseudo_reloc_item_v1 * o; - for (o = (runtime_pseudo_reloc_item_v1 *) v2_hdr; + runtime_pseudo_reloc_item_v1 * o=(runtime_pseudo_reloc_item_v1*)v2_hdr; + debug_printf("Iterating through %d items", + ((ptrdiff_t)end-(ptrdiff_t)o)/sizeof(runtime_pseudo_reloc_item_v1)); + for (; o < (runtime_pseudo_reloc_item_v1 *)end; o++) { @@ -232,6 +292,10 @@ do_pseudo_reloc (void * start, void * en newval = (*((DWORD*) reloc_target)) + o->addend; __write_memory ((void *) reloc_target, &newval, sizeof (DWORD)); } + /* + * Initialize variables in function for latter use. + */ + auto_protect_for(0); return; } @@ -251,7 +315,8 @@ do_pseudo_reloc (void * start, void * en /* Walk over header. */ r = (runtime_pseudo_reloc_item_v2 *) &v2_hdr[1]; - + debug_printf("Iterating through %d items", + ((ptrdiff_t)end-(ptrdiff_t)r)/sizeof(runtime_pseudo_reloc_item_v2)); for (; r < (runtime_pseudo_reloc_item_v2 *) end; r++) { /* location where new address will be written */ @@ -322,7 +387,11 @@ do_pseudo_reloc (void * start, void * en break; #endif } - } + } + /* + * Initialize variables in function for latter use. + */ + auto_protect_for(0); } #ifdef __CYGWIN__ @@ -330,7 +399,12 @@ extern "C" void _pei386_runtime_relocator (per_process *u) { if (u && CYGWIN_VERSION_USE_PSEUDO_RELOC_IN_DLL (u)) - do_pseudo_reloc (u->pseudo_reloc_start, u->pseudo_reloc_end, u->image_base); + { + DWORD tick = GetTickCount(); + do_pseudo_reloc(u->pseudo_reloc_start, u->pseudo_reloc_end, u->image_base); + debug_printf("HMODULE %p did pseudo-relocation in %Dms", + u->image_base, GetTickCount()-tick); + } } #else extern "C" void