XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
#include "../NativePal.h"

// XFESystem implementation of x64 DIV/IDIV operand decoding. Both zero divisors
// and quotient overflow cause #DE. Microsoft's MIT-licensed NativeAOT Unix PAL
// (v10.0.12 HardwareExceptions.cpp) similarly inspects the divisor before handing
// the exception to the unchanged official managed exception handler.
namespace {
struct Instruction {
    const volatile uint8_t* bytes;
    unsigned offset;
    bool byte(uint8_t& result) { if(offset==15)return false;result=bytes[offset++];return true; }
    bool displacement(unsigned count,int64_t& result) {
        uint32_t value=0;uint8_t next;
        for(unsigned i=0;i<count;i++){if(!byte(next))return false;value|=(uint32_t)next<<(8*i);}
        result=count==1?(int8_t)value:(int32_t)value;return true;
    }
};
uint64_t reg(const XfeRuntimeInterruptFrame& f,unsigned number) {
    switch(number) {
        case 0:return f.rax;case 1:return f.rcx;case 2:return f.rdx;case 3:return f.rbx;
        case 4:return f.rsp;case 5:return f.rbp;case 6:return f.rsi;case 7:return f.rdi;
        case 8:return f.r8;case 9:return f.r9;case 10:return f.r10;case 11:return f.r11;
        case 12:return f.r12;case 13:return f.r13;case 14:return f.r14;case 15:return f.r15;
        default:return 0;
    }
}
uint64_t segment_base(unsigned segment) {
    if(segment!=0x64 && segment!=0x65)return 0;
    uint32_t low,high;
    __asm__ volatile("rdmsr":"=a"(low),"=d"(high):"c"(segment==0x64?0xc0000100U:0xc0000101U));
    return ((uint64_t)high<<32)|low;
}
}
extern "C" int XfeRuntimeClassifyDivideFault(const XfeRuntimeInterruptFrame* frame,uint32_t* code)
{
    if(!frame || !frame->rip || !code)return 0;
    Instruction instruction{(const volatile uint8_t*)frame->rip,0};
    bool operand16=false,address32=false;uint8_t rex=0,segment=0,opcode;
    for(;;) {
        if(!instruction.byte(opcode))return 0;
        if(opcode>=0x40 && opcode<=0x4f){rex=opcode;continue;}
        bool prefix=true;
        switch(opcode) {
            case 0x66:operand16=true;break;
            case 0x67:address32=true;break;
            case 0x26:case 0x2e:case 0x36:case 0x3e:case 0x64:case 0x65:segment=opcode;break;
            case 0xf0:case 0xf2:case 0xf3:break;
            default:prefix=false;break;
        }
        if(!prefix)break;
        rex=0; // A REX prefix has effect only after the last legacy prefix.
    }
    if(opcode!=0xf6 && opcode!=0xf7)return 0;
    uint8_t modrm;if(!instruction.byte(modrm))return 0;
    unsigned operation=(modrm>>3)&7;if(operation!=6 && operation!=7)return 0;
    unsigned width=opcode==0xf6?8:(rex&8)?64:operand16?16:32;
    unsigned mode=modrm>>6,operand=modrm&7;
    uint64_t divisor;
    if(mode==3) {
        if(width==8 && !rex && operand>=4)divisor=reg(*frame,operand-4)>>8;
        else divisor=reg(*frame,operand|((rex&1)?8:0));
    } else {
        uint64_t address=0;int64_t displacement=0;bool ripRelative=false;
        if(operand==4) {
            uint8_t sib;if(!instruction.byte(sib))return 0;
            unsigned base=sib&7,index=(sib>>3)&7;
            if(mode==0 && base==5) { if(!instruction.displacement(4,displacement))return 0; }
            else address=reg(*frame,base|((rex&1)?8:0));
            if(index!=4 || (rex&2))address+=reg(*frame,index|((rex&2)?8:0))<<(sib>>6);
        } else if(mode==0 && operand==5) {
            if(!instruction.displacement(4,displacement))return 0;ripRelative=true;
        } else address=reg(*frame,operand|((rex&1)?8:0));
        if(mode==1 && !instruction.displacement(1,displacement))return 0;
        if(mode==2 && !instruction.displacement(4,displacement))return 0;
        if(ripRelative)address=frame->rip+instruction.offset;
        address+=(uint64_t)displacement;
        if(address32)address=(uint32_t)address;
        address+=segment_base(segment);
        // The processor successfully read this operand before raising #DE.
        // The BSP remains stopped on its exception stack throughout decoding.
        divisor=0;auto bytes=(const volatile uint8_t*)address;
        for(unsigned i=0;i<width/8;i++)divisor|=(uint64_t)bytes[i]<<(8*i);
    }
    if(width<64)divisor&=(1ULL<<width)-1;
    *code=divisor?0xc0000095U:0xc0000094U;
    return 1;
}