Try   HackMD

2017q3 Homework3 (simulator)

contributed by <HMKRL>


觀察 full-stack-hello

driver.c 開始觀察,得知 vm 啟動的程式碼如下:

case LOAD_ELF_AND_EVAL: {
    vm_env *env = vm_new();
    load_from_elf(env, in_fd);
    hook_opcodes(env);
    vm_run(env);
    vm_free(env);
    break;
}

vm_env 的結構如下

struct __vm_env {
    vm_inst insts[INSTS_MAX_SIZE];             /* Program instructions */
    vm_value cpool[CPOOL_MAX_SIZE];            /* Constant pool */
    vm_value temps[TEMPS_MAX_SIZE];            /* Temporary storage */
    vm_opcode_impl impl[OPCODE_IMPL_MAX_SIZE]; /* OPCODE impl */
    vm_regs r;
    int insts_count;
    int cpool_count;
    int temps_count;
};

function call stack 位於 temps

其中 register 部份

typedef struct {
    size_t pc;    // program counter.
    size_t sp;    // stack runs from the end of 'temps' region.
    size_t from;  // the immediate PC before last branch/return.
    size_t to;    // the immediate PC after last branch/return.
} vm_regs;

vm_run 的部份大量使用 macro, 因此採用 gcc -E 觀察展開後的 vm_run

    const static void *labels[] = {&&OP_HALT, &&OP_ADD, &&OP_SUB, &&OP_PRINT, &&OP_JLT, &&OP_JLE, &&OP_JZ, &&OP_JGE, &&OP_JGT, &&OP_JNZ, &&OP_JMP, &&OP_MUL, &&OP_DIV, &&OP_MOD, &&OP_CALL, &&OP_RET, &&OP_AND, &&OP_OR, &&OP_NOT, &&OP_XOR, &&OP_LSL, &&OP_LSR, &&OP_ASR,}; \
    goto *labels[env->insts[env->r.pc].opcode];

此處採用了 gcc computed goto 跳至 pc 所指向的 instruction, 以避免 switch-case 造成的 branch:

參考此處,其中解釋 computed goto 細節:

  • 不像 switch-case 需要確認資料是否在範圍內(default 需要),因此可以減少指令數目
  • jump 至不同位置的程式碼是分開的,因此有利於處理器 branch-prediction. switch-case 的 jump 位於同一個指令,較難對各個情況的 branch 進行預測

說話不精確,改用 computed goto 仍有 branch,請詳細描述具體落差,以及用計算機結構的觀點闡述

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
jserv

typedef struct {
    int opcode;
    vm_operand op1;
    vm_operand op2;
    int result;
} vm_inst;

每個 instruction 會透過以下方法執行:

OP_ADD : do { 
             if (env->impl[env->insts[env->r.pc].opcode].handler) 
                 env->impl[env->insts[env->r.pc].opcode].handler( 
                         vm_get_op_value(env, &env->insts[env->r.pc].op1), 
                         vm_get_op_value(env, &env->insts[env->r.pc].op2), 
                         vm_get_temp_value(env, env->insts[env->r.pc].result)
                         ); 
             do { 
                 ++env->r.pc; 
                 goto *labels[env->insts[env->r.pc].opcode]; 
             } while (0); 
         } while (0);

TO HTYISABUG: do{} while(0); 是為了避免單行 if 沒加大括弧造成巨集不完整的手法(參考此處)

術語叫做 dangling else

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
jserv

ISA 格式

參考 tests/mul.s

mul $3 $2 #1        ; multiply: (3)*(2)
print #1
mul $3 $-2 #2       ; multiply: (3)*(-2)
print #2

可知 $X 代表常數,#X 則是 register
可用的 register 上限則是 CPOOL_MAX_SIZE