Box86源码剖析(三)

本文涉及的产品
公网NAT网关,每月750个小时 15CU
简介: Box86源码剖析(三)

Box86源码剖析

Box86

前文回顾

源码阅读

Run()

跳转系统调用函数实现:x86Syscall(emu);

总结

动态指令翻译的过程

举例说明:

底层调用库接口使用流程

Box86

20201020144418445.png

前文回顾

在前面的代码阅读过程中,我们已经成功找到了真正去翻译程序并执行的入口函数 Run(),具体内容可以参考下面链接:


Box86源码剖析(一)

Box86源码剖析(二)


前面看到的内容概况下来如下:

20201104172805749.png

源码阅读

Run()

从前面,我们看到 Box86 的真正进行指令翻译和执行的入口在于 x86run.c 文件中的 Run() 函数,该函数的实现太长,这里就取前半部分看一下:



int Run(x86emu_t *emu, int step)
{
    uint8_t opcode;
    uint8_t nextop;
    reg32_t *oped;
    uint8_t tmp8u, tmp8u2;
    int8_t tmp8s;
    uint16_t tmp16u, tmp16u2;
    int16_t tmp16s;
    uint32_t tmp32u, tmp32u2, tmp32u3;
    int32_t tmp32s, tmp32s2;
    uint64_t tmp64u;
    int64_t tmp64s;
    uintptr_t ip;
    double d;
    float f;
    int64_t ll;
    sse_regs_t *opex, eax1;
    mmx_regs_t *opem, eam1;
    if(emu->quit)
        return 0;
    //ref opcode: http://ref.x86asm.net/geek32.html#xA1
    printf_log(LOG_DEBUG, "Run X86 (%p), EIP=%p, Stack=%p\n", emu, (void*)R_EIP, emu->context->stack);
#define F8      *(uint8_t*)(ip++)
#define F8S     *(int8_t*)(ip++)
#define F16     *(uint16_t*)(ip+=2, ip-2)
#define F32     *(uint32_t*)(ip+=4, ip-4)
#define F32S    *(int32_t*)(ip+=4, ip-4)
#define PK(a)   *(uint8_t*)(ip+a)
#ifdef DYNAREC
#define STEP if(step) goto stepout;
#else
#define STEP
#endif
    static const void* baseopcodes[256] ={
    &&_0x00_0,  &&_0x00_1,  &&_0x00_2,  &&_0x00_3,  &&_0x00_4,  &&_0x00_5,  &&_0x06,    &&_0x07,      //0x00-0x07
    &&_0x08_0,  &&_0x08_1,  &&_0x08_2,  &&_0x08_3,  &&_0x08_4,  &&_0x08_5,  &&_0x0E,    &&_0x0F,      //0x08-0x0F
    &&_0x10_0,  &&_0x10_1,  &&_0x10_2,  &&_0x10_3,  &&_0x10_4,  &&_0x10_5,  &&_0x16,    &&_0x17,      //0x10-0x17
    &&_0x18_0,  &&_0x18_1,  &&_0x18_2,  &&_0x18_3,  &&_0x18_4,  &&_0x18_5,  &&_0x1E,    &&_0x1F,      //0x18-0x1F
    &&_0x20_0,  &&_0x20_1,  &&_0x20_2,  &&_0x20_3,  &&_0x20_4,  &&_0x20_5,  &&_0x26,    &&_0x27,      //0x20-0x27
    &&_0x28_0,  &&_0x28_1,  &&_0x28_2,  &&_0x28_3,  &&_0x28_4,  &&_0x28_5,  &&_0x2E,    &&_0x2F,      //0x28-0x2F
    &&_0x30_0,  &&_0x30_1,  &&_0x30_2,  &&_0x30_3,  &&_0x30_4,  &&_0x30_5,  &&_0x36,    &&_0x37,      //0x30-0x37
    &&_0x38,    &&_0x39,    &&_0x3A,    &&_0x3B,    &&_0x3C,    &&_0x3D,    &&_0x3E,    &&_0x3F,      //0x38-0x3F
    &&_0x40,    &&_0x41,    &&_0x42,    &&_0x43,    &&_0x44,    &&_0x45,    &&_0x46,    &&_0x47, 
    &&_0x48,    &&_0x49,    &&_0x4A,    &&_0x4B,    &&_0x4C,    &&_0x4D,    &&_0x4E,    &&_0x4F,     
    &&_0x50,    &&_0x51,    &&_0x52,    &&_0x53,    &&_0x54,    &&_0x55,    &&_0x56,    &&_0x57, 
    &&_0x58,    &&_0x59,    &&_0x5A,    &&_0x5B,    &&_0x5C,    &&_0x5D,    &&_0x5E,    &&_0x5F, 
    &&_0x60,    &&_0x61,    &&_0x62,    &&_0x63,    &&_0x64,    &&_0x65,    &&_0x66,    &&_0x67,
    &&_0x68,    &&_0x69,    &&_0x6A,    &&_0x6B,    &&_0x6C,    &&_0x6D,    &&_0x6E,    &&_0x6F,      //0x68-0x6F
    &&_0x70_0,  &&_0x70_1,  &&_0x70_2,  &&_0x70_3,  &&_0x70_4,  &&_0x70_5,  &&_0x70_6,  &&_0x70_7,    //0x70-0x77
    &&_0x70_8,  &&_0x70_9,  &&_0x70_A,  &&_0x70_B,  &&_0x70_C,  &&_0x70_D,  &&_0x70_E,  &&_0x70_F,    //0x78-0x7F
    &&_0x80,    &&_0x81,    &&_0x82,    &&_0x83,    &&_0x84,    &&_0x85,    &&_0x86,    &&_0x87,     
    &&_0x88,    &&_0x89,    &&_0x8A,    &&_0x8B,    &&_0x8C,    &&_0x8D,    &&_0x8E,    &&_0x8F,     
    &&_0x90,    &&_0x91,    &&_0x92,    &&_0x93,    &&_0x94,    &&_0x95,    &&_0x96,    &&_0x97, 
    &&_0x98,    &&_0x99,    &&_default, &&_0x9B,    &&_0x9C,    &&_0x9D,    &&_0x9E,    &&_0x9F,
    &&_0xA0,    &&_0xA1,    &&_0xA2,    &&_0xA3,    &&_0xA4,    &&_0xA5,    &&_0xA6,    &&_0xA7, 
    &&_0xA8,    &&_0xA9,    &&_0xAA,    &&_0xAB,    &&_0xAC,    &&_0xAD,    &&_0xAE,    &&_0xAF,     
    &&_0xB0,    &&_0xB1,    &&_0xB2,    &&_0xB3,    &&_0xB4,    &&_0xB5,    &&_0xB6,    &&_0xB7, 
    &&_0xB8,    &&_0xB9,    &&_0xBA,    &&_0xBB,    &&_0xBC,    &&_0xBD,    &&_0xBE,    &&_0xBF, 
    &&_0xC0,    &&_0xC1,    &&_0xC2,    &&_0xC3,    &&_0xC4,    &&_0xC5,    &&_0xC6,    &&_0xC7, 
    &&_0xC8,    &&_0xC9,    &&_default, &&_0xCB,    &&_0xCC,    &&_0xCD,    &&_default, &&_0xCF,      //0xC8-0xCF
    &&_0xD0,    &&_0xD1,    &&_0xD2,    &&_0xD3,    &&_0xD4,    &&_0xD5,    &&_0xD6,    &&_0xD7, 
    &&_0xD8,    &&_0xD9,    &&_0xDA,    &&_0xDB,    &&_0xDC,    &&_0xDD,    &&_0xDE,    &&_0xDF, 
    &&_0xE0,    &&_0xE1,    &&_0xE2,    &&_0xE3,    &&_0xE4,    &&_0xE5,    &&_0xE6,    &&_0xE7,
    &&_0xE8,    &&_0xE9,    &&_default, &&_0xEB,    &&_0xEC,    &&_0xED,    &&_default, &&_default,
    &&_0xF0,    &&_0xF1,    &&_0xF2,    &&_0xF3,    &&_default, &&_0xF5,    &&_0xF6,    &&_0xF7, 
    &&_0xF8,    &&_0xF9,    &&_0xFA,    &&_0xFB,    &&_0xFC,    &&_0xFD,    &&_0xFE,    &&_0xFF
    };
    static const void* opcodes0f[256] = {
    &&_0f_0x00, &&_0f_0x01, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x00-0x07
    &&_default, &&_default, &&_default, &&_0f_0x0B, &&_default ,&&_default, &&_default, &&_default, //0x08-0x0F
    &&_0f_0x10, &&_0f_0x11, &&_0f_0x12, &&_0f_0x13, &&_0f_0x14, &&_0f_0x15, &&_0f_0x16, &&_0f_0x17, //0x10-0x17 
    &&_0f_0x18, &&_default, &&_0f_0x1A, &&_0f_0x1B, &&_default ,&&_default, &&_default, &&_0f_0x1F, //0x18-0x1F
    &&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x20-0x27
    &&_0f_0x28, &&_0f_0x29, &&_0f_0x2A, &&_0f_0x2B, &&_0f_0x2C, &&_0f_0x2D, &&_0f_0x2E, &&_0f_0x2F, 
    &&_default, &&_0f_0x31, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x30-0x37
    &&_0f_0x38, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x38-0x3F
    &&_0f_0x40_0, &&_0f_0x40_1, &&_0f_0x40_2, &&_0f_0x40_3, &&_0f_0x40_4, &&_0f_0x40_5, &&_0f_0x40_6, &&_0f_0x40_7,
    &&_0f_0x40_8, &&_0f_0x40_9, &&_0f_0x40_A, &&_0f_0x40_B, &&_0f_0x40_C, &&_0f_0x40_D, &&_0f_0x40_E, &&_0f_0x40_F,
    &&_0f_0x50, &&_0f_0x51, &&_0f_0x52, &&_0f_0x53, &&_0f_0x54, &&_0f_0x55, &&_0f_0x56, &&_0f_0x57, //0x50-0x57
    &&_0f_0x58, &&_0f_0x59, &&_0f_0x5A, &&_0f_0x5B, &&_0f_0x5C, &&_0f_0x5D, &&_0f_0x5E, &&_0f_0x5F, 
    &&_0f_0x60, &&_0f_0x61, &&_0f_0x62, &&_0f_0x63, &&_0f_0x64 ,&&_0f_0x65, &&_0f_0x66, &&_0f_0x67, //0x60-0x67
    &&_0f_0x68, &&_0f_0x69, &&_0f_0x6A, &&_0f_0x6B, &&_default ,&&_default, &&_0f_0x6E, &&_0f_0x6F, //0x68-0x6F
    &&_0f_0x70, &&_0f_0x71, &&_0f_0x72, &&_0f_0x73, &&_0f_0x74 ,&&_0f_0x75, &&_0f_0x76, &&_0f_0x77, //0x70-0x77
    &&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_0f_0x7E, &&_0f_0x7F, //0x78-0x7F
    &&_0f_0x80_0, &&_0f_0x80_1, &&_0f_0x80_2, &&_0f_0x80_3, &&_0f_0x80_4, &&_0f_0x80_5, &&_0f_0x80_6, &&_0f_0x80_7,
    &&_0f_0x80_8, &&_0f_0x80_9, &&_0f_0x80_A, &&_0f_0x80_B, &&_0f_0x80_C, &&_0f_0x80_D, &&_0f_0x80_E, &&_0f_0x80_F,
    &&_0f_0x90_0, &&_0f_0x90_1, &&_0f_0x90_2, &&_0f_0x90_3, &&_0f_0x90_4, &&_0f_0x90_5, &&_0f_0x90_6, &&_0f_0x90_7,
    &&_0f_0x90_8, &&_0f_0x90_9, &&_0f_0x90_A, &&_0f_0x90_B, &&_0f_0x90_C, &&_0f_0x90_D, &&_0f_0x90_E, &&_0f_0x90_F,
    &&_0f_0xA0, &&_0f_0xA1, &&_0f_0xA2, &&_0f_0xA3, &&_0f_0xA4, &&_0f_0xA5, &&_default, &&_default, //0xA0-0xA7
    &&_0f_0xA8, &&_0f_0xA9, &&_default, &&_0f_0xAB, &&_0f_0xAC, &&_0f_0xAD, &&_0f_0xAE, &&_0f_0xAF, 
    &&_0f_0xB0, &&_0f_0xB1, &&_default, &&_0f_0xB3, &&_default, &&_default, &&_0f_0xB6, &&_0f_0xB7, 
    &&_default, &&_default, &&_0f_0xBA, &&_0f_0xBB, &&_0f_0xBC, &&_0f_0xBD, &&_0f_0xBE, &&_0f_0xBF, 
    &&_0f_0xC0, &&_0f_0xC1, &&_0f_0xC2, &&_0f_0xC3, &&_0f_0xC4, &&_0f_0xC5, &&_0f_0xC6, &&_0f_0xC7, 
    &&_0f_0xC8, &&_0f_0xC9, &&_0f_0xCA, &&_0f_0xCB, &&_0f_0xCC, &&_0f_0xCD, &&_0f_0xCE, &&_0f_0xCF, //0xC8-0xCF
    &&_default, &&_0f_0xD1, &&_0f_0xD2, &&_0f_0xD3, &&_0f_0xD4 ,&&_0f_0xD5, &&_default, &&_0f_0xD7, //0xD0-0xD7
    &&_0f_0xD8, &&_0f_0xD9, &&_default, &&_0f_0xDB, &&_0f_0xDC ,&&_0f_0xDD, &&_default, &&_0f_0xDF, //0xD8-0xDF
    &&_0f_0xE0, &&_0f_0xE1, &&_0f_0xE2, &&_0f_0xE3, &&_0f_0xE4 ,&&_0f_0xE5, &&_default, &&_0f_0xE7, //0xE0-0xE7
    &&_0f_0xE8, &&_0f_0xE9, &&_0f_0xEA, &&_0f_0xEB, &&_0f_0xEC ,&&_0f_0xED, &&_0f_0xEE, &&_0f_0xEF, //0xE8-0xEF
    &&_default, &&_0f_0xF1, &&_0f_0xF2, &&_0f_0xF3, &&_0f_0xF4 ,&&_0f_0xF5, &&_0f_0xF6, &&_0f_0xF7, //0xF0-0xF7
    &&_0f_0xF8, &&_0f_0xF9, &&_0f_0xFA, &&_default, &&_0f_0xFC ,&&_0f_0xFD, &&_0f_0xFE, &&_default  //0xF8-0xFF
    };
    static const void* opcodes66[256] = {
    &&_default, &&_66_0x00_1, &&_default, &&_66_0x00_3, &&_default ,&&_66_0x00_5, &&_66_0x06, &&_66_0x07, //0x00-0x07
    &&_default, &&_66_0x08_1, &&_default, &&_66_0x08_3, &&_default ,&&_66_0x08_5, &&_default, &&_66_0x0F, //0x08-0x0F
    &&_default, &&_66_0x10_1, &&_default, &&_66_0x10_3, &&_default ,&&_66_0x10_5, &&_default, &&_default, //0x10-0x17
    &&_default, &&_66_0x18_1, &&_default, &&_66_0x18_3, &&_default ,&&_66_0x18_5, &&_default, &&_default, //0x18-0x1F
    &&_default, &&_66_0x20_1, &&_default, &&_66_0x20_3, &&_default ,&&_66_0x20_5, &&_66_0x26, &&_default, //0x20-0x27
    &&_default, &&_66_0x28_1, &&_default, &&_66_0x28_3, &&_default ,&&_66_0x28_5, &&_66_0x2E, &&_default, //0x28-0x2F
    &&_default, &&_66_0x30_1, &&_default, &&_66_0x30_3, &&_default ,&&_66_0x30_5, &&_66_0x36, &&_default, //0x30-0x37
    &&_default, &&_66_0x39, &&_default, &&_66_0x3B, &&_default, &&_66_0x3D, &&_default, &&_default, //0x38-0x3F
    &&_66_0x40, &&_66_0x41, &&_66_0x42, &&_66_0x43, &&_66_0x44, &&_66_0x45, &&_66_0x46, &&_66_0x47, 
    &&_66_0x48, &&_66_0x49, &&_66_0x4A, &&_66_0x4B, &&_66_0x4C, &&_66_0x4D, &&_66_0x4E, &&_66_0x4F, 
    &&_66_0x50, &&_66_0x51, &&_66_0x52, &&_66_0x53, &&_66_0x54, &&_66_0x55, &&_66_0x56, &&_66_0x57, //0x50-0x57
    &&_66_0x58, &&_66_0x59, &&_66_0x5A, &&_66_0x5B, &&_66_0x5C, &&_66_0x5D, &&_66_0x5E, &&_66_0x5F, //0x58-0x5F
    &&_66_0x60, &&_66_0x61, &&_default, &&_default, &&_default ,&&_default, &&_66_0x66, &&_default, //0x60-0x67
    &&_66_0x68, &&_66_0x69, &&_66_0x6A, &&_66_0x6B, &&_default, &&_default, &&_default, &&_default, //0x68-0x6F
    &&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x70-0x77
    &&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x78-0x7F
    &&_default, &&_66_0x81, &&_default, &&_66_0x83, &&_default, &&_66_0x85, &&_default, &&_66_0x87, 
    &&_default, &&_66_0x89, &&_default, &&_66_0x8B, &&_66_0x8C, &&_default, &&_66_0x8E, &&_66_0x8F, 
    &&_66_0x90, &&_66_0x91, &&_66_0x92, &&_66_0x93, &&_66_0x94, &&_66_0x95, &&_66_0x96, &&_66_0x97, 
    &&_66_0x98, &&_66_0x99, &&_default, &&_default, &&_66_0x9C, &&_66_0x9D, &&_default, &&_default, //0x98-0x9F
    &&_default, &&_66_0xA1, &&_default, &&_66_0xA3, &&_default, &&_66_0xA5, &&_default, &&_66_0xA7, 
    &&_default, &&_66_0xA9, &&_default, &&_66_0xAB, &&_default, &&_66_0xAD, &&_default, &&_66_0xAF, //0xA8-0xAF
    &&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xB0-0xB7
    &&_66_0xB8, &&_66_0xB9, &&_66_0xBA, &&_66_0xBB, &&_66_0xBC, &&_66_0xBD, &&_66_0xBE, &&_66_0xBF, 
    &&_default, &&_66_0xC1, &&_default, &&_default, &&_default, &&_default, &&_default, &&_66_0xC7, 
    &&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xC8-0xCF
    &&_default, &&_66_0xD1, &&_default, &&_66_0xD3, &&_default, &&_default, &&_default, &&_default, //0xD0-0xD7
    &&_default, &&_66_0xD9, &&_default, &&_default, &&_default ,&&_66_0xDD, &&_default, &&_default, //0xD8-0xDF
    &&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xE0-0xE7
    &&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xE8-0xEF
    &&_default, &&_default, &&_66_0xF2, &&_66_0xF3, &&_default, &&_default, &&_default, &&_66_0xF7, 
    &&_66_0xF8, &&_66_0xF9, &&_default, &&_default, &&_default, &&_default, &&_default, &&_66_0xFF
    };
x86emurun:
    ip = R_EIP;
//    UnpackFlags(emu);
#ifdef HAVE_TRACE
_trace:
    __builtin_prefetch((void*)ip, 0, 0); 
    emu->prev2_ip = emu->prev_ip;
    emu->prev_ip = R_EIP;
    R_EIP=ip;
    if(my_context->dec && (
        (trace_end == 0) 
        || ((ip >= trace_start) && (ip < trace_end))) )
            PrintTrace(emu, ip, 0);
    #define NEXT    goto _trace
#else
    #define NEXT    goto *baseopcodes[(R_EIP=ip, opcode=F8)]
#endif
#include "modrm.h"
    opcode = F8;
    goto *baseopcodes[opcode];
        #define GO(B, OP)                      \
        _##B##_0: \
            nextop = F8;               \
            GET_EB;             \
            EB->byte[0] = OP##8(emu, EB->byte[0], GB);  \
            NEXT;                              \
        _##B##_1: \
            nextop = F8;               \
            GET_ED;             \
            ED->dword[0] = OP##32(emu, ED->dword[0], GD.dword[0]); \
            NEXT;                              \
        _##B##_2: \
            nextop = F8;               \
            GET_EB;                   \
            GB = OP##8(emu, GB, EB->byte[0]); \
            NEXT;                              \
        _##B##_3: \
            nextop = F8;               \
            GET_ED;         \
            GD.dword[0] = OP##32(emu, GD.dword[0], ED->dword[0]); \
            NEXT;                              \
        _##B##_4: \
            R_AL = OP##8(emu, R_AL, F8); \
            NEXT;                              \
        _##B##_5: \
            R_EAX = OP##32(emu, R_EAX, F32); \
            NEXT;
        GO(0x00, add)                   /* ADD 0x00 -> 0x05 */
        GO(0x08, or)                    /*  OR 0x08 -> 0x0D */
        GO(0x10, adc)                   /* ADC 0x10 -> 0x15 */
        GO(0x18, sbb)                   /* SBB 0x18 -> 0x1D */
        GO(0x20, and)                   /* AND 0x20 -> 0x25 */
        GO(0x28, sub)                   /* SUB 0x28 -> 0x2D */
        GO(0x30, xor)                   /* XOR 0x30 -> 0x35 */
        //GO(0x38, cmp)                   /* CMP 0x38 -> 0x3D */    avoid affectation
        #undef GO
        _0x38:
            nextop = F8;
            GET_EB;
            cmp8(emu, EB->byte[0], GB);
            NEXT;


在代码里,能看到开头声明了两个静态数组 baseopcodes[] 和 opcodes0f[] 以及 opcodes66[] ,其内容如下:



 

static const void* baseopcodes[256] ={
    &&_0x00_0,  &&_0x00_1,  &&_0x00_2,  &&_0x00_3,  &&_0x00_4,  &&_0x00_5,  &&_0x06,    &&_0x07,      //0x00-0x07
    &&_0x08_0,  &&_0x08_1,  &&_0x08_2,  &&_0x08_3,  &&_0x08_4,  &&_0x08_5,  &&_0x0E,    &&_0x0F,      //0x08-0x0F
    &&_0x10_0,  &&_0x10_1,  &&_0x10_2,  &&_0x10_3,  &&_0x10_4,  &&_0x10_5,  &&_0x16,    &&_0x17,      //0x10-0x17
    &&_0x18_0,  &&_0x18_1,  &&_0x18_2,  &&_0x18_3,  &&_0x18_4,  &&_0x18_5,  &&_0x1E,    &&_0x1F,      //0x18-0x1F
    &&_0x20_0,  &&_0x20_1,  &&_0x20_2,  &&_0x20_3,  &&_0x20_4,  &&_0x20_5,  &&_0x26,    &&_0x27,      //0x20-0x27
    &&_0x28_0,  &&_0x28_1,  &&_0x28_2,  &&_0x28_3,  &&_0x28_4,  &&_0x28_5,  &&_0x2E,    &&_0x2F,      //0x28-0x2F
    &&_0x30_0,  &&_0x30_1,  &&_0x30_2,  &&_0x30_3,  &&_0x30_4,  &&_0x30_5,  &&_0x36,    &&_0x37,      //0x30-0x37
    &&_0x38,    &&_0x39,    &&_0x3A,    &&_0x3B,    &&_0x3C,    &&_0x3D,    &&_0x3E,    &&_0x3F,      //0x38-0x3F
    &&_0x40,    &&_0x41,    &&_0x42,    &&_0x43,    &&_0x44,    &&_0x45,    &&_0x46,    &&_0x47, 
    &&_0x48,    &&_0x49,    &&_0x4A,    &&_0x4B,    &&_0x4C,    &&_0x4D,    &&_0x4E,    &&_0x4F,     
    &&_0x50,    &&_0x51,    &&_0x52,    &&_0x53,    &&_0x54,    &&_0x55,    &&_0x56,    &&_0x57, 
    &&_0x58,    &&_0x59,    &&_0x5A,    &&_0x5B,    &&_0x5C,    &&_0x5D,    &&_0x5E,    &&_0x5F, 
    &&_0x60,    &&_0x61,    &&_0x62,    &&_0x63,    &&_0x64,    &&_0x65,    &&_0x66,    &&_0x67,
    &&_0x68,    &&_0x69,    &&_0x6A,    &&_0x6B,    &&_0x6C,    &&_0x6D,    &&_0x6E,    &&_0x6F,      //0x68-0x6F
    &&_0x70_0,  &&_0x70_1,  &&_0x70_2,  &&_0x70_3,  &&_0x70_4,  &&_0x70_5,  &&_0x70_6,  &&_0x70_7,    //0x70-0x77
    &&_0x70_8,  &&_0x70_9,  &&_0x70_A,  &&_0x70_B,  &&_0x70_C,  &&_0x70_D,  &&_0x70_E,  &&_0x70_F,    //0x78-0x7F
    &&_0x80,    &&_0x81,    &&_0x82,    &&_0x83,    &&_0x84,    &&_0x85,    &&_0x86,    &&_0x87,     
    &&_0x88,    &&_0x89,    &&_0x8A,    &&_0x8B,    &&_0x8C,    &&_0x8D,    &&_0x8E,    &&_0x8F,     
    &&_0x90,    &&_0x91,    &&_0x92,    &&_0x93,    &&_0x94,    &&_0x95,    &&_0x96,    &&_0x97, 
    &&_0x98,    &&_0x99,    &&_default, &&_0x9B,    &&_0x9C,    &&_0x9D,    &&_0x9E,    &&_0x9F,
    &&_0xA0,    &&_0xA1,    &&_0xA2,    &&_0xA3,    &&_0xA4,    &&_0xA5,    &&_0xA6,    &&_0xA7, 
    &&_0xA8,    &&_0xA9,    &&_0xAA,    &&_0xAB,    &&_0xAC,    &&_0xAD,    &&_0xAE,    &&_0xAF,     
    &&_0xB0,    &&_0xB1,    &&_0xB2,    &&_0xB3,    &&_0xB4,    &&_0xB5,    &&_0xB6,    &&_0xB7, 
    &&_0xB8,    &&_0xB9,    &&_0xBA,    &&_0xBB,    &&_0xBC,    &&_0xBD,    &&_0xBE,    &&_0xBF, 
    &&_0xC0,    &&_0xC1,    &&_0xC2,    &&_0xC3,    &&_0xC4,    &&_0xC5,    &&_0xC6,    &&_0xC7, 
    &&_0xC8,    &&_0xC9,    &&_default, &&_0xCB,    &&_0xCC,    &&_0xCD,    &&_default, &&_0xCF,      //0xC8-0xCF
    &&_0xD0,    &&_0xD1,    &&_0xD2,    &&_0xD3,    &&_0xD4,    &&_0xD5,    &&_0xD6,    &&_0xD7, 
    &&_0xD8,    &&_0xD9,    &&_0xDA,    &&_0xDB,    &&_0xDC,    &&_0xDD,    &&_0xDE,    &&_0xDF, 
    &&_0xE0,    &&_0xE1,    &&_0xE2,    &&_0xE3,    &&_0xE4,    &&_0xE5,    &&_0xE6,    &&_0xE7,
    &&_0xE8,    &&_0xE9,    &&_default, &&_0xEB,    &&_0xEC,    &&_0xED,    &&_default, &&_default,
    &&_0xF0,    &&_0xF1,    &&_0xF2,    &&_0xF3,    &&_default, &&_0xF5,    &&_0xF6,    &&_0xF7, 
    &&_0xF8,    &&_0xF9,    &&_0xFA,    &&_0xFB,    &&_0xFC,    &&_0xFD,    &&_0xFE,    &&_0xFF
    };
    static const void* opcodes0f[256] = {
    &&_0f_0x00, &&_0f_0x01, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x00-0x07
    &&_default, &&_default, &&_default, &&_0f_0x0B, &&_default ,&&_default, &&_default, &&_default, //0x08-0x0F
    &&_0f_0x10, &&_0f_0x11, &&_0f_0x12, &&_0f_0x13, &&_0f_0x14, &&_0f_0x15, &&_0f_0x16, &&_0f_0x17, //0x10-0x17 
    &&_0f_0x18, &&_default, &&_0f_0x1A, &&_0f_0x1B, &&_default ,&&_default, &&_default, &&_0f_0x1F, //0x18-0x1F
    &&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x20-0x27
    &&_0f_0x28, &&_0f_0x29, &&_0f_0x2A, &&_0f_0x2B, &&_0f_0x2C, &&_0f_0x2D, &&_0f_0x2E, &&_0f_0x2F, 
    &&_default, &&_0f_0x31, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x30-0x37
    &&_0f_0x38, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x38-0x3F
    &&_0f_0x40_0, &&_0f_0x40_1, &&_0f_0x40_2, &&_0f_0x40_3, &&_0f_0x40_4, &&_0f_0x40_5, &&_0f_0x40_6, &&_0f_0x40_7,
    &&_0f_0x40_8, &&_0f_0x40_9, &&_0f_0x40_A, &&_0f_0x40_B, &&_0f_0x40_C, &&_0f_0x40_D, &&_0f_0x40_E, &&_0f_0x40_F,
    &&_0f_0x50, &&_0f_0x51, &&_0f_0x52, &&_0f_0x53, &&_0f_0x54, &&_0f_0x55, &&_0f_0x56, &&_0f_0x57, //0x50-0x57
    &&_0f_0x58, &&_0f_0x59, &&_0f_0x5A, &&_0f_0x5B, &&_0f_0x5C, &&_0f_0x5D, &&_0f_0x5E, &&_0f_0x5F, 
    &&_0f_0x60, &&_0f_0x61, &&_0f_0x62, &&_0f_0x63, &&_0f_0x64 ,&&_0f_0x65, &&_0f_0x66, &&_0f_0x67, //0x60-0x67
    &&_0f_0x68, &&_0f_0x69, &&_0f_0x6A, &&_0f_0x6B, &&_default ,&&_default, &&_0f_0x6E, &&_0f_0x6F, //0x68-0x6F
    &&_0f_0x70, &&_0f_0x71, &&_0f_0x72, &&_0f_0x73, &&_0f_0x74 ,&&_0f_0x75, &&_0f_0x76, &&_0f_0x77, //0x70-0x77
    &&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_0f_0x7E, &&_0f_0x7F, //0x78-0x7F
    &&_0f_0x80_0, &&_0f_0x80_1, &&_0f_0x80_2, &&_0f_0x80_3, &&_0f_0x80_4, &&_0f_0x80_5, &&_0f_0x80_6, &&_0f_0x80_7,
    &&_0f_0x80_8, &&_0f_0x80_9, &&_0f_0x80_A, &&_0f_0x80_B, &&_0f_0x80_C, &&_0f_0x80_D, &&_0f_0x80_E, &&_0f_0x80_F,
    &&_0f_0x90_0, &&_0f_0x90_1, &&_0f_0x90_2, &&_0f_0x90_3, &&_0f_0x90_4, &&_0f_0x90_5, &&_0f_0x90_6, &&_0f_0x90_7,
    &&_0f_0x90_8, &&_0f_0x90_9, &&_0f_0x90_A, &&_0f_0x90_B, &&_0f_0x90_C, &&_0f_0x90_D, &&_0f_0x90_E, &&_0f_0x90_F,
    &&_0f_0xA0, &&_0f_0xA1, &&_0f_0xA2, &&_0f_0xA3, &&_0f_0xA4, &&_0f_0xA5, &&_default, &&_default, //0xA0-0xA7
    &&_0f_0xA8, &&_0f_0xA9, &&_default, &&_0f_0xAB, &&_0f_0xAC, &&_0f_0xAD, &&_0f_0xAE, &&_0f_0xAF, 
    &&_0f_0xB0, &&_0f_0xB1, &&_default, &&_0f_0xB3, &&_default, &&_default, &&_0f_0xB6, &&_0f_0xB7, 
    &&_default, &&_default, &&_0f_0xBA, &&_0f_0xBB, &&_0f_0xBC, &&_0f_0xBD, &&_0f_0xBE, &&_0f_0xBF, 
    &&_0f_0xC0, &&_0f_0xC1, &&_0f_0xC2, &&_0f_0xC3, &&_0f_0xC4, &&_0f_0xC5, &&_0f_0xC6, &&_0f_0xC7, 
    &&_0f_0xC8, &&_0f_0xC9, &&_0f_0xCA, &&_0f_0xCB, &&_0f_0xCC, &&_0f_0xCD, &&_0f_0xCE, &&_0f_0xCF, //0xC8-0xCF
    &&_default, &&_0f_0xD1, &&_0f_0xD2, &&_0f_0xD3, &&_0f_0xD4 ,&&_0f_0xD5, &&_default, &&_0f_0xD7, //0xD0-0xD7
    &&_0f_0xD8, &&_0f_0xD9, &&_default, &&_0f_0xDB, &&_0f_0xDC ,&&_0f_0xDD, &&_default, &&_0f_0xDF, //0xD8-0xDF
    &&_0f_0xE0, &&_0f_0xE1, &&_0f_0xE2, &&_0f_0xE3, &&_0f_0xE4 ,&&_0f_0xE5, &&_default, &&_0f_0xE7, //0xE0-0xE7
    &&_0f_0xE8, &&_0f_0xE9, &&_0f_0xEA, &&_0f_0xEB, &&_0f_0xEC ,&&_0f_0xED, &&_0f_0xEE, &&_0f_0xEF, //0xE8-0xEF
    &&_default, &&_0f_0xF1, &&_0f_0xF2, &&_0f_0xF3, &&_0f_0xF4 ,&&_0f_0xF5, &&_0f_0xF6, &&_0f_0xF7, //0xF0-0xF7
    &&_0f_0xF8, &&_0f_0xF9, &&_0f_0xFA, &&_default, &&_0f_0xFC ,&&_0f_0xFD, &&_0f_0xFE, &&_default  //0xF8-0xFF
    };
    static const void* opcodes66[256] = {
    &&_default, &&_66_0x00_1, &&_default, &&_66_0x00_3, &&_default ,&&_66_0x00_5, &&_66_0x06, &&_66_0x07, //0x00-0x07
    &&_default, &&_66_0x08_1, &&_default, &&_66_0x08_3, &&_default ,&&_66_0x08_5, &&_default, &&_66_0x0F, //0x08-0x0F
    &&_default, &&_66_0x10_1, &&_default, &&_66_0x10_3, &&_default ,&&_66_0x10_5, &&_default, &&_default, //0x10-0x17
    &&_default, &&_66_0x18_1, &&_default, &&_66_0x18_3, &&_default ,&&_66_0x18_5, &&_default, &&_default, //0x18-0x1F
    &&_default, &&_66_0x20_1, &&_default, &&_66_0x20_3, &&_default ,&&_66_0x20_5, &&_66_0x26, &&_default, //0x20-0x27
    &&_default, &&_66_0x28_1, &&_default, &&_66_0x28_3, &&_default ,&&_66_0x28_5, &&_66_0x2E, &&_default, //0x28-0x2F
    &&_default, &&_66_0x30_1, &&_default, &&_66_0x30_3, &&_default ,&&_66_0x30_5, &&_66_0x36, &&_default, //0x30-0x37
    &&_default, &&_66_0x39, &&_default, &&_66_0x3B, &&_default, &&_66_0x3D, &&_default, &&_default, //0x38-0x3F
    &&_66_0x40, &&_66_0x41, &&_66_0x42, &&_66_0x43, &&_66_0x44, &&_66_0x45, &&_66_0x46, &&_66_0x47, 
    &&_66_0x48, &&_66_0x49, &&_66_0x4A, &&_66_0x4B, &&_66_0x4C, &&_66_0x4D, &&_66_0x4E, &&_66_0x4F, 
    &&_66_0x50, &&_66_0x51, &&_66_0x52, &&_66_0x53, &&_66_0x54, &&_66_0x55, &&_66_0x56, &&_66_0x57, //0x50-0x57
    &&_66_0x58, &&_66_0x59, &&_66_0x5A, &&_66_0x5B, &&_66_0x5C, &&_66_0x5D, &&_66_0x5E, &&_66_0x5F, //0x58-0x5F
    &&_66_0x60, &&_66_0x61, &&_default, &&_default, &&_default ,&&_default, &&_66_0x66, &&_default, //0x60-0x67
    &&_66_0x68, &&_66_0x69, &&_66_0x6A, &&_66_0x6B, &&_default, &&_default, &&_default, &&_default, //0x68-0x6F
    &&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x70-0x77
    &&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x78-0x7F
    &&_default, &&_66_0x81, &&_default, &&_66_0x83, &&_default, &&_66_0x85, &&_default, &&_66_0x87, 
    &&_default, &&_66_0x89, &&_default, &&_66_0x8B, &&_66_0x8C, &&_default, &&_66_0x8E, &&_66_0x8F, 
    &&_66_0x90, &&_66_0x91, &&_66_0x92, &&_66_0x93, &&_66_0x94, &&_66_0x95, &&_66_0x96, &&_66_0x97, 
    &&_66_0x98, &&_66_0x99, &&_default, &&_default, &&_66_0x9C, &&_66_0x9D, &&_default, &&_default, //0x98-0x9F
    &&_default, &&_66_0xA1, &&_default, &&_66_0xA3, &&_default, &&_66_0xA5, &&_default, &&_66_0xA7, 
    &&_default, &&_66_0xA9, &&_default, &&_66_0xAB, &&_default, &&_66_0xAD, &&_default, &&_66_0xAF, //0xA8-0xAF
    &&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xB0-0xB7
    &&_66_0xB8, &&_66_0xB9, &&_66_0xBA, &&_66_0xBB, &&_66_0xBC, &&_66_0xBD, &&_66_0xBE, &&_66_0xBF, 
    &&_default, &&_66_0xC1, &&_default, &&_default, &&_default, &&_default, &&_default, &&_66_0xC7, 
    &&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xC8-0xCF
    &&_default, &&_66_0xD1, &&_default, &&_66_0xD3, &&_default, &&_default, &&_default, &&_default, //0xD0-0xD7
    &&_default, &&_66_0xD9, &&_default, &&_default, &&_default ,&&_66_0xDD, &&_default, &&_default, //0xD8-0xDF
    &&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xE0-0xE7
    &&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xE8-0xEF
    &&_default, &&_default, &&_66_0xF2, &&_66_0xF3, &&_default, &&_default, &&_default, &&_66_0xF7, 
    &&_66_0xF8, &&_66_0xF9, &&_default, &&_default, &&_default, &&_default, &&_default, &&_66_0xFF
    };


这些静态数组变量中存放的都是以 && 开头的成员,而在 C 语言中 && 是表明后面跟随的东西是一个标号,具体可参考:

X86指令解析

所以在后面用到的其中一个用法是:


#define F8      *(uint8_t*)(ip++)
    opcode = F8;
    goto *baseopcodes[opcode];


这里的 ip 其实就是作为指令地址存在,每次取指后都会自动加一指向下一行指令,而当前取出的指令的第一个字节( *(uint8_t*) )会赋值给 opcode ,然后调用 goto 语句跳转到 *baseopcodes[opcode] 对应的标号下去执行。

比如,如果 ip 第一个字节的数据取出来是 0xF8 ,则会对应跳转到下面部分去执行,这是一个清除进位标志的操作( CLC )


   

_0xF8:                      /* CLC *///清除进位标志位
            CHECK_FLAGS(emu);
            CLEAR_FLAG(F_CF);
            NEXT;


跳转系统调用函数实现:x86Syscall(emu);

通过对 Run() 函数的简单理解,已经基本明白了 Box86 是如何去翻译 x86 可执行程序的了。Box86 将 x86 可执行程序的二进制读取进来,根据 x86 二进制指令格式进行解析,将其分析成对应的操作动作去工作。但是在 Linux 下,除了基本的内存读写操作、加减数据等等基本操作外,还会遇到调用系统调用函数的部分。具体流程可以参考下面这篇文章


Linux内核:基于int指令的经典系统调用过程分析


在 Box86 中,同样的,当指令解析到 int 0x80 这条指令的时候,就会跳转到自己的 x86Syscall(emu); 去执行对应的系统调用,具体如下:


 

_0xCD:                      /* INT Ib */
            nextop = F8;
            if(nextop == 0x80) {
                emu->old_ip = R_EIP;
                R_EIP = ip;
                x86Syscall(emu);
                ip = R_EIP;
                if(emu->quit) goto fini;
            } else {
                int tid = GetTID();
                printf_log(LOG_NONE, "%04d|%p: Ignoring Unsupported Int %02Xh\n", tid, (void*)ip, nextop);
                emu->old_ip = R_EIP;
                R_EIP = ip;
                emu->quit = 1;
                emu->error |= ERR_UNIMPL;
                goto fini;
            }
            NEXT;


而 x86Syscall(emu); 函数的具体实现如下,将可以用当前环境的操作还是调用当前环境的函数去实现,而会导致环境不一致的情况时就调用自己封装的对应函数去实现。



void EXPORT x86Syscall(x86emu_t *emu)
{
    RESET_FLAGS(emu);
    uint32_t s = R_EAX;
    printf_log(LOG_DEBUG, "%p: Calling syscall 0x%02X (%d) %p %p %p %p %p", (void*)R_EIP, s, s, (void*)R_EBX, (void*)R_ECX, (void*)R_EDX, (void*)R_ESI, (void*)R_EDI); 
    // check wrapper first
    int cnt = sizeof(syscallwrap) / sizeof(scwrap_t);
    for (int i=0; i<cnt; i++) {
        if(syscallwrap[i].x86s == s) {
            int sc = syscallwrap[i].nats;
            switch(syscallwrap[i].nbpars) {
                case 0: *(int32_t*)&R_EAX = syscall(sc); break;
                case 1: *(int32_t*)&R_EAX = syscall(sc, R_EBX); break;
                case 2: if(s==33) {printf_log(LOG_DUMP, " => sys_access(\"%s\", %d)\n", (char*)R_EBX, R_ECX);}; *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX); break;
                case 3: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX, R_EDX); break;
                case 4: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX, R_EDX, R_ESI); break;
                case 5: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI); break;
                case 6: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI, R_EBP); break;
                default:
                   printf_log(LOG_NONE, "ERROR, Unimplemented syscall wrapper (%d, %d)\n", s, syscallwrap[i].nbpars); 
                   emu->quit = 1;
                   return;
            }
            printf_log(LOG_DEBUG, " => 0x%x\n", R_EAX);
            return;
        }
    }
    switch (s) {
        case 1: // sys_exit
            emu->quit = 1;
            emu->exit = 1;
            R_EAX = R_EBX; // faking the syscall here, we don't want to really terminate the program now
            break;
        case 3:  // sys_read
            R_EAX = (uint32_t)read((int)R_EBX, (void*)R_ECX, (size_t)R_EDX);
            break;
        case 4:  // sys_write
            R_EAX = (uint32_t)write((int)R_EBX, (void*)R_ECX, (size_t)R_EDX);
            break;
        case 5: // sys_open
            if(s==5) {printf_log(LOG_DEBUG, " => sys_open(\"%s\", %d, %d)", (char*)R_EBX, of_convert(R_ECX), R_EDX);}; 
            //R_EAX = (uint32_t)open((void*)R_EBX, of_convert(R_ECX), R_EDX);
            R_EAX = (uint32_t)my_open(emu, (void*)R_EBX, of_convert(R_ECX), R_EDX);
            break;
        case 6:  // sys_close
            R_EAX = (uint32_t)close((int)R_EBX);
            break;
#ifndef __NR_waitpid
        case 7: //sys_waitpid
            R_EAX = waitpid((pid_t)R_EBX, (int*)R_ECX, (int)R_EDX);
            break;
#endif
        case 11: // sys_execve
            {
                char* prog = (char*)R_EBX;
                char** argv = (char**)R_ECX;
                char** envv = (char**)R_EDX;
                printf_log(LOG_DUMP, " => sys_execve(\"%s\", %p(\"%s\", \"%s\", \"%s\"...), %p)\n", prog, argv, (argv && argv[0])?argv[0]:"nil", (argv && argv[0] && argv[1])?argv[1]:"nil", (argv && argv[0] && argv[1] && argv[2])?argv[2]:"nil", envv);
                R_EAX = my_execve(emu, (const char*)R_EBX, (void*)R_ECX, (void*)R_EDX);
            }
            break;
#ifndef __NR_time
        case 13:    // sys_time (it's deprecated and remove on ARM EABI it seems)
            R_EAX = time(NULL);
            break;
#endif
        case 54: // sys_ioctl
            R_EAX = (uint32_t)ioctl((int)R_EBX, R_ECX, R_EDX, R_ESI, R_EDI);
            break;
        case 55: // sys_fcntl
            if(R_ECX==4) {
                // filter out O_NONBLOCK so old stacally linked games that access X11 don't get EAGAIN error sometimes
                int tmp = of_convert((int)R_EDX)&(~O_NONBLOCK);
                if(R_EDX==0xFFFFF7FF) {
                    // special case for ~O_NONBLOCK...
                    int flags = fcntl(R_EBX, 3);
                    tmp = flags&~O_NONBLOCK;
                }
                R_EAX = (uint32_t)fcntl((int)R_EBX, (int)R_ECX, tmp);
            } else
                R_EAX = (uint32_t)fcntl((int)R_EBX, (int)R_ECX, R_EDX);
            break;
#ifndef __NR_getrlimit
        case 76:    // sys_getrlimit... this is the old version, using the new one. Maybe some tranform is needed?
            R_EAX = getrlimit(R_EBX, (void*)R_ECX);
            break;
#endif
#ifndef __NR_select
        case 82:   // select
            R_EAX = select(R_EBX, (fd_set*)R_ECX, (fd_set*)R_EDX, (fd_set*)R_ESI, (struct timeval*)R_EDI);
            break;
#endif
        case 90:    // old_mmap
            {
                struct mmap_arg_struct *st = (struct mmap_arg_struct*)R_EBX;
                R_EAX = (uintptr_t)mmap((void*)st->addr, st->len, st->prot, st->flags, st->fd, st->offset);
            }
            break;
#ifndef __NR_socketcall
        case 102: {
                unsigned long *args = (unsigned long *)R_ECX;
                // need to do all call "by hand"
                switch(R_EBX) {
                    case SYS_SOCKET: R_EAX = socket(args[0], args[1], args[2]); break;
                    case SYS_BIND: R_EAX = bind(args[0], (void*)args[1], args[2]); break;
                    case SYS_CONNECT: R_EAX = connect(args[0], (void*)args[1], args[2]); break;
                    case SYS_LISTEN: R_EAX = listen(args[0], args[1]); break;
                    case SYS_ACCEPT: R_EAX = accept(args[0], (void*)args[1], (void*)args[2]); break;
                    case SYS_GETSOCKNAME: R_EAX = getsockname(args[0], (void*)args[1], (void*)args[2]); break;
                    case SYS_GETPEERNAME: R_EAX = getpeername(args[0], (void*)args[1], (void*)args[2]); break;
                    case SYS_SOCKETPAIR: R_EAX = socketpair(args[0], args[1], args[2], (int*)args[3]); break;
                    case SYS_SEND: R_EAX = send(args[0], (void*)args[1], args[2], args[3]); break;
                    case SYS_RECV: R_EAX = recv(args[0], (void*)args[1], args[2], args[3]); break;
                    case SYS_SENDTO: R_EAX = sendto(args[0], (void*)args[1], args[2], args[3], (void*)args[4], args[5]); break;
                    case SYS_RECVFROM: R_EAX = recvfrom(args[0], (void*)args[1], args[2], args[3], (void*)args[4], (void*)args[5]); break;
                    case SYS_SHUTDOWN: R_EAX = shutdown(args[0], args[1]); break;
                    case SYS_SETSOCKOPT: R_EAX = setsockopt(args[0], args[1], args[2], (void*)args[3], args[4]); break;
                    case SYS_GETSOCKOPT: R_EAX = getsockopt(args[0], args[1], args[2], (void*)args[3], (void*)args[4]); break;
                    case SYS_SENDMSG: R_EAX = sendmsg(args[0], (void*)args[1], args[2]); break;
                    case SYS_RECVMSG: R_EAX = recvmsg(args[0], (void*)args[1], args[2]); break;
                    case SYS_ACCEPT4: R_EAX = my_accept4(emu, args[0], (void*)args[1], (void*)args[2], args[3]); break;
                    #ifdef SYS_RECVMMSG
                    case SYS_RECVMMSG: R_EAX = my_recvmmsg(emu, args[0], (void*)args[1], args[2], args[3], (void*)args[4]); break;
                    case SYS_SENDMMSG: R_EAX = my___sendmmsg(emu, args[0], (void*)args[1], args[2], args[3]); break;
                    #endif
                    default:
                        printf_log(LOG_DEBUG, "BOX86 Error on Syscall 102: Unknown Soket command %d\n", R_EBX);
                        R_EAX = -1;
                }
            }
            break;
#endif
#ifndef __NR_olduname
        case 109:   // olduname
            {
                struct utsname un;
                R_EAX = uname(&un);
                if(!R_EAX) {
                    struct oldold_utsname *old = (struct oldold_utsname*)R_EBX;
                    memcpy(old->sysname, un.sysname, 9);
                    memcpy(old->nodename, un.nodename, 9);
                    memcpy(old->release, un.release, 9);
                    memcpy(old->version, un.version, 9);
                    strcpy(old->machine, "i686");
                }
            }
            break;
#endif
#ifndef __NR_iopl
        case 110:   // iopl
            R_EAX = 0;  // only on x86, so return 0...
            break;
#endif
        case 119: // sys_sigreturn
            emu->quit = 1;  // we should be inside a DynaCall in a sigaction callback....
            break;
        case 120:   // clone
            {
                //struct x86_pt_regs *regs = (struct x86_pt_regs *)R_EDI;
                // lets duplicate the emu
                void* stack_base = (void*)R_ECX;
                int stack_size = 0;
                if(!R_ECX) {
                    // allocate a new stack...
                    stack_size = 1024*1024;
                    stack_base = malloc(stack_size); // why not 1M... (normal operation do copy on write, simpler to just copy)
                    // copy value from old stack to new stack
                    int size_to_copy = (uintptr_t)emu->init_stack + emu->size_stack - (R_ESP);
                    memcpy(stack_base-size_to_copy, (void*)R_ESP, size_to_copy);
                }
                x86emu_t * newemu = NewX86Emu(emu->context, R_EIP, (uintptr_t)stack_base, stack_size, (R_ECX)?0:1);
                SetupX86Emu(newemu);
                CloneEmu(newemu, emu);
                SetESP(newemu, (uintptr_t)stack_base);
                // setup registers
                /*if(regs) {
                    SetEAX(newemu, regs->eax);
                    SetEBX(newemu, regs->ebx);
                    SetECX(newemu, regs->ecx);
                    SetEDX(newemu, regs->edx);
                    SetEDI(newemu, regs->edi);
                    SetESI(newemu, regs->esi);
                    SetEBP(newemu, regs->ebp);
                    SetESP(newemu, (uintptr_t)stack_base - size_to_copy);
                }
                SetESP(newemu, (uintptr_t)stack_base - size_to_copy);*/
                void* mystack = (R_EBX&CLONE_VM)?malloc(1024*1024):NULL;  // stack for own process... memory leak, but no practical way to remove it
                int ret = clone(clone_fn, (void*)((R_EBX&CLONE_VM)?((uintptr_t)mystack+1024*1024):0), R_EBX, newemu, R_ESI, R_EDI, R_EBP);
                //int r = syscall(__NR_clone, R_EBX, (R_EBX&CLONE_VM)?((uintptr_t)mystack):0, R_EDX, R_ESI, NULL);  // cannot use that syscall in C: how to setup the stack?!
                R_EAX = ret;
            }
            break;
        case 122:   // uname
            {
                struct utsname un;
                R_EAX = uname(&un);
                if(!R_EAX) {
                    struct old_utsname *old = (struct old_utsname*)R_EBX;
                    memcpy(old->sysname, un.sysname, 65);
                    memcpy(old->nodename, un.nodename, 65);
                    memcpy(old->release, un.release, 65);
                    memcpy(old->version, un.version, 65);
                    strcpy(old->machine, "i686");
                }
            }
            break;
        case 123:   // SYS_modify_ldt
            R_EAX = my_modify_ldt(emu, R_EBX, (thread_area_t*)R_ECX, R_EDX);
            break;
        case 168: // sys_poll
            R_EAX = (uint32_t)poll((void*)R_EBX, R_ECX, (int)R_EDX);
            break;
        case 173: // sys_rt_sigreturn
            emu->quit = 1;  // we should be inside a DynaCall in a sigaction callback....
            break;
        case 174: // sys_rt_sigaction
            //printf_log(LOG_NONE, "Warning, Ignoring sys_rt_sigaction(0x%02X, %p, %p)\n", R_EBX, (void*)R_ECX, (void*)R_EDX);
            R_EAX = my_syscall_sigaction(emu, R_EBX, (void*)R_ECX, (void*)R_EDX, R_ESI);
            break;
        case 190:   // vfork
            {
                int r = vfork();
                R_EAX = r;
            }
            break;
        case 195:   // stat64
            {   
                struct stat64 st;
                unsigned int r = syscall(__NR_stat64, R_EBX, &st);
                UnalignStat64(&st, (void*)R_ECX);
                R_EAX = r;
            }
            break;
        case 196:   // lstat64
            {   
                struct stat64 st;
                unsigned int r = syscall(__NR_lstat64, R_EBX, &st);
                UnalignStat64(&st, (void*)R_ECX);
                R_EAX = r;
            }
            break;
        case 197:   // fstat64
            {   
                struct stat64 st;
                unsigned int r = syscall(__NR_fstat64, R_EBX, &st);
                UnalignStat64(&st, (void*)R_ECX);
                R_EAX = r;
            }
            break;
        case 221: // sys_fcntl64
            if(R_ECX==4) {
                int tmp = of_convert((int)R_EDX);
                R_EAX = (uint32_t)fcntl((int)R_EBX, R_ECX, tmp);
            } else
                R_EAX = (uint32_t)fcntl((int)R_EBX, (int)R_ECX, R_EDX);
            break;
        case 243: // set_thread_area
            R_EAX = my_set_thread_area((thread_area_t*)R_EBX);
            break;
#ifndef NOALIGN
        case 254: // epoll_create
            R_EAX = my_epoll_create(emu, (int)R_EBX);
            break;
        case 255: // epoll_ctl
            R_EAX = my_epoll_ctl(emu, (int)R_EBX, (int)R_ECX, (int)R_EDX, (void*)R_ESI);
            break;
        case 256: // epoll_wait
            R_EAX = my_epoll_wait(emu, (int)R_EBX, (void*)R_ECX, (int)R_EDX, (int)R_ESI);
            break;
#endif
        case 270:   // tgkill
            R_EAX = syscall(__NR_tgkill, R_EBX, R_ECX, R_EDX);
            break;
#ifndef NOALIGN
        case 329:   // epoll_create1
            R_EAX = my_epoll_create1(emu, of_convert(R_EBX));
            break;
#endif
#ifndef __NR_getrandom
        case 355:  // getrandom
            R_EAX = my_getrandom(emu, (void*)R_EBX, R_ECX, R_EDX);
            break;
#endif
        default:
            printf_log(LOG_INFO, "Error: Unsupported Syscall 0x%02Xh (%d)\n", s, s);
            emu->quit = 1;
            emu->error |= ERR_UNIMPL;
            return;
    }
    printf_log(LOG_DEBUG, " => 0x%x\n", R_EAX);
}


