Esempio n. 1
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.
 *
 * Using this function eliminates the requirement with older
 * pseudo-reloc implementations, that sections containing
 * pseudo-relocs (such as .text and .rdata) be permanently
 * marked writable. This older behavior sabotaged any memory
 * savings achieved by shared libraries on win32 -- and was
 * slower, too.  However, on cygwin as of binutils 2.20 the
 * .text section is still marked writable, and the .rdata section
 * is folded into the (writable) .data when --enable-auto-import.
 */
static void
__write_memory (void *addr, const void *src, size_t len)
{
#ifndef __MINGW64_VERSION_MAJOR
    MEMORY_BASIC_INFORMATION b;
    DWORD oldprot;
#endif /* ! __MINGW64_VERSION_MAJOR */

    if (!len)
        return;

#ifndef __MINGW64_VERSION_MAJOR
    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);
#else /* ! __MINGW64_VERSION_MAJOR */
    mark_section_writable ((LPVOID) addr);
#endif  /* __MINGW64_VERSION_MAJOR */

    /* write the data. */
    memcpy (addr, src, len);
    /* Restore original protection. */
#ifndef __MINGW64_VERSION_MAJOR
    if (b.Protect != PAGE_EXECUTE_READWRITE && b.Protect != PAGE_READWRITE)
        VirtualProtect (b.BaseAddress, b.RegionSize, oldprot, &oldprot);
