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):