封装对应的函数实现的例子如下:


EXPORT int my_epoll_create(x86emu_t* emu, int size)
{
    return epoll_create(size);
}
EXPORT int my_epoll_create1(x86emu_t* emu, int flags)
{
    return epoll_create1(flags);
}
EXPORT int32_t my_epoll_ctl(x86emu_t* emu, int32_t epfd, int32_t op, int32_t fd, void* event)
{
    struct epoll_event _event[1] = {0};
    if(event && (op!=EPOLL_CTL_DEL))
        AlignEpollEvent(_event, event, 1);
    return epoll_ctl(epfd, op, fd, event?_event:event);
}
EXPORT int32_t my_epoll_wait(x86emu_t* emu, int32_t epfd, void* events, int32_t maxevents, int32_t timeout)
{
    struct epoll_event _events[maxevents];
    AlignEpollEvent(_events, events, maxevents);
    int32_t ret = epoll_wait(epfd, _events, maxevents, timeout);
    if(ret>0)
        UnalignEpollEvent(events, _events, ret);
    return ret;
}


总结

接下来分析 Box86 的几部分重点内容:


动态指令翻译的过程

具体 X86 指令(opcode)参考 opcode

2020112611425325.png

举例说明:

这里的 opcode X86 指令解析可参考 opcode解析 这篇博客,这里详细说明的 opcode 机器码的几个部分和解析流程。参考刚刚给出的 x86 opcode 查找表能够根据机器码前缀 66 、0F等数据最终找到当前要翻译执行的指令码。可以查找 GitHub 上有关汇编代码的项目来查找对应的指令和描述及需要解析的操作。

