fxsave导致读/写受保护的内存 [英] fxsave causing reading/writing protected memory

查看:87
本文介绍了fxsave导致读/写受保护的内存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尽管此块不受管理,但我正在尝试在C ++/CLI中创建函数:

I''m trying to make a function in C++/CLI though this block is unmanaged :

int MXCSR_MASK()
{
    if (FXSAVE_SUPPORTED())
    {
        unsigned char *buffer = new unsigned char[512];
        __asm{
            fxsave [buffer]
        }
        return *(int*)(buffer + 28);
    }
    return 0;
}



只是应该使用FXSAVE指令从CPU获得一个标志.当它执行fxsave指令时,我得到一个System.AccessViolationException,它将指示我有错误的地址,但我也尝试首先将指针移到eax中,然后使用它.我也尝试过使用对齐的缓冲区.在所有测试中,异常都会奇怪地报告:

访问冲突读取位置0xffffffff.

该指令是否可能无法在用户模式代码中使用,或者我缺少某些内容?



感谢下面的回答者.奇迹般有效.但是,我进行了一些更改,以防止MSVC ++抱怨ebp被修改:



this is simply supposed to get a flag from the CPU using the FXSAVE instruction. When it does the fxsave instruction, I get a System.AccessViolationException which would indicate that I have the wrong address, but I also tried first moving the pointer into eax and then using that. I also tried using an aligned buffer. In all tests the Exception strangely reports:

Access violation reading location 0xffffffff.

Is it possible that this instruction can''t be used in user mode code or am I missing something?



Thanks to the answerer below. Works like a charm. However, I changed it slightly to keep MSVC++ from complaining about ebp being modified:

int MXCSR_MASK()
{
    if (FXSAVE_SUPPORTED())
    {
        int result;
        __asm
        {
            mov     ebx, esp
            and     esp, 0FFFFFFF0h
            sub     esp, 512
            fxsave  [esp]
            mov     eax, DWORD PTR [esp + 28]
            mov     result, eax
            mov     esp, ebx
        }
        return result;
    }
    return 0;
}


我不知道为什么我在运行时手动更改指针(以查看是否将其固定)到对齐的地址没有用.再次感谢.


I wonder why my manual changing of the pointer at runtime (just to see if it fixed it) to an aligned address did not work. Thanks again.

推荐答案

在用户和内核模式下都可以使用 fxsave 指令,但是您缺少一个约束:目标地址该操作的字节必须在16个字节的边界上对齐(请参阅英特尔®64和IA-32体系结构软件开发人员手册,第2-455页,第2A卷).
问题在于,新操作符分配的内存在字节绑定上对齐.您可以使用以下代码:

The fxsave instruction could be used both in user and kernel mode, but you are missing a constraint: the destination adress of that operation must be aligned on 16 bytes boundaries (see Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 2A at page 3-455).
The problem is that memory allocated by the new operator is aligned on byte bundaries. You could use the code below:

int MXCSR_MASK()
{
    if (FXSAVE_SUPPORTED())
    {
        int result;
        __asm
        {
            push    ebp
            mov     ebp, esp
            and     esp, 0FFFFFFF0h
            sub     esp, 512
            fxsave  [esp]
            mov     eax, DWORD PTR [esp + 28]
            mov     result, eax
            mov     esp, ebp
            pop     ebp
        }
        return result;
    }
    return 0;
}


我认为您已手动修改了 buffer 变量,以确保其指向与16个字节边界对齐的地址;这还不够,因为 fxsave 指令要求它进行的所有内存访问均与16个字节的边界对齐,这意味着:


  • buffer 指向的缓冲区必须位于与16个字节的Bundaries对齐的地址上
  • buffer 变量的地址必须与16个字节对齐字节边界
I think you have manually modified the buffer variable to ensure that it points to an address aligned to 16 bytes boundaries; this is not enough because the fxsave instruction requires that all the memory accesses it does are aligned to 16 bytes boundaries, this means that:


  • the buffer pointed by buffer must be at an address aligned to 16 bytes bundaries
  • the address of the buffer variable must be aligned to 16 bytes boundaries

  1. 向该函数添加一个虚拟DWORD局部变量,该变量在 buffer 变量声明之前的行中声明(这将在堆栈中将 buffer 的地址向下移4个字节并使其与16个字节的边界对齐)


  1. add a dummy DWORD local variable to the function, declared on the line that preceed the buffer variable declaration (this will shift down the address of buffer on the stack by 4 bytes and make it aligned to 16 bytes boundsries)

int MXCSR_MASK()
{
   if (FXSAVE_SUPPORTED())
   {
      DWORD dummy = 0;
      unsigned char *buffer = new unsigned char[512];
      __asm fxsave [buffer]
      return *(int*)(buffer + 28);
   }
   return 0;
}

  • 您可以将缓冲区指向的地址移至寄存器,然后通过它调用 fxsave

  • you can move the address pointed by buffer to a register and then call fxsave through it

    int MXCSR_MASK()
    {
       if (FXSAVE_SUPPORTED())
       {
          unsigned char *buffer = new unsigned char[512];
          __asm
          {
             mov eax, [buffer]
             fxsave [eax]
          }
          return *(int*)(buffer + 28);
       }
       return 0;
    }



  • 但是,最好的解决方案是我在上一个答案中所写的解决方案,因为它不依赖于内存管理器分配缓冲区的方式,并且它的性能更好,因为它为 fxsave存储的512字节腾出了空间. 直接放在堆栈上,然后立即将其删除;调用new运算符需要C ++运行时进行某种工作,以便在堆上分配该内存,然后在不再需要该内存时将其释放.



    However, the best solution is the one that I wrote on my previous answer, because it is not dependant on how the memory manager allocate your buffer, and its performance are better, because it make room for the 512 bytes stored by fxsave directly on the stack and immediately remove them; a call to the new operator involves some kind of work for the C++ runtime to allocate that memory on the heap and then to deallocate it when it''s no longer needed.


    这篇关于fxsave导致读/写受保护的内存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