[hellogcc] Re: [hellogcc] [投稿] QEMU Internal - Block Chaining 3/3

  • From: Liu <proljc@xxxxxxxxx>
  • To: hellogcc@xxxxxxxxxxxxx
  • Date: Sat, 1 Oct 2011 23:35:24 +0800

2011/10/1 陳韋任 <chenwj@xxxxxxxxxxxxxx>:
>           Copyright (c) 2011 陳韋任 (Chen Wei-Ren)
>
> 2. Block Chaining
>
>  由 guest binary -> TCG IR 的過程中,gen_goto_tb 會做 block chaining 的準備。
> 我們先來看何時會呼叫到 gen_goto_tb。以 i386 為例,遇到 guest binary 中的條件
> 分支和直接跳轉都會呼叫 gen_goto_tb (target-i386/translate.c)。這邊以條件分支
> 當例子:
>
> static inline void gen_jcc(DisasContext *s, int b,
>                           target_ulong val, target_ulong next_eip)
> {
>    int l1, l2, cc_op;
>
>    cc_op = s->cc_op;
>    gen_update_cc_op(s);
>    if (s->jmp_opt) { // use direct block chaining for direct jumps
>        l1 = gen_new_label();
>        gen_jcc1(s, cc_op, b, l1);
>
>        gen_goto_tb(s, 0, next_eip); // 我猜是 taken
>
>        gen_set_label(l1);
>        gen_goto_tb(s, 1, val); // 我猜是 not taken
>        s->is_jmp = DISAS_TB_JUMP;
>    } else {
>
>      /* 忽略不提 */
>
>    }
> }
>
>  - gen_goto_tb。強烈建議閱讀 Porting QEMU to Plan 9: QEMU Internals and Port Strategy
>    2.2.3 和 2.2.4 節,也別忘了 http://qemu.sourcearchive.com 。
>
> // tb_num 代表目前 tb block linking 分支情況。eip 代表跳轉目標。
> static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong eip)
> {
>    TranslationBlock *tb;
>    target_ulong pc;
>
>    // s->pc 代表翻譯至目前 guest binary 的所在位址。tb->pc 表示 guest binary 的起始位址。
>    // 注意! 這裡 s->cs_base + eip 代表跳轉位址; s->pc 代表目前翻譯到的 guest pc。
>    pc = s->cs_base + eip; // 計算跳轉目標的 pc
>    tb = s->tb; // 目前 tb
>    // http://lists.nongnu.org/archive/html/qemu-devel/2011-08/msg02249.html
>    // http://lists.gnu.org/archive/html/qemu-devel/2011-09/msg03065.html
>    // 滿足底下兩個條件之一,則可以做 direct block linking
>    // 第一,跳轉目標和目前 tb 起始的 pc 同屬一個 guest page。
>    // 第二,跳轉目標和目前翻譯到的 pc 同屬一個 guest page。
>    if ((pc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) ||
>        (pc & TARGET_PAGE_MASK) == ((s->pc - 1) & TARGET_PAGE_MASK))  {
>        // 如果 guest jump 指令和其跳轉位址同屬一個 guest page,則做 direct block linking。
>
>        tcg_gen_goto_tb(tb_num); // 生成準備做 block linking 的 TCG IR。詳情請見之後描述。
>
>        // 更新 env 的 eip,使其指向此 tb 之後欲執行指令的位址。
>        // tb_find_fast 會用 eip 查找該 TB 是否已被翻譯過。
>        gen_jmp_im(eip);
>
>        // 最終回到 QEMU tcg_qemu_tb_exec,賦值給 next_tb。
>        // 注意! tb_num 會被 next_tb & 3 取出,由此可以得知 block chaining 的方向。
>        tcg_gen_exit_tb((tcg_target_long)tb + tb_num);
>    } else {
>        /* jump to another page: currently not optimized */
>        gen_jmp_im(eip);
>        gen_eob(s);
>    }
> }
>
>  o tcg_gen_goto_tb 生成 TCG IR。
>
> static inline void tcg_gen_goto_tb(int idx)
> {
>    tcg_gen_op1i(INDEX_op_goto_tb, idx);
> }
>  o tcg_out_op (tcg/i386/tcg-target.c) 將 TCG IR 翻成 host binary。
>    注意! 這邊利用 patch jmp 跳轉位址達成 block linking。
>
> static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
>                              const TCGArg *args, const int *const_args)
> {
>    case INDEX_op_goto_tb:
>        if (s->tb_jmp_offset) {
>            /* direct jump method */
>            tcg_out8(s, OPC_JMP_long); /* jmp im */
>            // 紀錄將來要 patch 的地方。
>            s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
>            // jmp 的參數為 jmp 下一個指令與目標的偏移量。
>            // 如果還沒做 block chaining,則 jmp 0 代表 fall through。
>            tcg_out32(s, 0);
>        } else {
>
>            /* 在此忽略 */
>
>        }
>        // 留待將來 "reset" direct jump 之用。
>        s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
>        break;
> }
>
>  回答上一篇最後留下的問題。在還未 patch code cache 中的分支跳轉指令的跳轉位址,
> 它會 fall through,還記得 jmp 0 嗎? 我這邊在列出 gen_goto_tb 的部分內容:
>
>        tcg_gen_goto_tb(tb_num);
>
>        // Fall through
>
>        // 更新 env 的 eip,使其指向此 tb 之後欲執行指令的位址。
>        // tb_find_fast 會用 eip 查找該 TB 是否已被翻譯過。
>        gen_jmp_im(eip);
>
>        // 最終回到 QEMU tcg_qemu_tb_exec,賦值給 next_tb。
>        // 注意! tb_num 會被 next_tb & 3 取出,由此可以得知 block chaining 的方向。
>        tcg_gen_exit_tb((tcg_target_long)tb + tb_num);
>
> 目前執行的 tb 會賦值給 next_tb (末兩位編碼 block chaining 的方向)。等待下一次迴圈,
> tb_find_fast 回傳 next_tb 的下一個 tb。
>
>  if (next_tb != 0 && tb->page_addr[1] == -1) {
>      // 這邊利用 TranlationBlock 指針的最低有效位後兩位指引 block chaining 的方向。
>      // next_tb -> tb
>      tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
>  }
>
> That's it! That's how direct block chaining is done in QEMU, I think... :-)
>
>
> --
> Wei-Ren Chen (陳韋任)
> Computer Systems Lab, Institute of Information Science,
> Academia Sinica, Taiwan (R.O.C.)
> Tel:886-2-2788-3799 #1667
>
>

good! 促进了两岸科技交流啊!

Other related posts:

  • » [hellogcc] Re: [hellogcc] [投稿] QEMU Internal - Block Chaining 3/3 - Liu