asm-dude ,在该项目中的 wiki 界面能够查到出错或者翻译执行的指令,如下界面:

2020112611474223.png

从这里能够看到,指令 PALIGNR 就是 66 0F 4A 0F 或者 NP 0F 3A 0F 操作码对应的指令操作。这条指令通过阅读后面的描述可以知道是拼接后面两个寄存器的数据,并右移立即数[imm8]个字节数,将最终的数据存放到目标寄存器中。


了解到当前执行出错或者缺少的指令翻译后,我们可以将对应的操作添加到 box86 的对应位置中去。其中模拟器版本的操作存放在 emu/x86run.c emu/run0f.c emu/run660f.c 等文件中,根据指令首字节的数据分别找到对应的 0F 或者 66中的对应位置。而寄存器版本(对应使用arm操作指令的版本)操作就需要添加到 dynerec/dynerec_arm_00.c dynerec/dynerec_arm_0f.c dynerec/deynrec_arm_660f.c 这些文件中的对应位置去。


底层调用库接口使用流程

Box86 使用动态库有两种方式,


  • 使用 BOX86_LD_LIBRARY_PATH 环境变量指定的 i386 架构的动态库,这样的库在运行过程中其实是处于再次动态翻译执行的方式去读取调用的。
  • 另一种就是会去读取 ARM 机器上本地的一些库,但是在使用过程中其实是 box86 本身基于这些库的接口使用 dlopen 、dlsym等动态调用接口去读取本地动态库并使用的,虽然接口需要编写实现,但是使用过程中却不需要再次进行指令翻译,因为本身这些库就是 ARM 版本的本地库。

