/[gxemul]/trunk/src/bintrans_i386.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /trunk/src/bintrans_i386.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (hide annotations)
Mon Oct 8 16:18:27 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 84898 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.815 2005/06/27 23:04:35 debug Exp $
20050617	Experimenting some more with netbooting OpenBSD/sgi. Adding
		a hack which allows emulated ethernet networks to be
		distributed across multiple emulator processes.
20050618	Minor updates (documentation, dummy YAMON emulation, etc).
20050620	strcpy/strcat -> strlcpy/strlcat updates.
		Some more progress on evbmips (Malta).
20050621	Adding a section to doc/configfiles.html about ethernet
		emulation across multiple hosts.
		Beginning the work on the ARM translation engine (using the
		dynamic-but-not-binary translation method).
		Fixing a bintrans bug: 0x9fc00000 should always be treated as
		PROM area, just as 0xbfc00000 is.
		Minor progress on Malta emulation (the PCI-ISA bus).
20050622	NetBSD/evbmips can now be installed (using another emulated
		machine) and run (including userland and so on). :-)
		Spliting up the bintrans haddr_entry field into two (one for
		read, one for write). Probably not much of a speed increase,
		though.
		Updating some NetBSD 2.0 -> 2.0.2 in the documentation.
20050623	Minor updates (documentation, the TODO file, etc).
		gzipped kernels are now always automagically gunzipped when
		loaded.
20050624	Adding a dummy Playstation Portable (PSP) mode, just barely
		enough to run Hello World (in weird colors :-).
		Removing the -b command line option; old bintrans is enabled
		by default instead. It makes more sense.
		Trying to finally fix the non-working performance measurement
		thing (instr/second etc).
20050625	Continuing on the essential basics for ARM emulation. Two
		instructions seem to work, a branch and a simple "mov". (The
		mov arguments are not correct yet.) Performance is definitely
		reasonable.
		Various other minor updates.
		Adding the ARM "bl" instruction.
		Adding support for combining multiple ARM instructions into one
		function call. ("mov" + "mov" is the only one implemented so
		far, but it seems to work.)
		Cleaning up some IP32 interrupt things (crime/mace); disabling
		the PS/2 keyboard controller on IP32, so that NetBSD/sgimips
		boots into userland again.
20050626	Finally! NetBSD/sgimips netboots. Adding instructions to
		doc/guestoses.html on how to set up an nfs server etc.
		Various other minor fixes.
		Playstation Portable ".pbp" files can now be used directly.
		(The ELF part of the .pbp is extracted transparently.)
		Converting some sprintf -> snprintf.
		Adding some more instructions to the ARM disassembler.
20050627	More ARM updates. Adding some simple ldr(b), str(b),
		cmps, and conditional branch instructions, enough to run
		a simple Hello World program.
		All ARM instructions are now inlined/generated for all possible
		condition codes.
		Adding add and sub, and more load/store instructions.
		Removing dummy files: cpu_alpha.c, cpu_hppa.c, and cpu_sparc.c.
		Some minor documentation updates; preparing for a 0.3.4
		release. Updating some URLs.

==============  RELEASE 0.3.4  ==============


