vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

rts.S (7376B)


      1 //
      2 // Assembly-language runtime support for translated vx32 code.
      3 //
      4 
      5 #include "libvx32/asm.h"
      6 #include "libvx32/os.h"
      7 
      8 
      9 // The method we use to get back out to host code differs for 32/64-bit hosts.
     10 #ifdef __i386
     11 #ifdef __APPLE__
     12 #define RETURN	jmp	vxrun_return_stub
     13 	.section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5
     14 vxrun_return_stub:
     15 	.indirect_symbol EXT(vxrun_return)
     16 	hlt ; hlt ; hlt ; hlt ; hlt
     17 #else	// i386, not APPLE
     18 #define RETURN	jmp	EXT(vxrun_return)
     19 #endif	// i386, not APPLE
     20 #else	// x86-64
     21 #define	RETURN	ljmpl	*VSEG:VXEMU_RETPTR
     22 #endif
     23 
     24 
     25 	.text
     26 
     27 	// All the following runtime support code is 32-bit
     28 	// (even on 64-bit hosts).
     29 	.code32
     30 
     31 	.globl	EXT(vx_rts_S_start)
     32 EXT(vx_rts_S_start):
     33 
     34 
     35 // Look up a vx32 EIP and jump to the corresponding translated code entrypoint,
     36 // then back-patching the calling instruction to point to the translated code.
     37 //
     38 // Called from trampolines embedded out-of-line in translated code.
     39 // The inline jmp/jcc instruction looks like this:
     40 //		jmp	2f		// ALWAYS uses a rel32, not a rel8
     41 //	1:
     42 //
     43 // A translated call instruction is the same, except prefixed by:
     44 //		pushl	$<return_eip>
     45 //
     46 // Then the out-of-line trampoline code looks like this:
     47 //	2:	movl	$3f,VSEG:vx_jmpinfo
     48 //		jmp	vx_lookup_backpatch
     49 //	3:	.long	dest_eip
     50 //		.long	3b-1b		// offset of jmp inst to backpatch
     51 //
     52 	.globl	EXT(vxrun_lookup_backpatch)
     53 EXT(vxrun_lookup_backpatch):
     54 
     55 	// Save registers we'll need, and load the jump information.
     56 	movl	%edx,VSEG:VXEMU_EDX
     57 	movl	VSEG:VXEMU_JMPINFO,%edx	// edx: jmpinfo pointer
     58 	movl	%ebx,VSEG:VXEMU_EBX
     59 	movl	VSEG:(%edx),%ebx	// ebx: target eip
     60 	movl	%ecx,VSEG:VXEMU_ECX
     61 	movl	%ebx,%ecx		// ecx: target eip
     62 	movl	%eax,VSEG:VXEMU_EAX
     63 
     64 	// Save condition codes (except for DF, which we don't modify here).
     65 	// We use LAHF and SAHF instead of pushf/popf because the latter
     66 	// would require us to reload the stack segment, which is slow.
     67 	// But unfortunately the OF is not in the low 8 bits of EFLAGS
     68 	// covered by LAHF/SAHF, so we have to save that flag separately.
     69 	lahf		// Copy low 8 bits of EFLAGS into AH
     70 	seto	%al	// Set %al to 0x00 or 0xff according to OF
     71 
     72 	// Hash the vx32 target EIP into ecx.
     73 	shrl	$10,%ecx
     74 	addl	%ebx,%ecx
     75 	shrl	$10,%ecx
     76 	subl	%ebx,%ecx
     77 
     78 1:	// Look up the appropriate hash table entry
     79 	andl	VSEG:VXEMU_ETABMASK,%ecx
     80 	cmpl	VSEG:VXEMU_ETAB(,%ecx,8),%ebx
     81 	jne	2f
     82 
     83 	// Found the correct entry!
     84 	// Get the translated code entrypoint into ebx.
     85 	movl	VSEG:VXEMU_ETAB+4(,%ecx,8),%ebx
     86 
     87 	// Backpatch the original jmp instruction with this translated target.
     88 	// %edx still points to the jmpinfo structure.
     89 	movl	VSEG:4(%edx),%edx	// find end of original jmp insn
     90 	lea	7(%ebx),%ecx		// skip target's load-ebx prolog
     91 	subl	%edx,%ecx		// form 32-bit relative jmp target
     92 	subl	VSEG:VXEMU_EMUPTR,%edx	// form vxemu-relative jmp insn offset
     93 	movl	%ecx,VSEG:-4(%edx)	// patch jmp insn
     94 
     95 	// Restore condition codes.
     96 	shrb	$1,%al	// Restore overflow flag
     97 	sahf		// Restore low 8 bits of EFLAGS
     98 
     99 	// Restore other registers
    100 	movl	VSEG:VXEMU_EAX,%eax
    101 	movl	VSEG:VXEMU_ECX,%ecx
    102 	movl	VSEG:VXEMU_EDX,%edx
    103 
    104 	// Jump to appropriate translated code entrypoint.
    105 	// The translated code will restore ebx before doing anything else.
    106 	jmp	*%ebx
    107 
    108 2:	// Not the correct entry - walk forward until we find
    109 	// the correct entry or the first empty one.
    110 	incl	%ecx
    111 	cmpl	$-1,VSEG:VXEMU_ETAB-8(,%ecx,8)	// XX NULLSRCEIP
    112 	jne	1b
    113 
    114 3:	// No correct entry - drop back to C to translate more code.
    115 
    116 	// Save EIP that we were trying to jump to
    117 	movl	%ebx,VSEG:VXEMU_EIP
    118 
    119 	// Restore condition codes
    120 	shrb	$1,%al	// Restore overflow flag
    121 	sahf		// Restore low 8 bits of EFLAGS
    122 
    123 	// Indicate that we're returning due to a translation miss
    124 	movl	$0,%eax		// Careful not to trash condition codes
    125 
    126 	// Return to host code.
    127 	RETURN
    128 
    129 
    130 
    131 // Look up a vx32 EIP and jump to the corresponding translated code entrypoint,
    132 // without backpatching.  Used to handle indirect jmps and calls.
    133 //
    134 // The generated code for an indirect jump looks basically like this:
    135 //		movl	%ebx,VSEG:VXEMU_EBX
    136 //		movl	<indirect_ea>,%ebx
    137 //		jmp	vx_lookup_indirect
    138 //
    139 // The generated code for an indirect call is as follows:
    140 //		movl	%ebx,VSEG:VXEMU_EBX
    141 //		movl	<indirect_ea>,%ebx
    142 //		pushl	$<return_eip>
    143 //		jmp	vx_lookup_indirect
    144 //
    145 // Finally, the code generated for a RET instruction looks like this:
    146 //		movl	%ebx,VSEG:VXEMU_EBX
    147 //		popl	%ebx
    148 //		jmp	vx_lookup_indirect
    149 //
    150 	.p2align 4
    151 	.globl	EXT(vxrun_lookup_indirect)
    152 EXT(vxrun_lookup_indirect):
    153 
    154 	// Save more registers we'll need
    155 	movl	%eax,VSEG:VXEMU_EAX
    156 	movl	%ecx,VSEG:VXEMU_ECX
    157 
    158 	// Save condition codes (except for DF, which we don't modify here).
    159 	// We use LAHF and SAHF instead of pushf/popf because the latter
    160 	// would require us to reload the stack segment, which is slow.
    161 	// But unfortunately the OF is not in the low 8 bits of EFLAGS
    162 	// covered by LAHF/SAHF, so we have to save that flag separately.
    163 	lahf		// Copy low 8 bits of EFLAGS into AH
    164 	seto	%al	// Set %al to 0x00 or 0xff according to OF
    165 
    166 	// Hash the vx32 EIP into ecx.
    167 	movl	%ebx,%ecx
    168 	shrl	$10,%ecx
    169 	addl	%ebx,%ecx
    170 	shrl	$10,%ecx
    171 	subl	%ebx,%ecx
    172 
    173 1:	// Look up the appropriate hash table entry
    174 	andl	VSEG:VXEMU_ETABMASK,%ecx
    175 	cmpl	VSEG:VXEMU_ETAB(,%ecx,8),%ebx
    176 	jne	2f
    177 
    178 	// Found the correct entry!
    179 	// Get the translated code entrypoint into ebx.
    180 	movl	VSEG:VXEMU_ETAB+4(,%ecx,8),%ebx
    181 
    182 	// Restore condition codes.
    183 	shrb	$1,%al	// Restore overflow flag
    184 	sahf		// Restore low 8 bits of EFLAGS
    185 
    186 	// Restore other registers
    187 	movl	VSEG:VXEMU_EAX,%eax
    188 	movl	VSEG:VXEMU_ECX,%ecx
    189 
    190 	// Jump to appropriate translated code entrypoint.
    191 	// The translated code will restore ebx before doing anything else.
    192 	jmp	*%ebx
    193 
    194 2:	// Not the correct entry - walk forward until we find
    195 	// the correct entry or the first empty one.
    196 	incl	%ecx
    197 	cmpl	$-1,VSEG:VXEMU_ETAB-8(,%ecx,8)	// XX NULLSRCEIP
    198 	jne	1b
    199 
    200 3:	// No correct entry - drop back to C to translate more code.
    201 	movl	%edx,VSEG:VXEMU_EDX
    202 
    203 	// Save EIP that we were trying to jump to
    204 	movl	%ebx,VSEG:VXEMU_EIP
    205 
    206 	// Restore condition codes
    207 	shrb	$1,%al	// Restore overflow flag
    208 	sahf		// Restore low 8 bits of EFLAGS
    209 
    210 	// Indicate that we're returning due to a translation miss
    211 	movl	$0,%eax		// Careful not to trash condition codes
    212 
    213 	// Jump to host code.
    214 	RETURN
    215 
    216 
    217 // Return from running translated code, generating a VX trap.
    218 // Assumes the environment's EAX has already been saved
    219 // and EAX now contains the trap code to return.
    220 	.p2align 4
    221 	.globl	EXT(vxrun_gentrap)
    222 EXT(vxrun_gentrap):
    223 gentrap:
    224 	movl	%ebx,VSEG:VXEMU_EBX
    225 	movl	%ecx,VSEG:VXEMU_ECX
    226 	movl	%edx,VSEG:VXEMU_EDX
    227 	// vxrun_return will save the others
    228 
    229 	// Besides returning it, also record trap number in emu struct.
    230 	movl	%eax,VSEG:VXEMU_TRAPNO
    231 
    232 	RETURN
    233 
    234 
    235 // Special "pseudo-fragment" entrypoint used as the dstip
    236 // for unused entries in the entrypoint hash table.
    237 // The corresponding srcip in unused entries is -1, an invalid VX address.
    238 // This way we can keep the unused entry check
    239 // off the critical "cache hit" path for collision-free entrypoint lookups:
    240 // if VX code does jump to address -1, it'll just wind up here.
    241 	.globl	EXT(vxrun_nullfrag)
    242 EXT(vxrun_nullfrag):
    243 	movl	VSEG:VXEMU_EBX,%ebx	// standard fragment prolog
    244 	movl	%eax,VSEG:VXEMU_EAX	// standard trap generation code
    245 	movl	$0x106,%eax		// VXTRAP_INVALID
    246 	jmp	gentrap
    247 
    248 
    249 	.globl	EXT(vx_rts_S_end)
    250 EXT(vx_rts_S_end):