第一种方式其实就是指定环境变量到提供的 i386 动态库路径即可,这没什么可说的。最主要是第二种方式。


这里关于第二种方式能够本地调用的库的明细其实都写在 Box86 源码中的 src/library_list.h 文件中,根据宏 GO 会去自动生成对应的库接口 init等等调用接口,并自动调用 dlopen 打开对应的本地动态库,并且通过事先编辑好的接口函数去调用 dlsym 去获取需要调用的接口函数并使用。这样的话,当我们需要对 Box86 添加 ARM 本地动态库接口时,只需要在 src/wrapped/ 目录下添加对应的接口文件,具体编写可以参考下面的两个文件:


wrappedicon_private.c 文件添加的需要调用的本地动态库名称 iconvName =

"libiconv.so.2"; 。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define _GNU_SOURCE         /* See feature_test_macros(7) */
#include <dlfcn.h>
#include "wrappedlibs.h"
#include "wrapper.h"
#include "bridge.h"
#include "librarian/library_private.h"
#include "x86emu.h"
const char* iconvName = "libiconv.so.2";
#define LIBNAME iconv
#include "wrappedlib_init.h"


wrappedicon_private.h 文件,这里的 GO 宏就是为了指出需要用该动态库的哪些 API ,通过这个宏声明就会自动调用 dlsym 去从动态库中获取对应的函数接口。


