Annotation of tme/libtme/host/x86/rc-x86-chain.c, revision 1.1.1.1

1.1       root        1: /* $Id: rc-x86-chain.c,v 1.3 2010/02/15 22:15:59 fredette Exp $ */
                      2: 
                      3: /* libtme/host/x86/rc-x86-chain.c - x86 host recode chain support: */
                      4: 
                      5: /*
                      6:  * Copyright (c) 2009 Matt Fredette
                      7:  * All rights reserved.
                      8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  * 3. All advertising materials mentioning features or use of this software
                     18:  *    must display the following acknowledgement:
                     19:  *      This product includes software developed by Matt Fredette.
                     20:  * 4. The name of the author may not be used to endorse or promote products
                     21:  *    derived from this software without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     24:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     25:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     26:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
                     27:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
                     28:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     29:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                     31:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
                     32:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     33:  * POSSIBILITY OF SUCH DAMAGE.
                     34:  */
                     35: 
                     36: _TME_RCSID("$Id: rc-x86-chain.c,v 1.3 2010/02/15 22:15:59 fredette Exp $");
                     37: 
                     38: /* macros: */
                     39: 
                     40: /* the x86 register for the pointer to the token for the current
                     41:    instruction TLB entry: */
                     42: #define TME_RECODE_X86_REG_CHAIN_ITLB_CURRENT_TOKEN    (TME_RECODE_X86_REG_TLB)
                     43: 
                     44: /* the x86 register for the chain return address: */
                     45: #define TME_RECODE_X86_REG_CHAIN_RETURN_ADDRESS                (TME_RECODE_X86_REG_TLB)
                     46: 
                     47: /* the x86 register for the chain return address stack pointer: */
                     48: #define TME_RECODE_X86_REG_CHAIN_RAS_POINTER           (TME_RECODE_X86_REG_TLB_SCRATCH)
                     49: 
                     50: /* the x86 register for the fixup address: */
                     51: #define TME_RECODE_X86_REG_CHAIN_FIXUP_ADDRESS         (TME_RECODE_X86_REG_TLB_SCRATCH)
                     52: 
                     53: /* the x86 register for the guest instructions source address: */
                     54: /* NB: we use the a register to take advantage of the fact that there
                     55:    is a special cmp $imm, %a form that will save a byte in each
                     56:    instruction thunk: */
                     57: #define TME_RECODE_X86_REG_CHAIN_GUEST_SRC             (TME_RECODE_X86_REG_A)
                     58: 
                     59: /* this gives the one or two opcode bytes for a cmp $imm32,
                     60:    %TME_RECODE_X86_REG_CHAIN_GUEST_SRC: */
                     61: #if TME_RECODE_X86_REG_CHAIN_GUEST_SRC != TME_RECODE_X86_REG_A
                     62: #error "TME_RECODE_X86_REG_CHAIN_GUEST_SRC changed"
                     63: #endif
                     64: #define TME_RECODE_X86_INSN_CMP_Iz_REG_CHAIN_GUEST_SRC         \
                     65:   (TME_RECODE_X86_REX_B(TME_RECODE_SIZE_HOST,                  \
                     66:                        TME_RECODE_X86_REG_CHAIN_GUEST_SRC)     \
                     67:    + ((TME_RECODE_X86_OPCODE_BINOP_CMP                         \
                     68:        + TME_RECODE_X86_OPCODE_BINOP_Iz_A)                     \
                     69:       << (8 * (TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32))))
                     70: 
                     71: /* this gives the one opcode byte for a movl $imm32, %TME_RECODE_X86_REG_TLB_SCRATCH: */
                     72: #if TME_RECODE_X86_REG(TME_RECODE_X86_REG_TLB_SCRATCH) != TME_RECODE_X86_REG_TLB_SCRATCH
                     73: #error "TME_RECODE_X86_REG_TLB_SCRATCH changed"
                     74: #endif
                     75: #define TME_RECODE_X86_INSN_MOVL_IMM32_REG_TLB_SCRATCH         \
                     76:   TME_RECODE_X86_OPCODE_MOV_Iv_Gv(TME_RECODE_X86_REG_TLB_SCRATCH)
                     77: 
                     78: /* this gives the three opcode bytes for a lea disp32(%ip),
                     79:    %TME_RECODE_X86_REG_TLB_SCRATCH: */
                     80: #define TME_RECODE_X86_INSN_LEA_DISP32_IP_REG_TLB_SCRATCH      \
                     81:   (TME_RECODE_X86_REX_R(TME_RECODE_SIZE_HOST,                  \
                     82:                        TME_RECODE_X86_REG_TLB_SCRATCH)         \
                     83:    + (TME_RECODE_X86_OPCODE_LEA                                        \
                     84:       << 8)                                                    \
                     85:    + (TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_EA(TME_RECODE_X86_EA_BASE_IP),\
                     86:                                  TME_RECODE_X86_REG(TME_RECODE_X86_REG_TLB_SCRATCH))\
                     87:       << 16))
                     88: 
                     89: /* this gives the two opcode bytes for a movq $imm64,
                     90:    %TME_RECODE_X86_REG_TLB_SCRATCH: */
                     91: #define TME_RECODE_X86_INSN_MOVQ_IMM64_REG_TLB_SCRATCH         \
                     92:   (TME_RECODE_X86_REX_R(TME_RECODE_SIZE_HOST,                  \
                     93:                        TME_RECODE_X86_REG_TLB_SCRATCH)         \
                     94:    + (TME_RECODE_X86_OPCODE_MOV_Iv_Gv(TME_RECODE_X86_REG_TLB_SCRATCH)\
                     95:       << 8))
                     96: 
                     97: /* this gives the three opcode bytes for a testb $imm8, addr32: */
                     98: #define TME_RECODE_X86_INSN_TESTB_IMM8_ADDR32                  \
                     99:   (TME_RECODE_X86_OPCODE_GRP3_Eb                               \
                    100:    + (TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_EA(TME_RECODE_X86_EA_BASE_SIB),\
                    101:                                  TME_RECODE_X86_OPCODE_GRP3_TEST)\
                    102:       << 8)                                                    \
                    103:    + (TME_RECODE_X86_SIB(TME_RECODE_X86_SIB_BASE_NONE,         \
                    104:                         TME_RECODE_X86_SIB_INDEX_NONE,         \
                    105:                         1)                                     \
                    106:       << 16))
                    107: 
                    108: /* this gives the two opcode bytes for a testb $imm8, disp32(%ip): */
                    109: #define TME_RECODE_X86_INSN_TESTB_IMM8_DISP32_IP               \
                    110:   (TME_RECODE_X86_OPCODE_GRP3_Eb                               \
                    111:    + (TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_EA(TME_RECODE_X86_EA_BASE_IP),\
                    112:                                  TME_RECODE_X86_OPCODE_GRP3_TEST)\
                    113:       << 8))
                    114: 
                    115: /* this gives the two opcode bytes for a testb $imm8,
                    116:    disp32(%TME_RECODE_X86_REG_CHAIN_GUEST_SRC): */
                    117: #if TME_RECODE_X86_REG(TME_RECODE_X86_REG_CHAIN_GUEST_SRC) != TME_RECODE_X86_REG_CHAIN_GUEST_SRC
                    118: #error "TME_RECODE_X86_REG_CHAIN_GUEST_SRC changed"
                    119: #endif
                    120: #define TME_RECODE_X86_INSN_TESTB_IMM8_DISP32_REG_CHAIN_GUEST_SRC \
                    121:   (TME_RECODE_X86_OPCODE_GRP3_Eb                               \
                    122:    + (TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_EA_DISP32(TME_RECODE_X86_REG_CHAIN_GUEST_SRC),\
                    123:                                  TME_RECODE_X86_OPCODE_GRP3_TEST)\
                    124:       << 8))
                    125: 
                    126: /* this is the size of a jcc epilogue instruction: */
                    127: #define TME_RECODE_X86_CHAIN_IN_SIZE_JCC_EPILOGUE      \
                    128:   (6   /* jcc epilogue */)
                    129: 
                    130: /* this is the size of the chain in far instructions on an ia32 host: */
                    131: #define TME_RECODE_IA32_CHAIN_IN_SIZE_FAR              \
                    132:   (5   /* cmpl $imm32, %eax */                         \
                    133:    + TME_RECODE_X86_CHAIN_IN_SIZE_JCC_EPILOGUE         \
                    134:    + 7  /* testb $imm8, addr32 */                      \
                    135:    + TME_RECODE_X86_CHAIN_IN_SIZE_JCC_EPILOGUE)
                    136: 
                    137: /* the size of cmpq $imm32, %TME_RECODE_X86_REG_CHAIN_GUEST_SRC ; jnz
                    138:    epilogue */
                    139: #define TME_RECODE_X86_64_CHAIN_IN_SIZE_CMPQ_IMM32_JNZ \
                    140:   (6   /* cmpq $imm32, %rax */                         \
                    141:    + TME_RECODE_X86_CHAIN_IN_SIZE_JCC_EPILOGUE)
                    142: 
                    143: /* the size of cmpq %reg, %reg ; jnz epilogue */
                    144: #define TME_RECODE_X86_64_CHAIN_IN_SIZE_CMP_JNZ                \
                    145:   (3   /* cmpq %reg, %reg */                           \
                    146:    + TME_RECODE_X86_CHAIN_IN_SIZE_JCC_EPILOGUE)
                    147: 
                    148: /* the size of movl $imm32, %reg ; cmpq %reg, %reg ; jnz epilogue */
                    149: #define TME_RECODE_X86_64_CHAIN_IN_SIZE_MOVL_CMP_JNZ   \
                    150:   (5   /* movl $imm32, %reg */                         \
                    151:    + TME_RECODE_X86_64_CHAIN_IN_SIZE_CMP_JNZ)
                    152: 
                    153: /* the size of lea disp32(%ip), %reg ; cmpq %reg, %reg ; jnz epilogue */
                    154: #define TME_RECODE_X86_64_CHAIN_IN_SIZE_LEA_IP_CMP_JNZ \
                    155:   (7   /* leaq disp32(%ip), %reg */                    \
                    156:    + TME_RECODE_X86_64_CHAIN_IN_SIZE_CMP_JNZ)
                    157: 
                    158: /* the size of movq $imm64, %reg ; cmpq %reg, %reg ; jnz epilogue */
                    159: #define TME_RECODE_X86_64_CHAIN_IN_SIZE_MOVQ_CMP_JNZ   \
                    160:   (10  /* movq $imm64, %reg */                         \
                    161:    + TME_RECODE_X86_64_CHAIN_IN_SIZE_CMP_JNZ)
                    162: 
                    163: /* the size of testb $imm8, addr32 ; jz epilogue */
                    164: #define TME_RECODE_X86_64_CHAIN_IN_SIZE_TESTB_ADDR32_JZ        \
                    165:   (8   /* testb $imm8, addr32 */                       \
                    166:    + TME_RECODE_X86_CHAIN_IN_SIZE_JCC_EPILOGUE)
                    167: 
                    168: /* the size of testb $imm8, base32(%reg) ; jz epilogue */
                    169: #define TME_RECODE_X86_64_CHAIN_IN_SIZE_TESTB_BASE_JZ  \
                    170:   (7   /* testb $imm8, addr32 */                       \
                    171:    + TME_RECODE_X86_CHAIN_IN_SIZE_JCC_EPILOGUE)
                    172: 
                    173: /* the size of movq $imm64, %reg ; testb $imm32, (%reg) ; jz epilogue */
                    174: #define TME_RECODE_X86_64_CHAIN_IN_SIZE_MOVQ_TESTB_JZ  \
                    175:   (10  /* movq $imm64, %reg */                         \
                    176:    + 3 /* testb $imm32, (%reg) */                      \
                    177:    + TME_RECODE_X86_CHAIN_IN_SIZE_JCC_EPILOGUE)
                    178: 
                    179: /* this gives a chain subs: */
                    180: #if (TME_RECODE_CHAIN_INFO_CONDITIONAL | TME_RECODE_CHAIN_INFO_FAR) != 3
                    181: #error "TME_RECODE_CHAIN_INFO_ values changed"
                    182: #endif
                    183: #if (TME_RECODE_CHAIN_INFO_JUMP != 4 || TME_RECODE_CHAIN_INFO_RETURN != 8)
                    184: #error "TME_RECODE_CHAIN_INFO_ values changed"
                    185: #endif
                    186: #define TME_RECODE_X86_CHAIN_SUBS(chain_thunk, chain_info)\
                    187:   ((chain_thunk)->tme_recode_x86_chain_thunk_subs      \
                    188:    [(chain_info)                                       \
                    189:     & (TME_RECODE_CHAIN_INFO_CONDITIONAL               \
                    190:        | TME_RECODE_CHAIN_INFO_FAR                     \
                    191:        | TME_RECODE_CHAIN_INFO_JUMP                    \
                    192:        | TME_RECODE_CHAIN_INFO_RETURN)])
                    193: 
                    194: /* these give a chain fixup target for the regular target or alternate
                    195:    target: */
                    196: #if TME_RECODE_CHAIN_INFO_FAR != 2 || TME_RECODE_CHAIN_INFO_ALTERNATE_FAR == 0
                    197: #error "TME_RECODE_CHAIN_INFO_ values changed"
                    198: #endif
                    199: #define TME_RECODE_X86_CHAIN_FIXUP_TARGET(ic, chain_info) \
                    200:   ((ic)->tme_recode_x86_ic_chain_fixup_target          \
                    201:    [((chain_info) & TME_RECODE_CHAIN_INFO_FAR)         \
                    202:     + (((chain_info) / TME_RECODE_CHAIN_INFO_CALL) & 1)])
                    203: #define TME_RECODE_X86_CHAIN_FIXUP_TARGET_ALTERNATE(ic, chain_info) \
                    204:   ((ic)->tme_recode_x86_ic_chain_fixup_target          \
                    205:    [4                                                  \
                    206:     + (((chain_info) / TME_RECODE_CHAIN_INFO_ALTERNATE_FAR) & 1)])
                    207: 
                    208: /* on an ia32 host, an entry on the return address stack is the
                    209:    absolute address of either an instructions thunk or the chain
                    210:    epilogue.  on an x86-64 host, an entry on the return address stack
                    211:    is the instructions thunk offset of either an instructions thunk or
                    212:    the chain epilogue: */
                    213: #if TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32
                    214: #define TME_RECODE_X86_CHAIN_RETURN_ADDRESS(ic, insns_thunk)\
                    215:   ((tme_recode_ras_entry_t) (insns_thunk))
                    216: #else  /* TME_RECODE_SIZE_HOST == TME_RECODE_SIZE_32 */
                    217: #define TME_RECODE_X86_CHAIN_RETURN_ADDRESS(ic, insns_thunk)\
                    218:   tme_recode_thunk_off_to_pointer(ic,                  \
                    219:                                  insns_thunk,          \
                    220:                                  tme_recode_ras_entry_t)
                    221: #endif /* TME_RECODE_SIZE_HOST == TME_RECODE_SIZE_32 */
                    222: 
                    223: /* this emits instructions for a chain epilogue: */
                    224: static void
                    225: _tme_recode_x86_chain_epilogue(struct tme_recode_ic *ic)
                    226: {
                    227:   tme_uint8_t *thunk_bytes;
                    228: 
                    229:   /* start more instructions: */
                    230:   tme_recode_x86_insns_start(ic, thunk_bytes);
                    231: 
                    232:   /* set the instructions thunk offset of the chain epilogue: */
                    233:   ic->tme_recode_x86_ic_chain_epilogue = tme_recode_build_to_thunk_off(ic, thunk_bytes);
                    234: 
                    235:   /* remove the recode carry flag stack word: */
                    236:   thunk_bytes
                    237:     = _tme_recode_x86_emit_adjust_sp(thunk_bytes,
                    238:                                     TME_BIT(TME_RECODE_SIZE_HOST
                    239:                                             - TME_RECODE_SIZE_8));
                    240: 
                    241:   /* pop all callee-saved registers: */
                    242:   if (TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32) {
                    243:     _tme_recode_x86_emit_reg_pop(thunk_bytes, TME_RECODE_X86_REG_N(15));
                    244:     _tme_recode_x86_emit_reg_pop(thunk_bytes, TME_RECODE_X86_REG_N(14));
                    245:     _tme_recode_x86_emit_reg_pop(thunk_bytes, TME_RECODE_X86_REG_N(13));
                    246:     _tme_recode_x86_emit_reg_pop(thunk_bytes, TME_RECODE_X86_REG_N(12));
                    247:   }
                    248:   else {
                    249:     _tme_recode_x86_emit_reg_pop(thunk_bytes, TME_RECODE_X86_REG_DI);
                    250:     _tme_recode_x86_emit_reg_pop(thunk_bytes, TME_RECODE_X86_REG_SI);
                    251:   }
                    252:   _tme_recode_x86_emit_reg_pop(thunk_bytes, TME_RECODE_X86_REG_B);
                    253:   _tme_recode_x86_emit_reg_pop(thunk_bytes, TME_RECODE_X86_REG_BP);
                    254: 
                    255:   /* emit the return: */
                    256:   thunk_bytes[0] = TME_RECODE_X86_OPCODE_RET;
                    257:   thunk_bytes++;
                    258: 
                    259:   /* finish these instructions: */
                    260:   tme_recode_x86_insns_finish(ic, thunk_bytes);
                    261: 
                    262:   /* finish the chain epilogue: */
                    263:   tme_recode_host_thunk_finish(ic);
                    264: }
                    265: 
                    266: /* this emits instructions to advance the fixup address register
                    267:    past a chain conditional six-byte jcc instruction: */
                    268: static tme_uint8_t *
                    269: _tme_recode_x86_chain_fixup_alternate(tme_uint8_t *thunk_bytes)
                    270: {
                    271: 
                    272:   /* NB: this is always a 32-bit instruction, even on an x86-64 host,
                    273:      because we end up converting the fixup address into an
                    274:      instructions thunk offset, which is only 32 bits: */
                    275:   assert (sizeof(tme_recode_thunk_off_t) == sizeof(tme_int32_t));
                    276:   thunk_bytes[0] = TME_RECODE_X86_OPCODE_GRP1_Ib_Ev;
                    277:   thunk_bytes[1]
                    278:     = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_REG(TME_RECODE_X86_REG_CHAIN_FIXUP_ADDRESS),
                    279:                                  TME_RECODE_X86_OPCODE_GRP1_BINOP(TME_RECODE_X86_OPCODE_BINOP_ADD));
                    280:   thunk_bytes[2] = 2 + sizeof(tme_int32_t);
                    281:   thunk_bytes += 3;
                    282:   return (thunk_bytes);
                    283: }
                    284: 
                    285: /* this emits instructions to make a constant for the third argument
                    286:    to the chain fixup function: */
                    287: static tme_uint8_t *
                    288: _tme_recode_x86_chain_fixup_arg2(tme_uint8_t *thunk_bytes,
                    289:                                 tme_uint32_t chain_info)
                    290: {
                    291: 
                    292:   /* if this is an ia32 host: */
                    293:   if (TME_RECODE_SIZE_HOST == TME_RECODE_SIZE_32) {
                    294: 
                    295:     /* push the argument: */
                    296:     assert (chain_info < 0x80);
                    297:     thunk_bytes[0] = TME_RECODE_X86_OPCODE_PUSH_Ib;
                    298:     thunk_bytes[1] = chain_info;
                    299:     thunk_bytes += 2;
                    300:   }
                    301: 
                    302:   /* otherwise, this is an x86-64 host: */
                    303:   else {
                    304: 
                    305:     /* load the third argument register: */
                    306:     thunk_bytes[0] = TME_RECODE_X86_OPCODE_MOV_Iv_Gv(TME_RECODE_X86_REG_D);
                    307:     *((tme_uint32_t *) &thunk_bytes[1]) = chain_info;
                    308:     thunk_bytes += 1 + sizeof(tme_uint32_t);
                    309:   }
                    310: 
                    311:   return (thunk_bytes);
                    312: }   
                    313: 
                    314: /* this emits instructions for the chain fixup targets for chain jump
                    315:    far, chain call far, and chain call near: */
                    316: static void
                    317: _tme_recode_x86_chain_fixup_target(struct tme_recode_ic *ic,
                    318:                                   tme_uint32_t chain_info,
                    319:                                   const tme_uint8_t *thunk_bytes_fixup_call)
                    320: {
                    321:   tme_uint8_t *thunk_bytes;
                    322: 
                    323:   /* start more instructions: */
                    324:   tme_recode_x86_insns_start(ic, thunk_bytes);
                    325: 
                    326:   /* set next fixup target: */
                    327:   TME_RECODE_X86_CHAIN_FIXUP_TARGET(ic,
                    328:                                    chain_info)
                    329:     = tme_recode_build_to_thunk_off(ic, thunk_bytes);
                    330: 
                    331:   /* make the third argument for the chain fixup function: */
                    332:   thunk_bytes = _tme_recode_x86_chain_fixup_arg2(thunk_bytes, chain_info);
                    333: 
                    334:   /* jmp to the common chain fixup call point: */
                    335:   thunk_bytes
                    336:     = _tme_recode_x86_emit_jmp(thunk_bytes,
                    337:                               TME_RECODE_X86_OPCODE_JMP_RELz,
                    338:                               thunk_bytes_fixup_call);
                    339: 
                    340:   /* finish these instructions: */
                    341:   tme_recode_x86_insns_finish(ic, thunk_bytes);
                    342: }
                    343: 
                    344: /* this makes the chain fixup targets for a new IC: */
                    345: static void
                    346: _tme_recode_x86_chain_fixup_targets(struct tme_recode_ic *ic)
                    347: {
                    348:   tme_uint8_t *thunk_bytes;
                    349:   const tme_uint8_t *thunk_bytes_fixup_call;
                    350:   unsigned long thunk_address0;
                    351:   unsigned int stack_adjust;
                    352: 
                    353:   /* start more instructions: */
                    354:   tme_recode_x86_insns_start(ic, thunk_bytes);
                    355: 
                    356:   /* the first fixup target is for chain jump alternate near: */
                    357:   TME_RECODE_X86_CHAIN_FIXUP_TARGET_ALTERNATE(ic,
                    358:                                              (TME_RECODE_CHAIN_INFO_JUMP
                    359:                                               + TME_RECODE_CHAIN_INFO_ALTERNATE_NEAR))
                    360:     = tme_recode_build_to_thunk_off(ic, thunk_bytes);
                    361: 
                    362:   /* advance the fixup address register past the chain jump
                    363:      conditional six-byte jcc instruction: */
                    364:   thunk_bytes = _tme_recode_x86_chain_fixup_alternate(thunk_bytes);
                    365: 
                    366:   /* the next fixup target is for chain jump near: */
                    367:   /* NB: this fixup target is also for chain return alternate near,
                    368:      which is treated like a chain jump near: */
                    369:   TME_RECODE_X86_CHAIN_FIXUP_TARGET(ic,
                    370:                                    (TME_RECODE_CHAIN_INFO_JUMP
                    371:                                     + TME_RECODE_CHAIN_INFO_NEAR))
                    372:     = tme_recode_build_to_thunk_off(ic, thunk_bytes);
                    373: 
                    374:   /* make the third argument for the chain fixup function: */
                    375:   thunk_bytes
                    376:     = _tme_recode_x86_chain_fixup_arg2(thunk_bytes,
                    377:                                       TME_RECODE_CHAIN_INFO_NEAR);
                    378: 
                    379:   /* this is the common chain fixup call point: */
                    380:   thunk_bytes_fixup_call = thunk_bytes;
                    381: 
                    382:   /* get the near address of the thunk at offset zero: */
                    383:   thunk_address0 = tme_recode_thunk_off_to_pointer(ic, 0, char *) - (char *) 0;
                    384: 
                    385:   /* convert the fixup address (which has been already truncated to 32
                    386:      bits) into the instructions thunk offset: */
                    387:   /* NB: this is always a 32-bit instruction, because a
                    388:      tme_recode_thunk_off_t is a tme_int32_t: */
                    389:   assert (sizeof(tme_recode_thunk_off_t) == sizeof(tme_int32_t));
                    390:   thunk_bytes[0] = TME_RECODE_X86_OPCODE_GRP1_Iz_Ev;
                    391:   thunk_bytes[1] = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_REG(TME_RECODE_X86_REG_CHAIN_FIXUP_ADDRESS),
                    392:                                               TME_RECODE_X86_OPCODE_GRP1_BINOP(TME_RECODE_X86_OPCODE_BINOP_SUB));
                    393:   *((tme_uint32_t *) &thunk_bytes[2]) = thunk_address0;
                    394:   thunk_bytes += 2 + sizeof(tme_uint32_t);
                    395: 
                    396:   /* if this is an ia32 host: */
                    397:   if (TME_RECODE_SIZE_HOST == TME_RECODE_SIZE_32) {
                    398: 
                    399:     /* push the arguments for the chain fixup function: */
                    400:     _tme_recode_x86_emit_reg_push(thunk_bytes, TME_RECODE_X86_REG_CHAIN_FIXUP_ADDRESS);
                    401:     _tme_recode_x86_emit_reg_push(thunk_bytes, TME_RECODE_X86_REG_IC);
                    402: 
                    403:     /* we will need to remove the arguments from the stack: */
                    404:     stack_adjust = sizeof(struct tme_ic *) + sizeof(tme_recode_thunk_off_t) + sizeof(tme_uint32_t);
                    405:   }
                    406: 
                    407:   /* otherwise, this is an x86-64 host: */
                    408:   else {
                    409: 
                    410:     /* copy the arguments for the guest jump chain function: */
                    411:     _tme_recode_x86_emit_reg_copy(thunk_bytes, TME_RECODE_X86_REG_IC, TME_RECODE_X86_REG_DI);
                    412:     _tme_recode_x86_emit_reg_copy(thunk_bytes, TME_RECODE_X86_REG_CHAIN_FIXUP_ADDRESS, TME_RECODE_X86_REG_SI);
                    413: 
                    414:     /* we don't need to adjust the stack.  NB that the instructions
                    415:        thunk, where the stack pointer is 16-byte aligned, jumped to
                    416:        us, so we don't have to align it for the x86-64 ABI: */
                    417:     stack_adjust = 0;
                    418:   }
                    419: 
                    420:   /* call the chain fixup function: */
                    421:   tme_recode_x86_insns_finish(ic, thunk_bytes);
                    422:   _tme_recode_x86_emit_transfer_func(ic,
                    423:                                     TME_RECODE_X86_OPCODE_CALL_RELz,
                    424:                                     ((void (*) _TME_P((void)))
                    425:                                      ic->tme_recode_ic_chain_fixup));
                    426:   tme_recode_x86_insns_start(ic, thunk_bytes);
                    427: 
                    428:   /* do any stack adjust: */
                    429:   if (stack_adjust) {
                    430:     thunk_bytes = _tme_recode_x86_emit_adjust_sp(thunk_bytes, stack_adjust);
                    431:   }
                    432: 
                    433:   /* jmp to the chain epilogue: */
                    434:   thunk_bytes
                    435:     = _tme_recode_x86_emit_jmp(thunk_bytes,
                    436:                               TME_RECODE_X86_OPCODE_JMP_RELz,
                    437:                               tme_recode_thunk_off_to_pointer(ic, 
                    438:                                                               ic->tme_recode_x86_ic_chain_epilogue,
                    439:                                                               tme_uint8_t *));
                    440: 
                    441:   /* the next fixup target is for chain jump alternate far: */
                    442:   TME_RECODE_X86_CHAIN_FIXUP_TARGET_ALTERNATE(ic,
                    443:                                              (TME_RECODE_CHAIN_INFO_JUMP
                    444:                                               + TME_RECODE_CHAIN_INFO_ALTERNATE_FAR))
                    445:     = tme_recode_build_to_thunk_off(ic, thunk_bytes);
                    446: 
                    447:   /* advance the fixup address register past the chain jump
                    448:      conditional six-byte jcc instruction: */
                    449:   thunk_bytes = _tme_recode_x86_chain_fixup_alternate(thunk_bytes);
                    450: 
                    451:   /* finish these instructions: */
                    452:   tme_recode_x86_insns_finish(ic, thunk_bytes);
                    453: 
                    454:   /* the next fixup target is for chain jump far: */
                    455:   _tme_recode_x86_chain_fixup_target(ic,
                    456:                                     TME_RECODE_CHAIN_INFO_FAR,
                    457:                                     thunk_bytes_fixup_call);
                    458: 
                    459:   /* the next fixup target is for chain call far: */
                    460:   _tme_recode_x86_chain_fixup_target(ic,
                    461:                                     (TME_RECODE_CHAIN_INFO_CALL
                    462:                                      + TME_RECODE_CHAIN_INFO_FAR),
                    463:                                     thunk_bytes_fixup_call);
                    464: 
                    465:   /* the next fixup target is for chain call near: */
                    466:   _tme_recode_x86_chain_fixup_target(ic,
                    467:                                     (TME_RECODE_CHAIN_INFO_CALL
                    468:                                      + TME_RECODE_CHAIN_INFO_NEAR),
                    469:                                     thunk_bytes_fixup_call);
                    470: 
                    471:   /* finish the fixup targets thunk: */
                    472:   tme_recode_host_thunk_finish(ic);
                    473: }
                    474: 
                    475: /* this emits a jmp to a chain subs: */
                    476: static tme_uint8_t *
                    477: _tme_recode_x86_chain_subs_jmp(struct tme_recode_ic *ic,
                    478:                               tme_uint32_t opcode,
                    479:                               struct tme_recode_chain_thunk *chain_thunk,
                    480:                               tme_uint32_t chain_info)
                    481: {
                    482:   tme_uint8_t *thunk_bytes;
                    483:   tme_uint8_t *thunk_bytes_jc;
                    484:   tme_recode_thunk_off_t chain_subs;
                    485:   tme_uint8_t *thunk_bytes_target;
                    486: 
                    487:   /* if this is a conditional jmp: */
                    488:   if (opcode != TME_RECODE_X86_OPCODE_JMP_RELb
                    489:       && opcode != TME_RECODE_X86_OPCODE_JMP_RELz) {
                    490: 
                    491:     /* define CF with the recode jump flag.  NB that the recode flags
                    492:        are now above the return address to the instructions thunk: */
                    493:     _tme_recode_x86_conds_testc(ic, TME_BIT(TME_RECODE_SIZE_HOST - TME_RECODE_SIZE_8) + TME_RECODE_FLAG_JUMP);
                    494:   }
                    495: 
                    496:   /* start more instructions: */
                    497:   tme_recode_x86_insns_start(ic, thunk_bytes);
                    498: 
                    499:   /* emit the jmp: */
                    500:   chain_subs = TME_RECODE_X86_CHAIN_SUBS(chain_thunk, chain_info);
                    501:   if (chain_subs == 0) {
                    502:     thunk_bytes_jc = thunk_bytes;
                    503:     thunk_bytes_target = (tme_uint8_t *) NULL;
                    504:   }
                    505:   else {
                    506:     thunk_bytes_jc = (tme_uint8_t *) NULL;
                    507:     thunk_bytes_target = tme_recode_thunk_off_to_pointer(ic, chain_subs, tme_uint8_t *);
                    508:   }
                    509:   thunk_bytes = _tme_recode_x86_emit_jmp(thunk_bytes, opcode, thunk_bytes_target);
                    510: 
                    511:   /* finish these instructions: */
                    512:   tme_recode_x86_insns_finish(ic, thunk_bytes);
                    513: 
                    514:   return (thunk_bytes_jc);
                    515: }
                    516: 
                    517: /* this emits instructions to add a sign-extended byte to the chain
                    518:    return address stack pointer, mask it, and then store it: */
                    519: static void
                    520: _tme_recode_x86_chain_ras_pointer_update(struct tme_recode_ic *ic,
                    521:                                         tme_int8_t addend)
                    522: {
                    523:   tme_uint8_t *thunk_bytes;
                    524:   tme_uint8_t ras_size;
                    525: 
                    526:   /* start these instructions: */
                    527:   tme_recode_x86_insns_start(ic, thunk_bytes);
                    528: 
                    529:   /* emit the add $imm8: */
                    530:   thunk_bytes[0] = TME_RECODE_X86_OPCODE_GRP1_Ib_Ev;
                    531:   thunk_bytes[1] = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_REG(TME_RECODE_X86_REG_CHAIN_RAS_POINTER),
                    532:                                               TME_RECODE_X86_OPCODE_GRP1_BINOP(TME_RECODE_X86_OPCODE_BINOP_ADD));
                    533:   thunk_bytes[2] = addend;
                    534:   thunk_bytes += 3;
                    535: 
                    536:   /* emit the and $imm8: */
                    537:   thunk_bytes[0] = TME_RECODE_X86_OPCODE_GRP1_Ib_Ev;
                    538:   thunk_bytes[1] = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_REG(TME_RECODE_X86_REG_CHAIN_RAS_POINTER),
                    539:                                               TME_RECODE_X86_OPCODE_GRP1_BINOP(TME_RECODE_X86_OPCODE_BINOP_AND));
                    540:   ras_size = ic->tme_recode_ic_chain_ras_size;
                    541:   assert (ras_size > 0 && (ras_size & (ras_size - 1)) == 0);
                    542:   thunk_bytes[2] = ras_size - 1;
                    543:   thunk_bytes += 3;
                    544: 
                    545:   /* store the chain return address stack pointer: */
                    546:   thunk_bytes[0] = (TME_RECODE_X86_OPCODE_BINOP_MOV + TME_RECODE_X86_OPCODE_BINOP_Gv_Ev);
                    547:   thunk_bytes = _tme_recode_x86_emit_ic_modrm(thunk_bytes + 1,
                    548:                                              ic->tme_recode_ic_chain_ras_pointer_offset,
                    549:                                              TME_RECODE_X86_REG_CHAIN_RAS_POINTER);
                    550: 
                    551:   /* finish these instructions: */
                    552:   tme_recode_x86_insns_finish(ic, thunk_bytes);
                    553: }
                    554: 
                    555: /* this emits an instruction to load or store an entry on the chain
                    556:    return address stack: */
                    557: static void
                    558: _tme_recode_x86_chain_ras_ls(struct tme_recode_ic *ic,
                    559:                             int store)
                    560: {
                    561:   tme_uint8_t *thunk_bytes;
                    562:   tme_int32_t ras_offset;
                    563: 
                    564:   /* start more instructions: */
                    565:   tme_recode_x86_insns_start(ic, thunk_bytes);
                    566: 
                    567:   /* emit the movl: */
                    568:   thunk_bytes[0]
                    569:     = (TME_RECODE_X86_OPCODE_BINOP_MOV
                    570:        + (store
                    571:          ? TME_RECODE_X86_OPCODE_BINOP_Gv_Ev
                    572:          : TME_RECODE_X86_OPCODE_BINOP_Ev_Gv));
                    573:   ras_offset = ic->tme_recode_ic_chain_ras_offset;
                    574:   thunk_bytes[1]
                    575:     = TME_RECODE_X86_MOD_OPREG_RM((ras_offset < 0x80
                    576:                                   ? TME_RECODE_X86_MOD_RM_EA_DISP8(TME_RECODE_X86_EA_BASE_SIB)
                    577:                                   : TME_RECODE_X86_MOD_RM_EA_DISP32(TME_RECODE_X86_EA_BASE_SIB)),
                    578:                                  TME_RECODE_X86_REG(TME_RECODE_X86_REG_CHAIN_RETURN_ADDRESS));
                    579:   thunk_bytes[2]
                    580:     = TME_RECODE_X86_SIB(TME_RECODE_X86_REG_IC,
                    581:                         TME_RECODE_X86_REG_CHAIN_RAS_POINTER,
                    582:                         sizeof(tme_recode_ras_entry_t));
                    583:   *((tme_uint32_t *) (thunk_bytes + 3)) = ras_offset;
                    584:   thunk_bytes += 3 + (ras_offset < 0x80 ? sizeof(tme_uint8_t) : sizeof(tme_uint32_t));
                    585: 
                    586:   /* finish these instructions: */
                    587:   tme_recode_x86_insns_finish(ic, thunk_bytes);
                    588: }
                    589: 
                    590: /* this emits instructions to push the chain return address stack: */
                    591: static void
                    592: _tme_recode_x86_chain_ras_push(struct tme_recode_ic *ic)
                    593: {
                    594:   tme_uint8_t *thunk_bytes;
                    595: 
                    596:   /* start more instructions: */
                    597:   tme_recode_x86_insns_start(ic, thunk_bytes);
                    598: 
                    599:   /* load the return address stack pointer: */
                    600:   thunk_bytes[0] = (TME_RECODE_X86_OPCODE_BINOP_MOV + TME_RECODE_X86_OPCODE_BINOP_Ev_Gv);
                    601:   thunk_bytes = _tme_recode_x86_emit_ic_modrm(thunk_bytes + 1,
                    602:                                              ic->tme_recode_ic_chain_ras_pointer_offset,
                    603:                                              TME_RECODE_X86_REG_CHAIN_RAS_POINTER);
                    604: 
                    605:   /* finish these instructions: */
                    606:   tme_recode_x86_insns_finish(ic, thunk_bytes);
                    607:   
                    608:   /* subtract one from the return address stack pointer, and store it: */
                    609:   _tme_recode_x86_chain_ras_pointer_update(ic, -1);
                    610: 
                    611:   /* store the return address: */
                    612:   _tme_recode_x86_chain_ras_ls(ic, TRUE);
                    613: }
                    614: 
                    615: /* this emits instructions to load or store the pointer to the token
                    616:    for the current recode instruction TLB entry: */
                    617: static void
                    618: _tme_recode_x86_chain_itlb_current_token_ls(struct tme_recode_ic *ic,
                    619:                                            int store)
                    620: {
                    621:   tme_uint8_t *thunk_bytes;
                    622: 
                    623:   /* start more instructions: */
                    624:   tme_recode_x86_insns_start(ic, thunk_bytes);
                    625: 
                    626:   /* load or store the pointer to the token for the current recode
                    627:      instruction TLB entry: */
                    628:   if (TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32) {
                    629:     *(thunk_bytes++)
                    630:       = TME_RECODE_X86_REX_B(TME_RECODE_SIZE_HOST,
                    631:                             TME_RECODE_X86_REG_CHAIN_ITLB_CURRENT_TOKEN);
                    632:   }
                    633:   thunk_bytes[0]
                    634:     = (TME_RECODE_X86_OPCODE_BINOP_MOV
                    635:        + (store
                    636:          ? TME_RECODE_X86_OPCODE_BINOP_Gv_Ev
                    637:          : TME_RECODE_X86_OPCODE_BINOP_Ev_Gv));
                    638:   thunk_bytes = _tme_recode_x86_emit_ic_modrm(thunk_bytes + 1,
                    639:                                              ic->tme_recode_ic_itlb_current_token_offset,
                    640:                                              TME_RECODE_X86_REG_CHAIN_ITLB_CURRENT_TOKEN);
                    641: 
                    642:   /* finish these instructions: */
                    643:   tme_recode_x86_insns_finish(ic, thunk_bytes);
                    644: }
                    645: #define _tme_recode_x86_chain_itlb_current_token_load(ic) _tme_recode_x86_chain_itlb_current_token_ls(ic, FALSE)
                    646: 
                    647: /* this stores the pointer to the current recode instruction TLB entry: */
                    648: static void
                    649: _tme_recode_x86_chain_itlb_current_store(struct tme_recode_ic *ic,
                    650:                                         const struct tme_recode_x86_tlb_type *x86_tlb_type)
                    651: {
                    652:   tme_uint8_t *thunk_bytes;
                    653: 
                    654:   /* start more instructions: */
                    655:   tme_recode_x86_insns_start(ic, thunk_bytes);
                    656: 
                    657:   /* convert the pointer to the recode instruction TLB entry in
                    658:      TME_RECODE_X86_REG_TLB into a pointer to the token for that entry
                    659:      in TME_RECODE_X86_REG_CHAIN_ITLB_CURRENT_TOKEN: */
                    660: #if TME_RECODE_X86_REG_CHAIN_ITLB_CURRENT_TOKEN != TME_RECODE_X86_REG_TLB
                    661: #error "TME_RECODE_X86_REG_CHAIN_ITLB_CURRENT_TOKEN changed"
                    662: #endif
                    663:   thunk_bytes[0] = TME_RECODE_X86_OPCODE_GRP1_Ib_Ev;
                    664:   thunk_bytes[1] = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_REG(TME_RECODE_X86_REG_TLB),
                    665:                                               TME_RECODE_X86_OPCODE_GRP1_BINOP(TME_RECODE_X86_OPCODE_BINOP_ADD));
                    666:   assert (x86_tlb_type->tme_recode_tlb_type.tme_recode_tlb_type_offset_token < 0x80);
                    667:   thunk_bytes[2] = x86_tlb_type->tme_recode_tlb_type.tme_recode_tlb_type_offset_token;
                    668:   thunk_bytes += 3;
                    669: 
                    670:   /* finish these instructions: */
                    671:   tme_recode_x86_insns_finish(ic, thunk_bytes);
                    672: 
                    673:   /* store the pointer to the token for the current recode instruction
                    674:      TLB entry: */
                    675:   _tme_recode_x86_chain_itlb_current_token_ls(ic, TRUE);
                    676: }
                    677: 
                    678: /* this emits instructions for the call and jump chain subs, or for
                    679:    the return chain subs: */
                    680: static void
                    681: _tme_recode_x86_chain_subs(struct tme_recode_ic *ic,
                    682:                           const struct tme_recode_chain *chain,
                    683:                           struct tme_recode_chain_thunk *chain_thunk,
                    684:                           tme_uint32_t chain_info_call_or_return)
                    685: {
                    686:   tme_uint8_t *thunk_bytes_jmp_to_jump_far_unconditional;
                    687:   tme_uint8_t *thunk_bytes;
                    688:   struct tme_recode_x86_tlb_type x86_tlb_type;
                    689:   union tme_recode_reginfo reginfo;
                    690:   unsigned int rex;
                    691:   unsigned int reg_x86_address;
                    692:   tme_uint8_t *thunk_bytes_jcc_chain_counter;
                    693:   const tme_uint8_t *thunk_bytes_jmp_to_epilogue;
                    694: 
                    695:   /* the first chain subs is for a chain call far conditional or chain
                    696:      return far conditional: */
                    697:   TME_RECODE_X86_CHAIN_SUBS(chain_thunk,
                    698:                            (chain_info_call_or_return
                    699:                             + TME_RECODE_CHAIN_INFO_FAR
                    700:                             + TME_RECODE_CHAIN_INFO_CONDITIONAL))
                    701:     = tme_recode_build_to_thunk_off(ic, ic->tme_recode_ic_thunk_build_next);
                    702: 
                    703:   /* if the recode jump flag is false, jmp to the chain subs for a
                    704:      chain jump far unconditional: */
                    705:   thunk_bytes_jmp_to_jump_far_unconditional
                    706:     = _tme_recode_x86_chain_subs_jmp(ic,
                    707:                                     (TME_RECODE_X86_OPCODE_ESC_0F
                    708:                                      + (TME_RECODE_X86_OPCODE0F_JCC(TME_RECODE_X86_COND_NOT
                    709:                                                                     | TME_RECODE_X86_COND_C)
                    710:                                         << 8)),
                    711:                                     chain_thunk,
                    712:                                     (TME_RECODE_CHAIN_INFO_JUMP
                    713:                                      + TME_RECODE_CHAIN_INFO_FAR
                    714:                                      + TME_RECODE_CHAIN_INFO_UNCONDITIONAL));
                    715: 
                    716:   /* if this the chain subs for a chain return far conditional: */
                    717:   if (chain_info_call_or_return == TME_RECODE_CHAIN_INFO_RETURN) {
                    718: 
                    719:     /* throw away the return address to the instructions thunk: */
                    720:     tme_recode_x86_insns_start(ic, thunk_bytes);
                    721:     thunk_bytes = _tme_recode_x86_emit_adjust_sp(thunk_bytes,
                    722:                                                 TME_BIT(TME_RECODE_SIZE_HOST - TME_RECODE_SIZE_8));
                    723:     tme_recode_x86_insns_finish(ic, thunk_bytes);
                    724:   }
                    725: 
                    726:   /* the next chain subs is for a chain call far unconditional or a
                    727:      chain return far unconditional: */
                    728:   TME_RECODE_X86_CHAIN_SUBS(chain_thunk,
                    729:                            (chain_info_call_or_return
                    730:                             + TME_RECODE_CHAIN_INFO_FAR
                    731:                             + TME_RECODE_CHAIN_INFO_UNCONDITIONAL))
                    732:     = tme_recode_build_to_thunk_off(ic, ic->tme_recode_ic_thunk_build_next);
                    733: 
                    734:   /* if this is the chain subs for a chain call far unconditional: */
                    735:   if (chain_info_call_or_return == TME_RECODE_CHAIN_INFO_CALL) {
                    736: 
                    737:     /* push the chain return address stack: */
                    738:     _tme_recode_x86_chain_ras_push(ic);
                    739: 
                    740:     /* the next chain subs is for both a chain jump far conditional
                    741:        and a chain jump far unconditional: */
                    742:     TME_RECODE_X86_CHAIN_SUBS(chain_thunk,
                    743:                              (TME_RECODE_CHAIN_INFO_JUMP
                    744:                               + TME_RECODE_CHAIN_INFO_FAR
                    745:                               + TME_RECODE_CHAIN_INFO_CONDITIONAL))
                    746:       = tme_recode_build_to_thunk_off(ic, ic->tme_recode_ic_thunk_build_next);
                    747:     TME_RECODE_X86_CHAIN_SUBS(chain_thunk,
                    748:                              (TME_RECODE_CHAIN_INFO_JUMP
                    749:                               + TME_RECODE_CHAIN_INFO_FAR
                    750:                               + TME_RECODE_CHAIN_INFO_UNCONDITIONAL))
                    751:       = tme_recode_build_to_thunk_off(ic, ic->tme_recode_ic_thunk_build_next);
                    752: 
                    753:     /* fix up the jmp to the chain subs for a chain jump far
                    754:        unconditional: */
                    755:     _tme_recode_x86_fixup_jmp(thunk_bytes_jmp_to_jump_far_unconditional,
                    756:                              ic->tme_recode_ic_thunk_build_next);
                    757:   }
                    758: 
                    759:   /* load the pointer to the token for the current instruction TLB
                    760:      entry: */
                    761:   _tme_recode_x86_chain_itlb_current_token_load(ic);
                    762: 
                    763:   /* get the TLB type for the address type: */
                    764:   tme_recode_address_type_tlb_type(ic,
                    765:                                   &chain->tme_recode_chain_address_type,
                    766:                                   &x86_tlb_type.tme_recode_tlb_type);
                    767: 
                    768:   /* unbusy the token for the current instruction TLB entry: */
                    769: #if TME_RECODE_X86_REG_CHAIN_ITLB_CURRENT_TOKEN        != TME_RECODE_X86_REG_TLB
                    770: #error "TME_RECODE_X86_REG_CHAIN_ITLB_CURRENT_TOKEN changed"
                    771: #endif
                    772:   _tme_recode_x86_tlb_unbusy(ic, 0);
                    773: 
                    774:   /* load the PC to chain to: */
                    775:   reginfo = ic->tme_recode_ic_reginfo[chain->tme_recode_chain_reg_guest];
                    776:   reginfo.tme_recode_reginfo_tags_ruses
                    777:     = (TME_RECODE_REGINFO_TAGS_REG_HOST(_tme_recode_x86_tlb_reg_host_address(ic))
                    778:        + TME_RECODE_REGINFO_TAGS_VALID_SIZE(ic->tme_recode_ic_reg_size)
                    779:        + TME_RECODE_REGINFO_TAGS_CLEAN);
                    780:   ic->tme_recode_x86_ic_thunks_reg_guest_window_c = TME_RECODE_REG_GUEST_WINDOW_UNDEF;
                    781:   tme_recode_host_reg_move(ic,
                    782:                           chain->tme_recode_chain_reg_guest,
                    783:                           reginfo.tme_recode_reginfo_all);
                    784:   ic->tme_recode_x86_ic_thunks_reg_guest_window_c = TME_RECODE_REG_GUEST_WINDOW_UNDEF;
                    785: 
                    786:   /* find, busy, and check an instruction TLB entry: */
                    787:   _tme_recode_x86_tlb_busy(ic,
                    788:                           &chain->tme_recode_chain_address_type,
                    789:                           &x86_tlb_type);
                    790: 
                    791:   /* store the pointer to the current recode instruction TLB entry: */
                    792:   _tme_recode_x86_chain_itlb_current_store(ic, &x86_tlb_type);
                    793: 
                    794:   /* if this is the chain subs for a chain jump far conditional and
                    795:      a chain jump far unconditional: */
                    796:   if (chain_info_call_or_return == TME_RECODE_CHAIN_INFO_CALL) {
                    797: 
                    798:     /* the next chain subs is for both a chain jump near conditional
                    799:        and a chain jump near unconditional: */
                    800:     TME_RECODE_X86_CHAIN_SUBS(chain_thunk,
                    801:                              (TME_RECODE_CHAIN_INFO_JUMP
                    802:                               + TME_RECODE_CHAIN_INFO_NEAR
                    803:                               + TME_RECODE_CHAIN_INFO_CONDITIONAL))
                    804:       = tme_recode_build_to_thunk_off(ic, ic->tme_recode_ic_thunk_build_next);
                    805:     TME_RECODE_X86_CHAIN_SUBS(chain_thunk,
                    806:                              (TME_RECODE_CHAIN_INFO_JUMP
                    807:                               + TME_RECODE_CHAIN_INFO_NEAR
                    808:                               + TME_RECODE_CHAIN_INFO_UNCONDITIONAL))
                    809:       = tme_recode_build_to_thunk_off(ic, ic->tme_recode_ic_thunk_build_next);
                    810:   }
                    811: 
                    812:   /* start more instructions: */
                    813:   tme_recode_x86_insns_start(ic, thunk_bytes);
                    814: 
                    815:   /* subtract one from the guest chain counter: */
                    816:   thunk_bytes[0] = TME_RECODE_X86_OPCODE_GRP1_Ib_Ev;
                    817:   thunk_bytes[1] = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_EA_DISP32(TME_RECODE_X86_REG_IC),
                    818:                                               TME_RECODE_X86_OPCODE_GRP1_BINOP(TME_RECODE_X86_OPCODE_BINOP_SUB));
                    819:   *((tme_int32_t *) &thunk_bytes[2]) = ic->tme_recode_ic_chain_counter_offset;
                    820:   thunk_bytes[2 + sizeof(tme_int32_t)] = 1;
                    821:   thunk_bytes += 2 + sizeof(tme_int32_t) + 1;
                    822: 
                    823:   /* if this is the chain subs for a chain jump near conditional and a
                    824:      chain jump near unconditional: */
                    825:   if (chain_info_call_or_return == TME_RECODE_CHAIN_INFO_CALL) {
                    826: 
                    827:     /* load the return address to the instructions thunk into the
                    828:        fixup address register: */
                    829:     /* NB: this is always a 32-bit instruction, even on an x86-64
                    830:        host, because we end up converting the return address into an
                    831:        instructions thunk offset, which is only 32 bits: */
                    832:     assert (sizeof(tme_recode_thunk_off_t) == sizeof(tme_int32_t));
                    833:     rex = TME_RECODE_X86_REX_B(TME_RECODE_SIZE_32, TME_RECODE_X86_REG_CHAIN_FIXUP_ADDRESS);
                    834:     if (rex != 0) {
                    835:       *(thunk_bytes++) = rex;
                    836:     }
                    837:     thunk_bytes[0] = TME_RECODE_X86_OPCODE_BINOP_MOV + TME_RECODE_X86_OPCODE_BINOP_Ev_Gv;
                    838:     thunk_bytes[1] = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_EA(TME_RECODE_X86_EA_BASE_SIB),
                    839:                                                 TME_RECODE_X86_REG_CHAIN_FIXUP_ADDRESS);
                    840:     thunk_bytes[2] = TME_RECODE_X86_SIB(TME_RECODE_X86_REG_SP, TME_RECODE_X86_SIB_INDEX_NONE, 1);
                    841:     thunk_bytes += 3;
                    842:   }
                    843: 
                    844:   /* otherwise, this is the chain subs for a return far unconditional: */
                    845:   else {
                    846: 
                    847:     /* load the chain return address stack pointer: */
                    848:     thunk_bytes[0] = (TME_RECODE_X86_OPCODE_BINOP_MOV + TME_RECODE_X86_OPCODE_BINOP_Ev_Gv);
                    849:     thunk_bytes = _tme_recode_x86_emit_ic_modrm(thunk_bytes + 1,
                    850:                                                ic->tme_recode_ic_chain_ras_pointer_offset,
                    851:                                                TME_RECODE_X86_REG_CHAIN_RAS_POINTER);
                    852:   }
                    853: 
                    854:   /* if needed, copy the guest instructions source address into the
                    855:      correct register: */
                    856:   reg_x86_address
                    857:     = tme_recode_x86_reg_from_host[_tme_recode_x86_tlb_reg_host_address(ic)];
                    858:   if (reg_x86_address != TME_RECODE_X86_REG_CHAIN_GUEST_SRC) {
                    859:     _tme_recode_x86_emit_reg_copy(thunk_bytes, reg_x86_address, TME_RECODE_X86_REG_CHAIN_GUEST_SRC);
                    860:   }
                    861: 
                    862:   /* if the guest chain counter was zero or one, jmp to the code that
                    863:      handles a guest chain counter underflow: */
                    864:   thunk_bytes_jcc_chain_counter = thunk_bytes;
                    865:   thunk_bytes
                    866:     = _tme_recode_x86_emit_jmp(thunk_bytes,
                    867:                               TME_RECODE_X86_OPCODE_JCC(TME_RECODE_X86_COND_BE),
                    868:                               (tme_uint8_t *) NULL);
                    869: 
                    870:   /* finish these instructions: */
                    871:   tme_recode_x86_insns_finish(ic, thunk_bytes);
                    872: 
                    873:   /* if this is the chain subs for a chain jump near conditional and a
                    874:      chain jump near unconditional: */
                    875:   if (chain_info_call_or_return == TME_RECODE_CHAIN_INFO_CALL) {
                    876: 
                    877:     /* define CF with the recode jump flag.  NB that the recode flags
                    878:        are now above the return address to the instructions thunk: */
                    879:     _tme_recode_x86_conds_testc(ic, TME_BIT(TME_RECODE_SIZE_HOST - TME_RECODE_SIZE_8) + TME_RECODE_FLAG_JUMP);
                    880: 
                    881:     /* emit a return back to the instructions thunk: */
                    882:     tme_recode_x86_insns_start(ic, thunk_bytes);
                    883:     thunk_bytes[0] = TME_RECODE_X86_OPCODE_RET;
                    884:     thunk_bytes++;
                    885:     tme_recode_x86_insns_finish(ic, thunk_bytes);
                    886: 
                    887:     /* the next chain subs is for a chain call near conditional: */
                    888:     TME_RECODE_X86_CHAIN_SUBS(chain_thunk,
                    889:                              (TME_RECODE_CHAIN_INFO_CALL
                    890:                               + TME_RECODE_CHAIN_INFO_NEAR
                    891:                               + TME_RECODE_CHAIN_INFO_CONDITIONAL))
                    892:       = tme_recode_build_to_thunk_off(ic, ic->tme_recode_ic_thunk_build_next);
                    893: 
                    894:     /* if the recode jump flag is false, jmp to the chain subs for a
                    895:        chain jump near conditional: */
                    896:     _tme_recode_x86_chain_subs_jmp(ic,
                    897:                                   TME_RECODE_X86_OPCODE_JCC(TME_RECODE_X86_COND_NOT
                    898:                                                             | TME_RECODE_X86_COND_C),
                    899:                                   chain_thunk,
                    900:                                   (TME_RECODE_CHAIN_INFO_JUMP
                    901:                                    + TME_RECODE_CHAIN_INFO_NEAR
                    902:                                    + TME_RECODE_CHAIN_INFO_CONDITIONAL));
                    903: 
                    904:     /* the next chain subs is for a chain call near unconditional: */
                    905:     TME_RECODE_X86_CHAIN_SUBS(chain_thunk,
                    906:                              (TME_RECODE_CHAIN_INFO_CALL
                    907:                               + TME_RECODE_CHAIN_INFO_NEAR
                    908:                               + TME_RECODE_CHAIN_INFO_UNCONDITIONAL))
                    909:       = tme_recode_build_to_thunk_off(ic, ic->tme_recode_ic_thunk_build_next);
                    910: 
                    911:     /* push the chain return address stack: */
                    912:     _tme_recode_x86_chain_ras_push(ic);
                    913: 
                    914:     /* jmp to the chain subs for a chain jump near unconditional: */
                    915:     _tme_recode_x86_chain_subs_jmp(ic,
                    916:                                   TME_RECODE_X86_OPCODE_JMP_RELb,
                    917:                                   chain_thunk,
                    918:                                   (TME_RECODE_CHAIN_INFO_JUMP
                    919:                                    + TME_RECODE_CHAIN_INFO_NEAR
                    920:                                    + TME_RECODE_CHAIN_INFO_UNCONDITIONAL));
                    921:   }
                    922: 
                    923:   /* otherwise, this is the chain subs for a chain return far
                    924:      unconditional: */
                    925:   else {
                    926: 
                    927:     /* load the return address: */
                    928:     _tme_recode_x86_chain_ras_ls(ic, FALSE);
                    929: 
                    930:     /* add one to the return address stack pointer, and store it: */
                    931:     _tme_recode_x86_chain_ras_pointer_update(ic, 1);
                    932: 
                    933:     /* start more instructions: */
                    934:     tme_recode_x86_insns_start(ic, thunk_bytes);
                    935: 
                    936:     /* if this is an x86-64 host: */
                    937:     if (TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32) {
                    938: 
                    939:       /* emit an %ip-relative lea instruction, to load the address of
                    940:         thunk offset zero into the TLB scratch register: */
                    941:       thunk_bytes[0] = TME_RECODE_X86_REX_R(TME_RECODE_SIZE_HOST, TME_RECODE_X86_REG_TLB_SCRATCH);
                    942:       thunk_bytes[1] = TME_RECODE_X86_OPCODE_LEA;
                    943:       thunk_bytes[2] = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_EA(TME_RECODE_X86_EA_BASE_IP),
                    944:                                                   TME_RECODE_X86_REG(TME_RECODE_X86_REG_TLB_SCRATCH));
                    945:       thunk_bytes += 3 + sizeof(tme_int32_t);
                    946:       ((tme_int32_t *) thunk_bytes)[-1]
                    947:        = (0 - (tme_int32_t) tme_recode_build_to_thunk_off(ic, thunk_bytes));
                    948: 
                    949:       /* add the address of thunk offset zero into the return address register: */
                    950:       _tme_recode_x86_emit_reg_binop(thunk_bytes,
                    951:                                     TME_RECODE_X86_OPCODE_BINOP_ADD,
                    952:                                     TME_RECODE_X86_REG_TLB_SCRATCH,
                    953:                                     TME_RECODE_X86_REG_CHAIN_RETURN_ADDRESS);
                    954:     }
                    955: 
                    956:     /* emit the indirect jmp instruction with the return address
                    957:        register: */
                    958:     thunk_bytes[0] = TME_RECODE_X86_OPCODE_GRP5;
                    959:     thunk_bytes[1]
                    960:       = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_REG(TME_RECODE_X86_REG_CHAIN_RETURN_ADDRESS),
                    961:                                    TME_RECODE_X86_OPCODE_GRP5_JMP);
                    962:     thunk_bytes += 2;
                    963: 
                    964:     /* unknown indirect jmps are predicted to fallthrough; placing a UD2
                    965:        instruction after an indirect jmp can stop a processor from
                    966:        speculatively executing garbage fallthrough instructions: */
                    967:     thunk_bytes[0] = TME_RECODE_X86_OPCODE_ESC_0F;
                    968:     thunk_bytes[1] = TME_RECODE_X86_OPCODE0F_UD2;
                    969:     thunk_bytes += 2;
                    970: 
                    971:     /* finish these instructions: */
                    972:     tme_recode_x86_insns_finish(ic, thunk_bytes);
                    973:   }
                    974: 
                    975:   /* this is the code that handles an instruction TLB miss: */
                    976: 
                    977:   /* fix up the assist jcc(s) in the instruction TLB busy: */
                    978:   if (x86_tlb_type.tme_recode_x86_tlb_type_assist_jmp_address_ok != NULL) {
                    979:     _tme_recode_x86_fixup_jmp(x86_tlb_type.tme_recode_x86_tlb_type_assist_jmp_address_ok,
                    980:                              ic->tme_recode_ic_thunk_build_next);
                    981:   }
                    982:   _tme_recode_x86_fixup_jmp(x86_tlb_type.tme_recode_x86_tlb_type_assist_jmp,
                    983:                            ic->tme_recode_ic_thunk_build_next);
                    984: 
                    985:   /* store the pointer to the current recode instruction TLB entry: */
                    986:   /* NB: this is necessary because the instruction TLB that missed is
                    987:      still busy: */
                    988:   _tme_recode_x86_chain_itlb_current_store(ic, &x86_tlb_type);
                    989: 
                    990:   /* start more instructions: */
                    991:   tme_recode_x86_insns_start(ic, thunk_bytes);
                    992: 
                    993:   /* this is the code that jmps to the chain epilogue: */
                    994:   thunk_bytes_jmp_to_epilogue = thunk_bytes;
                    995: 
                    996:   /* if this is not for the chain return far subs: */
                    997:   if (chain_info_call_or_return != TME_RECODE_CHAIN_INFO_RETURN) {
                    998: 
                    999:     /* throw away the return address to the instructions thunk: */
                   1000:     thunk_bytes = _tme_recode_x86_emit_adjust_sp(thunk_bytes,
                   1001:                                                 TME_BIT(TME_RECODE_SIZE_HOST - TME_RECODE_SIZE_8));
                   1002:   }
                   1003: 
                   1004:   /* jmp to the chain epilogue: */
                   1005:   thunk_bytes
                   1006:     = _tme_recode_x86_emit_jmp(thunk_bytes,
                   1007:                               TME_RECODE_X86_OPCODE_JMP_RELz,
                   1008:                               tme_recode_thunk_off_to_pointer(ic, 
                   1009:                                                               ic->tme_recode_x86_ic_chain_epilogue,
                   1010:                                                               tme_uint8_t *));
                   1011: 
                   1012:   /* this is the code that handles a guest chain counter underflow: */
                   1013:   _tme_recode_x86_fixup_jmp(thunk_bytes_jcc_chain_counter, thunk_bytes);
                   1014: 
                   1015:   /* clear the guest chain counter, since we may have wrapped it past
                   1016:      zero: */
                   1017:   thunk_bytes[0] = TME_RECODE_X86_OPCODE_MOV_Iz_Ev;
                   1018:   thunk_bytes[1] = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_EA_DISP32(TME_RECODE_X86_REG_IC),
                   1019:                                               0 /* undefined */);
                   1020:   *((tme_int32_t *) &thunk_bytes[2]) = ic->tme_recode_ic_chain_counter_offset;
                   1021:   *((tme_uint32_t *) &thunk_bytes[6]) = 0;
                   1022:   thunk_bytes += 2 + sizeof(tme_int32_t) + sizeof(tme_uint32_t);
                   1023: 
                   1024:   /* jmp to the code that jmps to the chain epilogue: */
                   1025:   thunk_bytes
                   1026:     = _tme_recode_x86_emit_jmp(thunk_bytes,
                   1027:                               TME_RECODE_X86_OPCODE_JMP_RELb,
                   1028:                               thunk_bytes_jmp_to_epilogue);
                   1029: 
                   1030:   /* finish these instructions: */
                   1031:   tme_recode_x86_insns_finish(ic, thunk_bytes);
                   1032: }
                   1033: 
                   1034: /* this emits instructions for a chain out: */
                   1035: static void
                   1036: _tme_recode_x86_chain_out(struct tme_recode_ic *ic,
                   1037:                          const struct tme_recode_insns_group *insns_group)
                   1038: {
                   1039:   tme_uint8_t *thunk_bytes;
                   1040:   tme_uint8_t *thunk_bytes_start;
                   1041:   tme_uint32_t chain_info;
                   1042: 
                   1043:   /* the chain subs, and a chain call instruction itself, destroy the
                   1044:      c register, so it won't hold the base offset of a guest register
                   1045:      window any more: */
                   1046:   ic->tme_recode_x86_ic_thunks_reg_guest_window_c = TME_RECODE_REG_GUEST_WINDOW_UNDEF;
                   1047: 
                   1048:   /* start more instructions: */
                   1049:   tme_recode_x86_insns_start(ic, thunk_bytes);
                   1050: 
                   1051:   /* remember where these instructions started: */
                   1052:   thunk_bytes_start = thunk_bytes;
                   1053: 
                   1054:   /* get the chain information: */
                   1055:   chain_info = insns_group->tme_recode_insns_group_chain_info;
                   1056: 
                   1057:   /* exactly one of jump, call, and return may be set: */
                   1058:   assert ((chain_info
                   1059:           & (TME_RECODE_CHAIN_INFO_JUMP
                   1060:              | TME_RECODE_CHAIN_INFO_CALL
                   1061:              | TME_RECODE_CHAIN_INFO_RETURN)) != 0
                   1062:          && ((chain_info
                   1063:               & (TME_RECODE_CHAIN_INFO_JUMP
                   1064:                  | TME_RECODE_CHAIN_INFO_CALL
                   1065:                  | TME_RECODE_CHAIN_INFO_RETURN))
                   1066:              & ((chain_info
                   1067:                  & (TME_RECODE_CHAIN_INFO_JUMP
                   1068:                     | TME_RECODE_CHAIN_INFO_CALL
                   1069:                     | TME_RECODE_CHAIN_INFO_RETURN))
                   1070:                 - 1)) == 0);
                   1071: 
                   1072:   /* there is no such thing as a chain return near: */
                   1073:   assert ((chain_info & TME_RECODE_CHAIN_INFO_RETURN) == 0
                   1074:          || (chain_info
                   1075:              & (TME_RECODE_CHAIN_INFO_NEAR
                   1076:                 | TME_RECODE_CHAIN_INFO_FAR)) != TME_RECODE_CHAIN_INFO_NEAR);
                   1077: 
                   1078:   /* if this is a chain conditional, and the alternate target is far,
                   1079:      force the main target to be far, since the alternate target needs
                   1080:      the information generated by a chain far subs: */
                   1081:   assert (((chain_info
                   1082:            & (TME_RECODE_CHAIN_INFO_ALTERNATE_NEAR
                   1083:               | TME_RECODE_CHAIN_INFO_ALTERNATE_FAR))
                   1084:           == TME_RECODE_CHAIN_INFO_ALTERNATE_NEAR)
                   1085:          || ((chain_info
                   1086:               & (TME_RECODE_CHAIN_INFO_UNCONDITIONAL
                   1087:                  | TME_RECODE_CHAIN_INFO_CONDITIONAL))
                   1088:              != TME_RECODE_CHAIN_INFO_UNCONDITIONAL));
                   1089: #if TME_RECODE_CHAIN_INFO_FAR == 0 || TME_RECODE_CHAIN_INFO_ALTERNATE_FAR <= TME_RECODE_CHAIN_INFO_FAR
                   1090: #error "TME_RECODE_CHAIN_INFO_ values changed"
                   1091: #endif
                   1092:   chain_info
                   1093:     |= ((chain_info
                   1094:         / (TME_RECODE_CHAIN_INFO_ALTERNATE_FAR
                   1095:            / TME_RECODE_CHAIN_INFO_FAR))
                   1096:        & TME_RECODE_CHAIN_INFO_FAR);
                   1097: 
                   1098:   /* if this is a chain call: */
                   1099:   if (chain_info & TME_RECODE_CHAIN_INFO_CALL) {
                   1100: 
                   1101:     /* load the return address register with a value that indicates
                   1102:        the chain epilogue.  this will later get fixed up to indicate
                   1103:        the instructions thunk to return to: */
                   1104:     thunk_bytes[0] = TME_RECODE_X86_OPCODE_MOV_Iv_Gv(TME_RECODE_X86_REG_CHAIN_RETURN_ADDRESS);
                   1105:     *((tme_uint32_t *) (thunk_bytes + 1))
                   1106:       = TME_RECODE_X86_CHAIN_RETURN_ADDRESS(ic, ic->tme_recode_x86_ic_chain_epilogue);
                   1107:     thunk_bytes += 1 + sizeof(tme_uint32_t);
                   1108:   }
                   1109: 
                   1110:   /* if this is a chain return unconditional, jump to the chain subs,
                   1111:      otherwise call the chain subs: */
                   1112:   thunk_bytes[0]
                   1113:     = (((chain_info
                   1114:         & (TME_RECODE_CHAIN_INFO_RETURN
                   1115:            + (TME_RECODE_CHAIN_INFO_UNCONDITIONAL
                   1116:               | TME_RECODE_CHAIN_INFO_CONDITIONAL)))
                   1117:        == (TME_RECODE_CHAIN_INFO_RETURN
                   1118:            + TME_RECODE_CHAIN_INFO_UNCONDITIONAL))
                   1119:        ? TME_RECODE_X86_OPCODE_JMP_RELz
                   1120:        : TME_RECODE_X86_OPCODE_CALL_RELz);
                   1121:   thunk_bytes += 1 + sizeof(tme_int32_t);
                   1122:   ((tme_int32_t *) thunk_bytes)[-1]
                   1123:     = (TME_RECODE_X86_CHAIN_SUBS(insns_group->tme_recode_insns_group_chain_thunk,
                   1124:                                 chain_info)
                   1125:        - tme_recode_build_to_thunk_off(ic, thunk_bytes));
                   1126: 
                   1127:   /* for the regular target, emit the unconditional jmp instruction,
                   1128:      or the conditional jc instruction, to the chain fixup target: */
                   1129:   if ((chain_info
                   1130:        & (TME_RECODE_CHAIN_INFO_UNCONDITIONAL
                   1131:          | TME_RECODE_CHAIN_INFO_CONDITIONAL))
                   1132:       == TME_RECODE_CHAIN_INFO_UNCONDITIONAL) {
                   1133:     thunk_bytes[0] = TME_RECODE_X86_OPCODE_JMP_RELz;
                   1134:   }
                   1135:   else {
                   1136:     *((tme_uint16_t *) thunk_bytes)
                   1137:       = (TME_RECODE_X86_OPCODE_ESC_0F
                   1138:         + (TME_RECODE_X86_OPCODE0F_JCC(TME_RECODE_X86_COND_C)
                   1139:            << 8));
                   1140:     thunk_bytes++;
                   1141:   }
                   1142:   thunk_bytes += 1 + sizeof(tme_int32_t);
                   1143:   ((tme_int32_t *) thunk_bytes)[-1]
                   1144:     = (TME_RECODE_X86_CHAIN_FIXUP_TARGET(ic, chain_info)
                   1145:        - tme_recode_build_to_thunk_off(ic, thunk_bytes));
                   1146: 
                   1147:   /* if this is a chain conditional instruction: */
                   1148:   if ((chain_info
                   1149:        & (TME_RECODE_CHAIN_INFO_UNCONDITIONAL
                   1150:          | TME_RECODE_CHAIN_INFO_CONDITIONAL))
                   1151:       != TME_RECODE_CHAIN_INFO_UNCONDITIONAL) {
                   1152: 
                   1153:     /* for the alternate target, emit the unconditional jmp
                   1154:        instruction to the chain fixup target alternate: */
                   1155:     thunk_bytes[0] = TME_RECODE_X86_OPCODE_JMP_RELz;
                   1156:     thunk_bytes += 1 + sizeof(tme_int32_t);
                   1157:     ((tme_int32_t *) thunk_bytes)[-1]
                   1158:       = (TME_RECODE_X86_CHAIN_FIXUP_TARGET_ALTERNATE(ic, chain_info)
                   1159:         - tme_recode_build_to_thunk_off(ic, thunk_bytes));
                   1160:   }
                   1161: 
                   1162:   /* check the size of the chain out: */
                   1163:   assert ((thunk_bytes - thunk_bytes_start)
                   1164:          <= TME_RECODE_X86_CHAIN_OUT_SIZE_MAX);
                   1165: 
                   1166:   /* finish these instructions: */
                   1167:   tme_recode_x86_insns_finish(ic, thunk_bytes);
                   1168: }
                   1169: 
                   1170: /* if the given address is reachable with an effective address using
                   1171:    an address in another register, this returns the signed 32-bit
                   1172:    displacement, otherwise this returns zero: */
                   1173: static inline tme_int32_t
                   1174: _tme_recode_x86_chain_base_disp32(const tme_shared tme_uint8_t *base,
                   1175:                                  const tme_shared tme_uint8_t *pointer)
                   1176: {
                   1177:   signed long disp;
                   1178: 
                   1179:   disp = pointer - base;
                   1180:   return (disp == (tme_int32_t) disp
                   1181:          ? disp
                   1182:          : 0);
                   1183: }
                   1184: 
                   1185: /* if the given address is reachable with a PC-relative effective
                   1186:    address, this returns the signed 32-bit displacement, otherwise
                   1187:    this returns zero: */
                   1188: static inline tme_int32_t
                   1189: _tme_recode_x86_chain_ip_disp32(const struct tme_recode_ic *ic,
                   1190:                                const tme_uint8_t *thunk_bytes,
                   1191:                                const tme_shared tme_uint8_t *pointer)
                   1192: {
                   1193:   tme_recode_thunk_off_t thunk_off;
                   1194:   const tme_uint8_t *ip;
                   1195: 
                   1196:   thunk_off = tme_recode_build_to_thunk_off(ic, thunk_bytes);
                   1197:   ip = tme_recode_thunk_off_to_pointer(ic, thunk_off, const tme_uint8_t *);
                   1198:   return (_tme_recode_x86_chain_base_disp32(ip, pointer));
                   1199: }
                   1200: 
                   1201: /* this emits instructions for a chain in: */
                   1202: static void
                   1203: _tme_recode_x86_chain_in(struct tme_recode_ic *ic,
                   1204:                         const struct tme_recode_insns_group *insns_group)
                   1205: {
                   1206:   tme_uint8_t *thunk_bytes;
                   1207:   tme_uint8_t *thunk_bytes_start;
                   1208:   const tme_shared tme_uint8_t *insns_group_src;
                   1209:   unsigned int size_insns_group_src;
                   1210:   tme_int32_t disp32;
                   1211:   unsigned int rex;
                   1212:   const tme_shared tme_uint8_t *insns_group_valid_byte;
                   1213:   unsigned int size_insns_group_valid_byte;
                   1214: 
                   1215:   /* start more instructions: */
                   1216:   tme_recode_x86_insns_start(ic, thunk_bytes);
                   1217: 
                   1218:   /* remember where these instructions started: */
                   1219:   thunk_bytes_start = thunk_bytes;
                   1220: 
                   1221:   /* get the guest instructions source address: */
                   1222:   insns_group_src = insns_group->tme_recode_insns_group_src;
                   1223: 
                   1224:   /* if this is an ia32 host, or if this is an x86-64 host and the
                   1225:      guest instructions source address fits in a sign-extended 32
                   1226:      bits: */
                   1227:   if (TME_RECODE_SIZE_HOST == TME_RECODE_SIZE_32
                   1228:       || (((tme_int32_t)
                   1229:           (signed long)
                   1230:           insns_group_src)
                   1231:          == (signed long) insns_group_src)) {
                   1232: 
                   1233:     /* emit a cmpl $imm32, %reg or cmpq $imm32, %reg: */
                   1234:     if (TME_RECODE_SIZE_HOST == TME_RECODE_SIZE_32) {
                   1235:       thunk_bytes[0] = (tme_uint8_t) TME_RECODE_X86_INSN_CMP_Iz_REG_CHAIN_GUEST_SRC;
                   1236:     }
                   1237:     else {
                   1238:       *((tme_uint16_t *) thunk_bytes) = TME_RECODE_X86_INSN_CMP_Iz_REG_CHAIN_GUEST_SRC;
                   1239:     }
                   1240:     *((tme_int32_t *) &thunk_bytes[(TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32) + 1])
                   1241:       = (signed long) insns_group_src;
                   1242:     thunk_bytes += (TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32) + 1 + sizeof(tme_int32_t);
                   1243: 
                   1244:     /* assume that this is an x86-64 host, and set the size of the
                   1245:        instructions that check the guest instruction source address
                   1246:        matches the instructions thunk: */
                   1247:     size_insns_group_src = TME_RECODE_X86_64_CHAIN_IN_SIZE_CMPQ_IMM32_JNZ;
                   1248:   }
                   1249: 
                   1250:   /* otherwise, this is an x86-64 host and the guest instructions
                   1251:      source address doesn't fit in a sign-extended 32 bits: */
                   1252:   else {
                   1253: 
                   1254:     /* if the guest instructions source address fits in 32 bits: */
                   1255:     if (TME_RECODE_SIZE_FITS((unsigned long) insns_group_src,
                   1256:                             TME_RECODE_SIZE_32)) {
                   1257: 
                   1258:       /* emit a movl $imm32, %reg: */
                   1259:       thunk_bytes[0] = TME_RECODE_X86_INSN_MOVL_IMM32_REG_TLB_SCRATCH;
                   1260:       *((tme_uint32_t *) &thunk_bytes[1]) = (unsigned long) insns_group_src;
                   1261:       thunk_bytes += 1 + sizeof(tme_uint32_t);
                   1262: 
                   1263:       /* set the size of the instructions that check the guest
                   1264:         instruction source address matches the instructions thunk: */
                   1265:       size_insns_group_src = TME_RECODE_X86_64_CHAIN_IN_SIZE_MOVL_CMP_JNZ;
                   1266:     }
                   1267: 
                   1268:     /* otherwise, if the guest instructions source address is within a
                   1269:        signed 32-bit displacement of the %ip of an lea
                   1270:        instruction: */
                   1271:     else if ((disp32
                   1272:              = _tme_recode_x86_chain_ip_disp32(ic,
                   1273:                                                (thunk_bytes
                   1274:                                                 + 1 /* rex */
                   1275:                                                 + 1 /* lea */
                   1276:                                                 + 1 /* modR/M */
                   1277:                                                 + sizeof(disp32)),
                   1278:                                                insns_group_src))) {
                   1279: 
                   1280:       /* emit an lea disp32(%ip), %reg: */
                   1281:       thunk_bytes[0] = (tme_uint8_t) TME_RECODE_X86_INSN_LEA_DISP32_IP_REG_TLB_SCRATCH;
                   1282:       *((tme_uint16_t *) &thunk_bytes[1]) = (TME_RECODE_X86_INSN_LEA_DISP32_IP_REG_TLB_SCRATCH >> 8);
                   1283:       *((tme_int32_t *) &thunk_bytes[3]) = disp32;
                   1284:       thunk_bytes += 1 + 2 + sizeof(disp32);
                   1285: 
                   1286:       /* set the size of the instructions that check the guest
                   1287:         instruction source address matches the instructions thunk: */
                   1288:       size_insns_group_src = TME_RECODE_X86_64_CHAIN_IN_SIZE_LEA_IP_CMP_JNZ;
                   1289:     }
                   1290: 
                   1291:     /* otherwise, the guest instructions source address can't be
                   1292:        generated: */
                   1293:     else {
                   1294: 
                   1295:       /* emit a movq $imm64, %reg: */
                   1296:       *((tme_uint16_t *) thunk_bytes) = TME_RECODE_X86_INSN_MOVQ_IMM64_REG_TLB_SCRATCH;
                   1297:       *((unsigned long *) &thunk_bytes[2]) = (unsigned long) insns_group_src;
                   1298:       thunk_bytes += 1 + 1 + TME_BIT(TME_RECODE_SIZE_HOST - TME_RECODE_SIZE_8);
                   1299: 
                   1300:       /* set the size of the instructions that check the guest
                   1301:         instruction source address matches the instructions thunk: */
                   1302:       size_insns_group_src = TME_RECODE_X86_64_CHAIN_IN_SIZE_MOVQ_CMP_JNZ;
                   1303:     }
                   1304: 
                   1305:     /* emit a cmpq %reg, %reg: */
                   1306:     rex = (TME_RECODE_X86_REX_B(TME_RECODE_SIZE_HOST,
                   1307:                                TME_RECODE_X86_REG_CHAIN_GUEST_SRC)
                   1308:           | TME_RECODE_X86_REX_R(TME_RECODE_SIZE_HOST,
                   1309:                                  TME_RECODE_X86_REG_TLB_SCRATCH));
                   1310:     assert (rex != 0);
                   1311:     thunk_bytes[0] = rex;
                   1312:     *((tme_uint16_t *) &thunk_bytes[1])
                   1313:       = ((TME_RECODE_X86_OPCODE_BINOP_CMP
                   1314:          + TME_RECODE_X86_OPCODE_BINOP_Ev_Gv)
                   1315:         + (TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_REG(TME_RECODE_X86_REG_CHAIN_GUEST_SRC),
                   1316:                                        TME_RECODE_X86_REG(TME_RECODE_X86_REG_TLB_SCRATCH))
                   1317:            << 8));
                   1318:     thunk_bytes += 3;
                   1319:   }
                   1320: 
                   1321:   /* if the guest instructions source address doesn't match this
                   1322:      instructions thunk, jump to the chain epilogue: */
                   1323:   *((tme_uint16_t *) thunk_bytes)
                   1324:     = (TME_RECODE_X86_OPCODE_ESC_0F
                   1325:        + (TME_RECODE_X86_OPCODE0F_JCC(TME_RECODE_X86_COND_NOT | TME_RECODE_X86_COND_Z)
                   1326:          << 8));
                   1327:   thunk_bytes += 2 + sizeof(tme_int32_t);
                   1328:   ((tme_int32_t *) thunk_bytes)[-1]
                   1329:     = (ic->tme_recode_x86_ic_chain_epilogue
                   1330:        - tme_recode_build_to_thunk_off(ic, thunk_bytes));
                   1331: 
                   1332:   /* get the guest instructions valid byte address: */
                   1333:   insns_group_valid_byte = insns_group->tme_recode_insns_group_valid_byte;
                   1334: 
                   1335:   /* if this is an ia32 host: */
                   1336:   if (TME_RECODE_SIZE_HOST == TME_RECODE_SIZE_32) {
                   1337: 
                   1338:     /* emit the opcode and addr32 for a testb $imm8, addr32: */
                   1339:     *((tme_uint16_t *) thunk_bytes)
                   1340:       = (TME_RECODE_X86_OPCODE_GRP3_Eb
                   1341:         + (TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_EA(TME_RECODE_X86_EA_BASE_NONE),
                   1342:                                        TME_RECODE_X86_OPCODE_GRP3_TEST)
                   1343:            << 8));
                   1344:     *((tme_uint32_t *) &thunk_bytes[2]) = (unsigned long) insns_group_valid_byte;
                   1345:     thunk_bytes += 2 + sizeof(tme_uint32_t);
                   1346: 
                   1347:     /* silence uninitialized variable warnings: */
                   1348:     size_insns_group_valid_byte = 0;
                   1349:   }
                   1350: 
                   1351:   /* otherwise, this is an x86-64 host: */
                   1352:   else {
                   1353: 
                   1354:     /* assume that we can emit a testb followed by a jz, and emit the
                   1355:        first opcode byte for the testb: */
                   1356:     thunk_bytes[0] = TME_RECODE_X86_OPCODE_GRP3_Eb;
                   1357:     thunk_bytes++;
                   1358: 
                   1359:     /* if the guest instructions valid byte address fits in a
                   1360:        sign-extended 32 bits: */
                   1361:     if (((tme_int32_t)
                   1362:         (signed long)
                   1363:         insns_group_valid_byte)
                   1364:        == (signed long) insns_group_valid_byte) {
                   1365: 
                   1366:       /* emit the modR/M, SIB, and disp32 for a testb $imm8, addr32: */
                   1367:       *((tme_uint16_t *) thunk_bytes) = TME_RECODE_X86_INSN_TESTB_IMM8_ADDR32 >> 8;
                   1368:       *((tme_int32_t *) &thunk_bytes[2]) = (signed long) insns_group_valid_byte;
                   1369:       thunk_bytes += 2 + sizeof(tme_int32_t);
                   1370: 
                   1371:       /* set the size of the instructions that check that the guest
                   1372:         instructions are still valid: */
                   1373:       size_insns_group_valid_byte = TME_RECODE_X86_64_CHAIN_IN_SIZE_TESTB_ADDR32_JZ;
                   1374:     }
                   1375: 
                   1376:     /* otherwise, if the guest instructions valid byte address is
                   1377:        within a signed 32-bit displacement of the %ip of the testb
                   1378:        instruction: */
                   1379:     else if ((disp32
                   1380:              = _tme_recode_x86_chain_ip_disp32(ic,
                   1381:                                                (thunk_bytes
                   1382:                                                 + 1 /* testb */
                   1383:                                                 + 1 /* modR/M */
                   1384:                                                 + sizeof(disp32)
                   1385:                                                 + 1 /* imm8 */),
                   1386:                                                insns_group_valid_byte))) {
                   1387: 
                   1388:       /* emit the modR/M and disp32 for a testb $imm8, disp32(%ip): */
                   1389:       thunk_bytes[0] = TME_RECODE_X86_INSN_TESTB_IMM8_DISP32_IP >> 8;
                   1390:       *((tme_int32_t *) &thunk_bytes[1]) = disp32;
                   1391:       thunk_bytes += 1 + sizeof(disp32);
                   1392: 
                   1393:       /* set the size of the instructions that check that the guest
                   1394:         instructions are still valid: */
                   1395:       size_insns_group_valid_byte = TME_RECODE_X86_64_CHAIN_IN_SIZE_TESTB_BASE_JZ;
                   1396:     }
                   1397: 
                   1398:     /* otherwise, if the guest instructions valid byte address is
                   1399:        within a signed 32-bit displacement of the guest instructions
                   1400:        source address: */
                   1401:     else if ((disp32
                   1402:              = _tme_recode_x86_chain_base_disp32(insns_group_src,
                   1403:                                                  insns_group_valid_byte))) {
                   1404: 
                   1405:       /* emit the modR/M and disp32 for a testb $imm8, disp32(%reg): */
                   1406:       thunk_bytes[0] = TME_RECODE_X86_INSN_TESTB_IMM8_DISP32_REG_CHAIN_GUEST_SRC >> 8;
                   1407:       *((tme_int32_t *) &thunk_bytes[1]) = disp32;
                   1408:       thunk_bytes += 1 + sizeof(disp32);
                   1409: 
                   1410:       /* set the size of the instructions that check that the guest
                   1411:         instructions are still valid: */
                   1412:       size_insns_group_valid_byte = TME_RECODE_X86_64_CHAIN_IN_SIZE_TESTB_BASE_JZ;
                   1413:     }
                   1414: 
                   1415:     /* otherwise, the guest instructions valid byte address can't be
                   1416:        generated: */
                   1417:     else {
                   1418: 
                   1419:       /* emit a movq $imm64, %reg: */
                   1420:       /* NB: thunk_bytes has already been advanced by one: */
                   1421:       *((tme_uint16_t *) &thunk_bytes[0 - 1]) = TME_RECODE_X86_INSN_MOVQ_IMM64_REG_TLB_SCRATCH;
                   1422:       *((unsigned long *) &thunk_bytes[2 - 1]) = (unsigned long) insns_group_valid_byte;
                   1423:       thunk_bytes += -1 + 1 + 1 + TME_BIT(TME_RECODE_SIZE_HOST - TME_RECODE_SIZE_8);
                   1424: 
                   1425:       /* emit the opcode and modR/M for a testb $imm8, (%reg): */
                   1426:       *((tme_uint16_t *) thunk_bytes)
                   1427:        = (TME_RECODE_X86_OPCODE_GRP3_Eb
                   1428:           + (TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_EA(TME_RECODE_X86_REG_TLB_SCRATCH),
                   1429:                                          TME_RECODE_X86_OPCODE_GRP3_TEST)
                   1430:              << 8));
                   1431:       thunk_bytes += 2;
                   1432: 
                   1433:       /* set the size of the instructions that check that the guest
                   1434:         instructions are still valid: */
                   1435:       size_insns_group_valid_byte = TME_RECODE_X86_64_CHAIN_IN_SIZE_MOVQ_TESTB_JZ;
                   1436:     }
                   1437:   }
                   1438: 
                   1439:   /* emit the $imm8, and if the guest instructions aren't valid, jump
                   1440:      to the chain epilogue: */
                   1441:   thunk_bytes[0] = insns_group->tme_recode_insns_group_valid_mask;
                   1442:   *((tme_uint16_t *) &thunk_bytes[1])
                   1443:     = (TME_RECODE_X86_OPCODE_ESC_0F
                   1444:        + (TME_RECODE_X86_OPCODE0F_JCC(TME_RECODE_X86_COND_Z)
                   1445:          << 8));
                   1446:   thunk_bytes += 1 + 2 + sizeof(tme_int32_t);
                   1447:   ((tme_int32_t *) thunk_bytes)[-1]
                   1448:     = (ic->tme_recode_x86_ic_chain_epilogue
                   1449:        - tme_recode_build_to_thunk_off(ic, thunk_bytes));
                   1450: 
                   1451:   /* check the size of the chain in: */
                   1452:   assert ((thunk_bytes - thunk_bytes_start)
                   1453:          <= TME_RECODE_X86_CHAIN_IN_SIZE_MAX);
                   1454: 
                   1455:   /* check the sizes of the instructions that we need to skip for a
                   1456:      chain in near: */
                   1457:   assert ((thunk_bytes - thunk_bytes_start)
                   1458:          == (TME_RECODE_SIZE_HOST == TME_RECODE_SIZE_32
                   1459:              ? TME_RECODE_IA32_CHAIN_IN_SIZE_FAR
                   1460:              : (size_insns_group_src
                   1461:                 + size_insns_group_valid_byte)));
                   1462: 
                   1463:   /* finish these instructions: */
                   1464:   tme_recode_x86_insns_finish(ic, thunk_bytes);
                   1465: }
                   1466: 
                   1467: /* this makes the chain prologue for a new IC: */
                   1468: static void
                   1469: _tme_recode_x86_chain_prologue(struct tme_recode_ic *ic,
                   1470:                               const struct tme_recode_chain *chain,
                   1471:                               struct tme_recode_chain_thunk *chain_thunk)
                   1472: {
                   1473:   tme_uint8_t *thunk_bytes;
                   1474:   unsigned int reg_x86_insns_thunk;
                   1475:   unsigned long thunk_address0;
                   1476: 
                   1477:   /* start more instructions: */
                   1478:   tme_recode_x86_insns_start(ic, thunk_bytes);
                   1479: 
                   1480:   /* set the chain prologue: */
                   1481:   chain_thunk->tme_recode_x86_chain_thunk_prologue
                   1482:     = tme_recode_thunk_off_to_pointer(ic,
                   1483:                                      tme_recode_build_to_thunk_off(ic, thunk_bytes),
                   1484:                                      void (*) _TME_P((struct tme_ic *, tme_recode_thunk_off_t)));
                   1485: 
                   1486:   /* push all callee-saved registers: */
                   1487:   _tme_recode_x86_emit_reg_push(thunk_bytes, TME_RECODE_X86_REG_BP);
                   1488:   _tme_recode_x86_emit_reg_push(thunk_bytes, TME_RECODE_X86_REG_B);
                   1489:   if (TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32) {
                   1490:     _tme_recode_x86_emit_reg_push(thunk_bytes, TME_RECODE_X86_REG_N(12));
                   1491:     _tme_recode_x86_emit_reg_push(thunk_bytes, TME_RECODE_X86_REG_N(13));
                   1492:     _tme_recode_x86_emit_reg_push(thunk_bytes, TME_RECODE_X86_REG_N(14));
                   1493:     _tme_recode_x86_emit_reg_push(thunk_bytes, TME_RECODE_X86_REG_N(15));
                   1494:   }
                   1495:   else {
                   1496:     _tme_recode_x86_emit_reg_push(thunk_bytes, TME_RECODE_X86_REG_SI);
                   1497:     _tme_recode_x86_emit_reg_push(thunk_bytes, TME_RECODE_X86_REG_DI);
                   1498:   }
                   1499: 
                   1500:   /* the instructions thunk offset and address will be in the si register: */
                   1501:   reg_x86_insns_thunk = TME_RECODE_X86_REG_SI;
                   1502: 
                   1503:   /* if this is an x86-64 host: */
                   1504:   if (TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32) {
                   1505: 
                   1506:     /* copy the struct tme_ic * argument into the ic register: */
                   1507:     _tme_recode_x86_emit_reg_copy(thunk_bytes, TME_RECODE_X86_REG_DI, TME_RECODE_X86_REG_IC);
                   1508: 
                   1509:     /* the instructions thunk offset is already in the second argument register: */
                   1510:     assert (reg_x86_insns_thunk == TME_RECODE_X86_REG_SI);
                   1511:   }
                   1512: 
                   1513:   /* otherwise, this is an ia32 host: */
                   1514:   else {
                   1515: 
                   1516:     /* load the struct tme_ic * argument from the stack: */
                   1517:     /* NB: the magic 5 below is for the four callee-saved registers
                   1518:        that we pushed above, plus the return address: */
                   1519:     thunk_bytes[0] = (TME_RECODE_X86_OPCODE_BINOP_MOV + TME_RECODE_X86_OPCODE_BINOP_Ev_Gv);
                   1520:     thunk_bytes[1] = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_EA_DISP8(TME_RECODE_X86_EA_BASE_SIB),
                   1521:                                                 TME_RECODE_X86_REG_IC);
                   1522:     thunk_bytes[2] = TME_RECODE_X86_SIB(TME_RECODE_X86_REG_SP, TME_RECODE_X86_SIB_INDEX_NONE, 1);
                   1523:     thunk_bytes[3] = (TME_BIT(TME_RECODE_SIZE_HOST - TME_RECODE_SIZE_8) * 5);
                   1524:     thunk_bytes += 4;
                   1525: 
                   1526:     /* load the instructions thunk offset from the stack: */
                   1527:     /* NB: the magic 6 below is for the four callee-saved registers
                   1528:        that we pushed above, plus the return address, plus the struct
                   1529:        tme_ic * argument: */
                   1530:     thunk_bytes[0] = (TME_RECODE_X86_OPCODE_BINOP_MOV + TME_RECODE_X86_OPCODE_BINOP_Ev_Gv);
                   1531:     thunk_bytes[1] = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_EA_DISP8(TME_RECODE_X86_EA_BASE_SIB),
                   1532:                                                 reg_x86_insns_thunk);
                   1533:     thunk_bytes[2] = TME_RECODE_X86_SIB(TME_RECODE_X86_REG_SP, TME_RECODE_X86_SIB_INDEX_NONE, 1);
                   1534:     thunk_bytes[3] = (TME_BIT(TME_RECODE_SIZE_HOST - TME_RECODE_SIZE_8) * 6);
                   1535:     thunk_bytes += 4;
                   1536:   }
                   1537: 
                   1538:   /* get the near address of the thunk at offset zero: */
                   1539:   thunk_address0 = tme_recode_thunk_off_to_pointer(ic, 0, char *) - (char *) 0;
                   1540: 
                   1541:   /* if this is an ia32 host, or if this is an x86-64 host and the
                   1542:      near address of the thunk at offset zero fits in 32 bits: */
                   1543:   if (TME_RECODE_SIZE_HOST == TME_RECODE_SIZE_32
                   1544:       || thunk_address0 == (tme_uint32_t) thunk_address0) {
                   1545: 
                   1546:     /* add the near address of the thunk at offset zero to the
                   1547:        instructions thunk offset: */
                   1548:     thunk_bytes[0] = TME_RECODE_X86_OPCODE_GRP1_Iz_Ev;
                   1549:     thunk_bytes[1] = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_REG(reg_x86_insns_thunk),
                   1550:                                                 TME_RECODE_X86_OPCODE_GRP1_BINOP(TME_RECODE_X86_OPCODE_BINOP_ADD));
                   1551:     *((tme_uint32_t *) &thunk_bytes[2]) = thunk_address0;
                   1552:     thunk_bytes += 2 + sizeof(tme_uint32_t);
                   1553:   }
                   1554: 
                   1555:   /* otherwise, this is an x86-64 host and the near address of the
                   1556:      thunk at offset zero doesn't fit in 32 bits: */
                   1557:   else {
                   1558: 
                   1559:     /* zero-extend the instructions thunk offset to 64 bits: */
                   1560:     thunk_bytes[0]
                   1561:       = (TME_RECODE_X86_OPCODE_BINOP_MOV
                   1562:         + TME_RECODE_X86_OPCODE_BINOP_Gv_Ev);
                   1563:     thunk_bytes[1]
                   1564:       = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_REG(reg_x86_insns_thunk),
                   1565:                                    TME_RECODE_X86_REG(reg_x86_insns_thunk));
                   1566:     thunk_bytes += 2;
                   1567: 
                   1568:     /* load the near address of the thunk at offset zero into the TLB
                   1569:        scratch register: */
                   1570:     *((tme_uint16_t *) &thunk_bytes[0]) = TME_RECODE_X86_INSN_MOVQ_IMM64_REG_TLB_SCRATCH;
                   1571:     *((unsigned long *) &thunk_bytes[2]) = thunk_address0;
                   1572:     thunk_bytes += 2 + TME_BIT(TME_RECODE_SIZE_HOST - TME_RECODE_SIZE_8);
                   1573: 
                   1574:     /* add the TLB scratch register to the instructions thunk
                   1575:        offset: */
                   1576:     _tme_recode_x86_emit_reg_binop(thunk_bytes,
                   1577:                                   TME_RECODE_X86_OPCODE_BINOP_ADD,
                   1578:                                   TME_RECODE_X86_REG_TLB_SCRATCH,
                   1579:                                   reg_x86_insns_thunk);
                   1580:   }
                   1581: 
                   1582:   /* allocate one word on the stack for the recode flag bytes.  NB
                   1583:      that on x86-64, this returns the stack pointer to 16-byte
                   1584:      alignment as required by the ABI: */
                   1585:   thunk_bytes
                   1586:     = _tme_recode_x86_emit_adjust_sp(thunk_bytes,
                   1587:                                     (0 - TME_BIT(TME_RECODE_SIZE_HOST
                   1588:                                                  - TME_RECODE_SIZE_8)));
                   1589: 
                   1590:   /* call the chain jump far unconditional subs: */
                   1591:   thunk_bytes[0] = TME_RECODE_X86_OPCODE_CALL_RELz;
                   1592:   thunk_bytes += 1 + sizeof(tme_int32_t);
                   1593:   ((tme_int32_t *) thunk_bytes)[-1]
                   1594:     = (TME_RECODE_X86_CHAIN_SUBS(chain_thunk,
                   1595:                                 (TME_RECODE_CHAIN_INFO_JUMP
                   1596:                                  + TME_RECODE_CHAIN_INFO_FAR
                   1597:                                  + TME_RECODE_CHAIN_INFO_UNCONDITIONAL))
                   1598:        - tme_recode_build_to_thunk_off(ic, thunk_bytes));
                   1599: 
                   1600:   /* do the indirect jmp into the instructions thunk: */
                   1601:   assert (TME_RECODE_X86_REX_B(0, reg_x86_insns_thunk) == 0);
                   1602:   thunk_bytes[0] = TME_RECODE_X86_OPCODE_GRP5;
                   1603:   thunk_bytes[1] = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_REG(reg_x86_insns_thunk),
                   1604:                                               TME_RECODE_X86_OPCODE_GRP5_JMP);
                   1605:   thunk_bytes += 2;
                   1606: 
                   1607:   /* unknown indirect jmps are predicted to fallthrough; placing a UD2
                   1608:      instruction after an indirect jmp can stop a processor from
                   1609:      speculatively executing garbage fallthrough instructions: */
                   1610:   thunk_bytes[0] = TME_RECODE_X86_OPCODE_ESC_0F;
                   1611:   thunk_bytes[1] = TME_RECODE_X86_OPCODE0F_UD2;
                   1612:   thunk_bytes += 2;
                   1613: 
                   1614:   /* finish these instructions: */
                   1615:   tme_recode_x86_insns_finish(ic, thunk_bytes);
                   1616: 
                   1617:   /* finish the chain prologue: */
                   1618:   tme_recode_host_thunk_finish(ic);
                   1619: }
                   1620: 
                   1621: /* this returns a chain thunk: */
                   1622: const struct tme_recode_chain_thunk *
                   1623: tme_recode_chain_thunk(struct tme_recode_ic *ic,
                   1624:                       const struct tme_recode_chain *chain)
                   1625: {
                   1626:   struct tme_recode_chain_thunk *chain_thunk;
                   1627: 
                   1628:   /* if the chain fixup targets haven't been made yet: */
                   1629:   if (TME_RECODE_X86_CHAIN_FIXUP_TARGET_ALTERNATE(ic,
                   1630:                                                  (TME_RECODE_CHAIN_INFO_JUMP
                   1631:                                                   + TME_RECODE_CHAIN_INFO_ALTERNATE_NEAR))
                   1632:       == 0) {
                   1633: 
                   1634:     /* make the chain fixup targets: */
                   1635:     _tme_recode_x86_chain_fixup_targets(ic);
                   1636:   }
                   1637: 
                   1638:   /* start the thunk for the chain subs: */
                   1639:   if (!tme_recode_host_thunk_start(ic)) {
                   1640:     abort();
                   1641:   }
                   1642:   chain_thunk = tme_new0(struct tme_recode_chain_thunk, 1);
                   1643: 
                   1644:   /* make the chain subs for chain calls and chain jumps: */
                   1645:   _tme_recode_x86_chain_subs(ic,
                   1646:                             chain,
                   1647:                             chain_thunk,
                   1648:                             TME_RECODE_CHAIN_INFO_CALL);
                   1649:   
                   1650:   /* make the chain subs for chain returns: */
                   1651:   _tme_recode_x86_chain_subs(ic,
                   1652:                             chain,
                   1653:                             chain_thunk,
                   1654:                             TME_RECODE_CHAIN_INFO_RETURN);
                   1655: 
                   1656:   /* finish the thunk for the chain subs: */
                   1657:   tme_recode_host_thunk_finish(ic);
                   1658: 
                   1659:   /* start the thunk for the chain prologue: */
                   1660:   if (!tme_recode_host_thunk_start(ic)) {
                   1661:     abort();
                   1662:   }
                   1663: 
                   1664:   /* make the chain prologue: */
                   1665:   _tme_recode_x86_chain_prologue(ic,
                   1666:                                 chain,
                   1667:                                 chain_thunk);
                   1668: 
                   1669:   /* finish the thunk for the chain prologue: */
                   1670:   tme_recode_host_thunk_finish(ic);
                   1671: 
                   1672:   return (chain_thunk);
                   1673: }
                   1674: 
                   1675: /* this clears the return address stack: */
                   1676: void
                   1677: tme_recode_chain_ras_clear(const struct tme_recode_ic *recode_ic,
                   1678:                           struct tme_ic *ic)
                   1679: {
                   1680:   tme_recode_ras_entry_t *_ras_entry;
                   1681:   tme_uint32_t ras_size;
                   1682:   tme_recode_ras_entry_t ras_entry;
                   1683: 
                   1684:   /* clear the return address stack: */
                   1685:   ras_entry
                   1686:     = TME_RECODE_X86_CHAIN_RETURN_ADDRESS(recode_ic,
                   1687:                                          recode_ic->tme_recode_x86_ic_chain_epilogue);
                   1688:   _ras_entry
                   1689:     = ((tme_recode_ras_entry_t *) 
                   1690:        (((tme_uint8_t *) ic)
                   1691:        + recode_ic->tme_recode_ic_chain_ras_offset));
                   1692:   ras_size = recode_ic->tme_recode_ic_chain_ras_size;
                   1693:   do {
                   1694:     _ras_entry[ras_size - 1] = ras_entry;
                   1695:   } while (--ras_size);
                   1696: 
                   1697:   /* make sure that the return address stack pointer is valid: */
                   1698:   assert (*((tme_uint32_t *)
                   1699:            (((tme_uint8_t *) ic)
                   1700:             + recode_ic->tme_recode_ic_chain_ras_pointer_offset))
                   1701:          < recode_ic->tme_recode_ic_chain_ras_size);
                   1702: }
                   1703: 
                   1704: /* this fixes up a chain: */
                   1705: tme_recode_thunk_off_t
                   1706: tme_recode_chain_fixup(struct tme_recode_ic *ic,
                   1707:                       tme_recode_thunk_off_t chain_fixup,
                   1708:                       tme_uint32_t chain_info,
                   1709:                       tme_recode_thunk_off_t insns_thunk_next,
                   1710:                       tme_recode_thunk_off_t insns_thunk_return)
                   1711: {
                   1712:   tme_uint32_t return_imm32;
                   1713:   tme_uint16_t insn_0_15_buffer;
                   1714:   tme_uint32_t insn_0_15;
                   1715:   const tme_uint8_t *thunk_bytes;
                   1716:   tme_uint8_t opcode_buffer;
                   1717:   tme_int32_t displacement;
                   1718: 
                   1719:   /* if this is a chain call: */
                   1720:   if (chain_info & TME_RECODE_CHAIN_INFO_CALL) {
                   1721: 
                   1722:     /* there must be a return instructions thunk: */
                   1723:     assert (insns_thunk_return != 0);
                   1724: 
                   1725:     /* a chain call emits:
                   1726: 
                   1727:        movl    $imm32, %TME_RECODE_X86_REG_CHAIN_RETURN_ADDRESS
                   1728:        call    chain_subs_call_{near|far}_{unconditional|conditional}
                   1729:        jmp/jnc chain_fixup_call_{near|far}
                   1730: 
                   1731:        on an ia32 host, the $imm32 is the absolute address of the
                   1732:        instructions thunk to chain to.  on an x86-64 host, the $imm32
                   1733:        is the offset of the instructions thunk to chain to. on both
                   1734:        hosts, before fixup, the $imm32 indicates the chain epilogue.
                   1735:        fix up the $imm32: */
                   1736:     /* NB: chain_fixup points to the jump instruction.  the call
                   1737:        instruction is a call rel32, which is five bytes long, and the
                   1738:        $imm32 is immediately before that: */
                   1739:     return_imm32 = TME_RECODE_X86_CHAIN_RETURN_ADDRESS(ic, insns_thunk_return);
                   1740:     tme_recode_thunk_off_write(ic,
                   1741:                               (chain_fixup
                   1742:                                - (5
                   1743:                                   + sizeof(tme_uint32_t))),
                   1744:                               tme_uint32_t,
                   1745:                               return_imm32);
                   1746:   }
                   1747: 
                   1748:   /* if this is a chain near: */
                   1749:   if ((chain_info
                   1750:        & (TME_RECODE_CHAIN_INFO_NEAR
                   1751:          | TME_RECODE_CHAIN_INFO_FAR))
                   1752:       == TME_RECODE_CHAIN_INFO_NEAR) {
                   1753: 
                   1754:     /* if this is an ia32 host: */
                   1755:     if (TME_RECODE_SIZE_HOST == TME_RECODE_SIZE_32) {
                   1756: 
                   1757:       /* advance the next instructions thunk offset past the chain
                   1758:         in far checks: */
                   1759:       insns_thunk_next += TME_RECODE_IA32_CHAIN_IN_SIZE_FAR;
                   1760:     }
                   1761: 
                   1762:     /* otherwise, this is an x86-64 host: */
                   1763:     else {
                   1764: 
                   1765:       /* read the first two bytes of the first instruction of the
                   1766:         chain in.  this instruction starts checking that the guest
                   1767:         instruction source address matches the instructions thunk: */
                   1768:       insn_0_15 = *tme_recode_thunk_off_read(ic, insns_thunk_next, tme_uint16_t, insn_0_15_buffer);
                   1769: 
                   1770:       /* if this instruction is a cmpq $imm32, %reg: */
                   1771:       if (insn_0_15 == (tme_uint16_t) TME_RECODE_X86_INSN_CMP_Iz_REG_CHAIN_GUEST_SRC) {
                   1772: 
                   1773:        /* advance the next instructions thunk offset past the cmpq
                   1774:           $imm32, %reg; jnz epilogue */
                   1775:        insns_thunk_next += TME_RECODE_X86_64_CHAIN_IN_SIZE_CMPQ_IMM32_JNZ;
                   1776:       }
                   1777: 
                   1778:       /* if this instruction is an lea disp32(%ip), %reg: */
                   1779:       if (insn_0_15 == (tme_uint16_t) TME_RECODE_X86_INSN_LEA_DISP32_IP_REG_TLB_SCRATCH) {
                   1780: 
                   1781:        /* advance the next instructions thunk offset past the lea
                   1782:           disp32(%ip), %reg ; cmpq %reg, %reg ; jnz epilogue */
                   1783:        insns_thunk_next += TME_RECODE_X86_64_CHAIN_IN_SIZE_LEA_IP_CMP_JNZ;
                   1784:       }
                   1785: 
                   1786:       /* if this instruction is a movq $imm64, %reg: */
                   1787:       if (insn_0_15 == (tme_uint16_t) TME_RECODE_X86_INSN_MOVQ_IMM64_REG_TLB_SCRATCH) {
                   1788: 
                   1789:        /* advance the next instructions thunk offset past the movq
                   1790:           $imm64, %reg ; cmpq %reg, %reg ; jnz epilogue */
                   1791:        insns_thunk_next += TME_RECODE_X86_64_CHAIN_IN_SIZE_MOVQ_CMP_JNZ;
                   1792:       }
                   1793: 
                   1794:       /* if this instruction is a movl $imm32, %reg: */
                   1795:       if (((tme_uint8_t) insn_0_15) == TME_RECODE_X86_INSN_MOVL_IMM32_REG_TLB_SCRATCH) {
                   1796: 
                   1797:        /* advance the next instructions thunk offset past the movl
                   1798:           $imm32, %reg ; cmpq %reg, %reg ; jnz epilogue */
                   1799:        insns_thunk_next += TME_RECODE_X86_64_CHAIN_IN_SIZE_MOVL_CMP_JNZ;
                   1800:       }
                   1801: 
                   1802:       /* read the first two bytes of the next instruction of the chain
                   1803:         in.  this instruction starts checking that the guest
                   1804:         instructions are still valid: */
                   1805:       insn_0_15 = *tme_recode_thunk_off_read(ic, insns_thunk_next, tme_uint16_t, insn_0_15_buffer);
                   1806: 
                   1807:       /* if this instruction is a testb $imm8, addr32: */
                   1808:       if (insn_0_15 == (tme_uint16_t) TME_RECODE_X86_INSN_TESTB_IMM8_ADDR32) {
                   1809: 
                   1810:        /* advance the next instructions thunk offset past the testb
                   1811:           $imm8, addr32 ; jz epilogue */
                   1812:        insns_thunk_next += TME_RECODE_X86_64_CHAIN_IN_SIZE_TESTB_ADDR32_JZ;
                   1813:       }
                   1814: 
                   1815:       /* if this instruction is a testb $imm8, disp32(%ip): */
                   1816:       if (insn_0_15 == (tme_uint16_t) TME_RECODE_X86_INSN_TESTB_IMM8_DISP32_IP) {
                   1817: 
                   1818:        /* advance the next instructions thunk offset past the testb
                   1819:           $imm8, disp32(%ip) ; jz epilogue */
                   1820:        insns_thunk_next += TME_RECODE_X86_64_CHAIN_IN_SIZE_TESTB_BASE_JZ;
                   1821:       }
                   1822: 
                   1823:       /* if this instruction is a testb $imm8, disp32(%reg): */
                   1824:       if (insn_0_15 == (tme_uint16_t) TME_RECODE_X86_INSN_TESTB_IMM8_DISP32_REG_CHAIN_GUEST_SRC) {
                   1825: 
                   1826:        /* advance the next instructions thunk offset past the testb
                   1827:           $imm8, disp32(%reg) ; jz epilogue */
                   1828:        insns_thunk_next += TME_RECODE_X86_64_CHAIN_IN_SIZE_TESTB_BASE_JZ;
                   1829:       }
                   1830: 
                   1831:       /* if this instruction is a movq $imm64, %reg: */
                   1832:       if (insn_0_15 == TME_RECODE_X86_INSN_MOVQ_IMM64_REG_TLB_SCRATCH) {
                   1833: 
                   1834:        /* advance the next instructions thunk offset past the movq
                   1835:           $imm64, %reg ; testb $imm8, (%reg) ; jz epilogue */
                   1836:        insns_thunk_next += TME_RECODE_X86_64_CHAIN_IN_SIZE_MOVQ_TESTB_JZ;
                   1837:       }
                   1838:     }    
                   1839:   }
                   1840: 
                   1841:   /* all chain fixup instructions are unconditional or conditional
                   1842:      jump instructions with 32-bit displacements at their ends.
                   1843:      unconditional jump instructions are five bytes, and conditional
                   1844:      jump instructions are six bytes because they are escaped: */
                   1845:      
                   1846:   /* read the first opcode byte of the jump instruction: */
                   1847:   thunk_bytes = tme_recode_thunk_off_read(ic, chain_fixup, tme_uint8_t, opcode_buffer);
                   1848: 
                   1849:   /* advance the chain fixup offset to the jump instruction displacement: */
                   1850:   chain_fixup += (*thunk_bytes == TME_RECODE_X86_OPCODE_ESC_0F) + 1;
                   1851: 
                   1852:   /* rewrite the displacement for the instructions thunk: */
                   1853:   displacement = insns_thunk_next - (chain_fixup + sizeof(tme_int32_t));
                   1854:   tme_recode_thunk_off_write(ic, chain_fixup, tme_int32_t, displacement);
                   1855: 
                   1856:   /* return the next instructions thunk offset: */
                   1857:   return (insns_thunk_next);
                   1858: }
                   1859: 
                   1860: #ifdef TME_RECODE_DEBUG
                   1861: #include <stdio.h>
                   1862: 
                   1863: /* this host function dumps a chain thunk: */
                   1864: void
                   1865: tme_recode_chain_thunk_dump(const struct tme_recode_ic *ic,
                   1866:                            const struct tme_recode_chain_thunk *chain_thunk)
                   1867: {
                   1868:   tme_uint32_t chain_info;
                   1869:   const char *s;
                   1870:   tme_recode_thunk_off_t insns_thunk;
                   1871: 
                   1872:   printf("  x86 chain prologue: x/10i %p\n",
                   1873:         chain_thunk->tme_recode_x86_chain_thunk_prologue);
                   1874:   for (chain_info = 0;
                   1875:        chain_info <= (TME_RECODE_CHAIN_INFO_UNCONDITIONAL
                   1876:                      | TME_RECODE_CHAIN_INFO_CONDITIONAL
                   1877:                      | TME_RECODE_CHAIN_INFO_NEAR
                   1878:                      | TME_RECODE_CHAIN_INFO_FAR
                   1879:                      | TME_RECODE_CHAIN_INFO_JUMP
                   1880:                      | TME_RECODE_CHAIN_INFO_RETURN
                   1881:                      | TME_RECODE_CHAIN_INFO_CALL);
                   1882:        chain_info++) {
                   1883:     switch (chain_info
                   1884:            & (TME_RECODE_CHAIN_INFO_JUMP
                   1885:               | TME_RECODE_CHAIN_INFO_RETURN
                   1886:               | TME_RECODE_CHAIN_INFO_CALL)) {
                   1887:     case TME_RECODE_CHAIN_INFO_JUMP: s = "jump"; break;
                   1888:     case TME_RECODE_CHAIN_INFO_RETURN:
                   1889:       s = "return";
                   1890:       if ((chain_info & TME_RECODE_CHAIN_INFO_FAR) == 0) {
                   1891:        continue;
                   1892:       }
                   1893:       break;
                   1894:     case TME_RECODE_CHAIN_INFO_CALL: s = "call"; break;
                   1895:     default: continue;
                   1896:     }
                   1897:     insns_thunk = TME_RECODE_X86_CHAIN_SUBS(chain_thunk, chain_info);
                   1898:     printf("  x86 chain %s %s %s subs: x/10i %p\n",
                   1899:           s,
                   1900:           (chain_info & TME_RECODE_CHAIN_INFO_FAR
                   1901:            ? "far"
                   1902:            : "near"),
                   1903:           (chain_info & TME_RECODE_CHAIN_INFO_CONDITIONAL
                   1904:            ? "conditional"
                   1905:            : "unconditional"),
                   1906:           tme_recode_thunk_off_to_pointer(ic,
                   1907:                                           insns_thunk,
                   1908:                                           void (*)(void)));
                   1909:   }
                   1910:   insns_thunk
                   1911:     = TME_RECODE_X86_CHAIN_FIXUP_TARGET_ALTERNATE(ic,
                   1912:                                                  (TME_RECODE_CHAIN_INFO_JUMP
                   1913:                                                   + TME_RECODE_CHAIN_INFO_ALTERNATE_NEAR));
                   1914:   printf("  x86 chain fixup chain jump alternate near: x/10i %p\n",
                   1915:         tme_recode_thunk_off_to_pointer(ic,
                   1916:                                         insns_thunk,
                   1917:                                         void (*)(void)));
                   1918:   insns_thunk
                   1919:     = TME_RECODE_X86_CHAIN_FIXUP_TARGET(ic,
                   1920:                                        (TME_RECODE_CHAIN_INFO_JUMP
                   1921:                                         + TME_RECODE_CHAIN_INFO_NEAR));
                   1922:   printf("  x86 chain fixup chain jump near, chain return alternate near: x/10i %p\n",
                   1923:         tme_recode_thunk_off_to_pointer(ic,
                   1924:                                         insns_thunk,
                   1925:                                         void (*)(void)));
                   1926:   insns_thunk
                   1927:     = TME_RECODE_X86_CHAIN_FIXUP_TARGET_ALTERNATE(ic,
                   1928:                                                  (TME_RECODE_CHAIN_INFO_JUMP
                   1929:                                                   + TME_RECODE_CHAIN_INFO_ALTERNATE_FAR));
                   1930:   printf("  x86 chain fixup chain jump alternate far: x/3i %p\n",
                   1931:         tme_recode_thunk_off_to_pointer(ic,
                   1932:                                         insns_thunk,
                   1933:                                         void (*)(void)));
                   1934:   insns_thunk
                   1935:     = TME_RECODE_X86_CHAIN_FIXUP_TARGET(ic,
                   1936:                                        (TME_RECODE_CHAIN_INFO_JUMP
                   1937:                                         + TME_RECODE_CHAIN_INFO_FAR));
                   1938:   printf("  x86 chain fixup chain jump far: x/2i %p\n",
                   1939:         tme_recode_thunk_off_to_pointer(ic,
                   1940:                                         insns_thunk,
                   1941:                                         void (*)(void)));
                   1942:   insns_thunk
                   1943:     = TME_RECODE_X86_CHAIN_FIXUP_TARGET(ic,
                   1944:                                        (TME_RECODE_CHAIN_INFO_CALL
                   1945:                                         + TME_RECODE_CHAIN_INFO_FAR));
                   1946:   printf("  x86 chain fixup chain call far: x/2i %p\n",
                   1947:         tme_recode_thunk_off_to_pointer(ic,
                   1948:                                         insns_thunk,
                   1949:                                         void (*)(void)));
                   1950:   insns_thunk
                   1951:     = TME_RECODE_X86_CHAIN_FIXUP_TARGET(ic,
                   1952:                                        (TME_RECODE_CHAIN_INFO_CALL
                   1953:                                         + TME_RECODE_CHAIN_INFO_NEAR));
                   1954:   printf("  x86 chain fixup chain call near: x/2i %p\n",
                   1955:         tme_recode_thunk_off_to_pointer(ic,
                   1956:                                         insns_thunk,
                   1957:                                         void (*)(void)));
                   1958: }
                   1959: 
                   1960: #endif /* TME_RECODE_DEBUG */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.