代码之家  ›  专栏  ›  技术社区  ›  Barry

FS寄存器为空

  •  1
  • Barry  · 技术社区  · 9 年前

    我必须实现一个基于SEH的异常处理程序。 首先,我编写了以下示例代码,在这里我尝试使用 飞行时间 登记

    #include <iostream>
    #include <exception>
    #include <windows.h>
    
    using namespace std;
    
    
    EXCEPTION_DISPOSITION myHandler(
        _EXCEPTION_RECORD *ExcRecord,
        void * EstablisherFrame,
        _CONTEXT *ContextRecord,
        void * DispatcherContext)
    {
        cout << "In the exception handler" << endl;
        cout << "Just a demo. exiting..." << endl;
        return ExceptionContinueExecution;
    }
    
    int main()
    {
        cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!
    
        EXCEPTION_REGISTRATION myExceptReg;
        EXCEPTION_REGISTRATION *pReg = &myExceptReg;
        myExceptReg.handler = myHandler;
        DWORD prev;
    
        asm("movl %fs:0 , %eax");
        asm("movl %%eax , %0": "=r" (prev));
    
        myExceptReg.prev = (EXCEPTION_REGISTRATION*) prev;
    
        asm ("movl %0, %%eax" : "=m" (pReg));
        asm("movl %eax , %fs:0");
    
        //      int* ptr = 0;
        //      exception e;
    
        return 0;
    }
    

    当我调试代码时,我看到 飞行时间 寄存器是 .执行后程序崩溃 asm(“移动%fs:0,%eax”);

    以下是此代码的等效程序集示例。

    000000000000401626:   mov     %rax,%rcx
    000000000000401629:   callq   0x44d7a0 <std::ostream::operator<<(std::ostream& (*)(std::ostream&))>
    32                  EXCEPTION_REGISTRATION *pReg = &myExceptReg;
    00000000000040162e:   lea     0x20(%rbp),%rax
    000000000000401632:   mov     %rax,0x18(%rbp)
    33                  myExceptReg.handler = myHandler;
    000000000000401636:   lea     -0x13d(%rip),%rax        # 0x401500     <myHandler(_EXCEPTION_RECORD*, void*, _CONTEXT*, void*)>
    00000000000040163d:   mov     %rax,0x28(%rbp)
    36                  asm("movl %fs:0 , %eax");
    000000000000401641:   mov     %fs:0x0,%eax
    37                  asm("movl %%eax , %0": "=r" (prev));
    000000000000401649:   mov     %eax,%ebx
    00000000000040164b:   mov     %ebx,0x3c(%rbp)
    39                  myExceptReg.prev = (EXCEPTION_REGISTRATION*) prev;
    00000000000040164e:   mov     0x3c(%rbp),%eax
    000000000000401651:   mov     %rax,0x20(%rbp)
    41                  asm ("movl %0, %%eax" : "=m" (pReg));
    000000000000401655:   mov     0x18(%rbp),%eax
    42                  asm("movl %eax , %fs:0");
    000000000000401658:   mov     %eax,%fs:0x0
    50                  return 0;
    

    问题可能是什么?

    2 回复  |  直到 9 年前
        1
  •  1
  •   David Wohlferd    9 年前

    综上所述:

    调试输出显示代码是为64位编译的,并且(正如Hans所指出的)所使用的异常处理样式仅对32位有效。确保代码编译为32位可以解决问题。

    如果这回答了您的问题,请单击左侧的复选标记,以便获得业力。

        2
  •  0
  •   Community CDub    5 年前

    除了64位的问题之外,你还无缘无故地大吃一惊 %eax (没有告诉编译器)。

    我很惊讶它竟然能和你的原始消息源一起工作。你很幸运,编译器正在重写 %eax公司 不管怎么说,可能是因为你 -O0 做一些讨厌的代码,永远不会把任何东西长时间保存在寄存器中。因此,只要在编译时启用了优化,您的代码就会崩溃。

    你也很幸运,编译器没有在两个asm语句之间插入任何指令 %eax公司 。永远不要指望寄存器或标志在两个asm块之间存活:在单个块中使用多条指令。

    除此之外, asm ("movl %0, %%eax" : "=m" (pReg)); 告诉编译器asm语句覆盖 pReg 而不读取旧值。再一次,只有 -0 避免了此错误,因为它没有优化 pReg = &myExceptReg; 如果 pReg基因 无论如何都会被覆盖。具有 -O1 或更高, 你应该期待 pReg基因 未初始化 .


    使用以下内容

    void* prev;
    asm volatile("mov %%fs:0, %0": "=r" (prev));
    ...
    asm volatile("movl %0, %%fs:0" : : "re" (pReg) : "memory");
    // reg or immediate source, but not memory, are encodable with a memory destination
    

    当被询问时,编译器将负责将变量保存在寄存器中。如果它想存储 prev 稍后回到记忆中,它会这样做的。没有必要强迫它这样做,而且 "=r" (prev) 刚刚从生成了一个冗余的reg reg移动 %eax公司 无论gcc决定保留什么其他reg 上一篇 在里面

    由于(根据Hans的说法),此代码仅在32位时有用,所以我在 movl 存储到内存的后缀,因此编译器可以在不需要寄存器来确定操作数大小时确定操作数的大小。(即,当该值是全局或静态符号的编译时常量地址时。)

    除此之外,此源代码可以编译为正确的64位代码,因为它没有显式命名任何寄存器。

    您可以删除 "e" 约束的一部分 l 后缀,以便在32位和64位之间轻松移植第二个asm语句,代价是迫使编译器浪费一条指令,将地址先放入寄存器,即使不需要。在64位模式下, mov r/m64, imm32 (英特尔语法)是您所需要的。我用过 an "e" constraint 而不是 "i" 因为不能对任意64位常量进行编码,所以只能对32位常量进行符号扩展。幸运的是,在默认代码模型中,符号地址可以安全地假定为低2GB。链接器可以将地址填入32位重定位。

    要使它在32位和64位之间可移植地使用立即数操作数,您需要让它输出64位的“movq”。我认为您必须使用预处理器来测试i386和amd64。 if(sizeof(void*) == 4) { asm("movl ..."); } else { asm("movq..."); } 也许也能起作用。这会使代码变得非常难看 -0 ,但分支的假面仍会聚集(到 mov r/m32, imm32 )永远不要跑。