#if !(defined(GO) && defined(GOM) && defined(GO2) && defined(DATA))
#error Meh....
#endif
GO(iconv_canonicalize, pFp)
GO(libiconv, uFppppp)
GO(libiconv_close, iFp)
GO(libiconv_open, pFpp)
GO(libiconv_open_into, iFppp)
GO(libiconv_set_relocation_prefix, vFpp)
GO(libiconvctl, iFpip)
//GO(libiconvlist, vFpp) // this one have callbacks


以上这些添加完成后,需要在 src/library_list.h 文件中添加对应动态库调用的声明,如下:


GO("libSM.so.6", libsm)
GO("libICE.so.6", libice)
GO("libusb-1.0.so.0", libusb1)
GO("libncursesw.so.5", libncursesw)
GO("libformw.so.5", libformw)
GO("libncurses.so.5", libncurses)
GO("libtinfo.so.5", libtinfo)
GO("libncurses.so.6", libncurses6)
GO("libtinfo.so.6", libtinfo6)
GO("libtcmalloc_minimal.so.4", tcmallocminimal)
GO("libmpg123.so.0", mpg123)
GO("libgnutls.so.30", gnutls)
GO("libcups.so.2", libcups)
GO("d3dadapter9.so.1", d3dadapter9)


关于 Box86 的一些操作,就先描述到这里,如果还有需要了解的部分,可以在评论里告诉我啊,我会尽快添加的。😃