1 dpavlin 2 /*
2     * Copyright (C) 2004-2005 Anders Gavare. All rights reserved.
3     *
4     * Redistribution and use in source and binary forms, with or without
5     * modification, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright
8     * notice, this list of conditions and the following disclaimer.
9     * 2. Redistributions in binary form must reproduce the above copyright
10     * notice, this list of conditions and the following disclaimer in the
11     * documentation and/or other materials provided with the distribution.
12     * 3. The name of the author may not be used to endorse or promote products
13     * derived from this software without specific prior written permission.
14     *
15     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18     * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25     * SUCH DAMAGE.
26     *
27     *
28 dpavlin 10 * $Id: bintrans_i386.c,v 1.76 2005/06/22 10:12:25 debug Exp $
29 dpavlin 2 *
30     * i386 specific code for dynamic binary translation.
31     * See bintrans.c for more information. Included from bintrans.c.
32     *
33     * Translated code uses the following conventions at all time:
34     *
35     * esi points to the cpu struct
36     * edi lowest 32 bits of cpu->pc
37     * ebp contains cpu->bintrans_instructions_executed
38     */
39    
40    
41     struct cpu dummy_cpu;
42     struct mips_coproc dummy_coproc;
43     struct vth32_table dummy_vth32_table;
44    
45    
46     /*
47     * bintrans_host_cacheinvalidate()
48     *
49     * Invalidate the host's instruction cache. On i386, this isn't necessary,
50     * so this is an empty function.
51     */
52     static void bintrans_host_cacheinvalidate(unsigned char *p, size_t len)
53     {
54     /* Do nothing. */
55     }
56    
57    
58     /* offsetof (in stdarg.h) could possibly be used, but I'm not sure
59     if it will take care of the compiler problems... */
60    
61     #define ofs_i (((size_t)&dummy_cpu.cd.mips.bintrans_instructions_executed) - ((size_t)&dummy_cpu))
62     #define ofs_pc (((size_t)&dummy_cpu.pc) - ((size_t)&dummy_cpu))
63     #define ofs_pc_last (((size_t)&dummy_cpu.cd.mips.pc_last) - ((size_t)&dummy_cpu))
64     #define ofs_tabl0 (((size_t)&dummy_cpu.cd.mips.vaddr_to_hostaddr_table0) - ((size_t)&dummy_cpu))
65     #define ofs_chunks ((size_t)&dummy_vth32_table.bintrans_chunks[0] - (size_t)&dummy_vth32_table)
66     #define ofs_chunkbase ((size_t)&dummy_cpu.cd.mips.chunk_base_address - (size_t)&dummy_cpu)
67    
68    
69     static void (*bintrans_runchunk)(struct cpu *, unsigned char *);
70     static void (*bintrans_jump_to_32bit_pc)(struct cpu *);
71 dpavlin 10 static void (*bintrans_load_32bit)(struct cpu *);
72     static void (*bintrans_store_32bit)(struct cpu *);
73 dpavlin 2
74    
75     /*
76     * bintrans_write_quickjump():
77     */
78     static void bintrans_write_quickjump(struct memory *mem,
79     unsigned char *quickjump_code, uint32_t chunkoffset)
80     {
81     uint32_t i386_addr;
82     unsigned char *a = quickjump_code;
83    
84     i386_addr = chunkoffset + (size_t)mem->translation_code_chunk_space;
85     i386_addr = i386_addr - ((size_t)a + 5);
86    
87     /* printf("chunkoffset=%i, %08x %08x %i\n",
88     chunkoffset, i386_addr, a, ofs); */
89    
90     *a++ = 0xe9;
91     *a++ = i386_addr;
92     *a++ = i386_addr >> 8;
93     *a++ = i386_addr >> 16;
94     *a++ = i386_addr >> 24;
95     }
96    
97    
98     /*
99     * bintrans_write_chunkreturn():
100     */
101     static void bintrans_write_chunkreturn(unsigned char **addrp)
102     {
103     unsigned char *a = *addrp;
104     *a++ = 0xc3; /* ret */
105     *addrp = a;
106     }
107    
108    
109     /*
110     * bintrans_write_chunkreturn_fail():
111     */
112     static void bintrans_write_chunkreturn_fail(unsigned char **addrp)
113     {
114     unsigned char *a = *addrp;
115    
116     /* 81 cd 00 00 00 01 orl $0x1000000,%ebp */
117     *a++ = 0x81; *a++ = 0xcd;
118     *a++ = 0; *a++ = 0; *a++ = 0; *a++ = 0x01; /* TODO: not hardcoded */
119    
120     *a++ = 0xc3; /* ret */
121     *addrp = a;
122     }
123    
124    
125     /*
126     * bintrans_write_pc_inc():
127     */
128     static void bintrans_write_pc_inc(unsigned char **addrp)
129     {
130     unsigned char *a = *addrp;
131    
132     /* 83 c7 04 add $0x4,%edi */
133     *a++ = 0x83; *a++ = 0xc7; *a++ = 4;
134    
135     #if 0
136     if (!bintrans_32bit_only) {
137     int ofs;
138     /* 83 96 zz zz zz zz 00 adcl $0x0,zz(%esi) */
139     ofs = ((size_t)&dummy_cpu.pc) - (size_t)&dummy_cpu;
140     ofs += 4;
141     *a++ = 0x83; *a++ = 0x96;
142     *a++ = ofs & 255;
143     *a++ = (ofs >> 8) & 255;
144     *a++ = (ofs >> 16) & 255;
145     *a++ = (ofs >> 24) & 255;
146     *a++ = 0;
147     }
148     #endif
149    
150     /* 45 inc %ebp */
151     *a++ = 0x45;
152    
153     *addrp = a;
154     }
155    
156    
157     /*
158     * load_pc_into_eax_edx():
159     */
160     static void load_pc_into_eax_edx(unsigned char **addrp)
161     {
162     unsigned char *a;
163     a = *addrp;
164    
165     /* 89 f8 mov %edi,%eax */
166     *a++ = 0x89; *a++ = 0xf8;
167    
168     #if 0
169     if (bintrans_32bit_only) {
170     /* 99 cltd */
171     *a++ = 0x99;
172     } else
173     #endif
174     {
175     int ofs = ((size_t)&dummy_cpu.pc) - (size_t)&dummy_cpu;
176     /* 8b 96 3c 30 00 00 mov 0x303c(%esi),%edx */
177     ofs += 4;
178     *a++ = 0x8b; *a++ = 0x96;
179     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
180     }
181    
182     *addrp = a;
183     }
184    
185    
186     /*
187     * store_eax_edx_into_pc():
188     */
189     static void store_eax_edx_into_pc(unsigned char **addrp)
190     {
191     unsigned char *a;
192     int ofs = ((size_t)&dummy_cpu.pc) - (size_t)&dummy_cpu;
193     a = *addrp;
194    
195     /* 89 c7 mov %eax,%edi */
196     *a++ = 0x89; *a++ = 0xc7;
197    
198     /* 89 96 3c 30 00 00 mov %edx,0x303c(%esi) */
199     ofs += 4;
200     *a++ = 0x89; *a++ = 0x96;
201     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
202    
203     *addrp = a;
204     }
205    
206    
207     /*
208     * load_into_eax_edx():
209     *
210     * Usage: load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rs]); etc.
211     */
212     static void load_into_eax_edx(unsigned char **addrp, void *p)
213     {
214     unsigned char *a;
215     int ofs = (size_t)p - (size_t)&dummy_cpu;
216     a = *addrp;
217    
218     /* 8b 86 38 30 00 00 mov 0x3038(%esi),%eax */
219     *a++ = 0x8b; *a++ = 0x86;
220     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
221    
222     #if 0
223     if (bintrans_32bit_only) {
224     /* 99 cltd */
225     *a++ = 0x99;
226     } else
227     #endif
228     {
229     /* 8b 96 3c 30 00 00 mov 0x303c(%esi),%edx */
230     ofs += 4;
231     *a++ = 0x8b; *a++ = 0x96;
232     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
233     }
234    
235     *addrp = a;
236     }
237    
238    
239     /*
240     * load_into_eax_and_sign_extend_into_edx():
241     *
242     * Usage: load_into_eax_and_sign_extend_into_edx(&a, &dummy_cpu.cd.mips.gpr[rs]); etc.
243     */
244     static void load_into_eax_and_sign_extend_into_edx(unsigned char **addrp, void *p)
245     {
246     unsigned char *a;
247     int ofs = (size_t)p - (size_t)&dummy_cpu;
248     a = *addrp;
249    
250     /* 8b 86 38 30 00 00 mov 0x3038(%esi),%eax */
251     *a++ = 0x8b; *a++ = 0x86;
252     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
253    
254     /* 99 cltd */
255     *a++ = 0x99;
256    
257     *addrp = a;
258     }
259    
260    
261     /*
262     * load_into_eax_dont_care_about_edx():
263     *
264     * Usage: load_into_eax_dont_care_about_edx(&a, &dummy_cpu.cd.mips.gpr[rs]); etc.
265     */
266     static void load_into_eax_dont_care_about_edx(unsigned char **addrp, void *p)
267     {
268     unsigned char *a;
269     int ofs = (size_t)p - (size_t)&dummy_cpu;
270     a = *addrp;
271    
272     /* 8b 86 38 30 00 00 mov 0x3038(%esi),%eax */
273     *a++ = 0x8b; *a++ = 0x86;
274     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
275    
276     *addrp = a;
277     }
278    
279    
280     /*
281     * store_eax_edx():
282     *
283     * Usage: store_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rs]); etc.
284     */
285     static void store_eax_edx(unsigned char **addrp, void *p)
286     {
287     unsigned char *a;
288     int ofs = (size_t)p - (size_t)&dummy_cpu;
289     a = *addrp;
290    
291     /* 89 86 38 30 00 00 mov %eax,0x3038(%esi) */
292     *a++ = 0x89; *a++ = 0x86;
293     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
294    
295     /* 89 96 3c 30 00 00 mov %edx,0x303c(%esi) */
296     ofs += 4;
297     *a++ = 0x89; *a++ = 0x96;
298     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
299    
300     *addrp = a;
301     }
302    
303    
304     /*
305     * bintrans_write_instruction__lui():
306     */
307     static int bintrans_write_instruction__lui(unsigned char **addrp, int rt, int imm)
308     {
309     unsigned char *a;
310    
311     a = *addrp;
312     if (rt == 0)
313     goto rt0;
314    
315     /* b8 00 00 dc fe mov $0xfedc0000,%eax */
316     *a++ = 0xb8; *a++ = 0; *a++ = 0;
317     *a++ = imm & 255; *a++ = imm >> 8;
318    
319     /* 99 cltd */
320     *a++ = 0x99;
321    
322     store_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
323     *addrp = a;
324    
325     rt0:
326     bintrans_write_pc_inc(addrp);
327     return 1;
328     }
329    
330    
331     /*
332     * bintrans_write_instruction__jr():
333     */
334     static int bintrans_write_instruction__jr(unsigned char **addrp,
335     int rs, int rd, int special)
336     {
337     unsigned char *a;
338     int ofs;
339    
340     a = *addrp;
341    
342     /*
343     * Perform the jump by setting cpu->delay_slot = TO_BE_DELAYED
344     * and cpu->delay_jmpaddr = gpr[rs].
345     */
346    
347     /* c7 86 38 30 00 00 01 00 00 00 movl $0x1,0x3038(%esi) */
348     ofs = ((size_t)&dummy_cpu.cd.mips.delay_slot) - (size_t)&dummy_cpu;
349     *a++ = 0xc7; *a++ = 0x86;
350     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
351     *a++ = TO_BE_DELAYED; *a++ = 0; *a++ = 0; *a++ = 0;
352    
353     #if 0
354     if (bintrans_32bit_only)
355     load_into_eax_and_sign_extend_into_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
356     else
357     #endif
358     load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
359    
360     store_eax_edx(&a, &dummy_cpu.cd.mips.delay_jmpaddr);
361    
362     if (special == SPECIAL_JALR && rd != 0) {
363     /* gpr[rd] = retaddr (pc + 8) */
364    
365     #if 0
366     if (bintrans_32bit_only) {
367     load_pc_into_eax_edx(&a);
368     /* 83 c0 08 add $0x8,%eax */
369     *a++ = 0x83; *a++ = 0xc0; *a++ = 0x08;
370     } else
371     #endif
372     {
373     load_pc_into_eax_edx(&a);
374     /* 83 c0 08 add $0x8,%eax */
375     /* 83 d2 00 adc $0x0,%edx */
376     *a++ = 0x83; *a++ = 0xc0; *a++ = 0x08;
377     *a++ = 0x83; *a++ = 0xd2; *a++ = 0x00;
378     }
379    
380     store_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rd]);
381     }
382    
383     *addrp = a;
384     bintrans_write_pc_inc(addrp);
385     return 1;
386     }
387    
388    
389     /*
390     * bintrans_write_instruction__mfmthilo():
391     */
392     static int bintrans_write_instruction__mfmthilo(unsigned char **addrp,
393     int rd, int from_flag, int hi_flag)
394     {
395     unsigned char *a;
396    
397     a = *addrp;
398    
399     if (from_flag) {
400     if (rd != 0) {
401     /* mfhi or mflo */
402     if (hi_flag)
403     load_into_eax_edx(&a, &dummy_cpu.cd.mips.hi);
404     else
405     load_into_eax_edx(&a, &dummy_cpu.cd.mips.lo);
406     store_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rd]);
407     }
408     } else {
409     /* mthi or mtlo */
410     load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rd]);
411     if (hi_flag)
412     store_eax_edx(&a, &dummy_cpu.cd.mips.hi);
413     else
414     store_eax_edx(&a, &dummy_cpu.cd.mips.lo);
415     }
416    
417     *addrp = a;
418     bintrans_write_pc_inc(addrp);
419     return 1;
420     }
421    
422    
423     /*
424     * bintrans_write_instruction__addiu_etc():
425     */
426     static int bintrans_write_instruction__addiu_etc(unsigned char **addrp,
427     int rt, int rs, int imm, int instruction_type)
428     {
429     unsigned char *a;
430     unsigned int uimm;
431    
432     /* TODO: overflow detection for ADDI and DADDI */
433     switch (instruction_type) {
434     case HI6_ADDI:
435     case HI6_DADDI:
436     return 0;
437     }
438    
439     a = *addrp;
440    
441     if (rt == 0)
442     goto rt0;
443    
444     uimm = imm & 0xffff;
445    
446     if (uimm == 0 && (instruction_type == HI6_ADDIU ||
447     instruction_type == HI6_ADDI)) {
448     load_into_eax_and_sign_extend_into_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
449     store_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
450     goto rt0;
451     }
452    
453     if (uimm == 0 && (instruction_type == HI6_DADDIU ||
454     instruction_type == HI6_DADDI || instruction_type == HI6_ORI)) {
455     load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
456     store_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
457     goto rt0;
458     }
459    
460     #if 0
461     if (bintrans_32bit_only)
462     load_into_eax_and_sign_extend_into_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
463     else
464     #endif
465     load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
466    
467     switch (instruction_type) {
468     case HI6_ADDIU:
469     case HI6_DADDIU:
470     case HI6_ADDI:
471     case HI6_DADDI:
472     if (imm & 0x8000) {
473     /* 05 39 fd ff ff add $0xfffffd39,%eax */
474     /* 83 d2 ff adc $0xffffffff,%edx */
475     *a++ = 0x05; *a++ = uimm; *a++ = uimm >> 8; *a++ = 0xff; *a++ = 0xff;
476     if (instruction_type == HI6_DADDIU) {
477     *a++ = 0x83; *a++ = 0xd2; *a++ = 0xff;
478     }
479     } else {
480     /* 05 c7 02 00 00 add $0x2c7,%eax */
481     /* 83 d2 00 adc $0x0,%edx */
482     *a++ = 0x05; *a++ = uimm; *a++ = uimm >> 8; *a++ = 0; *a++ = 0;
483     if (instruction_type == HI6_DADDIU) {
484     *a++ = 0x83; *a++ = 0xd2; *a++ = 0;
485     }
486     }
487     if (instruction_type == HI6_ADDIU) {
488     /* 99 cltd */
489     *a++ = 0x99;
490     }
491     break;
492     case HI6_ANDI:
493     /* 25 34 12 00 00 and $0x1234,%eax */
494     /* 31 d2 xor %edx,%edx */
495     *a++ = 0x25; *a++ = uimm; *a++ = uimm >> 8; *a++ = 0; *a++ = 0;
496     *a++ = 0x31; *a++ = 0xd2;
497     break;
498     case HI6_ORI:
499     /* 0d 34 12 00 00 or $0x1234,%eax */
500     *a++ = 0xd; *a++ = uimm; *a++ = uimm >> 8; *a++ = 0; *a++ = 0;
501     break;
502     case HI6_XORI:
503     /* 35 34 12 00 00 xor $0x1234,%eax */
504     *a++ = 0x35; *a++ = uimm; *a++ = uimm >> 8; *a++ = 0; *a++ = 0;
505     break;
506     case HI6_SLTIU:
507     /* set if less than, unsigned. (compare edx:eax to ecx:ebx) */
508     /* ecx:ebx = the immediate value */
509     /* bb dc fe ff ff mov $0xfffffedc,%ebx */
510     /* b9 ff ff ff ff mov $0xffffffff,%ecx */
511     /* or */
512     /* 29 c9 sub %ecx,%ecx */
513     #if 0
514     if (bintrans_32bit_only) {
515     /* 99 cltd */
516     *a++ = 0x99;
517     }
518     #endif
519     *a++ = 0xbb; *a++ = uimm; *a++ = uimm >> 8;
520     if (uimm & 0x8000) {
521     *a++ = 0xff; *a++ = 0xff;
522     *a++ = 0xb9; *a++ = 0xff; *a++ = 0xff; *a++ = 0xff; *a++ = 0xff;
523     } else {
524     *a++ = 0; *a++ = 0;
525     *a++ = 0x29; *a++ = 0xc9;
526     }
527    
528     /* if edx <= ecx and eax < ebx then 1, else 0. */
529     /* 39 ca cmp %ecx,%edx */
530     /* 77 0b ja <ret0> */
531     /* 39 d8 cmp %ebx,%eax */
532     /* 73 07 jae 58 <ret0> */
533     *a++ = 0x39; *a++ = 0xca;
534     *a++ = 0x77; *a++ = 0x0b;
535     *a++ = 0x39; *a++ = 0xd8;
536     *a++ = 0x73; *a++ = 0x07;
537    
538     /* b8 01 00 00 00 mov $0x1,%eax */
539     /* eb 02 jmp <common> */
540     *a++ = 0xb8; *a++ = 1; *a++ = 0; *a++ = 0; *a++ = 0;
541     *a++ = 0xeb; *a++ = 0x02;
542    
543     /* ret0: */
544     /* 29 c0 sub %eax,%eax */
545     *a++ = 0x29; *a++ = 0xc0;
546    
547     /* common: */
548     /* 99 cltd */
549     *a++ = 0x99;
550     break;
551     case HI6_SLTI:
552     /* set if less than, signed. (compare edx:eax to ecx:ebx) */
553     /* ecx:ebx = the immediate value */
554     /* bb dc fe ff ff mov $0xfffffedc,%ebx */
555     /* b9 ff ff ff ff mov $0xffffffff,%ecx */
556     /* or */
557     /* 29 c9 sub %ecx,%ecx */
558     #if 0
559     if (bintrans_32bit_only) {
560     /* 99 cltd */
561     *a++ = 0x99;
562     }
563     #endif
564     *a++ = 0xbb; *a++ = uimm; *a++ = uimm >> 8;
565     if (uimm & 0x8000) {
566     *a++ = 0xff; *a++ = 0xff;
567     *a++ = 0xb9; *a++ = 0xff; *a++ = 0xff; *a++ = 0xff; *a++ = 0xff;
568     } else {
569     *a++ = 0; *a++ = 0;
570     *a++ = 0x29; *a++ = 0xc9;
571     }
572    
573     /* if edx > ecx then 0. */
574     /* if edx < ecx then 1. */
575     /* if eax < ebx then 1, else 0. */
576     /* 39 ca cmp %ecx,%edx */
577     /* 7c 0a jl <ret1> */
578     /* 7f 04 jg <ret0> */
579     /* 39 d8 cmp %ebx,%eax */
580     /* 7c 04 jl <ret1> */
581     *a++ = 0x39; *a++ = 0xca;
582     *a++ = 0x7c; *a++ = 0x0a;
583     *a++ = 0x7f; *a++ = 0x04;
584     *a++ = 0x39; *a++ = 0xd8;
585     *a++ = 0x7c; *a++ = 0x04;
586    
587     /* ret0: */
588     /* 29 c0 sub %eax,%eax */
589     /* eb 05 jmp <common> */
590     *a++ = 0x29; *a++ = 0xc0;
591     *a++ = 0xeb; *a++ = 0x05;
592    
593     /* ret1: */
594     /* b8 01 00 00 00 mov $0x1,%eax */
595     *a++ = 0xb8; *a++ = 1; *a++ = 0; *a++ = 0; *a++ = 0;
596    
597     /* common: */
598     /* 99 cltd */
599     *a++ = 0x99;
600     break;
601     }
602    
603     store_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
604    
605     rt0:
606     *addrp = a;
607     bintrans_write_pc_inc(addrp);
608     return 1;
609     }
610    
611    
612     /*
613     * bintrans_write_instruction__jal():
614     */
615     static int bintrans_write_instruction__jal(unsigned char **addrp,
616     int imm, int link)
617     {
618     unsigned char *a;
619     uint32_t subimm;
620     int ofs;
621    
622     a = *addrp;
623    
624     load_pc_into_eax_edx(&a);
625    
626     if (link) {
627     /* gpr[31] = pc + 8 */
628     #if 0
629     if (bintrans_32bit_only) {
630     /* 50 push %eax */
631     /* 83 c0 08 add $0x8,%eax */
632     *a++ = 0x50;
633     *a++ = 0x83; *a++ = 0xc0; *a++ = 0x08;
634     } else
635     #endif
636     {
637     /* 50 push %eax */
638     /* 52 push %edx */
639     /* 83 c0 08 add $0x8,%eax */
640     /* 83 d2 00 adc $0x0,%edx */
641     *a++ = 0x50;
642     *a++ = 0x52;
643     *a++ = 0x83; *a++ = 0xc0; *a++ = 0x08;
644     *a++ = 0x83; *a++ = 0xd2; *a++ = 0x00;
645     }
646     store_eax_edx(&a, &dummy_cpu.cd.mips.gpr[31]);
647     #if 0
648     if (bintrans_32bit_only) {
649     /* 58 pop %eax */
650     *a++ = 0x58;
651     } else
652     #endif
653     {
654     /* 5a pop %edx */
655     /* 58 pop %eax */
656     *a++ = 0x5a;
657     *a++ = 0x58;
658     }
659     }
660    
661     /* delay_jmpaddr = top 36 bits of pc together with lowest 28 bits of imm*4: */
662     imm *= 4;
663    
664     /* Add 4, because the jump is from the delay slot: */
665     /* 83 c0 04 add $0x4,%eax */
666     /* 83 d2 00 adc $0x0,%edx */
667     *a++ = 0x83; *a++ = 0xc0; *a++ = 0x04;
668     *a++ = 0x83; *a++ = 0xd2; *a++ = 0x00;
669    
670     /* c1 e8 1c shr $0x1c,%eax */
671     /* c1 e0 1c shl $0x1c,%eax */
672     *a++ = 0xc1; *a++ = 0xe8; *a++ = 0x1c;
673     *a++ = 0xc1; *a++ = 0xe0; *a++ = 0x1c;
674    
675     subimm = imm;
676     subimm &= 0x0fffffff;
677    
678     /* 0d 78 56 34 12 or $0x12345678,%eax */
679     *a++ = 0x0d; *a++ = subimm; *a++ = subimm >> 8;
680     *a++ = subimm >> 16; *a++ = subimm >> 24;
681    
682     store_eax_edx(&a, &dummy_cpu.cd.mips.delay_jmpaddr);
683    
684     /* c7 86 38 30 00 00 01 00 00 00 movl $0x1,0x3038(%esi) */
685     ofs = ((size_t)&dummy_cpu.cd.mips.delay_slot) - (size_t)&dummy_cpu;
686     *a++ = 0xc7; *a++ = 0x86;
687     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
688     *a++ = TO_BE_DELAYED; *a++ = 0; *a++ = 0; *a++ = 0;
689    
690     *addrp = a;
691     bintrans_write_pc_inc(addrp);
692     return 1;
693     }
694    
695    
696     /*
697     * bintrans_write_instruction__addu_etc():
698     */
699     static int bintrans_write_instruction__addu_etc(unsigned char **addrp,
700     int rd, int rs, int rt, int sa, int instruction_type)
701     {
702     unsigned char *a;
703     int load64 = 0, do_store = 1;
704    
705     /* TODO: Not yet */
706     switch (instruction_type) {
707     case SPECIAL_MULT:
708     case SPECIAL_MULTU:
709     case SPECIAL_DIV:
710     case SPECIAL_DIVU:
711     if (rd != 0)
712     return 0;
713     break;
714     case SPECIAL_DSLL:
715     case SPECIAL_DSLL32:
716     case SPECIAL_DSRA:
717     case SPECIAL_DSRA32:
718     case SPECIAL_DSRL:
719     case SPECIAL_DSRL32:
720     case SPECIAL_MOVZ:
721     case SPECIAL_MOVN:
722     bintrans_write_chunkreturn_fail(addrp);
723     return 0;
724     }
725    
726     switch (instruction_type) {
727     case SPECIAL_DADDU:
728     case SPECIAL_DSUBU:
729     case SPECIAL_OR:
730     case SPECIAL_AND:
731     case SPECIAL_NOR:
732     case SPECIAL_XOR:
733     case SPECIAL_DSLL:
734     case SPECIAL_DSRL:
735     case SPECIAL_DSRA:
736     case SPECIAL_DSLL32:
737     case SPECIAL_DSRL32:
738     case SPECIAL_DSRA32:
739     case SPECIAL_SLT:
740     case SPECIAL_SLTU:
741     load64 = 1;
742     }
743    
744     switch (instruction_type) {
745     case SPECIAL_MULT:
746     case SPECIAL_MULTU:
747     case SPECIAL_DIV:
748     case SPECIAL_DIVU:
749     break;
750     default:
751     if (rd == 0)
752     goto rd0;
753     }
754    
755     a = *addrp;
756    
757     if ((instruction_type == SPECIAL_ADDU || instruction_type == SPECIAL_DADDU
758     || instruction_type == SPECIAL_OR) && rt == 0) {
759     if (load64)
760     load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
761     else
762     load_into_eax_and_sign_extend_into_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
763     store_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rd]);
764     *addrp = a;
765     goto rd0;
766     }
767    
768     /* edx:eax = rs, ecx:ebx = rt */
769     if (load64) {
770     load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
771     /* 89 c3 mov %eax,%ebx */
772     /* 89 d1 mov %edx,%ecx */
773     *a++ = 0x89; *a++ = 0xc3; *a++ = 0x89; *a++ = 0xd1;
774     load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
775     } else {
776     load_into_eax_and_sign_extend_into_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
777     /* 89 c3 mov %eax,%ebx */
778     /* 89 d1 mov %edx,%ecx */
779     *a++ = 0x89; *a++ = 0xc3; *a++ = 0x89; *a++ = 0xd1;
780     load_into_eax_and_sign_extend_into_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
781     }
782    
783     switch (instruction_type) {
784     case SPECIAL_ADDU:
785     /* 01 d8 add %ebx,%eax */
786     /* 99 cltd */
787     *a++ = 0x01; *a++ = 0xd8;
788     *a++ = 0x99;
789     break;
790     case SPECIAL_DADDU:
791     /* 01 d8 add %ebx,%eax */
792     /* 11 ca adc %ecx,%edx */
793     *a++ = 0x01; *a++ = 0xd8;
794     *a++ = 0x11; *a++ = 0xca;
795     break;
796     case SPECIAL_SUBU:
797     /* 29 d8 sub %ebx,%eax */
798     /* 99 cltd */
799     *a++ = 0x29; *a++ = 0xd8;
800     *a++ = 0x99;
801     break;
802     case SPECIAL_DSUBU:
803     /* 29 d8 sub %ebx,%eax */
804     /* 19 ca sbb %ecx,%edx */
805     *a++ = 0x29; *a++ = 0xd8;
806     *a++ = 0x19; *a++ = 0xca;
807     break;
808     case SPECIAL_AND:
809     /* 21 d8 and %ebx,%eax */
810     /* 21 ca and %ecx,%edx */
811     *a++ = 0x21; *a++ = 0xd8;
812     *a++ = 0x21; *a++ = 0xca;
813     break;
814     case SPECIAL_OR:
815     /* 09 d8 or %ebx,%eax */
816     /* 09 ca or %ecx,%edx */
817     *a++ = 0x09; *a++ = 0xd8;
818     *a++ = 0x09; *a++ = 0xca;
819     break;
820     case SPECIAL_NOR:
821     /* 09 d8 or %ebx,%eax */
822     /* 09 ca or %ecx,%edx */
823     /* f7 d0 not %eax */
824     /* f7 d2 not %edx */
825     *a++ = 0x09; *a++ = 0xd8;
826     *a++ = 0x09; *a++ = 0xca;
827     *a++ = 0xf7; *a++ = 0xd0;
828     *a++ = 0xf7; *a++ = 0xd2;
829     break;
830     case SPECIAL_XOR:
831     /* 31 d8 xor %ebx,%eax */
832     /* 31 ca xor %ecx,%edx */
833     *a++ = 0x31; *a++ = 0xd8;
834     *a++ = 0x31; *a++ = 0xca;
835     break;
836     case SPECIAL_SLL:
837     /* 89 d8 mov %ebx,%eax */
838     /* c1 e0 1f shl $0x1f,%eax */
839     /* 99 cltd */
840     *a++ = 0x89; *a++ = 0xd8;
841     if (sa == 1) {
842     *a++ = 0xd1; *a++ = 0xe0;
843     } else {
844     *a++ = 0xc1; *a++ = 0xe0; *a++ = sa;
845     }
846     *a++ = 0x99;
847     break;
848     case SPECIAL_SRA:
849     /* 89 d8 mov %ebx,%eax */
850     /* c1 f8 1f sar $0x1f,%eax */
851     /* 99 cltd */
852     *a++ = 0x89; *a++ = 0xd8;
853     if (sa == 1) {
854     *a++ = 0xd1; *a++ = 0xf8;
855     } else {
856     *a++ = 0xc1; *a++ = 0xf8; *a++ = sa;
857     }
858     *a++ = 0x99;
859     break;
860     case SPECIAL_SRL:
861     /* 89 d8 mov %ebx,%eax */
862     /* c1 e8 1f shr $0x1f,%eax */
863     /* 99 cltd */
864     *a++ = 0x89; *a++ = 0xd8;
865     if (sa == 1) {
866     *a++ = 0xd1; *a++ = 0xe8;
867     } else {
868     *a++ = 0xc1; *a++ = 0xe8; *a++ = sa;
869     }
870     *a++ = 0x99;
871     break;
872     case SPECIAL_SLTU:
873     /* set if less than, unsigned. (compare edx:eax to ecx:ebx) */
874     /* if edx <= ecx and eax < ebx then 1, else 0. */
875     /* 39 ca cmp %ecx,%edx */
876     /* 77 0b ja <ret0> */
877     /* 39 d8 cmp %ebx,%eax */
878     /* 73 07 jae 58 <ret0> */
879     *a++ = 0x39; *a++ = 0xca;
880     *a++ = 0x77; *a++ = 0x0b;
881     *a++ = 0x39; *a++ = 0xd8;
882     *a++ = 0x73; *a++ = 0x07;
883    
884     /* b8 01 00 00 00 mov $0x1,%eax */
885     /* eb 02 jmp <common> */
886     *a++ = 0xb8; *a++ = 1; *a++ = 0; *a++ = 0; *a++ = 0;
887     *a++ = 0xeb; *a++ = 0x02;
888    
889     /* ret0: */
890     /* 29 c0 sub %eax,%eax */
891     *a++ = 0x29; *a++ = 0xc0;
892    
893     /* common: */
894     /* 99 cltd */
895     *a++ = 0x99;
896     break;
897     case SPECIAL_SLT:
898     /* set if less than, signed. (compare edx:eax to ecx:ebx) */
899     /* if edx > ecx then 0. */
900     /* if edx < ecx then 1. */
901     /* if eax < ebx then 1, else 0. */
902     /* 39 ca cmp %ecx,%edx */
903     /* 7c 0a jl <ret1> */
904     /* 7f 04 jg <ret0> */
905     /* 39 d8 cmp %ebx,%eax */
906     /* 7c 04 jl <ret1> */
907     *a++ = 0x39; *a++ = 0xca;
908     *a++ = 0x7c; *a++ = 0x0a;
909     *a++ = 0x7f; *a++ = 0x04;
910     *a++ = 0x39; *a++ = 0xd8;
911     *a++ = 0x7c; *a++ = 0x04;
912    
913     /* ret0: */
914     /* 29 c0 sub %eax,%eax */
915     /* eb 05 jmp <common> */
916     *a++ = 0x29; *a++ = 0xc0;
917     *a++ = 0xeb; *a++ = 0x05;
918    
919     /* ret1: */
920     /* b8 01 00 00 00 mov $0x1,%eax */
921     *a++ = 0xb8; *a++ = 1; *a++ = 0; *a++ = 0; *a++ = 0;
922    
923     /* common: */
924     /* 99 cltd */
925     *a++ = 0x99;
926     break;
927     case SPECIAL_SLLV:
928     /* rd = rt << (rs&31) (logical) eax = ebx << (eax&31) */
929     /* xchg ebx,eax, then we can do eax = eax << (ebx&31) */
930     /* 93 xchg %eax,%ebx */
931     /* 89 d9 mov %ebx,%ecx */
932     /* 83 e1 1f and $0x1f,%ecx */
933     /* d3 e0 shl %cl,%eax */
934     *a++ = 0x93;
935     *a++ = 0x89; *a++ = 0xd9;
936     *a++ = 0x83; *a++ = 0xe1; *a++ = 0x1f;
937     *a++ = 0xd3; *a++ = 0xe0;
938     /* 99 cltd */
939     *a++ = 0x99;
940     break;
941     case SPECIAL_SRLV:
942     /* rd = rt >> (rs&31) (logical) eax = ebx >> (eax&31) */
943     /* xchg ebx,eax, then we can do eax = eax >> (ebx&31) */
944     /* 93 xchg %eax,%ebx */
945     /* 89 d9 mov %ebx,%ecx */
946     /* 83 e1 1f and $0x1f,%ecx */
947     /* d3 e8 shr %cl,%eax */
948     *a++ = 0x93;
949     *a++ = 0x89; *a++ = 0xd9;
950     *a++ = 0x83; *a++ = 0xe1; *a++ = 0x1f;
951     *a++ = 0xd3; *a++ = 0xe8;
952     /* 99 cltd */
953     *a++ = 0x99;
954     break;
955     case SPECIAL_SRAV:
956     /* rd = rt >> (rs&31) (arithmetic) eax = ebx >> (eax&31) */
957     /* xchg ebx,eax, then we can do eax = eax >> (ebx&31) */
958     /* 93 xchg %eax,%ebx */
959     /* 89 d9 mov %ebx,%ecx */
960     /* 83 e1 1f and $0x1f,%ecx */
961     /* d3 f8 sar %cl,%eax */
962     *a++ = 0x93;
963     *a++ = 0x89; *a++ = 0xd9;
964     *a++ = 0x83; *a++ = 0xe1; *a++ = 0x1f;
965     *a++ = 0xd3; *a++ = 0xf8;
966     /* 99 cltd */
967     *a++ = 0x99;
968     break;
969     case SPECIAL_MULT:
970     case SPECIAL_MULTU:
971     /* 57 push %edi */
972     *a++ = 0x57;
973     if (instruction_type == SPECIAL_MULT) {
974     /* f7 eb imul %ebx */
975     *a++ = 0xf7; *a++ = 0xeb;
976     } else {
977     /* f7 e3 mul %ebx */
978     *a++ = 0xf7; *a++ = 0xe3;
979     }
980     /* here: edx:eax = hi:lo */
981     /* 89 d7 mov %edx,%edi */
982     /* 99 cltd */
983     *a++ = 0x89; *a++ = 0xd7;
984     *a++ = 0x99;
985     /* here: edi=hi, edx:eax = sign-extended lo */
986     store_eax_edx(&a, &dummy_cpu.cd.mips.lo);
987     /* 89 f8 mov %edi,%eax */
988     /* 99 cltd */
989     *a++ = 0x89; *a++ = 0xf8;
990     *a++ = 0x99;
991     /* here: edx:eax = sign-extended hi */
992     store_eax_edx(&a, &dummy_cpu.cd.mips.hi);
993     /* 5f pop %edi */
994     *a++ = 0x5f;
995     do_store = 0;
996     break;
997     case SPECIAL_DIV:
998     case SPECIAL_DIVU:
999     /*
1000     * In: edx:eax = rs, ecx:ebx = rt
1001     * Out: LO = rs / rt, HI = rs % rt
1002     */
1003     /* Division by zero on MIPS is undefined, but on
1004     i386 it causes an exception, so we'll try to
1005     avoid that. */
1006     *a++ = 0x83; *a++ = 0xfb; *a++ = 0x00; /* cmp $0x0,%ebx */
1007     *a++ = 0x75; *a++ = 0x01; /* jne skip_inc */
1008     *a++ = 0x43; /* inc %ebx */
1009    
1010     /* 57 push %edi */
1011     *a++ = 0x57;
1012     if (instruction_type == SPECIAL_DIV) {
1013     *a++ = 0x99; /* cltd */
1014     *a++ = 0xf7; *a++ = 0xfb; /* idiv %ebx */
1015     } else {
1016     *a++ = 0x29; *a++ = 0xd2; /* sub %edx,%edx */
1017     *a++ = 0xf7; *a++ = 0xf3; /* div %ebx */
1018     }
1019     /* here: edx:eax = hi:lo */
1020     /* 89 d7 mov %edx,%edi */
1021     /* 99 cltd */
1022     *a++ = 0x89; *a++ = 0xd7;
1023     *a++ = 0x99;
1024     /* here: edi=hi, edx:eax = sign-extended lo */
1025     store_eax_edx(&a, &dummy_cpu.cd.mips.lo);
1026     /* 89 f8 mov %edi,%eax */
1027     /* 99 cltd */
1028     *a++ = 0x89; *a++ = 0xf8;
1029     *a++ = 0x99;
1030     /* here: edx:eax = sign-extended hi */
1031     store_eax_edx(&a, &dummy_cpu.cd.mips.hi);
1032     /* 5f pop %edi */
1033     *a++ = 0x5f;
1034     do_store = 0;
1035     break;
1036     #if 0
1037     /* TODO: These are from bintrans_alpha.c. Translate them to i386. */
1038    
1039     case SPECIAL_DSLL:
1040     *a++ = 0x21; *a++ = 0x17 + ((sa & 7) << 5); *a++ = 0x40 + (sa >> 3); *a++ = 0x48; /* sll t1,sa,t0 */
1041     break;
1042     case SPECIAL_DSLL32:
1043     sa += 32;
1044     *a++ = 0x21; *a++ = 0x17 + ((sa & 7) << 5); *a++ = 0x40 + (sa >> 3); *a++ = 0x48; /* sll t1,sa,t0 */
1045     break;
1046     case SPECIAL_DSRA:
1047     *a++ = 0x81; *a++ = 0x17 + ((sa & 7) << 5); *a++ = 0x40 + (sa >> 3); *a++ = 0x48; /* sra t1,sa,t0 */
1048     break;
1049     case SPECIAL_DSRA32:
1050     sa += 32;
1051     *a++ = 0x81; *a++ = 0x17 + ((sa & 7) << 5); *a++ = 0x40 + (sa >> 3); *a++ = 0x48; /* sra t1,sa,t0 */
1052     break;
1053     case SPECIAL_DSRL:
1054     /* Note: bits of sa are distributed among two different bytes. */
1055     *a++ = 0x81; *a++ = 0x16 + ((sa & 7) << 5); *a++ = 0x40 + (sa >> 3); *a++ = 0x48;
1056     break;
1057     case SPECIAL_DSRL32:
1058     /* Note: bits of sa are distributed among two different bytes. */
1059     sa += 32;
1060     *a++ = 0x81; *a++ = 0x16 + ((sa & 7) << 5); *a++ = 0x40 + (sa >> 3); *a++ = 0x48;
1061     break;
1062     #endif
1063     }
1064    
1065     if (do_store)
1066     store_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rd]);
1067    
1068     *addrp = a;
1069     rd0:
1070     bintrans_write_pc_inc(addrp);
1071     return 1;
1072     }
1073    
1074    
1075     /*
1076     * bintrans_write_instruction__mfc_mtc():
1077     */
1078     static int bintrans_write_instruction__mfc_mtc(struct memory *mem,
1079     unsigned char **addrp, int coproc_nr, int flag64bit, int rt,
1080     int rd, int mtcflag)
1081     {
1082     unsigned char *a, *failskip;
1083     int ofs;
1084    
1085     if (mtcflag && flag64bit) {
1086     /* dmtc */
1087     return 0;
1088     }
1089    
1090     /*
1091     * NOTE: Only a few registers are readable without side effects.
1092     */
1093     if (rt == 0 && !mtcflag)
1094     return 0;
1095    
1096     if (coproc_nr >= 1)
1097     return 0;
1098    
1099     if (rd == COP0_RANDOM || rd == COP0_COUNT)
1100     return 0;
1101    
1102     a = *addrp;
1103    
1104     /*************************************************************
1105     *
1106     * TODO: Check for kernel mode, or Coproc X usability bit!
1107     *
1108     *************************************************************/
1109    
1110     /* 8b 96 3c 30 00 00 mov 0x303c(%esi),%edx */
1111     ofs = ((size_t)&dummy_cpu.cd.mips.coproc[0]) - (size_t)&dummy_cpu;
1112     *a++ = 0x8b; *a++ = 0x96;
1113     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1114    
1115     /* here, edx = cpu->coproc[0] */
1116    
1117     if (mtcflag) {
1118     /* mtc */
1119    
1120     /* TODO: This code only works for mtc0, not dmtc0 */
1121    
1122     /* 8b 9a 38 30 00 00 mov 0x3038(%edx),%ebx */
1123     ofs = ((size_t)&dummy_coproc.reg[rd]) - (size_t)&dummy_coproc;
1124     *a++ = 0x8b; *a++ = 0x9a;
1125     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1126    
1127     load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
1128    
1129     /*
1130     * Here: eax contains the value in register rt,
1131     * ebx contains the coproc register rd value.
1132     *
1133     * In the general case, only allow mtc if it does not
1134     * change the coprocessor register!
1135     */
1136    
1137     switch (rd) {
1138    
1139     case COP0_INDEX:
1140     break;
1141    
1142     case COP0_ENTRYLO0:
1143     case COP0_ENTRYLO1:
1144     /* TODO: Not all bits are writable! */
1145     break;
1146    
1147     case COP0_EPC:
1148     break;
1149    
1150     case COP0_STATUS:
1151     /* Only allow updates to the status register if
1152     the interrupt enable bits were changed, but no
1153     other bits! */
1154     /* 89 c1 mov %eax,%ecx */
1155     /* 89 da mov %ebx,%edx */
1156     /* 81 e1 00 00 e7 0f and $0x0fe70000,%ecx */
1157     /* 81 e2 00 00 e7 0f and $0x0fe70000,%edx */
1158     /* 39 ca cmp %ecx,%edx */
1159     /* 74 01 je <ok> */
1160     *a++ = 0x89; *a++ = 0xc1;
1161     *a++ = 0x89; *a++ = 0xda;
1162     *a++ = 0x81; *a++ = 0xe1; *a++ = 0x00; *a++ = 0x00;
1163     if (mem->bintrans_32bit_only) {
1164     *a++ = 0xe7; *a++ = 0x0f;
1165     } else {
1166     *a++ = 0xff; *a++ = 0xff;
1167     }
1168     *a++ = 0x81; *a++ = 0xe2; *a++ = 0x00; *a++ = 0x00;
1169     if (mem->bintrans_32bit_only) {
1170     *a++ = 0xe7; *a++ = 0x0f;
1171     } else {
1172     *a++ = 0xff; *a++ = 0xff;
1173     }
1174     *a++ = 0x39; *a++ = 0xca;
1175     *a++ = 0x74; failskip = a; *a++ = 0x00;
1176     bintrans_write_chunkreturn_fail(&a);
1177     *failskip = (size_t)a - (size_t)failskip - 1;
1178    
1179     /* Only allow the update if it would NOT cause
1180     an interrupt exception: */
1181    
1182     /* 8b 96 3c 30 00 00 mov 0x303c(%esi),%edx */
1183     ofs = ((size_t)&dummy_cpu.cd.mips.coproc[0]) - (size_t)&dummy_cpu;
1184     *a++ = 0x8b; *a++ = 0x96;
1185     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1186    
1187     /* 8b 9a 38 30 00 00 mov 0x3038(%edx),%ebx */
1188     ofs = ((size_t)&dummy_coproc.reg[COP0_CAUSE]) - (size_t)&dummy_coproc;
1189     *a++ = 0x8b; *a++ = 0x9a;
1190     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1191    
1192     /* 21 c3 and %eax,%ebx */
1193     /* 81 e3 00 ff 00 00 and $0xff00,%ebx */
1194     /* 83 fb 00 cmp $0x0,%ebx */
1195     /* 74 01 je <ok> */
1196     *a++ = 0x21; *a++ = 0xc3;
1197     *a++ = 0x81; *a++ = 0xe3; *a++ = 0x00;
1198     *a++ = 0xff; *a++ = 0x00; *a++ = 0x00;
1199     *a++ = 0x83; *a++ = 0xfb; *a++ = 0x00;
1200     *a++ = 0x74; failskip = a; *a++ = 0x00;
1201     bintrans_write_chunkreturn_fail(&a);
1202     *failskip = (size_t)a - (size_t)failskip - 1;
1203    
1204     break;
1205    
1206     default:
1207     /* 39 d8 cmp %ebx,%eax */
1208     /* 74 01 je <ok> */
1209     *a++ = 0x39; *a++ = 0xd8;
1210     *a++ = 0x74; failskip = a; *a++ = 0x00;
1211     bintrans_write_chunkreturn_fail(&a);
1212     *failskip = (size_t)a - (size_t)failskip - 1;
1213     }
1214    
1215     /* 8b 96 3c 30 00 00 mov 0x303c(%esi),%edx */
1216     ofs = ((size_t)&dummy_cpu.cd.mips.coproc[0]) - (size_t)&dummy_cpu;
1217     *a++ = 0x8b; *a++ = 0x96;
1218     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1219    
1220     /* 8d 9a 38 30 00 00 lea 0x3038(%edx),%ebx */
1221     ofs = ((size_t)&dummy_coproc.reg[rd]) - (size_t)&dummy_coproc;
1222     *a++ = 0x8d; *a++ = 0x9a;
1223     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1224    
1225     /* Sign-extend eax into edx:eax, and store it in
1226     coprocessor register rd: */
1227     /* 99 cltd */
1228     *a++ = 0x99;
1229    
1230     /* 89 03 mov %eax,(%ebx) */
1231     /* 89 53 04 mov %edx,0x4(%ebx) */
1232     *a++ = 0x89; *a++ = 0x03;
1233     *a++ = 0x89; *a++ = 0x53; *a++ = 0x04;
1234     } else {
1235     /* mfc */
1236    
1237     /* 8b 82 38 30 00 00 mov 0x3038(%edx),%eax */
1238     ofs = ((size_t)&dummy_coproc.reg[rd]) - (size_t)&dummy_coproc;
1239     *a++ = 0x8b; *a++ = 0x82;
1240     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1241    
1242     if (flag64bit) {
1243     /* Load high 32 bits: (note: edx gets overwritten) */
1244     /* 8b 92 3c 30 00 00 mov 0x303c(%edx),%edx */
1245     ofs += 4;
1246     *a++ = 0x8b; *a++ = 0x92;
1247     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1248     } else {
1249     /* 99 cltd */
1250     *a++ = 0x99;
1251     }
1252    
1253     store_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
1254     }
1255    
1256     *addrp = a;
1257     bintrans_write_pc_inc(addrp);
1258     return 1;
1259     }
1260    
1261    
1262     /*
1263     * bintrans_write_instruction__branch():
1264     */
1265     static int bintrans_write_instruction__branch(unsigned char **addrp,
1266     int instruction_type, int regimm_type, int rt, int rs, int imm)
1267     {
1268     unsigned char *a;
1269     unsigned char *skip1 = NULL, *skip2 = NULL;
1270     int ofs, likely = 0;
1271    
1272     switch (instruction_type) {
1273     case HI6_BEQL:
1274     case HI6_BNEL:
1275     case HI6_BLEZL:
1276     case HI6_BGTZL:
1277     likely = 1;
1278     }
1279    
1280     /* TODO: See the Alpha backend on how these could be implemented: */
1281     if (likely)
1282     return 0;
1283    
1284     a = *addrp;
1285    
1286     /*
1287     * edx:eax = gpr[rs]; ecx:ebx = gpr[rt];
1288     *
1289     * Compare for equality (BEQ).
1290     * If the result was zero, then it means equality; perform the
1291     * delayed jump. Otherwise: skip.
1292     */
1293    
1294     switch (instruction_type) {
1295     case HI6_BEQ:
1296     case HI6_BNE:
1297     load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
1298     /* 89 c3 mov %eax,%ebx */
1299     /* 89 d1 mov %edx,%ecx */
1300     *a++ = 0x89; *a++ = 0xc3; *a++ = 0x89; *a++ = 0xd1;
1301     }
1302     load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
1303    
1304     if (instruction_type == HI6_BEQ && rt != rs) {
1305     /* If rt != rs, then skip. */
1306     /* 39 c3 cmp %eax,%ebx */
1307     /* 75 05 jne 155 <skip> */
1308     /* 39 d1 cmp %edx,%ecx */
1309     /* 75 01 jne 155 <skip> */
1310     *a++ = 0x39; *a++ = 0xc3;
1311     *a++ = 0x75; skip1 = a; *a++ = 0x00;
1312     #if 0
1313     if (!bintrans_32bit_only)
1314     #endif
1315     {
1316     *a++ = 0x39; *a++ = 0xd1;
1317     *a++ = 0x75; skip2 = a; *a++ = 0x00;
1318     }
1319     }
1320    
1321     if (instruction_type == HI6_BNE) {
1322     /* If rt != rs, then ok. Otherwise skip. */
1323     #if 0
1324     if (bintrans_32bit_only) {
1325     /* 39 c3 cmp %eax,%ebx */
1326     /* 74 xx je <skip> */
1327     *a++ = 0x39; *a++ = 0xc3;
1328     *a++ = 0x74; skip2 = a; *a++ = 0x00;
1329     } else
1330     #endif
1331     {
1332     /* 39 c3 cmp %eax,%ebx */
1333     /* 75 06 jne 156 <bra> */
1334     /* 39 d1 cmp %edx,%ecx */
1335     /* 75 02 jne 156 <bra> */
1336     /* eb 01 jmp 157 <skip> */
1337     *a++ = 0x39; *a++ = 0xc3;
1338     *a++ = 0x75; *a++ = 0x06;
1339     *a++ = 0x39; *a++ = 0xd1;
1340     *a++ = 0x75; *a++ = 0x02;
1341     *a++ = 0xeb; skip2 = a; *a++ = 0x00;
1342     }
1343     }
1344    
1345     if (instruction_type == HI6_BLEZ) {
1346     /* If both eax and edx are zero, then do the branch. */
1347     /* 83 f8 00 cmp $0x0,%eax */
1348     /* 75 07 jne <nott> */
1349     /* 83 fa 00 cmp $0x0,%edx */
1350     /* 75 02 jne 23d <nott> */
1351     /* eb 01 jmp <branch> */
1352     *a++ = 0x83; *a++ = 0xf8; *a++ = 0x00;
1353     *a++ = 0x75; *a++ = 0x07;
1354     *a++ = 0x83; *a++ = 0xfa; *a++ = 0x00;
1355     *a++ = 0x75; *a++ = 0x02;
1356     *a++ = 0xeb; skip1 = a; *a++ = 0x00;
1357    
1358     /* If high bit of edx is set, then rs < 0. */
1359     /* f7 c2 00 00 00 80 test $0x80000000,%edx */
1360     /* 74 00 jz skip */
1361     *a++ = 0xf7; *a++ = 0xc2; *a++ = 0; *a++ = 0; *a++ = 0; *a++ = 0x80;
1362     *a++ = 0x74; skip2 = a; *a++ = 0x00;
1363    
1364     if (skip1 != NULL)
1365     *skip1 = (size_t)a - (size_t)skip1 - 1;
1366     skip1 = NULL;
1367     }
1368     if (instruction_type == HI6_BGTZ) {
1369     /* If both eax and edx are zero, then skip the branch. */
1370     /* 83 f8 00 cmp $0x0,%eax */
1371     /* 75 07 jne <nott> */
1372     /* 83 fa 00 cmp $0x0,%edx */
1373     /* 75 02 jne 23d <nott> */
1374     /* eb 01 jmp <skip> */
1375     *a++ = 0x83; *a++ = 0xf8; *a++ = 0x00;
1376     *a++ = 0x75; *a++ = 0x07;
1377     *a++ = 0x83; *a++ = 0xfa; *a++ = 0x00;
1378     *a++ = 0x75; *a++ = 0x02;
1379     *a++ = 0xeb; skip1 = a; *a++ = 0x00;
1380    
1381     /* If high bit of edx is set, then rs < 0. */
1382     /* f7 c2 00 00 00 80 test $0x80000000,%edx */
1383     /* 75 00 jnz skip */
1384     *a++ = 0xf7; *a++ = 0xc2; *a++ = 0; *a++ = 0; *a++ = 0; *a++ = 0x80;
1385     *a++ = 0x75; skip2 = a; *a++ = 0x00;
1386     }
1387     if (instruction_type == HI6_REGIMM && regimm_type == REGIMM_BLTZ) {
1388     /* If high bit of edx is set, then rs < 0. */
1389     /* f7 c2 00 00 00 80 test $0x80000000,%edx */
1390     /* 74 00 jz skip */
1391     *a++ = 0xf7; *a++ = 0xc2; *a++ = 0; *a++ = 0; *a++ = 0; *a++ = 0x80;
1392     *a++ = 0x74; skip2 = a; *a++ = 0x00;
1393     }
1394     if (instruction_type == HI6_REGIMM && regimm_type == REGIMM_BGEZ) {
1395     /* If high bit of edx is not set, then rs >= 0. */
1396     /* f7 c2 00 00 00 80 test $0x80000000,%edx */
1397     /* 75 00 jnz skip */
1398     *a++ = 0xf7; *a++ = 0xc2; *a++ = 0; *a++ = 0; *a++ = 0; *a++ = 0x80;
1399     *a++ = 0x75; skip2 = a; *a++ = 0x00;
1400     }
1401    
1402     /*
1403     * Perform the jump by setting cpu->delay_slot = TO_BE_DELAYED
1404     * and cpu->delay_jmpaddr = pc + 4 + (imm << 2).
1405     */
1406    
1407     /* c7 86 38 30 00 00 01 00 00 00 movl $0x1,0x3038(%esi) */
1408     ofs = ((size_t)&dummy_cpu.cd.mips.delay_slot) - (size_t)&dummy_cpu;
1409     *a++ = 0xc7; *a++ = 0x86;
1410     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1411     *a++ = TO_BE_DELAYED; *a++ = 0; *a++ = 0; *a++ = 0;
1412    
1413     load_pc_into_eax_edx(&a);
1414    
1415     /* 05 78 56 34 12 add $0x12345678,%eax */
1416     /* 83 d2 00 adc $0x0,%edx */
1417     /* or */
1418     /* 83 d2 ff adc $0xffffffff,%edx */
1419     imm = (imm << 2) + 4;
1420     *a++ = 0x05; *a++ = imm; *a++ = imm >> 8; *a++ = imm >> 16; *a++ = imm >> 24;
1421     if (imm >= 0) {
1422     *a++ = 0x83; *a++ = 0xd2; *a++ = 0x00;
1423     } else {
1424     *a++ = 0x83; *a++ = 0xd2; *a++ = 0xff;
1425     }
1426     store_eax_edx(&a, &dummy_cpu.cd.mips.delay_jmpaddr);
1427    
1428     if (skip1 != NULL)
1429     *skip1 = (size_t)a - (size_t)skip1 - 1;
1430     if (skip2 != NULL)
1431     *skip2 = (size_t)a - (size_t)skip2 - 1;
1432    
1433     *addrp = a;
1434     bintrans_write_pc_inc(addrp);
1435     return 1;
1436     }
1437    
1438    
1439     /*
1440     * bintrans_write_instruction__delayedbranch():
1441     */
1442     static int bintrans_write_instruction__delayedbranch(struct memory *mem,
1443     unsigned char **addrp, uint32_t *potential_chunk_p, uint32_t *chunks,
1444     int only_care_about_chunk_p, int p, int forward)
1445     {
1446     unsigned char *a, *skip=NULL, *failskip;
1447     int ofs;
1448     uint32_t i386_addr;
1449    
1450     a = *addrp;
1451    
1452     if (only_care_about_chunk_p)
1453     goto try_chunk_p;
1454    
1455     /* Skip all of this if there is no branch: */
1456     ofs = ((size_t)&dummy_cpu.cd.mips.delay_slot) - (size_t)&dummy_cpu;
1457    
1458     /* 8b 86 38 30 00 00 mov 0x3038(%esi),%eax */
1459     *a++ = 0x8b; *a++ = 0x86;
1460     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1461    
1462     /* 83 f8 00 cmp $0x0,%eax */
1463     /* 74 01 je 16b <skippa> */
1464     *a++ = 0x83; *a++ = 0xf8; *a++ = 0x00;
1465     *a++ = 0x74; skip = a; *a++ = 0;
1466    
1467     /*
1468     * Perform the jump by setting cpu->delay_slot = 0
1469     * and pc = cpu->delay_jmpaddr.
1470     */
1471    
1472     /* c7 86 38 30 00 00 00 00 00 00 movl $0x0,0x3038(%esi) */
1473     ofs = ((size_t)&dummy_cpu.cd.mips.delay_slot) - (size_t)&dummy_cpu;
1474     *a++ = 0xc7; *a++ = 0x86;
1475     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1476     *a++ = 0; *a++ = 0; *a++ = 0; *a++ = 0;
1477    
1478     /* REMEMBER old pc: */
1479     load_pc_into_eax_edx(&a);
1480     /* 89 c3 mov %eax,%ebx */
1481     /* 89 d1 mov %edx,%ecx */
1482     *a++ = 0x89; *a++ = 0xc3;
1483     *a++ = 0x89; *a++ = 0xd1;
1484     load_into_eax_edx(&a, &dummy_cpu.cd.mips.delay_jmpaddr);
1485     store_eax_edx_into_pc(&a);
1486    
1487     try_chunk_p:
1488    
1489     if (potential_chunk_p == NULL) {
1490     if (mem->bintrans_32bit_only) {
1491     #if 1
1492     /* 8b 86 78 56 34 12 mov 0x12345678(%esi),%eax */
1493     /* ff e0 jmp *%eax */
1494     ofs = ((size_t)&dummy_cpu.cd.mips.bintrans_jump_to_32bit_pc) - (size_t)&dummy_cpu;
1495     *a++ = 0x8b; *a++ = 0x86;
1496     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1497     *a++ = 0xff; *a++ = 0xe0;
1498    
1499     #else
1500     /* Don't execute too many instructions. */
1501     /* 81 fd f0 1f 00 00 cmpl $0x1ff0,%ebp */
1502     /* 7c 01 jl <okk> */
1503     /* c3 ret */
1504     *a++ = 0x81; *a++ = 0xfd;
1505     *a++ = (N_SAFE_BINTRANS_LIMIT-1) & 255;
1506     *a++ = ((N_SAFE_BINTRANS_LIMIT-1) >> 8) & 255; *a++ = 0; *a++ = 0;
1507     *a++ = 0x7c; failskip = a; *a++ = 0x01;
1508     bintrans_write_chunkreturn_fail(&a);
1509     *failskip = (size_t)a - (size_t)failskip - 1;
1510    
1511     /*
1512     * ebx = ((vaddr >> 22) & 1023) * sizeof(void *)
1513     *
1514     * 89 c3 mov %eax,%ebx
1515     * c1 eb 14 shr $20,%ebx
1516     * 81 e3 fc 0f 00 00 and $0xffc,%ebx
1517     */
1518     *a++ = 0x89; *a++ = 0xc3;
1519     *a++ = 0xc1; *a++ = 0xeb; *a++ = 0x14;
1520     *a++ = 0x81; *a++ = 0xe3; *a++ = 0xfc; *a++ = 0x0f; *a++ = 0; *a++ = 0;
1521    
1522     /*
1523     * ecx = vaddr_to_hostaddr_table0
1524     *
1525     * 8b 8e 34 12 00 00 mov 0x1234(%esi),%ecx
1526     */
1527     ofs = ((size_t)&dummy_cpu.cd.mips.vaddr_to_hostaddr_table0) - (size_t)&dummy_cpu;
1528     *a++ = 0x8b; *a++ = 0x8e;
1529     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1530    
1531     /*
1532     * ecx = vaddr_to_hostaddr_table0[a]
1533     *
1534     * 8b 0c 19 mov (%ecx,%ebx),%ecx
1535     */
1536     *a++ = 0x8b; *a++ = 0x0c; *a++ = 0x19;
1537    
1538     /*
1539     * ebx = ((vaddr >> 12) & 1023) * sizeof(void *)
1540     *
1541     * 89 c3 mov %eax,%ebx
1542     * c1 eb 0a shr $10,%ebx
1543     * 81 e3 fc 0f 00 00 and $0xffc,%ebx
1544     */
1545     *a++ = 0x89; *a++ = 0xc3;
1546     *a++ = 0xc1; *a++ = 0xeb; *a++ = 0x0a;
1547     *a++ = 0x81; *a++ = 0xe3; *a++ = 0xfc; *a++ = 0x0f; *a++ = 0; *a++ = 0;
1548    
1549     /*
1550     * ecx = vaddr_to_hostaddr_table0[a][b].cd.mips.chunks
1551     *
1552     * 8b 8c 19 56 34 12 00 mov 0x123456(%ecx,%ebx,1),%ecx
1553     */
1554     ofs = (size_t)&dummy_vth32_table.cd.mips.bintrans_chunks[0]
1555     - (size_t)&dummy_vth32_table;
1556    
1557     *a++ = 0x8b; *a++ = 0x8c; *a++ = 0x19;
1558     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1559    
1560     /*
1561     * ecx = NULL? Then return with failure.
1562     *
1563     * 83 f9 00 cmp $0x0,%ecx
1564     * 75 01 jne <okzzz>
1565     */
1566     *a++ = 0x83; *a++ = 0xf9; *a++ = 0x00;
1567     *a++ = 0x75; fail = a; *a++ = 0x00;
1568     bintrans_write_chunkreturn(&a);
1569     *fail = (size_t)a - (size_t)fail - 1;
1570    
1571     /*
1572     * 25 fc 0f 00 00 and $0xffc,%eax
1573     * 01 c1 add %eax,%ecx
1574     *
1575     * 8b 01 mov (%ecx),%eax
1576     *
1577     * 83 f8 00 cmp $0x0,%eax
1578     * 75 01 jne <ok>
1579     * c3 ret
1580     */
1581     *a++ = 0x25; *a++ = 0xfc; *a++ = 0x0f; *a++ = 0; *a++ = 0;
1582     *a++ = 0x01; *a++ = 0xc1;
1583    
1584     *a++ = 0x8b; *a++ = 0x01;
1585    
1586     *a++ = 0x83; *a++ = 0xf8; *a++ = 0x00;
1587     *a++ = 0x75; fail = a; *a++ = 0x01;
1588     bintrans_write_chunkreturn(&a);
1589     *fail = (size_t)a - (size_t)fail - 1;
1590    
1591     /* 03 86 78 56 34 12 add 0x12345678(%esi),%eax */
1592     /* ff e0 jmp *%eax */
1593     ofs = ((size_t)&dummy_cpu.cd.mips.chunk_base_address) - (size_t)&dummy_cpu;
1594     *a++ = 0x03; *a++ = 0x86;
1595     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1596     *a++ = 0xff; *a++ = 0xe0;
1597     #endif
1598     } else {
1599     /* Not much we can do here if this wasn't to the same physical page... */
1600    
1601     /* Don't execute too many instructions. */
1602     /* 81 fd f0 1f 00 00 cmpl $0x1ff0,%ebp */
1603     /* 7c 01 jl <okk> */
1604     /* c3 ret */
1605     *a++ = 0x81; *a++ = 0xfd;
1606     *a++ = (N_SAFE_BINTRANS_LIMIT-1) & 255;
1607     *a++ = ((N_SAFE_BINTRANS_LIMIT-1) >> 8) & 255; *a++ = 0; *a++ = 0;
1608     *a++ = 0x7c; failskip = a; *a++ = 0x01;
1609     bintrans_write_chunkreturn_fail(&a);
1610     *failskip = (size_t)a - (size_t)failskip - 1;
1611    
1612     /*
1613     * Compare the old pc (ecx:ebx) and the new pc (edx:eax). If they are on the
1614     * same virtual page (which means that they are on the same physical
1615     * page), then we can check the right chunk pointer, and if it
1616     * is non-NULL, then we can jump there. Otherwise just return.
1617     */
1618    
1619     /* Subtract 4 from the old pc first. (This is where the jump originated from.) */
1620     /* 83 eb 04 sub $0x4,%ebx */
1621     /* 83 d9 00 sbb $0x0,%ecx */
1622     *a++ = 0x83; *a++ = 0xeb; *a++ = 0x04;
1623     *a++ = 0x83; *a++ = 0xd9; *a++ = 0x00;
1624    
1625     /* 39 d1 cmp %edx,%ecx */
1626     /* 74 01 je 1b9 <ok2> */
1627     /* c3 ret */
1628     *a++ = 0x39; *a++ = 0xd1;
1629     *a++ = 0x74; *a++ = 0x01;
1630     *a++ = 0xc3;
1631    
1632     /* Remember new pc: */
1633     /* 89 c1 mov %eax,%ecx */
1634     *a++ = 0x89; *a++ = 0xc1;
1635    
1636     /* 81 e3 00 f0 ff ff and $0xfffff000,%ebx */
1637     /* 25 00 f0 ff ff and $0xfffff000,%eax */
1638     *a++ = 0x81; *a++ = 0xe3; *a++ = 0x00; *a++ = 0xf0; *a++ = 0xff; *a++ = 0xff;
1639     *a++ = 0x25; *a++ = 0x00; *a++ = 0xf0; *a++ = 0xff; *a++ = 0xff;
1640    
1641     /* 39 c3 cmp %eax,%ebx */
1642     /* 74 01 je <ok1> */
1643     /* c3 ret */
1644     *a++ = 0x39; *a++ = 0xc3;
1645     *a++ = 0x74; *a++ = 0x01;
1646     *a++ = 0xc3;
1647    
1648     /* 81 e1 ff 0f 00 00 and $0xfff,%ecx */
1649     *a++ = 0x81; *a++ = 0xe1; *a++ = 0xff; *a++ = 0x0f; *a++ = 0; *a++ = 0;
1650    
1651     /* 8b 81 78 56 34 12 mov 0x12345678(%ecx),%eax */
1652     ofs = (size_t)chunks;
1653     *a++ = 0x8b; *a++ = 0x81; *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1654    
1655     /* 83 f8 00 cmp $0x0,%eax */
1656     /* 75 01 jne 1cd <okjump> */
1657     /* c3 ret */
1658     *a++ = 0x83; *a++ = 0xf8; *a++ = 0x00;
1659     *a++ = 0x75; *a++ = 0x01;
1660     *a++ = 0xc3;
1661    
1662     /* 03 86 78 56 34 12 add 0x12345678(%esi),%eax */
1663     /* ff e0 jmp *%eax */
1664     ofs = ((size_t)&dummy_cpu.cd.mips.chunk_base_address) - (size_t)&dummy_cpu;
1665     *a++ = 0x03; *a++ = 0x86;
1666     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1667     *a++ = 0xff; *a++ = 0xe0;
1668     }
1669     } else {
1670     /*
1671     * Just to make sure that we don't become too unreliant
1672     * on the main program loop, we need to return every once
1673     * in a while (interrupts etc).
1674     *
1675     * Load the "nr of instructions executed" (which is an int)
1676     * and see if it is below a certain threshold. If so, then
1677     * we go on with the fast path (bintrans), otherwise we
1678     * abort by returning.
1679     */
1680     /* 81 fd f0 1f 00 00 cmpl $0x1ff0,%ebp */
1681     /* 7c 01 jl <okk> */
1682     /* c3 ret */
1683     if (!only_care_about_chunk_p && !forward) {
1684     *a++ = 0x81; *a++ = 0xfd;
1685     *a++ = (N_SAFE_BINTRANS_LIMIT-1) & 255;
1686     *a++ = ((N_SAFE_BINTRANS_LIMIT-1) >> 8) & 255; *a++ = 0; *a++ = 0;
1687     *a++ = 0x7c; failskip = a; *a++ = 0x01;
1688     bintrans_write_chunkreturn_fail(&a);
1689     *failskip = (size_t)a - (size_t)failskip - 1;
1690     }
1691    
1692     /*
1693     * potential_chunk_p points to an "uint32_t".
1694     * If this value is non-NULL, then it is a piece of i386
1695     * machine language code corresponding to the address
1696     * we're jumping to. Otherwise, those instructions haven't
1697     * been translated yet, so we have to return to the main
1698     * loop. (Actually, we have to add cpu->chunk_base_address.)
1699     *
1700     * Case 1: The value is non-NULL already at translation
1701     * time. Then we can make a direct (fast) native
1702     * i386 jump to the code chunk.
1703     *
1704     * Case 2: The value was NULL at translation time, then we
1705     * have to check during runtime.
1706     */
1707    
1708     /* Case 1: */
1709     /* printf("%08x ", *potential_chunk_p); */
1710     i386_addr = *potential_chunk_p +
1711     (size_t)mem->translation_code_chunk_space;
1712     i386_addr = i386_addr - ((size_t)a + 5);
1713     if ((*potential_chunk_p) != 0) {
1714     *a++ = 0xe9;
1715     *a++ = i386_addr;
1716     *a++ = i386_addr >> 8;
1717     *a++ = i386_addr >> 16;
1718     *a++ = i386_addr >> 24;
1719     } else {
1720     /* Case 2: */
1721    
1722     bintrans_register_potential_quick_jump(mem, a, p);
1723    
1724     i386_addr = (size_t)potential_chunk_p;
1725    
1726     /*
1727     * Load the chunk pointer into eax.
1728     * If it is NULL (zero), then skip the following jump.
1729     * Add chunk_base_address to eax, and jump to eax.
1730     */
1731    
1732     /* a1 78 56 34 12 mov 0x12345678,%eax */
1733     /* 83 f8 00 cmp $0x0,%eax */
1734     /* 75 01 jne <okaa> */
1735     /* c3 ret */
1736     *a++ = 0xa1;
1737     *a++ = i386_addr; *a++ = i386_addr >> 8;
1738     *a++ = i386_addr >> 16; *a++ = i386_addr >> 24;
1739     *a++ = 0x83; *a++ = 0xf8; *a++ = 0x00;
1740     *a++ = 0x75; *a++ = 0x01;
1741     *a++ = 0xc3;
1742    
1743     /* 03 86 78 56 34 12 add 0x12345678(%esi),%eax */
1744     /* ff e0 jmp *%eax */
1745     ofs = ((size_t)&dummy_cpu.cd.mips.chunk_base_address) - (size_t)&dummy_cpu;
1746     *a++ = 0x03; *a++ = 0x86;
1747     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
1748     *a++ = 0xff; *a++ = 0xe0;
1749     }
1750     }
1751    
1752     if (skip != NULL)
1753     *skip = (size_t)a - (size_t)skip - 1;
1754    
1755     *addrp = a;
1756     return 1;
1757     }
1758    
1759    
1760     /*
1761     * bintrans_write_instruction__loadstore():
1762     */
1763     static int bintrans_write_instruction__loadstore(struct memory *mem,
1764     unsigned char **addrp, int rt, int imm, int rs,
1765     int instruction_type, int bigendian)
1766     {
1767     unsigned char *a, *retfail, *generic64bit, *doloadstore,
1768     *okret0, *okret1, *okret2, *skip;
1769     int ofs, alignment, load=0, unaligned=0;
1770    
1771     /* TODO: Not yet: */
1772     if (instruction_type == HI6_LQ_MDMX || instruction_type == HI6_SQ)
1773     return 0;
1774    
1775     /* TODO: Not yet: */
1776     if (bigendian)
1777     return 0;
1778    
1779     switch (instruction_type) {
1780     case HI6_LQ_MDMX:
1781     case HI6_LDL:
1782     case HI6_LDR:
1783     case HI6_LD:
1784     case HI6_LWU:
1785     case HI6_LWL:
1786     case HI6_LWR:
1787     case HI6_LW:
1788     case HI6_LHU:
1789     case HI6_LH:
1790     case HI6_LBU:
1791     case HI6_LB:
1792     load = 1;
1793     if (rt == 0)
1794     return 0;
1795     }
1796    
1797     switch (instruction_type) {
1798     case HI6_LWL:
1799     case HI6_LWR:
1800     case HI6_LDL:
1801     case HI6_LDR:
1802     case HI6_SWL:
1803     case HI6_SWR:
1804     case HI6_SDL:
1805     case HI6_SDR:
1806     unaligned = 1;
1807     }
1808    
1809     a = *addrp;
1810    
1811     if (mem->bintrans_32bit_only)
1812     load_into_eax_dont_care_about_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
1813     else
1814     load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
1815    
1816     if (imm & 0x8000) {
1817     /* 05 34 f2 ff ff add $0xfffff234,%eax */
1818     /* 83 d2 ff adc $0xffffffff,%edx */
1819     *a++ = 5;
1820     *a++ = imm; *a++ = imm >> 8; *a++ = 0xff; *a++ = 0xff;
1821     if (!mem->bintrans_32bit_only) {
1822     *a++ = 0x83; *a++ = 0xd2; *a++ = 0xff;
1823     }
1824     } else {
1825     /* 05 34 12 00 00 add $0x1234,%eax */
1826     /* 83 d2 00 adc $0x0,%edx */
1827     *a++ = 5;
1828     *a++ = imm; *a++ = imm >> 8; *a++ = 0; *a++ = 0;
1829     if (!mem->bintrans_32bit_only) {
1830     *a++ = 0x83; *a++ = 0xd2; *a++ = 0;
1831     }
1832     }
1833    
1834     alignment = 0;
1835     switch (instruction_type) {
1836     case HI6_LQ_MDMX:
1837     case HI6_SQ:
1838     alignment = 15;
1839     break;
1840     case HI6_LD:
1841     case HI6_LDL:
1842     case HI6_LDR:
1843     case HI6_SD:
1844     case HI6_SDL:
1845     case HI6_SDR:
1846     alignment = 7;
1847     break;
1848     case HI6_LW:
1849     case HI6_LWL:
1850     case HI6_LWR:
1851     case HI6_LWU:
1852     case HI6_SW:
1853     case HI6_SWL:
1854     case HI6_SWR:
1855     alignment = 3;
1856     break;
1857     case HI6_LH:
1858     case HI6_LHU:
1859     case HI6_SH:
1860     alignment = 1;
1861     break;
1862     }
1863    
1864     if (unaligned) {
1865     /*
1866     * Perform the actual load/store from an
1867     * aligned address.
1868     *
1869     * 83 e0 fc and $0xfffffffc,%eax
1870     */
1871     *a++ = 0x83; *a++ = 0xe0; *a++ = 0xff - alignment;
1872     } else if (alignment > 0) {
1873     unsigned char *alignskip;
1874     /*
1875     * Check alignment:
1876     *
1877     * 89 c3 mov %eax,%ebx
1878     * 83 e3 01 and $0x1,%ebx
1879     * 74 01 jz <ok>
1880     * c3 ret
1881     */
1882     *a++ = 0x89; *a++ = 0xc3;
1883     *a++ = 0x83; *a++ = 0xe3; *a++ = alignment;
1884     *a++ = 0x74; alignskip = a; *a++ = 0x00;
1885     bintrans_write_chunkreturn_fail(&a);
1886     *alignskip = (size_t)a - (size_t)alignskip - 1;
1887     }
1888    
1889    
1890     /* Here, edx:eax = vaddr */
1891    
1892     if (mem->bintrans_32bit_only) {
1893     /* Call the quick lookup routine: */
1894 dpavlin 10 if (load)
1895     ofs = (size_t)bintrans_load_32bit;
1896     else
1897     ofs = (size_t)bintrans_store_32bit;
1898 dpavlin 2 ofs = ofs - ((size_t)a + 5);
1899     *a++ = 0xe8; *a++ = ofs; *a++ = ofs >> 8;
1900     *a++ = ofs >> 16; *a++ = ofs >> 24;
1901    
1902     /*
1903     * ecx = NULL? Then return with failure.
1904     *
1905     * 83 f9 00 cmp $0x0,%ecx
1906     * 75 01 jne <okzzz>
1907     */
1908     *a++ = 0x83; *a++ = 0xf9; *a++ = 0x00;
1909     *a++ = 0x75; retfail = a; *a++ = 0x00;
1910     bintrans_write_chunkreturn_fail(&a); /* ret (and fail) */
1911     *retfail = (size_t)a - (size_t)retfail - 1;
1912    
1913     /*
1914     * eax = offset within page = vaddr & 0xfff
1915     *
1916     * 25 ff 0f 00 00 and $0xfff,%eax
1917     */
1918     *a++ = 0x25; *a++ = 0xff; *a++ = 0x0f; *a++ = 0; *a++ = 0;
1919    
1920     /*
1921     * ecx = host address ( = host page + offset)
1922     *
1923     * 83 e1 fe and $0xfffffffe,%ecx clear the lowest bit
1924     * 01 c1 add %eax,%ecx
1925     */
1926     *a++ = 0x83; *a++ = 0xe1; *a++ = 0xfe;
1927     *a++ = 0x01; *a++ = 0xc1;
1928     } else {
1929     /*
1930     * If the load/store address has the top 32 bits set to
1931     * 0x00000000 or 0xffffffff, then we can use the 32-bit
1932     * lookup tables:
1933     *
1934    
1935     TODO: top 33 bits!!!!!!!
1936    
1937     * 83 fa 00 cmp $0x0,%edx
1938     * 74 05 je <ok32>
1939     * 83 fa ff cmp $0xffffffff,%edx
1940     * 75 01 jne <not32>
1941     */
1942     *a++ = 0x83; *a++ = 0xfa; *a++ = 0x00;
1943     *a++ = 0x74; *a++ = 0x05;
1944     *a++ = 0x83; *a++ = 0xfa; *a++ = 0xff;
1945     *a++ = 0x75; generic64bit = a; *a++ = 0x01;
1946    
1947     /* Call the quick lookup routine: */
1948 dpavlin 10 if (load)
1949     ofs = (size_t)bintrans_load_32bit;
1950     else
1951     ofs = (size_t)bintrans_store_32bit;
1952 dpavlin 2 ofs = ofs - ((size_t)a + 5);
1953     *a++ = 0xe8; *a++ = ofs; *a++ = ofs >> 8;
1954     *a++ = ofs >> 16; *a++ = ofs >> 24;
1955    
1956     /*
1957     * ecx = NULL? Then return with failure.
1958     *
1959     * 83 f9 00 cmp $0x0,%ecx
1960     * 75 01 jne <okzzz>
1961     */
1962     *a++ = 0x83; *a++ = 0xf9; *a++ = 0x00;
1963     *a++ = 0x75; retfail = a; *a++ = 0x00;
1964     bintrans_write_chunkreturn_fail(&a); /* ret (and fail) */
1965     *retfail = (size_t)a - (size_t)retfail - 1;
1966    
1967     /*
1968     * eax = offset within page = vaddr & 0xfff
1969     *
1970     * 25 ff 0f 00 00 and $0xfff,%eax
1971     */
1972     *a++ = 0x25; *a++ = 0xff; *a++ = 0x0f; *a++ = 0; *a++ = 0;
1973    
1974     /*
1975     * ecx = host address ( = host page + offset)
1976     *
1977     * 83 e1 fe and $0xfffffffe,%ecx clear the lowest bit
1978     * 01 c1 add %eax,%ecx
1979     */
1980     *a++ = 0x83; *a++ = 0xe1; *a++ = 0xfe;
1981     *a++ = 0x01; *a++ = 0xc1;
1982    
1983     *a++ = 0xeb; doloadstore = a; *a++ = 0x01;
1984    
1985    
1986     /* TODO: The stuff above is so similar to the pure 32-bit
1987     case that it should be factored out. */
1988    
1989    
1990     *generic64bit = (size_t)a - (size_t)generic64bit - 1;
1991    
1992     /*
1993     * 64-bit generic case:
1994     */
1995    
1996     /* push writeflag */
1997     *a++ = 0x6a; *a++ = load? 0 : 1;
1998    
1999     /* push vaddr (edx:eax) */
2000     *a++ = 0x52; *a++ = 0x50;
2001    
2002     /* push cpu (esi) */
2003     *a++ = 0x56;
2004    
2005     /* eax = points to the right function */
2006     ofs = ((size_t)&dummy_cpu.cd.mips.fast_vaddr_to_hostaddr) - (size_t)&dummy_cpu;
2007     *a++ = 0x8b; *a++ = 0x86;
2008     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
2009    
2010     /* ff d0 call *%eax */
2011     *a++ = 0xff; *a++ = 0xd0;
2012    
2013     /* 83 c4 08 add $0x10,%esp */
2014     *a++ = 0x83; *a++ = 0xc4; *a++ = 0x10;
2015    
2016     /* If eax is NULL, then return. */
2017     /* 83 f8 00 cmp $0x0,%eax */
2018     /* 75 01 jne 1cd <okjump> */
2019     /* c3 ret */
2020     *a++ = 0x83; *a++ = 0xf8; *a++ = 0x00;
2021     *a++ = 0x75; retfail = a; *a++ = 0x00;
2022     bintrans_write_chunkreturn_fail(&a); /* ret (and fail) */
2023     *retfail = (size_t)a - (size_t)retfail - 1;
2024    
2025     /* 89 c1 mov %eax,%ecx */
2026     *a++ = 0x89; *a++ = 0xc1;
2027    
2028     *doloadstore = (size_t)a - (size_t)doloadstore - 1;
2029     }
2030    
2031    
2032     if (!load) {
2033     if (alignment >= 7)
2034     load_into_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
2035     else
2036     load_into_eax_dont_care_about_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
2037     }
2038    
2039     switch (instruction_type) {
2040     case HI6_LD:
2041     /* 8b 01 mov (%ecx),%eax */
2042     /* 8b 51 04 mov 0x4(%ecx),%edx */
2043     *a++ = 0x8b; *a++ = 0x01;
2044     *a++ = 0x8b; *a++ = 0x51; *a++ = 0x04;
2045     break;
2046     case HI6_LWU:
2047     /* 8b 01 mov (%ecx),%eax */
2048     /* 31 d2 xor %edx,%edx */
2049     *a++ = 0x8b; *a++ = 0x01;
2050     *a++ = 0x31; *a++ = 0xd2;
2051     break;
2052     case HI6_LW:
2053     /* 8b 01 mov (%ecx),%eax */
2054     /* 99 cltd */
2055     *a++ = 0x8b; *a++ = 0x01;
2056     *a++ = 0x99;
2057     break;
2058     case HI6_LHU:
2059     /* 31 c0 xor %eax,%eax */
2060     /* 66 8b 01 mov (%ecx),%ax */
2061     /* 99 cltd */
2062     *a++ = 0x31; *a++ = 0xc0;
2063     *a++ = 0x66; *a++ = 0x8b; *a++ = 0x01;
2064     *a++ = 0x99;
2065     break;
2066     case HI6_LH:
2067     /* 66 8b 01 mov (%ecx),%ax */
2068     /* 98 cwtl */
2069     /* 99 cltd */
2070     *a++ = 0x66; *a++ = 0x8b; *a++ = 0x01;
2071     *a++ = 0x98;
2072     *a++ = 0x99;
2073     break;
2074     case HI6_LBU:
2075     /* 31 c0 xor %eax,%eax */
2076     /* 8a 01 mov (%ecx),%al */
2077     /* 99 cltd */
2078     *a++ = 0x31; *a++ = 0xc0;
2079     *a++ = 0x8a; *a++ = 0x01;
2080     *a++ = 0x99;
2081     break;
2082     case HI6_LB:
2083     /* 8a 01 mov (%ecx),%al */
2084     /* 66 98 cbtw */
2085     /* 98 cwtl */
2086     /* 99 cltd */
2087     *a++ = 0x8a; *a++ = 0x01;
2088     *a++ = 0x66; *a++ = 0x98;
2089     *a++ = 0x98;
2090     *a++ = 0x99;
2091     break;
2092    
2093     case HI6_LWL:
2094     load_into_eax_dont_care_about_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
2095     /* 05 34 f2 ff ff add $0xfffff234,%eax */
2096     *a++ = 5;
2097     *a++ = imm; *a++ = imm >> 8; *a++ = 0xff; *a++ = 0xff;
2098     /* 83 e0 03 and $0x03,%eax */
2099     *a++ = 0x83; *a++ = 0xe0; *a++ = alignment;
2100     /* 89 c3 mov %eax,%ebx */
2101     *a++ = 0x89; *a++ = 0xc3;
2102    
2103     load_into_eax_dont_care_about_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
2104    
2105     /* ALIGNED LOAD: */
2106     /* 8b 11 mov (%ecx),%edx */
2107     *a++ = 0x8b; *a++ = 0x11;
2108    
2109     /*
2110     * CASE 0:
2111     * memory = 0x12 0x34 0x56 0x78
2112     * register after lwl: 0x12 0x.. 0x.. 0x..
2113     */
2114     /* 83 fb 00 cmp $0x0,%ebx */
2115     /* 75 01 jne <skip> */
2116     *a++ = 0x83; *a++ = 0xfb; *a++ = 0x00;
2117     *a++ = 0x75; skip = a; *a++ = 0x01;
2118    
2119     /* c1 e2 18 shl $0x18,%edx */
2120     /* 25 ff ff ff 00 and $0xffffff,%eax */
2121     /* 09 d0 or %edx,%eax */
2122     *a++ = 0xc1; *a++ = 0xe2; *a++ = 0x18;
2123     *a++ = 0x25; *a++ = 0xff; *a++ = 0xff; *a++ = 0xff; *a++ = 0x00;
2124     *a++ = 0x09; *a++ = 0xd0;
2125    
2126     /* eb 00 jmp <okret> */
2127     *a++ = 0xeb; okret0 = a; *a++ = 0;
2128    
2129     *skip = (size_t)a - (size_t)skip - 1;
2130    
2131     /*
2132     * CASE 1:
2133     * memory = 0x12 0x34 0x56 0x78
2134     * register after lwl: 0x34 0x12 0x.. 0x..
2135     */
2136     /* 83 fb 01 cmp $0x1,%ebx */
2137     /* 75 01 jne <skip> */
2138     *a++ = 0x83; *a++ = 0xfb; *a++ = 0x01;
2139     *a++ = 0x75; skip = a; *a++ = 0x01;
2140    
2141     /* c1 e2 10 shl $0x10,%edx */
2142     /* 25 ff ff 00 00 and $0xffff,%eax */
2143     /* 09 d0 or %edx,%eax */
2144     *a++ = 0xc1; *a++ = 0xe2; *a++ = 0x10;
2145     *a++ = 0x25; *a++ = 0xff; *a++ = 0xff; *a++ = 0x00; *a++ = 0x00;
2146     *a++ = 0x09; *a++ = 0xd0;
2147    
2148     /* eb 00 jmp <okret> */
2149     *a++ = 0xeb; okret1 = a; *a++ = 0;
2150    
2151     *skip = (size_t)a - (size_t)skip - 1;
2152    
2153     /*
2154     * CASE 2:
2155     * memory = 0x12 0x34 0x56 0x78
2156     * register after lwl: 0x56 0x34 0x12 0x..
2157     */
2158     /* 83 fb 02 cmp $0x2,%ebx */
2159     /* 75 01 jne <skip> */
2160     *a++ = 0x83; *a++ = 0xfb; *a++ = 0x02;
2161     *a++ = 0x75; skip = a; *a++ = 0x01;
2162    
2163     /* c1 e2 08 shl $0x08,%edx */
2164     /* 25 ff 00 00 00 and $0xff,%eax */
2165     /* 09 d0 or %edx,%eax */
2166     *a++ = 0xc1; *a++ = 0xe2; *a++ = 0x08;
2167     *a++ = 0x25; *a++ = 0xff; *a++ = 0x00; *a++ = 0x00; *a++ = 0x00;
2168     *a++ = 0x09; *a++ = 0xd0;
2169    
2170     /* eb 00 jmp <okret> */
2171     *a++ = 0xeb; okret2 = a; *a++ = 0;
2172    
2173     *skip = (size_t)a - (size_t)skip - 1;
2174    
2175     /*
2176     * CASE 3:
2177     * memory = 0x12 0x34 0x56 0x78
2178     * register after lwl: 0x78 0x56 0x34 0x12
2179     */
2180     /* 89 d0 mov %edx,%eax */
2181     *a++ = 0x89; *a++ = 0xd0;
2182    
2183     /* okret: */
2184     *okret0 = (size_t)a - (size_t)okret0 - 1;
2185     *okret1 = (size_t)a - (size_t)okret1 - 1;
2186     *okret2 = (size_t)a - (size_t)okret2 - 1;
2187    
2188     /* 99 cltd */
2189     *a++ = 0x99;
2190     break;
2191    
2192     case HI6_LWR:
2193     load_into_eax_dont_care_about_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
2194     /* 05 34 f2 ff ff add $0xfffff234,%eax */
2195     *a++ = 5;
2196     *a++ = imm; *a++ = imm >> 8; *a++ = 0xff; *a++ = 0xff;
2197     /* 83 e0 03 and $0x03,%eax */
2198     *a++ = 0x83; *a++ = 0xe0; *a++ = alignment;
2199     /* 89 c3 mov %eax,%ebx */
2200     *a++ = 0x89; *a++ = 0xc3;
2201    
2202     load_into_eax_dont_care_about_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
2203    
2204     /* ALIGNED LOAD: */
2205     /* 8b 11 mov (%ecx),%edx */
2206     *a++ = 0x8b; *a++ = 0x11;
2207    
2208     /*
2209     * CASE 0:
2210     * memory = 0x12 0x34 0x56 0x78
2211     * register after lwr: 0x78 0x56 0x34 0x12
2212     */
2213     /* 83 fb 00 cmp $0x0,%ebx */
2214     /* 75 01 jne <skip> */
2215     *a++ = 0x83; *a++ = 0xfb; *a++ = 0x00;
2216     *a++ = 0x75; skip = a; *a++ = 0x01;
2217    
2218     /* 89 d0 mov %edx,%eax */
2219     *a++ = 0x89; *a++ = 0xd0;
2220    
2221     /* eb 00 jmp <okret> */
2222     *a++ = 0xeb; okret0 = a; *a++ = 0;
2223    
2224     *skip = (size_t)a - (size_t)skip - 1;
2225    
2226     /*
2227     * CASE 1:
2228     * memory = 0x12 0x34 0x56 0x78
2229     * register after lwr: 0x.. 0x78 0x56 0x34
2230     */
2231     /* 83 fb 01 cmp $0x1,%ebx */
2232     /* 75 01 jne <skip> */
2233     *a++ = 0x83; *a++ = 0xfb; *a++ = 0x01;
2234     *a++ = 0x75; skip = a; *a++ = 0x01;
2235    
2236     /* c1 ea 08 shr $0x8,%edx */
2237     /* 25 00 00 00 ff and $0xff000000,%eax */
2238     /* 09 d0 or %edx,%eax */
2239     *a++ = 0xc1; *a++ = 0xea; *a++ = 0x08;
2240     *a++ = 0x25; *a++ = 0x00; *a++ = 0x00; *a++ = 0x00; *a++ = 0xff;
2241     *a++ = 0x09; *a++ = 0xd0;
2242    
2243     /* eb 00 jmp <okret> */
2244     *a++ = 0xeb; okret1 = a; *a++ = 0;
2245    
2246     *skip = (size_t)a - (size_t)skip - 1;
2247    
2248     /*
2249     * CASE 2:
2250     * memory = 0x12 0x34 0x56 0x78
2251     * register after lwr: 0x.. 0x.. 0x78 0x56
2252     */
2253     /* 83 fb 02 cmp $0x2,%ebx */
2254     /* 75 01 jne <skip> */
2255     *a++ = 0x83; *a++ = 0xfb; *a++ = 0x02;
2256     *a++ = 0x75; skip = a; *a++ = 0x01;
2257    
2258     /* c1 ea 10 shr $0x10,%edx */
2259     /* 25 00 00 ff ff and $0xffff0000,%eax */
2260     /* 09 d0 or %edx,%eax */
2261     *a++ = 0xc1; *a++ = 0xea; *a++ = 0x10;
2262     *a++ = 0x25; *a++ = 0x00; *a++ = 0x00; *a++ = 0xff; *a++ = 0xff;
2263     *a++ = 0x09; *a++ = 0xd0;
2264    
2265     /* eb 00 jmp <okret> */
2266     *a++ = 0xeb; okret2 = a; *a++ = 0;
2267    
2268     *skip = (size_t)a - (size_t)skip - 1;
2269    
2270     /*
2271     * CASE 3:
2272     * memory = 0x12 0x34 0x56 0x78
2273     * register after lwr: 0x.. 0x.. 0x.. 0x78
2274     */
2275     /* c1 ea 18 shr $0x18,%edx */
2276     /* 25 00 ff ff ff and $0xffffff00,%eax */
2277     /* 09 d0 or %edx,%eax */
2278     *a++ = 0xc1; *a++ = 0xea; *a++ = 0x18;
2279     *a++ = 0x25; *a++ = 0x00; *a++ = 0xff; *a++ = 0xff; *a++ = 0xff;
2280     *a++ = 0x09; *a++ = 0xd0;
2281    
2282     /* okret: */
2283     *okret0 = (size_t)a - (size_t)okret0 - 1;
2284     *okret1 = (size_t)a - (size_t)okret1 - 1;
2285     *okret2 = (size_t)a - (size_t)okret2 - 1;
2286    
2287     /* 99 cltd */
2288     *a++ = 0x99;
2289     break;
2290    
2291     case HI6_SD:
2292     /* 89 01 mov %eax,(%ecx) */
2293     /* 89 51 04 mov %edx,0x4(%ecx) */
2294     *a++ = 0x89; *a++ = 0x01;
2295     *a++ = 0x89; *a++ = 0x51; *a++ = 0x04;
2296     break;
2297     case HI6_SW:
2298     /* 89 01 mov %eax,(%ecx) */
2299     *a++ = 0x89; *a++ = 0x01;
2300     break;
2301     case HI6_SH:
2302     /* 66 89 01 mov %ax,(%ecx) */
2303     *a++ = 0x66; *a++ = 0x89; *a++ = 0x01;
2304     break;
2305     case HI6_SB:
2306     /* 88 01 mov %al,(%ecx) */
2307     *a++ = 0x88; *a++ = 0x01;
2308     break;
2309    
2310     case HI6_SWL:
2311     load_into_eax_dont_care_about_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
2312     /* 05 34 f2 ff ff add $0xfffff234,%eax */
2313     *a++ = 5;
2314     *a++ = imm; *a++ = imm >> 8; *a++ = 0xff; *a++ = 0xff;
2315     /* 83 e0 03 and $0x03,%eax */
2316     *a++ = 0x83; *a++ = 0xe0; *a++ = alignment;
2317     /* 89 c3 mov %eax,%ebx */
2318     *a++ = 0x89; *a++ = 0xc3;
2319    
2320     load_into_eax_dont_care_about_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
2321    
2322     /* ALIGNED LOAD: */
2323     /* 8b 11 mov (%ecx),%edx */
2324     *a++ = 0x8b; *a++ = 0x11;
2325    
2326     /*
2327     * CASE 0:
2328     * memory (edx): 0x12 0x34 0x56 0x78
2329     * register (eax): 0x89abcdef
2330     * mem after swl: 0x89 0x.. 0x.. 0x..
2331     */
2332     /* 83 fb 00 cmp $0x0,%ebx */
2333     /* 75 01 jne <skip> */
2334     *a++ = 0x83; *a++ = 0xfb; *a++ = 0x00;
2335     *a++ = 0x75; skip = a; *a++ = 0x01;
2336    
2337     /* 81 e2 00 ff ff ff and $0xffffff00,%edx */
2338     /* c1 e8 18 shr $0x18,%eax */
2339     /* 09 d0 or %edx,%eax */
2340     *a++ = 0x81; *a++ = 0xe2; *a++ = 0x00; *a++ = 0xff; *a++ = 0xff; *a++ = 0xff;
2341     *a++ = 0xc1; *a++ = 0xe8; *a++ = 0x18;
2342     *a++ = 0x09; *a++ = 0xd0;
2343    
2344     /* eb 00 jmp <okret> */
2345     *a++ = 0xeb; okret0 = a; *a++ = 0;
2346    
2347     *skip = (size_t)a - (size_t)skip - 1;
2348    
2349     /*
2350     * CASE 1:
2351     * memory (edx): 0x12 0x34 0x56 0x78
2352     * register (eax): 0x89abcdef
2353     * mem after swl: 0xab 0x89 0x.. 0x..
2354     */
2355     /* 83 fb 01 cmp $0x1,%ebx */
2356     /* 75 01 jne <skip> */
2357     *a++ = 0x83; *a++ = 0xfb; *a++ = 0x01;
2358     *a++ = 0x75; skip = a; *a++ = 0x01;
2359    
2360     /* 81 e2 00 00 ff ff and $0xffff0000,%edx */
2361     /* c1 e8 10 shr $0x10,%eax */
2362     /* 09 d0 or %edx,%eax */
2363     *a++ = 0x81; *a++ = 0xe2; *a++ = 0x00; *a++ = 0x00; *a++ = 0xff; *a++ = 0xff;
2364     *a++ = 0xc1; *a++ = 0xe8; *a++ = 0x10;
2365     *a++ = 0x09; *a++ = 0xd0;
2366    
2367     /* eb 00 jmp <okret> */
2368     *a++ = 0xeb; okret1 = a; *a++ = 0;
2369    
2370     *skip = (size_t)a - (size_t)skip - 1;
2371    
2372     /*
2373     * CASE 2:
2374     * memory (edx): 0x12 0x34 0x56 0x78
2375     * register (eax): 0x89abcdef
2376     * mem after swl: 0xcd 0xab 0x89 0x..
2377     */
2378     /* 83 fb 02 cmp $0x2,%ebx */
2379     /* 75 01 jne <skip> */
2380     *a++ = 0x83; *a++ = 0xfb; *a++ = 0x02;
2381     *a++ = 0x75; skip = a; *a++ = 0x01;
2382    
2383     /* 81 e2 00 00 00 ff and $0xff000000,%edx */
2384     /* c1 e8 08 shr $0x08,%eax */
2385     /* 09 d0 or %edx,%eax */
2386     *a++ = 0x81; *a++ = 0xe2; *a++ = 0x00; *a++ = 0x00; *a++ = 0x00; *a++ = 0xff;
2387     *a++ = 0xc1; *a++ = 0xe8; *a++ = 0x08;
2388     *a++ = 0x09; *a++ = 0xd0;
2389    
2390     /* eb 00 jmp <okret> */
2391     *a++ = 0xeb; okret2 = a; *a++ = 0;
2392    
2393     *skip = (size_t)a - (size_t)skip - 1;
2394    
2395     /*
2396     * CASE 3:
2397     * memory (edx): 0x12 0x34 0x56 0x78
2398     * register (eax): 0x89abcdef
2399     * mem after swl: 0xef 0xcd 0xab 0x89
2400     */
2401     /* eax = eax :-) */
2402    
2403     /* okret: */
2404     *okret0 = (size_t)a - (size_t)okret0 - 1;
2405     *okret1 = (size_t)a - (size_t)okret1 - 1;
2406     *okret2 = (size_t)a - (size_t)okret2 - 1;
2407    
2408     /* Store back to memory: */
2409     /* 89 01 mov %eax,(%ecx) */
2410     *a++ = 0x89; *a++ = 0x01;
2411     break;
2412    
2413     case HI6_SWR:
2414     load_into_eax_dont_care_about_edx(&a, &dummy_cpu.cd.mips.gpr[rs]);
2415     /* 05 34 f2 ff ff add $0xfffff234,%eax */
2416     *a++ = 5;
2417     *a++ = imm; *a++ = imm >> 8; *a++ = 0xff; *a++ = 0xff;
2418     /* 83 e0 03 and $0x03,%eax */
2419     *a++ = 0x83; *a++ = 0xe0; *a++ = alignment;
2420     /* 89 c3 mov %eax,%ebx */
2421     *a++ = 0x89; *a++ = 0xc3;
2422    
2423     load_into_eax_dont_care_about_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
2424    
2425     /* ALIGNED LOAD: */
2426     /* 8b 11 mov (%ecx),%edx */
2427     *a++ = 0x8b; *a++ = 0x11;
2428    
2429     /*
2430     * CASE 0:
2431     * memory (edx): 0x12 0x34 0x56 0x78
2432     * register (eax): 0x89abcdef
2433     * mem after swr: 0xef 0xcd 0xab 0x89
2434     */
2435     /* 83 fb 00 cmp $0x0,%ebx */
2436     /* 75 01 jne <skip> */
2437     *a++ = 0x83; *a++ = 0xfb; *a++ = 0x00;
2438     *a++ = 0x75; skip = a; *a++ = 0x01;
2439    
2440     /* eax = eax, so do nothing */
2441    
2442     /* eb 00 jmp <okret> */
2443     *a++ = 0xeb; okret0 = a; *a++ = 0;
2444    
2445     *skip = (size_t)a - (size_t)skip - 1;
2446    
2447     /*
2448     * CASE 1:
2449     * memory (edx): 0x12 0x34 0x56 0x78
2450     * register (eax): 0x89abcdef
2451     * mem after swr: 0x12 0xef 0xcd 0xab
2452     */
2453     /* 83 fb 01 cmp $0x1,%ebx */
2454     /* 75 01 jne <skip> */
2455     *a++ = 0x83; *a++ = 0xfb; *a++ = 0x01;
2456     *a++ = 0x75; skip = a; *a++ = 0x01;
2457    
2458     /* 81 e2 ff 00 00 00 and $0x000000ff,%edx */
2459     /* c1 e0 08 shl $0x08,%eax */
2460     /* 09 d0 or %edx,%eax */
2461     *a++ = 0x81; *a++ = 0xe2; *a++ = 0xff; *a++ = 0x00; *a++ = 0x00; *a++ = 0x00;
2462     *a++ = 0xc1; *a++ = 0xe0; *a++ = 0x08;
2463     *a++ = 0x09; *a++ = 0xd0;
2464    
2465     /* eb 00 jmp <okret> */
2466     *a++ = 0xeb; okret1 = a; *a++ = 0;
2467    
2468     *skip = (size_t)a - (size_t)skip - 1;
2469    
2470     /*
2471     * CASE 2:
2472     * memory (edx): 0x12 0x34 0x56 0x78
2473     * register (eax): 0x89abcdef
2474     * mem after swr: 0x12 0x34 0xef 0xcd
2475     */
2476     /* 83 fb 02 cmp $0x2,%ebx */
2477     /* 75 01 jne <skip> */
2478     *a++ = 0x83; *a++ = 0xfb; *a++ = 0x02;
2479     *a++ = 0x75; skip = a; *a++ = 0x01;
2480    
2481     /* 81 e2 ff ff 00 00 and $0x0000ffff,%edx */
2482     /* c1 e0 10 shl $0x10,%eax */
2483     /* 09 d0 or %edx,%eax */
2484     *a++ = 0x81; *a++ = 0xe2; *a++ = 0xff; *a++ = 0xff; *a++ = 0x00; *a++ = 0x00;
2485     *a++ = 0xc1; *a++ = 0xe0; *a++ = 0x10;
2486     *a++ = 0x09; *a++ = 0xd0;
2487    
2488     /* eb 00 jmp <okret> */
2489     *a++ = 0xeb; okret2 = a; *a++ = 0;
2490    
2491     *skip = (size_t)a - (size_t)skip - 1;
2492    
2493     /*
2494     * CASE 3:
2495     * memory (edx): 0x12 0x34 0x56 0x78
2496     * register (eax): 0x89abcdef
2497     * mem after swr: 0x12 0x34 0x56 0xef
2498     */
2499     /* 81 e2 ff ff ff 00 and $0x00ffffff,%edx */
2500     /* c1 e0 18 shl $0x18,%eax */
2501     /* 09 d0 or %edx,%eax */
2502     *a++ = 0x81; *a++ = 0xe2; *a++ = 0xff; *a++ = 0xff; *a++ = 0xff; *a++ = 0x00;
2503     *a++ = 0xc1; *a++ = 0xe0; *a++ = 0x18;
2504     *a++ = 0x09; *a++ = 0xd0;
2505    
2506    
2507     /* okret: */
2508     *okret0 = (size_t)a - (size_t)okret0 - 1;
2509     *okret1 = (size_t)a - (size_t)okret1 - 1;
2510     *okret2 = (size_t)a - (size_t)okret2 - 1;
2511    
2512     /* Store back to memory: */
2513     /* 89 01 mov %eax,(%ecx) */
2514     *a++ = 0x89; *a++ = 0x01;
2515     break;
2516    
2517     default:
2518     bintrans_write_chunkreturn_fail(&a); /* ret (and fail) */
2519     }
2520    
2521     if (load && rt != 0)
2522     store_eax_edx(&a, &dummy_cpu.cd.mips.gpr[rt]);
2523    
2524     *addrp = a;
2525     bintrans_write_pc_inc(addrp);
2526     return 1;
2527     }
2528    
2529    
2530     /*
2531     * bintrans_write_instruction__tlb_rfe_etc():
2532     */
2533     static int bintrans_write_instruction__tlb_rfe_etc(unsigned char **addrp,
2534     int itype)
2535     {
2536     unsigned char *a;
2537     int ofs;
2538    
2539     switch (itype) {
2540     case CALL_TLBP:
2541     case CALL_TLBR:
2542     case CALL_TLBWR:
2543     case CALL_TLBWI:
2544     case CALL_RFE:
2545     case CALL_ERET:
2546     case CALL_SYSCALL:
2547     case CALL_BREAK:
2548     break;
2549     default:
2550     return 0;
2551     }
2552    
2553     a = *addrp;
2554    
2555     /* Put back PC into the cpu struct, both as pc and pc_last */
2556     *a++ = 0x89; *a++ = 0xbe; *a++ = ofs_pc&255;
2557     *a++ = (ofs_pc>>8)&255; *a++ = (ofs_pc>>16)&255;
2558     *a++ = (ofs_pc>>24)&255; /* mov %edi,pc(%esi) */
2559    
2560     *a++ = 0x89; *a++ = 0xbe; *a++ = ofs_pc_last&255;
2561     *a++ = (ofs_pc_last>>8)&255; *a++ = (ofs_pc_last>>16)&255;
2562     *a++ = (ofs_pc_last>>24)&255; /* mov %edi,pc_last(%esi) */
2563    
2564     /* ... and make sure that the high 32 bits are ALSO in pc_last: */
2565     /* 8b 86 38 12 00 00 mov 0x1238(%esi),%eax */
2566     ofs = ofs_pc + 4;
2567     *a++ = 0x8b; *a++ = 0x86; *a++ = ofs&255;
2568     *a++ = (ofs>>8)&255; *a++ = (ofs>>16)&255;
2569     *a++ = (ofs>>24)&255; /* mov %edi,pc(%esi) */
2570    
2571     /* 89 86 34 12 00 00 mov %eax,0x1234(%esi) */
2572     ofs = ofs_pc_last + 4;
2573     *a++ = 0x89; *a++ = 0x86; *a++ = ofs&255;
2574     *a++ = (ofs>>8)&255; *a++ = (ofs>>16)&255;
2575     *a++ = (ofs>>24)&255; /* mov %edi,pc(%esi) */
2576    
2577     switch (itype) {
2578     case CALL_TLBP:
2579     case CALL_TLBR:
2580     /* push readflag */
2581     *a++ = 0x6a; *a++ = (itype == CALL_TLBR);
2582     ofs = ((size_t)&dummy_cpu.cd.mips.bintrans_fast_tlbpr) - (size_t)&dummy_cpu;
2583     break;
2584     case CALL_TLBWR:
2585     case CALL_TLBWI:
2586     /* push randomflag */
2587     *a++ = 0x6a; *a++ = (itype == CALL_TLBWR);
2588     ofs = ((size_t)&dummy_cpu.cd.mips.bintrans_fast_tlbwri) - (size_t)&dummy_cpu;
2589     break;
2590     case CALL_SYSCALL:
2591     case CALL_BREAK:
2592     /* push randomflag */
2593     *a++ = 0x6a; *a++ = (itype == CALL_BREAK? EXCEPTION_BP : EXCEPTION_SYS);
2594     ofs = ((size_t)&dummy_cpu.cd.mips.bintrans_simple_exception) - (size_t)&dummy_cpu;
2595     break;
2596     case CALL_RFE:
2597     ofs = ((size_t)&dummy_cpu.cd.mips.bintrans_fast_rfe) - (size_t)&dummy_cpu;
2598     break;
2599     case CALL_ERET:
2600     ofs = ((size_t)&dummy_cpu.cd.mips.bintrans_fast_eret) - (size_t)&dummy_cpu;
2601     break;
2602     }
2603    
2604     /* push cpu (esi) */
2605     *a++ = 0x56;
2606    
2607     /* eax = points to the right function */
2608     *a++ = 0x8b; *a++ = 0x86;
2609     *a++ = ofs; *a++ = ofs >> 8; *a++ = ofs >> 16; *a++ = ofs >> 24;
2610    
2611     /* ff d0 call *%eax */
2612     *a++ = 0xff; *a++ = 0xd0;
2613    
2614     switch (itype) {
2615     case CALL_RFE:
2616     case CALL_ERET:
2617     /* 83 c4 04 add $4,%esp */
2618     *a++ = 0x83; *a++ = 0xc4; *a++ = 4;
2619     break;
2620     default:
2621     /* 83 c4 08 add $8,%esp */
2622     *a++ = 0x83; *a++ = 0xc4; *a++ = 8;
2623     break;
2624     }
2625    
2626     /* Load PC from the cpu struct. */
2627     *a++ = 0x8b; *a++ = 0xbe; *a++ = ofs_pc&255;
2628     *a++ = (ofs_pc>>8)&255; *a++ = (ofs_pc>>16)&255;
2629     *a++ = (ofs_pc>>24)&255; /* mov pc(%esi),%edi */
2630    
2631     *addrp = a;
2632    
2633     switch (itype) {
2634     case CALL_ERET:
2635     case CALL_SYSCALL:
2636     case CALL_BREAK:
2637     break;
2638     default:
2639     bintrans_write_pc_inc(addrp);
2640     }
2641    
2642     return 1;
2643     }
2644    
2645    
2646     /*
2647     * bintrans_backend_init():
2648     *
2649     * This is neccessary for broken GCC 2.x. (For GCC 3.x, this wouldn't be
2650     * neccessary, and the old code would have worked.)
2651     */
2652     static void bintrans_backend_init(void)
2653     {
2654     int size;
2655     unsigned char *p;
2656    
2657    
2658     /* "runchunk": */
2659     size = 64; /* NOTE: This MUST be enough, or we fail */
2660     p = (unsigned char *)mmap(NULL, size, PROT_READ | PROT_WRITE |
2661     PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0);
2662    
2663     /* If mmap() failed, try malloc(): */
2664     if (p == NULL) {
2665     p = malloc(size);
2666     if (p == NULL) {
2667     fprintf(stderr, "bintrans_backend_init():"
2668     " out of memory\n");
2669     exit(1);
2670     }
2671     }
2672    
2673     bintrans_runchunk = (void *)p;
2674    
2675     *p++ = 0x57; /* push %edi */
2676     *p++ = 0x56; /* push %esi */
2677     *p++ = 0x55; /* push %ebp */
2678     *p++ = 0x53; /* push %ebx */
2679    
2680     /*
2681     * In all translated code, esi points to the cpu struct, and
2682     * ebp is the nr of executed (translated) instructions.
2683     */
2684    
2685     /* 0=ebx, 4=ebp, 8=esi, 0xc=edi, 0x10=retaddr, 0x14=arg0, 0x18=arg1 */
2686    
2687     /* mov 0x8(%esp,1),%esi */
2688     *p++ = 0x8b; *p++ = 0x74; *p++ = 0x24; *p++ = 0x14;
2689    
2690     /* mov nr_instr(%esi),%ebp */
2691     *p++ = 0x8b; *p++ = 0xae; *p++ = ofs_i&255; *p++ = (ofs_i>>8)&255;
2692     *p++ = (ofs_i>>16)&255; *p++ = (ofs_i>>24)&255;
2693    
2694     /* mov pc(%esi),%edi */
2695     *p++ = 0x8b; *p++ = 0xbe; *p++ = ofs_pc&255; *p++ = (ofs_pc>>8)&255;
2696     *p++ = (ofs_pc>>16)&255; *p++ = (ofs_pc>>24)&255;
2697    
2698     /* call *0x18(%esp,1) */
2699     *p++ = 0xff; *p++ = 0x54; *p++ = 0x24; *p++ = 0x18;
2700    
2701     /* mov %ebp,0x1234(%esi) */
2702     *p++ = 0x89; *p++ = 0xae; *p++ = ofs_i&255; *p++ = (ofs_i>>8)&255;
2703     *p++ = (ofs_i>>16)&255; *p++ = (ofs_i>>24)&255;
2704    
2705     /* mov %edi,pc(%esi) */
2706     *p++ = 0x89; *p++ = 0xbe; *p++ = ofs_pc&255; *p++ = (ofs_pc>>8)&255;
2707     *p++ = (ofs_pc>>16)&255; *p++ = (ofs_pc>>24)&255;
2708    
2709     *p++ = 0x5b; /* pop %ebx */
2710     *p++ = 0x5d; /* pop %ebp */
2711     *p++ = 0x5e; /* pop %esi */
2712     *p++ = 0x5f; /* pop %edi */
2713     *p++ = 0xc3; /* ret */
2714    
2715    
2716    
2717     /* "jump_to_32bit_pc": */
2718     size = 128; /* NOTE: This MUST be enough, or we fail */
2719     p = (unsigned char *)mmap(NULL, size, PROT_READ | PROT_WRITE |
2720     PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0);
2721    
2722     /* If mmap() failed, try malloc(): */
2723     if (p == NULL) {
2724     p = malloc(size);
2725     if (p == NULL) {
2726     fprintf(stderr, "bintrans_backend_init():"
2727     " out of memory\n");
2728     exit(1);
2729     }
2730     }
2731    
2732     bintrans_jump_to_32bit_pc = (void *)p;
2733    
2734     /* Don't execute too many instructions. */
2735     /* 81 fd f0 1f 00 00 cmpl $0x1ff0,%ebp */
2736     /* 7c 01 jl <okk> */
2737     /* c3 ret */
2738     *p++ = 0x81; *p++ = 0xfd; *p++ = (N_SAFE_BINTRANS_LIMIT-1) & 255;
2739     *p++ = ((N_SAFE_BINTRANS_LIMIT-1) >> 8) & 255; *p++ = 0; *p++ = 0;
2740     *p++ = 0x7c; *p++ = 0x01;
2741     *p++ = 0xc3;
2742    
2743     /*
2744     * ebx = ((vaddr >> 22) & 1023) * sizeof(void *)
2745     *
2746     * 89 c3 mov %eax,%ebx
2747     * c1 eb 14 shr $20,%ebx
2748     * 81 e3 fc 0f 00 00 and $0xffc,%ebx
2749     */
2750     *p++ = 0x89; *p++ = 0xc3;
2751     *p++ = 0xc1; *p++ = 0xeb; *p++ = 0x14;
2752     *p++ = 0x81; *p++ = 0xe3; *p++ = 0xfc; *p++ = 0x0f; *p++ = 0; *p++ = 0;
2753    
2754     /*
2755     * ecx = vaddr_to_hostaddr_table0
2756     *
2757     * 8b 8e 34 12 00 00 mov 0x1234(%esi),%ecx
2758     */
2759     *p++ = 0x8b; *p++ = 0x8e;
2760     *p++ = ofs_tabl0 & 255; *p++ = (ofs_tabl0 >> 8) & 255;
2761     *p++ = (ofs_tabl0 >> 16) & 255; *p++ = (ofs_tabl0 >> 24) & 255;
2762    
2763     /*
2764     * ecx = vaddr_to_hostaddr_table0[a]
2765     *
2766     * 8b 0c 19 mov (%ecx,%ebx),%ecx
2767     */
2768     *p++ = 0x8b; *p++ = 0x0c; *p++ = 0x19;
2769    
2770     /*
2771     * ebx = ((vaddr >> 12) & 1023) * sizeof(void *)
2772     *
2773     * 89 c3 mov %eax,%ebx
2774     * c1 eb 0a shr $10,%ebx
2775     * 81 e3 fc 0f 00 00 and $0xffc,%ebx
2776     */
2777     *p++ = 0x89; *p++ = 0xc3;
2778     *p++ = 0xc1; *p++ = 0xeb; *p++ = 0x0a;
2779     *p++ = 0x81; *p++ = 0xe3; *p++ = 0xfc; *p++ = 0x0f; *p++ = 0; *p++ = 0;
2780    
2781     /*
2782     * ecx = vaddr_to_hostaddr_table0[a][b].cd.mips.chunks
2783     *
2784     * 8b 8c 19 56 34 12 00 mov 0x123456(%ecx,%ebx,1),%ecx
2785     */
2786     *p++ = 0x8b; *p++ = 0x8c; *p++ = 0x19; *p++ = ofs_chunks & 255;
2787     *p++ = (ofs_chunks >> 8) & 255; *p++ = (ofs_chunks >> 16) & 255;
2788     *p++ = (ofs_chunks >> 24) & 255;
2789    
2790     /*
2791     * ecx = NULL? Then return with failure.
2792     *
2793     * 83 f9 00 cmp $0x0,%ecx
2794     * 75 01 jne <okzzz>
2795     */
2796     *p++ = 0x83; *p++ = 0xf9; *p++ = 0x00;
2797     *p++ = 0x75; *p++ = 0x01;
2798     *p++ = 0xc3; /* TODO: failure? */
2799    
2800     /*
2801     * 25 fc 0f 00 00 and $0xffc,%eax
2802     * 01 c1 add %eax,%ecx
2803     *
2804     * 8b 01 mov (%ecx),%eax
2805     *
2806     * 83 f8 00 cmp $0x0,%eax
2807     * 75 01 jne <ok>
2808     * c3 ret
2809     */
2810     *p++ = 0x25; *p++ = 0xfc; *p++ = 0x0f; *p++ = 0; *p++ = 0;
2811     *p++ = 0x01; *p++ = 0xc1;
2812    
2813     *p++ = 0x8b; *p++ = 0x01;
2814    
2815     *p++ = 0x83; *p++ = 0xf8; *p++ = 0x00;
2816     *p++ = 0x75; *p++ = 0x01;
2817     *p++ = 0xc3; /* TODO: failure? */
2818    
2819     /* 03 86 78 56 34 12 add 0x12345678(%esi),%eax */
2820     /* ff e0 jmp *%eax */
2821     *p++ = 0x03; *p++ = 0x86; *p++ = ofs_chunkbase & 255;
2822     *p++ = (ofs_chunkbase >> 8) & 255; *p++ = (ofs_chunkbase >> 16) & 255;
2823     *p++ = (ofs_chunkbase >> 24) & 255;
2824     *p++ = 0xff; *p++ = 0xe0;
2825    
2826    
2827    
2828 dpavlin 10 /* "load_32bit": */
2829 dpavlin 2 size = 48; /* NOTE: This MUST be enough, or we fail */
2830     p = (unsigned char *)mmap(NULL, size, PROT_READ | PROT_WRITE |
2831     PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0);
2832    
2833     /* If mmap() failed, try malloc(): */
2834     if (p == NULL) {
2835     p = malloc(size);
2836     if (p == NULL) {
2837     fprintf(stderr, "bintrans_backend_init():"
2838     " out of memory\n");
2839     exit(1);
2840     }
2841     }
2842    
2843 dpavlin 10 bintrans_load_32bit = (void *)p;
2844 dpavlin 2
2845     /*
2846     * ebx = ((vaddr >> 22) & 1023) * sizeof(void *)
2847     *
2848     * 89 c3 mov %eax,%ebx
2849     * c1 eb 14 shr $20,%ebx
2850     * 81 e3 fc 0f 00 00 and $0xffc,%ebx
2851     */
2852     *p++ = 0x89; *p++ = 0xc3;
2853     *p++ = 0xc1; *p++ = 0xeb; *p++ = 0x14;
2854     *p++ = 0x81; *p++ = 0xe3; *p++ = 0xfc; *p++ = 0x0f; *p++ = 0; *p++ = 0;
2855    
2856     /*
2857     * ecx = vaddr_to_hostaddr_table0
2858     *
2859     * 8b 8e 34 12 00 00 mov 0x1234(%esi),%ecx
2860     */
2861     *p++ = 0x8b; *p++ = 0x8e; *p++ = ofs_tabl0 & 255;
2862     *p++ = (ofs_tabl0 >> 8) & 255;
2863     *p++ = (ofs_tabl0 >> 16) & 255; *p++ = (ofs_tabl0 >> 24) & 255;
2864    
2865     /*
2866     * ecx = vaddr_to_hostaddr_table0[a]
2867     *
2868     * 8b 0c 19 mov (%ecx,%ebx),%ecx
2869     */
2870     *p++ = 0x8b; *p++ = 0x0c; *p++ = 0x19;
2871    
2872     /*
2873     * ebx = ((vaddr >> 12) & 1023) * sizeof(void *)
2874     *
2875     * 89 c3 mov %eax,%ebx
2876     * c1 eb 0a shr $10,%ebx
2877     * 81 e3 fc 0f 00 00 and $0xffc,%ebx
2878     */
2879     *p++ = 0x89; *p++ = 0xc3;
2880     *p++ = 0xc1; *p++ = 0xeb; *p++ = 0x0a;
2881     *p++ = 0x81; *p++ = 0xe3; *p++ = 0xfc; *p++ = 0x0f; *p++ = 0; *p++ = 0;
2882    
2883     /*
2884 dpavlin 10 * ecx = vaddr_to_hostaddr_table0[a][b*2]
2885 dpavlin 2 *
2886 dpavlin 10 * 8b 0c 59 mov 0(%ecx,%ebx,2),%ecx
2887 dpavlin 2 */
2888 dpavlin 10 *p++ = 0x8b; *p++ = 0x0c; *p++ = 0x59;
2889    
2890     /* ret */
2891     *p++ = 0xc3;
2892    
2893    
2894    
2895     /* "store_32bit": */
2896     size = 48; /* NOTE: This MUST be enough, or we fail */
2897     p = (unsigned char *)mmap(NULL, size, PROT_READ | PROT_WRITE |
2898     PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0);
2899    
2900     /* If mmap() failed, try malloc(): */
2901     if (p == NULL) {
2902     p = malloc(size);
2903     if (p == NULL) {
2904     fprintf(stderr, "bintrans_backend_init():"
2905     " out of memory\n");
2906     exit(1);
2907     }
2908     }
2909    
2910     bintrans_store_32bit = (void *)p;
2911    
2912     /*
2913     * ebx = ((vaddr >> 22) & 1023) * sizeof(void *)
2914     *
2915     * 89 c3 mov %eax,%ebx
2916     * c1 eb 14 shr $20,%ebx
2917     * 81 e3 fc 0f 00 00 and $0xffc,%ebx
2918     */
2919     *p++ = 0x89; *p++ = 0xc3;
2920     *p++ = 0xc1; *p++ = 0xeb; *p++ = 0x14;
2921     *p++ = 0x81; *p++ = 0xe3; *p++ = 0xfc; *p++ = 0x0f; *p++ = 0; *p++ = 0;
2922    
2923     /*
2924     * ecx = vaddr_to_hostaddr_table0
2925     *
2926     * 8b 8e 34 12 00 00 mov 0x1234(%esi),%ecx
2927     */
2928     *p++ = 0x8b; *p++ = 0x8e; *p++ = ofs_tabl0 & 255;
2929     *p++ = (ofs_tabl0 >> 8) & 255;
2930     *p++ = (ofs_tabl0 >> 16) & 255; *p++ = (ofs_tabl0 >> 24) & 255;
2931    
2932     /*
2933     * ecx = vaddr_to_hostaddr_table0[a]
2934     *
2935     * 8b 0c 19 mov (%ecx,%ebx),%ecx
2936     */
2937 dpavlin 2 *p++ = 0x8b; *p++ = 0x0c; *p++ = 0x19;
2938    
2939 dpavlin 10 /*
2940     * ebx = ((vaddr >> 12) & 1023) * sizeof(void *)
2941     *
2942     * 89 c3 mov %eax,%ebx
2943     * c1 eb 0a shr $10,%ebx
2944     * 81 e3 fc 0f 00 00 and $0xffc,%ebx
2945     */
2946     *p++ = 0x89; *p++ = 0xc3;
2947     *p++ = 0xc1; *p++ = 0xeb; *p++ = 0x0a;
2948     *p++ = 0x81; *p++ = 0xe3; *p++ = 0xfc; *p++ = 0x0f; *p++ = 0; *p++ = 0;
2949    
2950     /*
2951     * ecx = vaddr_to_hostaddr_table0[a][b*2]
2952     *
2953     * 8b 4c 59 04 mov 4(%ecx,%ebx,2),%ecx
2954     */
2955     *p++ = 0x8b; *p++ = 0x4c; *p++ = 0x59; *p++ = 0x04;
2956    
2957 dpavlin 2 /* ret */
2958     *p++ = 0xc3;
2959     }
2960    

  ViewVC Help
Powered by ViewVC 1.1.26