Annotation of tme/libtme/host/x86/rc-x86-chain.c, revision 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.