#endif /* !__MINGW64_VERSION_MAJOR */
}
Esempio n. 2
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.
 *
 * Using this function eliminates the requirement with older
 * pseudo-reloc implementations, that sections containing
 * pseudo-relocs (such as .text and .rdata) be permanently
 * marked writable. This older behavior sabotaged any memory
 * savings achieved by shared libraries on win32 -- and was
 * slower, too.  However, on cygwin as of binutils 2.20 the
 * .text section is still marked writable, and the .rdata section
 * is folded into the (writable) .data when --enable-auto-import.
 */
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);
  /* 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);
}
Esempio n. 3
0
static void
mark_section_writable (LPVOID addr)
{
  MEMORY_BASIC_INFORMATION b;
  PIMAGE_SECTION_HEADER h;
  int i;

  for (i = 0; i < maxSections; i++)
    {
      if (the_secs[i].sec_start <= ((LPBYTE) addr)
          && ((LPBYTE) addr) < (the_secs[i].sec_start + the_secs[i].hash->Misc.VirtualSize))
        return;
    }
  h = __mingw_GetSectionForAddress (addr);
  if (!h)
    {
      __report_error ("Address %p has no image-section", addr);
      return;
    }
  the_secs[i].hash = h;
  the_secs[i].old_protect = 0;
  the_secs[i].sec_start = _GetPEImageBase () + h->VirtualAddress;

  if (!VirtualQuery (the_secs[i].sec_start, &b, sizeof(b)))
    {
      __report_error ("  VirtualQuery failed for %d bytes at address %p",
		      (int) h->Misc.VirtualSize, the_secs[i].sec_start);
      return;
    }

  if (b.Protect != PAGE_EXECUTE_READWRITE && b.Protect != PAGE_READWRITE)
    {
      if (!VirtualProtect (b.BaseAddress, b.RegionSize,
			   PAGE_EXECUTE_READWRITE,
			   &the_secs[i].old_protect))
	__report_error ("  VirtualProtect failed with code 0x%x",
	  (int) GetLastError ());
    }
  ++maxSections;
  return;
}
Esempio n. 4
0
static void
restore_modified_sections (void)
{
    int i;
    MEMORY_BASIC_INFORMATION b;
    DWORD oldprot;

    for (i = 0; i < maxSections; i++)
    {
        if (the_secs[i].old_protect == 0)
            continue;
        if (!VirtualQuery (the_secs[i].sec_start, &b, sizeof(b)))
        {
            __report_error ("  VirtualQuery failed for %d bytes at address %p",
                            (int) the_secs[i].hash->Misc.VirtualSize,
                            the_secs[i].sec_start);
            return;
        }
        VirtualProtect (b.BaseAddress, b.RegionSize, the_secs[i].old_protect,
                        &oldprot);
    }
}
Esempio n. 5
0
static void
do_pseudo_reloc (void * start, void * end, void * base)
{
    ptrdiff_t addr_imp, reldata;
    ptrdiff_t reloc_target = (ptrdiff_t) ((char *)end - (char*)start);
    runtime_pseudo_reloc_v2 *v2_hdr = (runtime_pseudo_reloc_v2 *) start;
    runtime_pseudo_reloc_item_v2 *r;

    /* A valid relocation list will contain at least one entry, and
     * one v1 data structure (the smallest one) requires two DWORDs.
     * So, if the relocation list is smaller than 8 bytes, bail.
     */
    if (reloc_target < 8)
        return;

    /* Check if this is the old pseudo relocation version.  */
    /* There are two kinds of v1 relocation lists:
     *   1) With a (v2-style) version header. In this case, the
     *      first entry in the list is a 3-DWORD structure, with
     *      value:
     *         { 0, 0, RP_VERSION_V1 }
     *      In this case, we skip to the next entry in the list,
     *      knowing that all elements after the head item can
     *      be cast to runtime_pseudo_reloc_item_v1.
     *   2) Without a (v2-style) version header. In this case, the
     *      first element in the list IS an actual v1 relocation
     *      record, which is two DWORDs.  Because there will never
     *      be a case where a v1 relocation record has both
     *      addend == 0 and target == 0, this case will not be
     *      confused with the prior one.
     * All current binutils, when generating a v1 relocation list,
     * use the second (e.g. original) form -- that is, without the
     * v2-style version header.
     */
    if (reloc_target >= 12
            && v2_hdr->magic1 == 0 && v2_hdr->magic2 == 0
            && v2_hdr->version == RP_VERSION_V1)
    {
        /* We have a list header item indicating that the rest
         * of the list contains v1 entries.  Move the pointer to
         * the first true v1 relocation record.  By definition,
         * that v1 element will not have both addend == 0 and
         * target == 0 (and thus, when interpreted as a
         * runtime_pseudo_reloc_v2, it will not have both
         * magic1 == 0 and magic2 == 0).
         */
        v2_hdr++;
    }

    if (v2_hdr->magic1 != 0 || v2_hdr->magic2 != 0)
    {
        /*************************
         * Handle v1 relocations *
         *************************/
        runtime_pseudo_reloc_item_v1 * o;
        for (o = (runtime_pseudo_reloc_item_v1 *) v2_hdr;
                o < (runtime_pseudo_reloc_item_v1 *)end;
                o++)
        {
            DWORD newval;
            reloc_target = (ptrdiff_t) base + o->target;
            newval = (*((DWORD*) reloc_target)) + o->addend;
            __write_memory ((void *) reloc_target, &newval, sizeof(DWORD));
        }
        return;
    }

    /* If we got this far, then we have relocations of version 2 or newer */

    /* Check if this is a known version.  */
    if (v2_hdr->version != RP_VERSION_V2)
    {
        __report_error ("  Unknown pseudo relocation protocol version %d.\n",
                        (int) v2_hdr->version);
        return;
    }

    /*************************
     * Handle v2 relocations *
     *************************/

    /* Walk over header. */
    r = (runtime_pseudo_reloc_item_v2 *) &v2_hdr[1];

    for (; r < (runtime_pseudo_reloc_item_v2 *) end; r++)
    {
        /* location where new address will be written */
        reloc_target = (ptrdiff_t) base + r->target;

        /* get sym pointer. It points either to the iat entry
         * of the referenced element, or to the stub function.
         */
        addr_imp = (ptrdiff_t) base + r->sym;
        addr_imp = *((ptrdiff_t *) addr_imp);

        /* read existing relocation value from image, casting to the
         * bitsize indicated by the 8 LSBs of flags. If the value is
         * negative, manually sign-extend to ptrdiff_t width. Raise an
         * error if the bitsize indicated by the 8 LSBs of flags is not
         * supported.
         */
        switch ((r->flags & 0xff))
        {
        case 8:
            reldata = (ptrdiff_t) (*((unsigned char *)reloc_target));
            if ((reldata & 0x80) != 0)
                reldata |= ~((ptrdiff_t) 0xff);
            break;
        case 16:
            reldata = (ptrdiff_t) (*((unsigned short *)reloc_target));
            if ((reldata & 0x8000) != 0)
                reldata |= ~((ptrdiff_t) 0xffff);
            break;
        case 32:
            reldata = (ptrdiff_t) (*((unsigned int *)reloc_target));
#ifdef _WIN64
            if ((reldata & 0x80000000) != 0)
                reldata |= ~((ptrdiff_t) 0xffffffff);
#endif
            break;
#ifdef _WIN64
        case 64:
            reldata = (ptrdiff_t) (*((unsigned long long *)reloc_target));
            break;
#endif
        default:
            reldata=0;
            __report_error ("  Unknown pseudo relocation bit size %d.\n",
                            (int) (r->flags & 0xff));
            break;
        }

        /* Adjust the relocation value */
        reldata -= ((ptrdiff_t) base + r->sym);
        reldata += addr_imp;

        /* Write the new relocation value back to *reloc_target */
        switch ((r->flags & 0xff))
        {
        case 8:
            __write_memory ((void *) reloc_target, &reldata, 1);
            break;
        case 16:
            __write_memory ((void *) reloc_target, &reldata, 2);
            break;
        case 32:
            __write_memory ((void *) reloc_target, &reldata, 4);
            break;
#ifdef _WIN64
        case 64:
            __write_memory ((void *) reloc_target, &reldata, 8);
            break;
#endif
        }
    }
}