相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
基于阿里云,构建一个企业web应用上云经典架构,让IT从业者体验企业级架构的实战训练。
高可用应用架构
欢迎来到“高可用应用架构”课程,本课程是“弹性计算Clouder系列认证“中的阶段四课程。本课程重点向您阐述了云服务器ECS的高可用部署方案,包含了弹性公网IP和负载均衡的概念及操作,通过本课程的学习您将了解在平时工作中,如何利用负载均衡和多台云服务器组建高可用应用架构,并通过弹性公网IP的方式对外提供稳定的互联网接入,使得您的网站更加稳定的同时可以接受更多人访问,掌握在阿里云上构建企业级大流量网站场景的方法。 学习完本课程后,您将能够: 理解高可用架构的含义并掌握基本实现方法 理解弹性公网IP的概念、功能以及应用场景 理解负载均衡的概念、功能以及应用场景 掌握网站高并发时如何处理的基本思路 完成多台Web服务器的负载均衡,从而实现高可用、高并发流量架构
相关文章
|
5月前
|
编解码 前端开发
前端知识笔记(十九)———px,em,rem,vw,vh之间的区别
前端知识笔记(十九)———px,em,rem,vw,vh之间的区别
61 0
|
10月前
|
Kubernetes Cloud Native 安全
一文彻底搞懂 Container
设想一下,在我们的日常项目开发过程中,存在一个应用服务,其使用一些基础库函数并具有某些依赖项。如果我们在不支持这些依赖项的环境平台上运行此应用程序,那么,我们可能会遇到意外错误。随着 DevOps 及云原生理念的注入,我们希望我们所开发的应用程序能够可以跨多个操作系统及平台正常运行。
230 0
|
存储
Box86源码剖析(二)
Box86源码剖析(二)
154 0
Box86源码剖析(二)
|
Linux 编译器
Box86源码剖析(一)
Box86源码剖析(一)
535 0
Box86源码剖析(一)
|
前端开发 开发者 UED
@keyframes是干什么的?底层原理是什么?
@keyframes是干什么的?底层原理是什么?
108 0
|
安全
一分钟搞懂 SOLID 原则
一分钟搞懂 SOLID 原则
152 0
一分钟搞懂 SOLID 原则
|
前端开发
前端项目实战133-前端box-sizing的border-sizing模式案例
前端项目实战133-前端box-sizing的border-sizing模式案例
60 0
|
前端开发
前端项目实战132-前端box-sizing两种计算方式
前端项目实战132-前端box-sizing两种计算方式
79 0
html+css实战162-圆角边框-基本使用
html+css实战162-圆角边框-基本使用
78 0
html+css实战162-圆角边框-基本使用
html+css实战95-border使用方法
html+css实战95-border使用方法
114 0
html+css实战95-border使用方法