|
|
1.1 ! root 1: /* $Id: rc-x86-regs.c,v 1.5 2010/02/15 22:23:15 fredette Exp $ */ ! 2: ! 3: /* libtme/host/x86/rc-x86-regs.c - x86 host recode register support: */ ! 4: ! 5: /* ! 6: * Copyright (c) 2007 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-regs.c,v 1.5 2010/02/15 22:23:15 fredette Exp $"); ! 37: ! 38: /* this maps a host register number to its x86 register number: */ ! 39: /* NB: these are in a very deliberate order: ! 40: ! 41: the registers that are preserved across a C function call come ! 42: first, from host register [0, TME_RECODE_REG_HOST_FREE_CALL) ! 43: ! 44: TME_RECODE_REG_HOST_SUBS_DST is used for the destination operand ! 45: for subs. it must be preserved across function calls, since subs ! 46: may call guest C functions. the hand-coded subs depend on the ! 47: specific x86 register(s) used for this host register. ! 48: ! 49: TME_RECODE_REG_HOST_SUBS_SRC1 is used for the src1 operand for ! 50: subs. it does not need to be preserved across function calls. the ! 51: hand-coded subs depend on the specific x86 register(s) used for ! 52: this host register. ! 53: ! 54: TME_RECODE_REG_HOST_SUBS_SRC0 is used for the src0 operand for subs ! 55: that compute multiple condition codes and/or need to call a guest C ! 56: function. it must not be preserved across function calls. ! 57: ! 58: NB that the c register is really a scratch register, not available ! 59: to the register allocator as either a host-size host register or as ! 60: part of a double-host-size host register. it is listed here since ! 61: subs can use TME_RECODE_REG_HOST_SUBS_SRC0 as a double-host-size ! 62: register anyways, and put the most-significant half of a value ! 63: there, and also to make the cc thunk generator simpler. ! 64: */ ! 65: #define TME_RECODE_X86_REG_HOST_UNDEF (TME_RECODE_REG_HOST_UNDEF + 1) ! 66: static const tme_uint8_t tme_recode_x86_reg_from_host[TME_RECODE_X86_REG_HOST_UNDEF] = { ! 67: #if (TME_RECODE_SIZE_HOST <= TME_RECODE_SIZE_32) ! 68: ! 69: #define TME_RECODE_X86_REG_HOST_SUBS_DST TME_RECODE_REG_HOST(0) ! 70: TME_RECODE_X86_REG_DI, /* host reg 0 */ ! 71: TME_RECODE_X86_REG_SI, /* host reg 1 */ ! 72: #define TME_RECODE_X86_REG_HOST_SUBS_SRC1 TME_RECODE_REG_HOST(2) ! 73: TME_RECODE_X86_REG_BP, /* host reg 2 */ ! 74: #define TME_RECODE_X86_REG_HOST_FREE_CALL TME_RECODE_REG_HOST(3) ! 75: TME_RECODE_X86_REG_A, /* host reg 3 */ ! 76: #define TME_RECODE_X86_REG_HOST_SUBS_SRC0 TME_RECODE_REG_HOST(4) ! 77: TME_RECODE_X86_REG_D, /* host reg 4 */ ! 78: TME_RECODE_X86_REG_C, /* not a true host register */ ! 79: ! 80: /* this returns the host register number for an argument register. ! 81: this is only valid for n == 1 and n == 2: */ ! 82: #define TME_RECODE_X86_REG_HOST_ARG(n) TME_RECODE_REG_HOST_UNDEF ! 83: ! 84: #else /* TME_RECODE_SIZE_HOST >= TME_RECODE_SIZE_32 */ ! 85: ! 86: /* the x86-64 register layout is very careful: ! 87: ! 88: a cc thunk that needs to chain to a guest function can't use most ! 89: of the argument registers, since they've already been loaded ! 90: with guest function arguments. however, it can use the nine ! 91: register (in the max-guest-is-host-size case, guest function ! 92: arguments will be in the di, si, dx, and cx registers, and in the ! 93: max-guest-is-double-host-size case, guest function arguments will ! 94: be in the di, si, dx, cx, and eight registers), and also the ten ! 95: and eleven registers. ! 96: ! 97: a cc thunk that doesn't need to chain to a guest function can use ! 98: the a, d, and c registers, which is good because they don't ! 99: require a rex prefix when used with setcc. */ ! 100: #define TME_RECODE_X86_REG_HOST_SUBS_DST TME_RECODE_REG_HOST(0) ! 101: TME_RECODE_X86_REG_N(12), /* host reg 0 */ ! 102: TME_RECODE_X86_REG_N(13), /* host reg 1 */ ! 103: TME_RECODE_X86_REG_N(14), /* host reg 2 */ ! 104: TME_RECODE_X86_REG_N(15), /* host reg 3 */ ! 105: #define TME_RECODE_X86_REG_HOST_SUBS_SRC1 TME_RECODE_REG_HOST(4) ! 106: TME_RECODE_X86_REG_BP, /* host reg 4 */ ! 107: #define TME_RECODE_X86_REG_HOST_FREE_CALL TME_RECODE_REG_HOST(5) ! 108: TME_RECODE_X86_REG_A, /* host reg 5 */ ! 109: TME_RECODE_X86_REG_N(10), /* host reg 6 */ ! 110: TME_RECODE_X86_REG_N(11), /* host reg 7 */ ! 111: TME_RECODE_X86_REG_DI, /* host reg 8 */ ! 112: TME_RECODE_X86_REG_SI, /* host reg 9 */ ! 113: TME_RECODE_X86_REG_N(8), /* host reg 10 */ ! 114: TME_RECODE_X86_REG_N(9), /* host reg 11 */ ! 115: #define TME_RECODE_X86_REG_HOST_SUBS_SRC0 TME_RECODE_REG_HOST(12) ! 116: TME_RECODE_X86_REG_D, /* host reg 12 */ ! 117: TME_RECODE_X86_REG_C, /* not a true host register */ ! 118: ! 119: /* this returns the host register number for an argument register. ! 120: this is only valid for n == 1 and n == 2: */ ! 121: #define TME_RECODE_X86_REG_HOST_ARG(n) \ ! 122: ((n) == 1 \ ! 123: ? TME_RECODE_REG_HOST(9) \ ! 124: : TME_RECODE_REG_HOST(12)) \ ! 125: ! 126: #endif /* TME_RECODE_SIZE_HOST >= TME_RECODE_SIZE_32 */ ! 127: }; ! 128: ! 129: /* this loads or stores a guest register: */ ! 130: void ! 131: tme_recode_host_reg_move(struct tme_recode_ic *ic, ! 132: tme_uint32_t reg_guest, ! 133: tme_uint32_t reginfo_all) ! 134: { ! 135: tme_uint8_t *thunk_bytes; ! 136: unsigned long window_i; ! 137: unsigned int reg_x86; ! 138: unsigned int reg_x86_other; ! 139: unsigned int size; ! 140: unsigned int rex; ! 141: tme_uint32_t reg_guest_offset; ! 142: unsigned int mod_reg_rm; ! 143: ! 144: /* start more instructions: */ ! 145: tme_recode_x86_insns_start(ic, thunk_bytes); ! 146: ! 147: /* if this is a windowed guest register: */ ! 148: if (TME_RECODE_REGINFO_TYPE_IS_WINDOW(reginfo_all)) { ! 149: ! 150: /* get the index of the window that this guest register is in: */ ! 151: window_i = TME_RECODE_REGINFO_TYPE_WHICH_WINDOW(reginfo_all); ! 152: ! 153: /* if the c register doesn't already hold this window's base: */ ! 154: if (ic->tme_recode_x86_ic_thunks_reg_guest_window_c != window_i) { ! 155: ! 156: /* if this is an x86-64 host: */ ! 157: if (TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32) { ! 158: ! 159: /* emit a movslq ic_window_base_offset(%ic), %rcx: */ ! 160: *((tme_uint32_t *) &thunk_bytes[0]) ! 161: = ((TME_RECODE_X86_REX_R(TME_RECODE_SIZE_HOST, TME_RECODE_X86_REG_C) ! 162: | TME_RECODE_X86_REX_B(0, TME_RECODE_X86_REG_IC)) ! 163: + (TME_RECODE_X86_OPCODE_MOVS_El_Gv ! 164: << 8) ! 165: + (TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_EA_DISP32(TME_RECODE_X86_REG_IC), ! 166: TME_RECODE_X86_REG_C) ! 167: << 16)); ! 168: *((tme_int32_t *) &thunk_bytes[3]) = ic->tme_recode_ic_window_base_offsets[window_i]; ! 169: thunk_bytes += (1 + 1 + 1 + sizeof(tme_int32_t)); ! 170: } ! 171: ! 172: /* otherwise, this is an ia32 host: */ ! 173: else { ! 174: ! 175: /* emit a movl ic_window_base_offset(%ic), %ecx: */ ! 176: *((tme_uint16_t *) &thunk_bytes[0]) ! 177: = ((TME_RECODE_X86_OPCODE_BINOP_MOV ! 178: + TME_RECODE_X86_OPCODE_BINOP_Ev_Gv) ! 179: + (TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_EA_DISP32(TME_RECODE_X86_REG_IC), ! 180: TME_RECODE_X86_REG_C) ! 181: << 8)); ! 182: *((tme_int32_t *) &thunk_bytes[2]) = ic->tme_recode_ic_window_base_offsets[window_i]; ! 183: thunk_bytes += (1 + 1 + sizeof(tme_int32_t)); ! 184: } ! 185: ! 186: /* the window base is now in the c register: */ ! 187: ic->tme_recode_x86_ic_thunks_reg_guest_window_c = window_i; ! 188: } ! 189: } ! 190: ! 191: /* if this is a load: */ ! 192: if (!TME_RECODE_REGINFO_TAGS_ARE_DIRTY(reginfo_all)) { ! 193: ! 194: /* if we may need it for a rex prefix, get the (first) x86 ! 195: register to load, otherwise just set reg_x86 to zero to ! 196: initialize it: */ ! 197: reg_x86 ! 198: = (TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32 ! 199: ? tme_recode_x86_reg_from_host[TME_RECODE_REGINFO_TAGS_WHICH_REG_HOST(reginfo_all)] ! 200: : 0); ! 201: ! 202: /* emit any rex prefix: */ ! 203: /* NB: since it's zero, for clarity we always use ! 204: TME_RECODE_X86_REG_X(0, TME_RECODE_X86_REG_C), even when the ! 205: guest register may not be windowed: */ ! 206: if (TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32) { ! 207: thunk_bytes[0] ! 208: = (TME_RECODE_X86_REX_R(TME_RECODE_SIZE_HOST, reg_x86) ! 209: | TME_RECODE_X86_REX_B(0, TME_RECODE_X86_REG_IC) ! 210: | TME_RECODE_X86_REX_X(TME_RECODE_X86_REG_C)); ! 211: } ! 212: ! 213: /* get the size to load: */ ! 214: size = TME_RECODE_REGINFO_TAGS_WHICH_VALID_SIZE(reginfo_all); ! 215: assert (size >= TME_RECODE_SIZE_8 && size <= TME_RECODE_SIZE_GUEST_MAX); ! 216: ! 217: /* if this is a host-size or double-host-size load: */ ! 218: if (__tme_predict_true(size >= TME_RECODE_SIZE_HOST)) { ! 219: ! 220: /* emit the opcode part of a movl @ea, %reg or a movq @ea, %reg: */ ! 221: thunk_bytes[(TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32) + 0] ! 222: = (TME_RECODE_X86_OPCODE_BINOP_MOV ! 223: + TME_RECODE_X86_OPCODE_BINOP_Ev_Gv); ! 224: } ! 225: ! 226: /* otherwise, if this is a 32-bit load on an x86-64 host: */ ! 227: else if (__tme_predict_true(TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32 ! 228: && size == TME_RECODE_SIZE_32)) { ! 229: ! 230: /* emit the opcode part of a movslq @ea, %reg: */ ! 231: thunk_bytes[1] = TME_RECODE_X86_OPCODE_MOVS_El_Gv; ! 232: } ! 233: ! 234: /* otherwise, this is either an 8- or 16-bit load: */ ! 235: else { ! 236: ! 237: /* emit the opcode part of a movsbl @ea, %reg or a movswl @ea, %reg: */ ! 238: *((tme_uint16_t *) &thunk_bytes[(TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32) + 0]) ! 239: = (size < TME_RECODE_SIZE_16 ! 240: ? (TME_RECODE_X86_OPCODE_ESC_0F + (TME_RECODE_X86_OPCODE0F_MOVS_Eb_Gv << 8)) ! 241: : (TME_RECODE_X86_OPCODE_ESC_0F + (TME_RECODE_X86_OPCODE0F_MOVS_Ew_Gv << 8))); ! 242: thunk_bytes++; ! 243: } ! 244: ! 245: /* advance thunk_bytes to the modR/M byte: */ ! 246: thunk_bytes += (TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32) + 1; ! 247: ! 248: /* if we didn't get it above, now get the (first) x86 register to ! 249: load: */ ! 250: if (TME_RECODE_SIZE_HOST <= TME_RECODE_SIZE_32) { ! 251: reg_x86 = tme_recode_x86_reg_from_host[TME_RECODE_REGINFO_TAGS_WHICH_REG_HOST(reginfo_all)]; ! 252: } ! 253: ! 254: /* this is not an 8-bit store of a register that doesn't have an ! 255: 8-bit encoding: */ ! 256: reg_x86_other = TME_RECODE_X86_REG_A; ! 257: } ! 258: ! 259: /* otherwise, this is a store: */ ! 260: else { ! 261: ! 262: /* get the size to store: */ ! 263: size = TME_RECODE_REGINFO_TAGS_WHICH_VALID_SIZE(reginfo_all); ! 264: assert (size >= TME_RECODE_SIZE_8 && size <= TME_RECODE_SIZE_GUEST_MAX); ! 265: ! 266: /* get the (first) x86 register to store: */ ! 267: reg_x86 = tme_recode_x86_reg_from_host[TME_RECODE_REGINFO_TAGS_WHICH_REG_HOST(reginfo_all)]; ! 268: ! 269: /* in case we have to use a different register to do the store, ! 270: remember the original register: */ ! 271: reg_x86_other = reg_x86; ! 272: ! 273: /* if this is an ia32 host, and an 8-bit store of a register ! 274: that doesn't have an 8-bit encoding: */ ! 275: if (TME_RECODE_SIZE_HOST <= TME_RECODE_SIZE_32 ! 276: && size == TME_RECODE_SIZE_8 ! 277: && reg_x86 >= TME_RECODE_X86_REG_SP) { ! 278: ! 279: /* swap this register with the d register: */ ! 280: thunk_bytes[0] = TME_RECODE_X86_OPCODE_BINOP_XCHG + TME_RECODE_X86_OPCODE_BINOP_Gv_Ev; ! 281: thunk_bytes[1] ! 282: = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_REG(reg_x86), ! 283: TME_RECODE_X86_REG_D); ! 284: thunk_bytes += 2; ! 285: ! 286: /* we are now storing the d register: */ ! 287: reg_x86 = TME_RECODE_X86_REG_D; ! 288: } ! 289: ! 290: /* if this is a 16-bit store: */ ! 291: if (__tme_predict_false(size == TME_RECODE_SIZE_16)) { ! 292: ! 293: /* emit the OPSIZ prefix: */ ! 294: thunk_bytes[0] = TME_RECODE_X86_PREFIX_OPSIZ; ! 295: thunk_bytes++; ! 296: } ! 297: ! 298: /* emit any rex prefix: */ ! 299: /* NB: since it's zero, for clarity we always use ! 300: TME_RECODE_X86_REG_X(0, TME_RECODE_X86_REG_C), even when the ! 301: guest register may not be windowed: */ ! 302: rex ! 303: = (TME_RECODE_X86_REX_R(TME_MIN(size, TME_RECODE_SIZE_HOST), reg_x86) ! 304: | TME_RECODE_X86_REX_B(0, TME_RECODE_X86_REG_IC) ! 305: | TME_RECODE_X86_REX_X(TME_RECODE_X86_REG_C)); ! 306: if (rex != 0) { ! 307: thunk_bytes[0] = rex; ! 308: thunk_bytes++; ! 309: } ! 310: ! 311: /* emit the opcode part of a movb/movw/movl/movq %reg, @ea: */ ! 312: thunk_bytes[0] ! 313: = (size >= TME_RECODE_SIZE_16 ! 314: ? (TME_RECODE_X86_OPCODE_BINOP_MOV + TME_RECODE_X86_OPCODE_BINOP_Gv_Ev) ! 315: : (TME_RECODE_X86_OPCODE_BINOP_MOV + TME_RECODE_X86_OPCODE_BINOP_Gb_Eb)); ! 316: thunk_bytes++; ! 317: } ! 318: ! 319: /* get the offset of the guest register: */ ! 320: reg_guest_offset ! 321: = (reg_guest ! 322: << (ic->tme_recode_ic_reg_size ! 323: - TME_RECODE_SIZE_8)); ! 324: ! 325: for (;;) { ! 326: ! 327: /* make the modR/M byte for this instruction, with a zero base ! 328: register field: */ ! 329: mod_reg_rm ! 330: = (TME_RECODE_X86_MOD_OPREG_RM(0, TME_RECODE_X86_REG(reg_x86)) ! 331: + (reg_guest_offset < 0x80 ! 332: ? TME_RECODE_X86_MOD_RM_EA_DISP8(0) ! 333: : TME_RECODE_X86_MOD_RM_EA_DISP32(0))); ! 334: ! 335: /* if this is a windowed guest register: */ ! 336: if (TME_RECODE_REGINFO_TYPE_IS_WINDOW(reginfo_all)) { ! 337: ! 338: /* emit the modR/M and scale-index-base bytes for this instruction: */ ! 339: thunk_bytes[0] = mod_reg_rm + TME_RECODE_X86_REG(TME_RECODE_X86_EA_BASE_SIB); ! 340: thunk_bytes++; ! 341: thunk_bytes[0] = TME_RECODE_X86_SIB(TME_RECODE_X86_REG_IC, TME_RECODE_X86_REG_C, 1); ! 342: } ! 343: else { ! 344: ! 345: /* emit the modR/M byte for this instruction: */ ! 346: thunk_bytes[0] = mod_reg_rm + TME_RECODE_X86_REG(TME_RECODE_X86_REG_IC); ! 347: } ! 348: ! 349: /* emit the displacement for this instruction: */ ! 350: *((tme_uint32_t *) &thunk_bytes[1]) = reg_guest_offset; ! 351: thunk_bytes += sizeof(tme_uint8_t) + sizeof(tme_int8_t); ! 352: if (reg_guest_offset >= 0x80) { ! 353: thunk_bytes += (sizeof(tme_int32_t) - sizeof(tme_int8_t)); ! 354: } ! 355: ! 356: /* if this is a double-host-size move: */ ! 357: if (TME_RECODE_SIZE_IS_DOUBLE_HOST(size)) { ! 358: ! 359: /* get the second x86 register to move: */ ! 360: reg_x86 = tme_recode_x86_reg_from_host[TME_RECODE_REGINFO_TAGS_WHICH_REG_HOST(reginfo_all) + 1]; ! 361: ! 362: /* emit any rex prefix: */ ! 363: /* NB: since it's zero, for clarity we always use ! 364: TME_RECODE_X86_REG_X(0, TME_RECODE_X86_REG_C), even when the ! 365: guest register may not be windowed: */ ! 366: if (TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32) { ! 367: thunk_bytes[0] ! 368: = (TME_RECODE_X86_REX_R(TME_RECODE_SIZE_HOST, reg_x86) ! 369: | TME_RECODE_X86_REX_B(0, TME_RECODE_X86_REG_IC) ! 370: | TME_RECODE_X86_REX_X(TME_RECODE_X86_REG_C)); ! 371: } ! 372: ! 373: /* emit the opcode part of a movl/movq @ea, %reg or a movl/movq %reg, @ea: */ ! 374: thunk_bytes[(TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32) + 0] ! 375: = (TME_RECODE_REGINFO_TAGS_ARE_DIRTY(reginfo_all) ! 376: ? (TME_RECODE_X86_OPCODE_BINOP_MOV + TME_RECODE_X86_OPCODE_BINOP_Gv_Ev) ! 377: : (TME_RECODE_X86_OPCODE_BINOP_MOV + TME_RECODE_X86_OPCODE_BINOP_Ev_Gv)); ! 378: ! 379: /* advance thunk_bytes to the modR/M byte: */ ! 380: thunk_bytes += (TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32) + 1; ! 381: ! 382: /* advance reg_guest_offset to the most-significant half of the guest register: */ ! 383: reg_guest_offset += TME_BIT(TME_RECODE_SIZE_HOST - TME_RECODE_SIZE_8); ! 384: ! 385: /* loop to emit the modR/M for this instruction: */ ! 386: size = TME_RECODE_SIZE_HOST; ! 387: continue; ! 388: } ! 389: ! 390: break; ! 391: } ! 392: ! 393: /* if this is an ia32 host, and this was an 8-bit store of a register ! 394: that doesn't have an 8-bit encoding: */ ! 395: if (TME_RECODE_SIZE_HOST <= TME_RECODE_SIZE_32 ! 396: && size == TME_RECODE_SIZE_8 ! 397: && reg_x86_other >= TME_RECODE_X86_REG_SP) { ! 398: ! 399: /* we swap the register with the d register above, and stored the ! 400: d register. swap the registers back: */ ! 401: thunk_bytes[0] = TME_RECODE_X86_OPCODE_BINOP_XCHG + TME_RECODE_X86_OPCODE_BINOP_Gv_Ev; ! 402: thunk_bytes[1] ! 403: = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_REG(reg_x86_other), ! 404: TME_RECODE_X86_REG_D); ! 405: thunk_bytes += 2; ! 406: } ! 407: ! 408: /* finish these instructions: */ ! 409: tme_recode_x86_insns_finish(ic, thunk_bytes); ! 410: } ! 411: ! 412: /* this copies a host register into another host register: */ ! 413: void ! 414: tme_recode_host_reg_copy(struct tme_recode_ic *ic, ! 415: unsigned long reg_host_src, ! 416: unsigned long reg_host_dst) ! 417: { ! 418: tme_uint8_t *thunk_bytes; ! 419: unsigned int size; ! 420: unsigned long reg_x86_src; ! 421: unsigned long reg_x86_dst; ! 422: ! 423: /* start more instructions: */ ! 424: tme_recode_x86_insns_start(ic, thunk_bytes); ! 425: ! 426: /* get the size to move: */ ! 427: size = ic->tme_recode_ic_reg_size; ! 428: ! 429: /* get the x86 registers in the (first) copy: */ ! 430: reg_x86_src = tme_recode_x86_reg_from_host[reg_host_src]; ! 431: reg_x86_dst = tme_recode_x86_reg_from_host[reg_host_dst]; ! 432: ! 433: for (;;) { ! 434: ! 435: /* if this is an x86-64 host: */ ! 436: if (TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32) { ! 437: ! 438: /* emit the rex prefix: */ ! 439: thunk_bytes[0] ! 440: = (TME_RECODE_X86_REX_B(TME_RECODE_SIZE_HOST, reg_x86_src) ! 441: | TME_RECODE_X86_REX_R(TME_RECODE_SIZE_HOST, reg_x86_dst)); ! 442: } ! 443: ! 444: /* emit the opcode part of a movl %src, %dst or a movq %src, %dst: */ ! 445: thunk_bytes[(TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32) + 0] ! 446: = (TME_RECODE_X86_OPCODE_BINOP_MOV ! 447: + TME_RECODE_X86_OPCODE_BINOP_Ev_Gv); ! 448: ! 449: /* emit the modR/M for this instruction: */ ! 450: thunk_bytes[(TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32) + 1] ! 451: = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_REG(reg_x86_src), ! 452: TME_RECODE_X86_REG(reg_x86_dst)); ! 453: ! 454: /* advance to the next instruction: */ ! 455: thunk_bytes += (TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32) + 2; ! 456: ! 457: /* if this is a double-host-size move: */ ! 458: if (TME_RECODE_SIZE_IS_DOUBLE_HOST(size)) { ! 459: ! 460: /* loop to do the second registers of the pairs: */ ! 461: reg_x86_src = tme_recode_x86_reg_from_host[reg_host_src + 1]; ! 462: reg_x86_dst = tme_recode_x86_reg_from_host[reg_host_dst + 1]; ! 463: size = TME_RECODE_SIZE_HOST; ! 464: continue; ! 465: } ! 466: ! 467: break; ! 468: } ! 469: ! 470: /* finish these instructions: */ ! 471: tme_recode_x86_insns_finish(ic, thunk_bytes); ! 472: } ! 473: ! 474: /* this zeroes a host register and returns the host register. if insn ! 475: is non-NULL, it also reserves the host register: */ ! 476: unsigned long ! 477: tme_recode_host_reg_zero(struct tme_recode_ic *ic, ! 478: const struct tme_recode_insn *insn, ! 479: unsigned long reg_host) ! 480: { ! 481: tme_uint8_t *thunk_bytes; ! 482: unsigned int size; ! 483: unsigned long reg_x86; ! 484: unsigned int rex; ! 485: ! 486: /* start more instructions: */ ! 487: tme_recode_x86_insns_start(ic, thunk_bytes); ! 488: ! 489: /* get the size to zero: */ ! 490: size = ic->tme_recode_ic_reg_size; ! 491: ! 492: /* get the x86 register to zero: */ ! 493: reg_x86 = tme_recode_x86_reg_from_host[reg_host]; ! 494: ! 495: for (;;) { ! 496: ! 497: /* if this is an x86-64 host: */ ! 498: if (TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32) { ! 499: ! 500: /* emit any rex prefix: */ ! 501: rex ! 502: = (TME_RECODE_X86_REX_B(TME_RECODE_SIZE_32, reg_x86) ! 503: | TME_RECODE_X86_REX_R(TME_RECODE_SIZE_32, reg_x86)); ! 504: thunk_bytes[0] = rex; ! 505: thunk_bytes += (rex > 0); ! 506: } ! 507: ! 508: /* emit the opcode part of a xorl %reg, %reg: */ ! 509: thunk_bytes[0] ! 510: = (TME_RECODE_X86_OPCODE_BINOP_XOR ! 511: + TME_RECODE_X86_OPCODE_BINOP_Ev_Gv); ! 512: ! 513: /* emit the modR/M for this instruction: */ ! 514: thunk_bytes[1] ! 515: = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_REG(reg_x86), ! 516: TME_RECODE_X86_REG(reg_x86)); ! 517: ! 518: /* advance to the next instruction: */ ! 519: thunk_bytes += 2; ! 520: ! 521: /* if this is a double-host-size zero: */ ! 522: if (TME_RECODE_SIZE_IS_DOUBLE_HOST(size)) { ! 523: ! 524: /* loop to do the second register of the pair: */ ! 525: reg_x86 = tme_recode_x86_reg_from_host[reg_host + 1]; ! 526: size = TME_RECODE_SIZE_HOST; ! 527: continue; ! 528: } ! 529: ! 530: break; ! 531: } ! 532: ! 533: /* finish these instructions: */ ! 534: tme_recode_x86_insns_finish(ic, thunk_bytes); ! 535: ! 536: /* return the host register, optionally reserving it: */ ! 537: return (insn == NULL ! 538: ? reg_host ! 539: : tme_recode_regs_host_reserve(ic, reg_host)); ! 540: } ! 541: ! 542: /* this fills a host register with an immediate, and reserves and ! 543: returns the host register: */ ! 544: unsigned long ! 545: tme_recode_host_reg_imm(struct tme_recode_ic *ic, ! 546: const struct tme_recode_insn *insn, ! 547: unsigned long reg_host) ! 548: { ! 549: tme_uint8_t *thunk_bytes; ! 550: unsigned int size; ! 551: unsigned long reg_x86; ! 552: tme_recode_uguest_t imm; ! 553: unsigned int size_part; ! 554: unsigned int rex; ! 555: ! 556: /* get the immediate: */ ! 557: imm = insn->tme_recode_insn_imm_uguest; ! 558: ! 559: /* if the immediate is zero: */ ! 560: if (imm == 0) { ! 561: ! 562: /* zero this host register: */ ! 563: return (tme_recode_host_reg_zero(ic, insn, reg_host)); ! 564: } ! 565: ! 566: /* start more instructions: */ ! 567: tme_recode_x86_insns_start(ic, thunk_bytes); ! 568: ! 569: /* get the size to fill: */ ! 570: size = insn->tme_recode_insn_size; ! 571: ! 572: /* get the x86 register to fill: */ ! 573: reg_x86 = tme_recode_x86_reg_from_host[reg_host]; ! 574: ! 575: for (;;) { ! 576: ! 577: /* assume that we will move a host-sized immediate: */ ! 578: size_part = TME_RECODE_SIZE_HOST; ! 579: ! 580: /* if this is an x86-64 host: */ ! 581: if (TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32) { ! 582: ! 583: /* if the most significant 32 bits of the immediate are zero, we ! 584: can move a 32-bit immediate instead of a 64-bit immediate: */ ! 585: size_part ! 586: = (TME_RECODE_SIZE_32 ! 587: + ((((unsigned long) imm) ! 588: & (((((unsigned long) 1) ! 589: << TME_BIT(TME_RECODE_SIZE_HOST - 1)) - 1) ! 590: << TME_BIT(TME_RECODE_SIZE_HOST - 1))) ! 591: != 0)); ! 592: ! 593: /* emit any rex prefix: */ ! 594: rex = TME_RECODE_X86_REX_B(size_part, reg_x86); ! 595: thunk_bytes[0] = rex; ! 596: thunk_bytes += (rex > 0); ! 597: } ! 598: ! 599: /* emit the opcode part of a movl $imm, %reg or movq $imm, %reg: */ ! 600: thunk_bytes[0] = TME_RECODE_X86_OPCODE_MOV_Iv_Gv(reg_x86); ! 601: ! 602: /* emit the immediate for this instruction: */ ! 603: *((unsigned long *) &thunk_bytes[1]) = imm; ! 604: ! 605: /* advance to the next instruction: */ ! 606: thunk_bytes += 1 + TME_BIT(size_part - TME_RECODE_SIZE_8); ! 607: ! 608: /* if this is a double-host-size immediate: */ ! 609: if (TME_RECODE_SIZE_IS_DOUBLE_HOST(size)) { ! 610: ! 611: /* advance to the second register of the pair: */ ! 612: reg_x86 = tme_recode_x86_reg_from_host[reg_host + 1]; ! 613: imm >>= TME_BIT(TME_RECODE_SIZE_HOST) * (TME_RECODE_SIZE_GUEST_MAX > TME_RECODE_SIZE_HOST); ! 614: ! 615: /* if the immediate is zero: */ ! 616: if (imm == 0) { ! 617: ! 618: /* if this is an x86-64 host: */ ! 619: if (TME_RECODE_SIZE_HOST > TME_RECODE_SIZE_32) { ! 620: ! 621: /* emit any rex prefix: */ ! 622: rex ! 623: = (TME_RECODE_X86_REX_B(TME_RECODE_SIZE_32, reg_x86) ! 624: | TME_RECODE_X86_REX_R(TME_RECODE_SIZE_32, reg_x86)); ! 625: thunk_bytes[0] = rex; ! 626: thunk_bytes += (rex > 0); ! 627: } ! 628: ! 629: /* emit the opcode part of a xorl %reg, %reg: */ ! 630: thunk_bytes[0] ! 631: = (TME_RECODE_X86_OPCODE_BINOP_XOR ! 632: + TME_RECODE_X86_OPCODE_BINOP_Ev_Gv); ! 633: ! 634: /* emit the modR/M for this instruction: */ ! 635: thunk_bytes[1] ! 636: = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_REG(reg_x86), ! 637: TME_RECODE_X86_REG(reg_x86)); ! 638: ! 639: /* advance to the next instruction: */ ! 640: thunk_bytes += 2; ! 641: ! 642: break; ! 643: } ! 644: ! 645: /* loop to do the second register of the pair: */ ! 646: size = TME_RECODE_SIZE_HOST; ! 647: continue; ! 648: } ! 649: ! 650: break; ! 651: } ! 652: ! 653: /* finish these instructions: */ ! 654: tme_recode_x86_insns_finish(ic, thunk_bytes); ! 655: ! 656: /* reserve and return the host register: */ ! 657: return (tme_recode_regs_host_reserve(ic, reg_host)); ! 658: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.