rts.S - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) 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):