- pavgb
- ucomiss
- enter
+ - mov imm32, %esp
+ - all "in" and "out" opcodes
- Memcheck: Implemented handling of more SSE(2) constructs
popl %eax
ret
+/*
+ Fetch a byte/word/dword from given port
+ On entry:
+ size 1, 2 or 4
+ port, replaced by result
+ RA
+*/
+.global VG_(helper_IN)
+VG_(helper_IN):
+ pushl %eax
+ pushl %edx
+ movl 16(%esp), %eax
+ movl 12(%esp), %edx
+ cmpl $4, %eax
+ je in_dword
+ cmpl $2, %eax
+ je in_word
+in_byte:
+ inb (%dx), %al
+ jmp in_done
+in_word:
+ in (%dx), %ax
+ jmp in_done
+in_dword:
+ inl (%dx),%eax
+in_done:
+ movl %eax,12(%esp)
+ popl %edx
+ popl %eax
+ ret
+
+/*
+ Write a byte/word/dword to given port
+ On entry:
+ size 1, 2 or 4
+ port
+ value
+ RA
+*/
+.global VG_(helper_OUT)
+VG_(helper_OUT):
+ pushl %eax
+ pushl %edx
+ movl 16(%esp), %edx
+ movl 12(%esp), %eax
+ cmpl $4, 20(%esp)
+ je out_dword
+ cmpl $2, 20(%esp)
+ je out_word
+out_byte:
+ outb %al,(%dx)
+ jmp out_done
+out_word:
+ out %ax,(%dx)
+ jmp out_done
+out_dword:
+ outl %eax,(%dx)
+out_done:
+ popl %edx
+ popl %eax
+ ret
+
/* Do the CPUID instruction.
On entry:
extern void VG_(helper_shrdl);
extern void VG_(helper_shrdw);
+extern void VG_(helper_IN);
+extern void VG_(helper_OUT);
+
extern void VG_(helper_RDTSC);
extern void VG_(helper_CPUID);
Int VGOFF_(helper_shldw) = INVALID_OFFSET;
Int VGOFF_(helper_shrdl) = INVALID_OFFSET;
Int VGOFF_(helper_shrdw) = INVALID_OFFSET;
+Int VGOFF_(helper_IN) = INVALID_OFFSET;
+Int VGOFF_(helper_OUT) = INVALID_OFFSET;
Int VGOFF_(helper_RDTSC) = INVALID_OFFSET;
Int VGOFF_(helper_CPUID) = INVALID_OFFSET;
Int VGOFF_(helper_BSWAP) = INVALID_OFFSET;
}
/* Allocate 1 word in baseBlock and set it to the given value. */
-static Int alloc_BaB_1_set ( Addr a )
+static Int alloc_BaB_1_set ( Addr a, const Char* what )
{
Int off = alloc_BaB(1);
VG_(baseBlock)[off] = (UInt)a;
+ if ( VG_( clo_verbosity ) > 1 )
+ VG_(printf)( "Allocated %d for %s\n", off*4, what );
return off;
}
{
UInt i;
for (i = 0; i < n; i++)
- offsets[i] = alloc_BaB_1_set( addrs[i] );
+ offsets[i] = alloc_BaB_1_set( addrs[i], "helper" );
}
Bool VG_(need_to_handle_esp_assignment)(void)
/* Helper functions. */
VGOFF_(helper_idiv_64_32)
- = alloc_BaB_1_set( (Addr) & VG_(helper_idiv_64_32) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_idiv_64_32), "idiv_64_32" );
VGOFF_(helper_div_64_32)
- = alloc_BaB_1_set( (Addr) & VG_(helper_div_64_32) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_div_64_32), "div_64_32" );
VGOFF_(helper_idiv_32_16)
- = alloc_BaB_1_set( (Addr) & VG_(helper_idiv_32_16) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_idiv_32_16), "idiv_32_16" );
VGOFF_(helper_div_32_16)
- = alloc_BaB_1_set( (Addr) & VG_(helper_div_32_16) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_div_32_16), "div_32_16" );
VGOFF_(helper_idiv_16_8)
- = alloc_BaB_1_set( (Addr) & VG_(helper_idiv_16_8) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_idiv_16_8), "idiv_16_8" );
VGOFF_(helper_div_16_8)
- = alloc_BaB_1_set( (Addr) & VG_(helper_div_16_8) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_div_16_8), "div_16_8" );
VGOFF_(helper_imul_32_64)
- = alloc_BaB_1_set( (Addr) & VG_(helper_imul_32_64) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_imul_32_64), "imul_32_64" );
VGOFF_(helper_mul_32_64)
- = alloc_BaB_1_set( (Addr) & VG_(helper_mul_32_64) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_mul_32_64), "mul_32_64" );
VGOFF_(helper_imul_16_32)
- = alloc_BaB_1_set( (Addr) & VG_(helper_imul_16_32) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_imul_16_32), "imul_16_32" );
VGOFF_(helper_mul_16_32)
- = alloc_BaB_1_set( (Addr) & VG_(helper_mul_16_32) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_mul_16_32), "mul_16_32" );
VGOFF_(helper_imul_8_16)
- = alloc_BaB_1_set( (Addr) & VG_(helper_imul_8_16) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_imul_8_16), "imul_8_16" );
VGOFF_(helper_mul_8_16)
- = alloc_BaB_1_set( (Addr) & VG_(helper_mul_8_16) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_mul_8_16), "mul_8_16" );
VGOFF_(helper_CLD)
- = alloc_BaB_1_set( (Addr) & VG_(helper_CLD) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_CLD), "helper_CLD" );
VGOFF_(helper_STD)
- = alloc_BaB_1_set( (Addr) & VG_(helper_STD) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_STD), "helper_STD" );
VGOFF_(helper_get_dirflag)
- = alloc_BaB_1_set( (Addr) & VG_(helper_get_dirflag) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_get_dirflag), "get_dirflag" );
VGOFF_(helper_CLC)
- = alloc_BaB_1_set( (Addr) & VG_(helper_CLC) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_CLC), "helper_CLC" );
VGOFF_(helper_STC)
- = alloc_BaB_1_set( (Addr) & VG_(helper_STC) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_STC), "helper_STC" );
VGOFF_(helper_shldl)
- = alloc_BaB_1_set( (Addr) & VG_(helper_shldl) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_shldl), "helper_shldl" );
VGOFF_(helper_shldw)
- = alloc_BaB_1_set( (Addr) & VG_(helper_shldw) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_shldw), "helper_shldw" );
VGOFF_(helper_shrdl)
- = alloc_BaB_1_set( (Addr) & VG_(helper_shrdl) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_shrdl), "helper_shrdl" );
VGOFF_(helper_shrdw)
- = alloc_BaB_1_set( (Addr) & VG_(helper_shrdw) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_shrdw), "helper_shrdw" );
VGOFF_(helper_RDTSC)
- = alloc_BaB_1_set( (Addr) & VG_(helper_RDTSC) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_RDTSC), "helper_RDTSC" );
VGOFF_(helper_CPUID)
- = alloc_BaB_1_set( (Addr) & VG_(helper_CPUID) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_CPUID), "helper_CPUID" );
VGOFF_(helper_bsf)
- = alloc_BaB_1_set( (Addr) & VG_(helper_bsf) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_bsf), "helper_bsf" );
VGOFF_(helper_bsr)
- = alloc_BaB_1_set( (Addr) & VG_(helper_bsr) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_bsr), "helper_bsr" );
VGOFF_(helper_fstsw_AX)
- = alloc_BaB_1_set( (Addr) & VG_(helper_fstsw_AX) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_fstsw_AX), "fstsw_AX" );
VGOFF_(helper_SAHF)
- = alloc_BaB_1_set( (Addr) & VG_(helper_SAHF) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_SAHF), "SAHF" );
VGOFF_(helper_LAHF)
- = alloc_BaB_1_set( (Addr) & VG_(helper_LAHF) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_LAHF), "LAHF" );
VGOFF_(helper_DAS)
- = alloc_BaB_1_set( (Addr) & VG_(helper_DAS) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_DAS), "DAS" );
VGOFF_(helper_DAA)
- = alloc_BaB_1_set( (Addr) & VG_(helper_DAA) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_DAA), "DAA" );
+ VGOFF_(helper_IN)
+ = alloc_BaB_1_set( (Addr) & VG_(helper_IN), "IN" );
+ VGOFF_(helper_OUT)
+ = alloc_BaB_1_set( (Addr) & VG_(helper_OUT), "OUT" );
VGOFF_(helper_undefined_instruction)
- = alloc_BaB_1_set( (Addr) & VG_(helper_undefined_instruction) );
+ = alloc_BaB_1_set( (Addr) & VG_(helper_undefined_instruction), "undefined" );
/* Allocate slots for noncompact helpers */
assign_helpers_in_baseBlock(VG_(n_noncompact_helpers),
uInstr2(cb, PUT, size, TempReg, tmp, ArchReg, ge_reg);
}
-
/* Handle binary integer instructions of the form
op E, G meaning
op reg-or-mem, reg
VG_(printf)("xlat%c [ebx]\n", nameISize(sz));
break;
+ /* ------------------------ IN / OUT ----------------------- */
+
+ case 0xE4: /* IN ib, %al */
+ case 0xE5: /* IN ib, %{e}ax */
+ case 0xEC: /* IN (%dx),%al */
+ case 0xED: /* IN (%dx),%{e}ax */
+ t1 = newTemp(cb);
+ t2 = newTemp(cb);
+ t3 = newTemp(cb);
+
+ uInstr0(cb, CALLM_S, 0);
+ /* operand size? */
+ uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
+ uLiteral(cb, ( opc == 0xE4 || opc == 0xEC ) ? 1 : sz);
+ uInstr1(cb, PUSH, 4, TempReg, t1);
+ /* port number ? */
+ if ( opc == 0xE4 || opc == 0xE5 ) {
+ abyte = getUChar(eip); eip++;
+ uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
+ uLiteral(cb, abyte);
+ }
+ else
+ uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
+
+ uInstr1(cb, PUSH, 4, TempReg, t2);
+ uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_IN));
+ uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
+ uInstr1(cb, POP, 4, TempReg, t2);
+ uInstr1(cb, CLEAR, 0, Lit16, 4);
+ uInstr0(cb, CALLM_E, 0);
+ uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EAX);
+ if (dis) {
+ if ( opc == 0xE4 || opc == 0xE5 )
+ VG_(printf)("in 0x%x, %%eax/%%ax/%%al\n", getUChar(eip-1) );
+ else
+ VG_(printf)("in (%%dx), %%eax/%%ax/%%al\n");
+ }
+ break;
+ case 0xE6: /* OUT %al,ib */
+ case 0xE7: /* OUT %{e}ax,ib */
+ case 0xEE: /* OUT %al,(%dx) */
+ case 0xEF: /* OUT %{e}ax,(%dx) */
+ t1 = newTemp(cb);
+ t2 = newTemp(cb);
+ t3 = newTemp(cb);
+
+ uInstr0(cb, CALLM_S, 0);
+ /* operand size? */
+ uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
+ uLiteral(cb, ( opc == 0xE6 || opc == 0xEE ) ? 1 : sz);
+ uInstr1(cb, PUSH, 4, TempReg, t1);
+ /* port number ? */
+ if ( opc == 0xE6 || opc == 0xE7 ) {
+ abyte = getUChar(eip); eip++;
+ uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
+ uLiteral(cb, abyte);
+ }
+ else
+ uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
+ uInstr1(cb, PUSH, 4, TempReg, t2);
+ uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t3);
+ uInstr1(cb, PUSH, 4, TempReg, t3);
+ uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_OUT));
+ uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
+ uInstr1(cb, CLEAR, 0, Lit16, 12);
+ uInstr0(cb, CALLM_E, 0);
+ if (dis) {
+ if ( opc == 0xE4 || opc == 0xE5 )
+ VG_(printf)("out %%eax/%%ax/%%al, 0x%x\n", getUChar(eip-1) );
+ else
+ VG_(printf)("out %%eax/%%ax/%%al, (%%dx)\n");
+ }
+ break;
+
/* ------------------------ (Grp1 extensions) ---------- */
case 0x80: /* Grp1 Ib,Eb */
/* Ensure there's enough space in a block to add one uinstr. */
-static __inline__
+static
void ensureUInstr ( UCodeBlock* cb )
{
if (cb->used == cb->size) {
extern Int VGOFF_(helper_RDTSC);
extern Int VGOFF_(helper_CPUID);
+extern Int VGOFF_(helper_IN);
+extern Int VGOFF_(helper_OUT);
+
extern Int VGOFF_(helper_bsf);
extern Int VGOFF_(helper_bsr);