Revision 367e86e8
b/Makefile | ||
---|---|---|
1 | 1 |
ARCH=i386 |
2 | 2 |
#ARCH=ppc |
3 |
HOST_CC=gcc |
|
3 | 4 |
|
4 | 5 |
ifeq ($(ARCH),i386) |
5 |
CFLAGS=-Wall -O2 -g |
|
6 |
CFLAGS=-Wall -O2 -g -fomit-frame-pointer
|
|
6 | 7 |
LDFLAGS=-g |
7 | 8 |
LIBS= |
8 | 9 |
CC=gcc |
... | ... | |
27 | 28 |
|
28 | 29 |
######################################################### |
29 | 30 |
|
30 |
DEFINES+=-D_GNU_SOURCE -DGEMU -DDOSEMU #-DNO_TRACE_MSGS |
|
31 |
DEFINES+=-D_GNU_SOURCE -DGEMU -DDOSEMU -DNO_TRACE_MSGS |
|
32 |
DEFINES+=-DCONFIG_PREFIX=\"/usr/local\" |
|
31 | 33 |
LDSCRIPT=$(ARCH).ld |
34 |
LIBS+=-ldl |
|
32 | 35 |
|
33 | 36 |
OBJS= i386/fp87.o i386/interp_main.o i386/interp_modrm.o i386/interp_16_32.o \ |
34 | 37 |
i386/interp_32_16.o i386/interp_32_32.o i386/emu-utils.o \ |
35 | 38 |
i386/dis8086.o i386/emu-ldt.o |
39 |
OBJS+=translate-i386.o op-i386.o |
|
36 | 40 |
OBJS+= elfload.o main.o thunk.o syscall.o |
37 |
|
|
38 | 41 |
SRCS = $(OBJS:.o=.c) |
39 | 42 |
|
40 | 43 |
all: gemu |
41 | 44 |
|
42 | 45 |
gemu: $(OBJS) |
43 |
$(CC) -Wl,-T,$(LDSCRIPT) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
|
|
46 |
$(CC) -Wl,-T,$(LDSCRIPT) $(LDFLAGS) -o $@ $^ $(LIBS)
|
|
44 | 47 |
|
45 | 48 |
depend: $(SRCS) |
46 | 49 |
$(CC) -MM $(CFLAGS) $^ 1>.depend |
47 | 50 |
|
51 |
# old i386 emulator |
|
52 |
i386/interp_32_32.o: i386/interp_32_32.c i386/interp_gen.h |
|
53 |
|
|
54 |
i386/interp_gen.h: i386/gencode |
|
55 |
./i386/gencode > $@ |
|
56 |
|
|
57 |
i386/gencode: i386/gencode.c |
|
58 |
$(CC) -O2 -Wall -g $< -o $@ |
|
59 |
|
|
60 |
# new i386 emulator |
|
61 |
dyngen: dyngen.c |
|
62 |
$(HOST_CC) -O2 -Wall -g $< -o $@ |
|
63 |
|
|
64 |
translate-i386.o: translate-i386.c op-i386.h cpu-i386.h |
|
65 |
|
|
66 |
op-i386.h: op-i386.o dyngen |
|
67 |
./dyngen -o $@ $< |
|
68 |
|
|
69 |
op-i386.o: op-i386.c opreg_template.h ops_template.h |
|
70 |
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< |
|
71 |
|
|
48 | 72 |
%.o: %.c |
49 | 73 |
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< |
50 | 74 |
|
51 | 75 |
clean: |
52 |
rm -f *.o *~ i386/*.o i386/*~ gemu hello test1 test2 TAGS |
|
53 |
|
|
54 |
hello: hello.c |
|
55 |
$(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $< |
|
76 |
rm -f *.o *~ i386/*.o i386/*~ gemu TAGS |
|
56 | 77 |
|
57 |
test1: test1.c |
|
58 |
$(CC) $(CFLAGS) -static $(LDFLAGS) -o $@ $< |
|
78 |
# various test targets |
|
79 |
test speed: gemu |
|
80 |
make -C tests $@ |
|
59 | 81 |
|
60 |
test2: test2.c
|
|
61 |
$(CC) $(CFLAGS) -static $(LDFLAGS) -o $@ $<
|
|
82 |
TAGS:
|
|
83 |
etags *.[ch] i386/*.[ch]
|
|
62 | 84 |
|
63 | 85 |
ifneq ($(wildcard .depend),) |
64 | 86 |
include .depend |
b/TODO | ||
---|---|---|
1 |
- swap all elf paramters |
|
1 |
- tests |
|
2 |
- signals |
|
3 |
- threads |
|
2 | 4 |
- fix printf for doubles (fp87.c bug ?) |
5 |
- make it self runnable (use same trick as ld.so : include its own relocator and libc) |
b/cpu-i386.h | ||
---|---|---|
1 |
#ifndef CPU_I386_H |
|
2 |
#define CPU_I386_H |
|
3 |
|
|
4 |
#define R_EAX 0 |
|
5 |
#define R_ECX 1 |
|
6 |
#define R_EDX 2 |
|
7 |
#define R_EBX 3 |
|
8 |
#define R_ESP 4 |
|
9 |
#define R_EBP 5 |
|
10 |
#define R_ESI 6 |
|
11 |
#define R_EDI 7 |
|
12 |
|
|
13 |
#define R_AL 0 |
|
14 |
#define R_CL 1 |
|
15 |
#define R_DL 2 |
|
16 |
#define R_BL 3 |
|
17 |
#define R_AH 4 |
|
18 |
#define R_CH 5 |
|
19 |
#define R_DH 6 |
|
20 |
#define R_BH 7 |
|
21 |
|
|
22 |
#define R_ES 0 |
|
23 |
#define R_CS 1 |
|
24 |
#define R_SS 2 |
|
25 |
#define R_DS 3 |
|
26 |
#define R_FS 4 |
|
27 |
#define R_GS 5 |
|
28 |
|
|
29 |
#define CC_C 0x0001 |
|
30 |
#define CC_P 0x0004 |
|
31 |
#define CC_A 0x0010 |
|
32 |
#define CC_Z 0x0040 |
|
33 |
#define CC_S 0x0080 |
|
34 |
#define CC_O 0x0800 |
|
35 |
|
|
36 |
#define TRAP_FLAG 0x0100 |
|
37 |
#define INTERRUPT_FLAG 0x0200 |
|
38 |
#define DIRECTION_FLAG 0x0400 |
|
39 |
#define IOPL_FLAG_MASK 0x3000 |
|
40 |
#define NESTED_FLAG 0x4000 |
|
41 |
#define BYTE_FL 0x8000 /* Intel reserved! */ |
|
42 |
#define RF_FLAG 0x10000 |
|
43 |
#define VM_FLAG 0x20000 |
|
44 |
/* AC 0x40000 */ |
|
45 |
|
|
46 |
enum { |
|
47 |
CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ |
|
48 |
CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */ |
|
49 |
CC_OP_MUL, /* modify all flags, C, O = (CC_SRC != 0) */ |
|
50 |
|
|
51 |
CC_OP_ADDB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ |
|
52 |
CC_OP_ADDW, |
|
53 |
CC_OP_ADDL, |
|
54 |
|
|
55 |
CC_OP_SUBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ |
|
56 |
CC_OP_SUBW, |
|
57 |
CC_OP_SUBL, |
|
58 |
|
|
59 |
CC_OP_LOGICB, /* modify all flags, CC_DST = res */ |
|
60 |
CC_OP_LOGICW, |
|
61 |
CC_OP_LOGICL, |
|
62 |
|
|
63 |
CC_OP_INCB, /* modify all flags except, CC_DST = res */ |
|
64 |
CC_OP_INCW, |
|
65 |
CC_OP_INCL, |
|
66 |
|
|
67 |
CC_OP_DECB, /* modify all flags except, CC_DST = res */ |
|
68 |
CC_OP_DECW, |
|
69 |
CC_OP_DECL, |
|
70 |
|
|
71 |
CC_OP_SHLB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */ |
|
72 |
CC_OP_SHLW, |
|
73 |
CC_OP_SHLL, |
|
74 |
|
|
75 |
CC_OP_NB, |
|
76 |
}; |
|
77 |
|
|
78 |
typedef struct CPU86State { |
|
79 |
/* standard registers */ |
|
80 |
uint32_t regs[8]; |
|
81 |
uint32_t pc; /* cs_case + eip value */ |
|
82 |
|
|
83 |
/* eflags handling */ |
|
84 |
uint32_t eflags; |
|
85 |
uint32_t cc_src; |
|
86 |
uint32_t cc_dst; |
|
87 |
uint32_t cc_op; |
|
88 |
int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */ |
|
89 |
|
|
90 |
/* segments */ |
|
91 |
uint8_t *segs_base[6]; |
|
92 |
uint32_t segs[6]; |
|
93 |
|
|
94 |
/* emulator internal variables */ |
|
95 |
uint32_t t0; /* temporary t0 storage */ |
|
96 |
uint32_t t1; /* temporary t1 storage */ |
|
97 |
uint32_t a0; /* temporary a0 storage (address) */ |
|
98 |
} CPU86State; |
|
99 |
|
|
100 |
static inline int ldub(void *ptr) |
|
101 |
{ |
|
102 |
return *(uint8_t *)ptr; |
|
103 |
} |
|
104 |
|
|
105 |
static inline int ldsb(void *ptr) |
|
106 |
{ |
|
107 |
return *(int8_t *)ptr; |
|
108 |
} |
|
109 |
|
|
110 |
static inline int lduw(void *ptr) |
|
111 |
{ |
|
112 |
return *(uint16_t *)ptr; |
|
113 |
} |
|
114 |
|
|
115 |
static inline int ldsw(void *ptr) |
|
116 |
{ |
|
117 |
return *(int16_t *)ptr; |
|
118 |
} |
|
119 |
|
|
120 |
static inline int ldl(void *ptr) |
|
121 |
{ |
|
122 |
return *(uint32_t *)ptr; |
|
123 |
} |
|
124 |
|
|
125 |
|
|
126 |
static inline void stb(void *ptr, int v) |
|
127 |
{ |
|
128 |
*(uint8_t *)ptr = v; |
|
129 |
} |
|
130 |
|
|
131 |
static inline void stw(void *ptr, int v) |
|
132 |
{ |
|
133 |
*(uint16_t *)ptr = v; |
|
134 |
} |
|
135 |
|
|
136 |
static inline void stl(void *ptr, int v) |
|
137 |
{ |
|
138 |
*(uint32_t *)ptr = v; |
|
139 |
} |
|
140 |
|
|
141 |
void port_outb(int addr, int val); |
|
142 |
void port_outw(int addr, int val); |
|
143 |
void port_outl(int addr, int val); |
|
144 |
int port_inb(int addr); |
|
145 |
int port_inw(int addr); |
|
146 |
int port_inl(int addr); |
|
147 |
|
|
148 |
#endif /* CPU_I386_H */ |
b/dyngen.c | ||
---|---|---|
1 |
#include <stdlib.h> |
|
2 |
#include <stdio.h> |
|
3 |
#include <stdarg.h> |
|
4 |
#include <inttypes.h> |
|
5 |
#include <elf.h> |
|
6 |
#include <unistd.h> |
|
7 |
#include <fcntl.h> |
|
8 |
|
|
9 |
#include "thunk.h" |
|
10 |
|
|
11 |
/* all dynamically generated functions begin with this code */ |
|
12 |
#define OP_PREFIX "op" |
|
13 |
|
|
14 |
int elf_must_swap(Elf32_Ehdr *h) |
|
15 |
{ |
|
16 |
union { |
|
17 |
uint32_t i; |
|
18 |
uint8_t b[4]; |
|
19 |
} swaptest; |
|
20 |
|
|
21 |
swaptest.i = 1; |
|
22 |
return (h->e_ident[EI_DATA] == ELFDATA2MSB) != |
|
23 |
(swaptest.b[0] == 0); |
|
24 |
} |
|
25 |
|
|
26 |
void swab16s(uint16_t *p) |
|
27 |
{ |
|
28 |
*p = bswap16(*p); |
|
29 |
} |
|
30 |
|
|
31 |
void swab32s(uint32_t *p) |
|
32 |
{ |
|
33 |
*p = bswap32(*p); |
|
34 |
} |
|
35 |
|
|
36 |
void swab64s(uint32_t *p) |
|
37 |
{ |
|
38 |
*p = bswap64(*p); |
|
39 |
} |
|
40 |
|
|
41 |
void elf_swap_ehdr(Elf32_Ehdr *h) |
|
42 |
{ |
|
43 |
swab16s(&h->e_type); /* Object file type */ |
|
44 |
swab16s(&h-> e_machine); /* Architecture */ |
|
45 |
swab32s(&h-> e_version); /* Object file version */ |
|
46 |
swab32s(&h-> e_entry); /* Entry point virtual address */ |
|
47 |
swab32s(&h-> e_phoff); /* Program header table file offset */ |
|
48 |
swab32s(&h-> e_shoff); /* Section header table file offset */ |
|
49 |
swab32s(&h-> e_flags); /* Processor-specific flags */ |
|
50 |
swab16s(&h-> e_ehsize); /* ELF header size in bytes */ |
|
51 |
swab16s(&h-> e_phentsize); /* Program header table entry size */ |
|
52 |
swab16s(&h-> e_phnum); /* Program header table entry count */ |
|
53 |
swab16s(&h-> e_shentsize); /* Section header table entry size */ |
|
54 |
swab16s(&h-> e_shnum); /* Section header table entry count */ |
|
55 |
swab16s(&h-> e_shstrndx); /* Section header string table index */ |
|
56 |
} |
|
57 |
|
|
58 |
void elf_swap_shdr(Elf32_Shdr *h) |
|
59 |
{ |
|
60 |
swab32s(&h-> sh_name); /* Section name (string tbl index) */ |
|
61 |
swab32s(&h-> sh_type); /* Section type */ |
|
62 |
swab32s(&h-> sh_flags); /* Section flags */ |
|
63 |
swab32s(&h-> sh_addr); /* Section virtual addr at execution */ |
|
64 |
swab32s(&h-> sh_offset); /* Section file offset */ |
|
65 |
swab32s(&h-> sh_size); /* Section size in bytes */ |
|
66 |
swab32s(&h-> sh_link); /* Link to another section */ |
|
67 |
swab32s(&h-> sh_info); /* Additional section information */ |
|
68 |
swab32s(&h-> sh_addralign); /* Section alignment */ |
|
69 |
swab32s(&h-> sh_entsize); /* Entry size if section holds table */ |
|
70 |
} |
|
71 |
|
|
72 |
void elf_swap_phdr(Elf32_Phdr *h) |
|
73 |
{ |
|
74 |
swab32s(&h->p_type); /* Segment type */ |
|
75 |
swab32s(&h->p_offset); /* Segment file offset */ |
|
76 |
swab32s(&h->p_vaddr); /* Segment virtual address */ |
|
77 |
swab32s(&h->p_paddr); /* Segment physical address */ |
|
78 |
swab32s(&h->p_filesz); /* Segment size in file */ |
|
79 |
swab32s(&h->p_memsz); /* Segment size in memory */ |
|
80 |
swab32s(&h->p_flags); /* Segment flags */ |
|
81 |
swab32s(&h->p_align); /* Segment alignment */ |
|
82 |
} |
|
83 |
|
|
84 |
int do_swap; |
|
85 |
int e_machine; |
|
86 |
|
|
87 |
uint16_t get16(uint16_t *p) |
|
88 |
{ |
|
89 |
uint16_t val; |
|
90 |
val = *p; |
|
91 |
if (do_swap) |
|
92 |
val = bswap16(val); |
|
93 |
return val; |
|
94 |
} |
|
95 |
|
|
96 |
uint32_t get32(uint32_t *p) |
|
97 |
{ |
|
98 |
uint32_t val; |
|
99 |
val = *p; |
|
100 |
if (do_swap) |
|
101 |
val = bswap32(val); |
|
102 |
return val; |
|
103 |
} |
|
104 |
|
|
105 |
void put16(uint16_t *p, uint16_t val) |
|
106 |
{ |
|
107 |
if (do_swap) |
|
108 |
val = bswap16(val); |
|
109 |
*p = val; |
|
110 |
} |
|
111 |
|
|
112 |
void put32(uint32_t *p, uint32_t val) |
|
113 |
{ |
|
114 |
if (do_swap) |
|
115 |
val = bswap32(val); |
|
116 |
*p = val; |
|
117 |
} |
|
118 |
|
|
119 |
void __attribute__((noreturn)) error(const char *fmt, ...) |
|
120 |
{ |
|
121 |
va_list ap; |
|
122 |
va_start(ap, fmt); |
|
123 |
fprintf(stderr, "dyngen: "); |
|
124 |
vfprintf(stderr, fmt, ap); |
|
125 |
fprintf(stderr, "\n"); |
|
126 |
va_end(ap); |
|
127 |
exit(1); |
|
128 |
} |
|
129 |
|
|
130 |
|
|
131 |
Elf32_Shdr *find_elf_section(Elf32_Shdr *shdr, int shnum, const char *shstr, |
|
132 |
const char *name) |
|
133 |
{ |
|
134 |
int i; |
|
135 |
const char *shname; |
|
136 |
Elf32_Shdr *sec; |
|
137 |
|
|
138 |
for(i = 0; i < shnum; i++) { |
|
139 |
sec = &shdr[i]; |
|
140 |
if (!sec->sh_name) |
|
141 |
continue; |
|
142 |
shname = shstr + sec->sh_name; |
|
143 |
if (!strcmp(shname, name)) |
|
144 |
return sec; |
|
145 |
} |
|
146 |
return NULL; |
|
147 |
} |
|
148 |
|
|
149 |
void *load_data(int fd, long offset, unsigned int size) |
|
150 |
{ |
|
151 |
char *data; |
|
152 |
|
|
153 |
data = malloc(size); |
|
154 |
if (!data) |
|
155 |
return NULL; |
|
156 |
lseek(fd, offset, SEEK_SET); |
|
157 |
if (read(fd, data, size) != size) { |
|
158 |
free(data); |
|
159 |
return NULL; |
|
160 |
} |
|
161 |
return data; |
|
162 |
} |
|
163 |
|
|
164 |
int strstart(const char *str, const char *val, const char **ptr) |
|
165 |
{ |
|
166 |
const char *p, *q; |
|
167 |
p = str; |
|
168 |
q = val; |
|
169 |
while (*q != '\0') { |
|
170 |
if (*p != *q) |
|
171 |
return 0; |
|
172 |
p++; |
|
173 |
q++; |
|
174 |
} |
|
175 |
if (ptr) |
|
176 |
*ptr = p; |
|
177 |
return 1; |
|
178 |
} |
|
179 |
|
|
180 |
#define MAX_ARGS 3 |
|
181 |
|
|
182 |
/* generate op code */ |
|
183 |
void gen_code(const char *name, unsigned long offset, unsigned long size, |
|
184 |
FILE *outfile, uint8_t *text, void *relocs, int nb_relocs, int reloc_sh_type, |
|
185 |
Elf32_Sym *symtab, char *strtab) |
|
186 |
{ |
|
187 |
int copy_size = 0; |
|
188 |
uint8_t *p_start, *p_end; |
|
189 |
int nb_args, i; |
|
190 |
uint8_t args_present[MAX_ARGS]; |
|
191 |
const char *sym_name, *p; |
|
192 |
|
|
193 |
/* compute exact size excluding return instruction */ |
|
194 |
p_start = text + offset; |
|
195 |
p_end = p_start + size; |
|
196 |
switch(e_machine) { |
|
197 |
case EM_386: |
|
198 |
{ |
|
199 |
uint8_t *p; |
|
200 |
p = p_end - 1; |
|
201 |
/* find ret */ |
|
202 |
while (p > p_start && *p != 0xc3) |
|
203 |
p--; |
|
204 |
/* skip double ret */ |
|
205 |
if (p > p_start && p[-1] == 0xc3) |
|
206 |
p--; |
|
207 |
if (p == p_start) |
|
208 |
error("empty code for %s", name); |
|
209 |
copy_size = p - p_start; |
|
210 |
} |
|
211 |
break; |
|
212 |
case EM_PPC: |
|
213 |
{ |
|
214 |
uint8_t *p; |
|
215 |
p = (void *)(p_end - 4); |
|
216 |
/* find ret */ |
|
217 |
while (p > p_start && get32((uint32_t *)p) != 0x4e800020) |
|
218 |
p -= 4; |
|
219 |
/* skip double ret */ |
|
220 |
if (p > p_start && get32((uint32_t *)(p - 4)) == 0x4e800020) |
|
221 |
p -= 4; |
|
222 |
if (p == p_start) |
|
223 |
error("empty code for %s", name); |
|
224 |
copy_size = p - p_start; |
|
225 |
} |
|
226 |
break; |
|
227 |
default: |
|
228 |
error("unsupported CPU (%d)", e_machine); |
|
229 |
} |
|
230 |
|
|
231 |
/* compute the number of arguments by looking at the relocations */ |
|
232 |
for(i = 0;i < MAX_ARGS; i++) |
|
233 |
args_present[i] = 0; |
|
234 |
|
|
235 |
if (reloc_sh_type == SHT_REL) { |
|
236 |
Elf32_Rel *rel; |
|
237 |
int n; |
|
238 |
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { |
|
239 |
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { |
|
240 |
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; |
|
241 |
if (strstart(sym_name, "__op_param", &p)) { |
|
242 |
n = strtoul(p, NULL, 10); |
|
243 |
if (n >= MAX_ARGS) |
|
244 |
error("too many arguments in %s", name); |
|
245 |
args_present[n - 1] = 1; |
|
246 |
} |
|
247 |
} |
|
248 |
} |
|
249 |
} else { |
|
250 |
Elf32_Rela *rel; |
|
251 |
int n; |
|
252 |
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { |
|
253 |
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { |
|
254 |
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; |
|
255 |
if (strstart(sym_name, "__op_param", &p)) { |
|
256 |
n = strtoul(p, NULL, 10); |
|
257 |
if (n >= MAX_ARGS) |
|
258 |
error("too many arguments in %s", name); |
|
259 |
args_present[n - 1] = 1; |
|
260 |
} |
|
261 |
} |
|
262 |
} |
|
263 |
} |
|
264 |
|
|
265 |
nb_args = 0; |
|
266 |
while (nb_args < MAX_ARGS && args_present[nb_args]) |
|
267 |
nb_args++; |
|
268 |
for(i = nb_args; i < MAX_ARGS; i++) { |
|
269 |
if (args_present[i]) |
|
270 |
error("inconsistent argument numbering in %s", name); |
|
271 |
} |
|
272 |
|
|
273 |
/* output C code */ |
|
274 |
fprintf(outfile, "extern void %s();\n", name); |
|
275 |
fprintf(outfile, "static inline void gen_%s(", name); |
|
276 |
if (nb_args == 0) { |
|
277 |
fprintf(outfile, "void"); |
|
278 |
} else { |
|
279 |
for(i = 0; i < nb_args; i++) { |
|
280 |
if (i != 0) |
|
281 |
fprintf(outfile, ", "); |
|
282 |
fprintf(outfile, "long param%d", i + 1); |
|
283 |
} |
|
284 |
} |
|
285 |
fprintf(outfile, ")\n"); |
|
286 |
fprintf(outfile, "{\n"); |
|
287 |
fprintf(outfile, " memcpy(gen_code_ptr, &%s, %d);\n", name, copy_size); |
|
288 |
|
|
289 |
/* patch relocations */ |
|
290 |
switch(e_machine) { |
|
291 |
case EM_386: |
|
292 |
{ |
|
293 |
Elf32_Rel *rel; |
|
294 |
char name[256]; |
|
295 |
int type; |
|
296 |
long addend; |
|
297 |
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { |
|
298 |
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { |
|
299 |
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; |
|
300 |
if (strstart(sym_name, "__op_param", &p)) { |
|
301 |
snprintf(name, sizeof(name), "param%s", p); |
|
302 |
} else { |
|
303 |
snprintf(name, sizeof(name), "(long)(&%s)", sym_name); |
|
304 |
} |
|
305 |
type = ELF32_R_TYPE(rel->r_info); |
|
306 |
addend = get32((uint32_t *)(text + rel->r_offset)); |
|
307 |
switch(type) { |
|
308 |
case R_386_32: |
|
309 |
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = %s + %ld;\n", |
|
310 |
rel->r_offset - offset, name, addend); |
|
311 |
break; |
|
312 |
case R_386_PC32: |
|
313 |
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = %s - (long)(gen_code_ptr + %ld) + %ld;\n", |
|
314 |
rel->r_offset - offset, name, rel->r_offset - offset, addend); |
|
315 |
break; |
|
316 |
default: |
|
317 |
error("unsupported i386 relocation (%d)", type); |
|
318 |
} |
|
319 |
} |
|
320 |
} |
|
321 |
} |
|
322 |
break; |
|
323 |
default: |
|
324 |
error("unsupported CPU for relocations (%d)", e_machine); |
|
325 |
} |
|
326 |
|
|
327 |
|
|
328 |
fprintf(outfile, " gen_code_ptr += %d;\n", copy_size); |
|
329 |
fprintf(outfile, "}\n\n"); |
|
330 |
} |
|
331 |
|
|
332 |
/* load an elf object file */ |
|
333 |
int load_elf(const char *filename, FILE *outfile) |
|
334 |
{ |
|
335 |
int fd; |
|
336 |
Elf32_Ehdr ehdr; |
|
337 |
Elf32_Shdr *sec, *shdr, *symtab_sec, *strtab_sec, *text_sec; |
|
338 |
int i, j, nb_syms; |
|
339 |
Elf32_Sym *symtab, *sym; |
|
340 |
const char *cpu_name; |
|
341 |
char *shstr, *strtab; |
|
342 |
uint8_t *text; |
|
343 |
void *relocs; |
|
344 |
int nb_relocs, reloc_sh_type; |
|
345 |
|
|
346 |
fd = open(filename, O_RDONLY); |
|
347 |
if (fd < 0) |
|
348 |
error("can't open file '%s'", filename); |
|
349 |
|
|
350 |
/* Read ELF header. */ |
|
351 |
if (read(fd, &ehdr, sizeof (ehdr)) != sizeof (ehdr)) |
|
352 |
error("unable to read file header"); |
|
353 |
|
|
354 |
/* Check ELF identification. */ |
|
355 |
if (ehdr.e_ident[EI_MAG0] != ELFMAG0 |
|
356 |
|| ehdr.e_ident[EI_MAG1] != ELFMAG1 |
|
357 |
|| ehdr.e_ident[EI_MAG2] != ELFMAG2 |
|
358 |
|| ehdr.e_ident[EI_MAG3] != ELFMAG3 |
|
359 |
|| ehdr.e_ident[EI_CLASS] != ELFCLASS32 |
|
360 |
|| ehdr.e_ident[EI_VERSION] != EV_CURRENT) { |
|
361 |
error("bad ELF header"); |
|
362 |
} |
|
363 |
|
|
364 |
do_swap = elf_must_swap(&ehdr); |
|
365 |
if (do_swap) |
|
366 |
elf_swap_ehdr(&ehdr); |
|
367 |
if (ehdr.e_type != ET_REL) |
|
368 |
error("ELF object file expected"); |
|
369 |
if (ehdr.e_version != EV_CURRENT) |
|
370 |
error("Invalid ELF version"); |
|
371 |
e_machine = ehdr.e_machine; |
|
372 |
|
|
373 |
/* read section headers */ |
|
374 |
shdr = load_data(fd, ehdr.e_shoff, ehdr.e_shnum * sizeof(Elf32_Shdr)); |
|
375 |
if (do_swap) { |
|
376 |
for(i = 0; i < ehdr.e_shnum; i++) { |
|
377 |
elf_swap_shdr(&shdr[i]); |
|
378 |
} |
|
379 |
} |
|
380 |
|
|
381 |
sec = &shdr[ehdr.e_shstrndx]; |
|
382 |
shstr = load_data(fd, sec->sh_offset, sec->sh_size); |
|
383 |
|
|
384 |
/* text section */ |
|
385 |
|
|
386 |
text_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".text"); |
|
387 |
if (!text_sec) |
|
388 |
error("could not find .text section"); |
|
389 |
text = load_data(fd, text_sec->sh_offset, text_sec->sh_size); |
|
390 |
|
|
391 |
/* find text relocations, if any */ |
|
392 |
nb_relocs = 0; |
|
393 |
relocs = NULL; |
|
394 |
reloc_sh_type = 0; |
|
395 |
for(i = 0; i < ehdr.e_shnum; i++) { |
|
396 |
sec = &shdr[i]; |
|
397 |
if ((sec->sh_type == SHT_REL || sec->sh_type == SHT_RELA) && |
|
398 |
sec->sh_info == (text_sec - shdr)) { |
|
399 |
reloc_sh_type = sec->sh_type; |
|
400 |
relocs = load_data(fd, sec->sh_offset, sec->sh_size); |
|
401 |
nb_relocs = sec->sh_size / sec->sh_entsize; |
|
402 |
if (do_swap) { |
|
403 |
if (sec->sh_type == SHT_REL) { |
|
404 |
Elf32_Rel *rel = relocs; |
|
405 |
for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) { |
|
406 |
swab32s(&rel->r_offset); |
|
407 |
swab32s(&rel->r_info); |
|
408 |
} |
|
409 |
} else { |
|
410 |
Elf32_Rela *rel = relocs; |
|
411 |
for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) { |
|
412 |
swab32s(&rel->r_offset); |
|
413 |
swab32s(&rel->r_info); |
|
414 |
swab32s(&rel->r_addend); |
|
415 |
} |
|
416 |
} |
|
417 |
} |
|
418 |
break; |
|
419 |
} |
|
420 |
} |
|
421 |
|
|
422 |
symtab_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".symtab"); |
|
423 |
if (!symtab_sec) |
|
424 |
error("could not find .symtab section"); |
|
425 |
strtab_sec = &shdr[symtab_sec->sh_link]; |
|
426 |
|
|
427 |
symtab = load_data(fd, symtab_sec->sh_offset, symtab_sec->sh_size); |
|
428 |
strtab = load_data(fd, strtab_sec->sh_offset, strtab_sec->sh_size); |
|
429 |
|
|
430 |
nb_syms = symtab_sec->sh_size / sizeof(Elf32_Sym); |
|
431 |
if (do_swap) { |
|
432 |
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { |
|
433 |
swab32s(&sym->st_name); |
|
434 |
swab32s(&sym->st_value); |
|
435 |
swab32s(&sym->st_size); |
|
436 |
swab16s(&sym->st_shndx); |
|
437 |
} |
|
438 |
} |
|
439 |
|
|
440 |
switch(e_machine) { |
|
441 |
case EM_386: |
|
442 |
cpu_name = "i386"; |
|
443 |
break; |
|
444 |
case EM_PPC: |
|
445 |
cpu_name = "ppc"; |
|
446 |
break; |
|
447 |
case EM_MIPS: |
|
448 |
cpu_name = "mips"; |
|
449 |
break; |
|
450 |
case EM_ARM: |
|
451 |
cpu_name = "arm"; |
|
452 |
break; |
|
453 |
case EM_SPARC: |
|
454 |
cpu_name = "sparc"; |
|
455 |
break; |
|
456 |
default: |
|
457 |
error("unsupported CPU (e_machine=%d)", e_machine); |
|
458 |
} |
|
459 |
|
|
460 |
fprintf(outfile, "#include \"gen-%s.h\"\n\n", cpu_name); |
|
461 |
|
|
462 |
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { |
|
463 |
const char *name; |
|
464 |
name = strtab + sym->st_name; |
|
465 |
if (strstart(name, "op_", NULL) || |
|
466 |
strstart(name, "op1_", NULL) || |
|
467 |
strstart(name, "op2_", NULL) || |
|
468 |
strstart(name, "op3_", NULL)) { |
|
469 |
#if 0 |
|
470 |
printf("%4d: %s pos=0x%08x len=%d\n", |
|
471 |
i, name, sym->st_value, sym->st_size); |
|
472 |
#endif |
|
473 |
if (sym->st_shndx != (text_sec - shdr)) |
|
474 |
error("invalid section for opcode (0x%x)", sym->st_shndx); |
|
475 |
gen_code(name, sym->st_value, sym->st_size, outfile, |
|
476 |
text, relocs, nb_relocs, reloc_sh_type, symtab, strtab); |
|
477 |
} |
|
478 |
} |
|
479 |
|
|
480 |
close(fd); |
|
481 |
return 0; |
|
482 |
} |
|
483 |
|
|
484 |
void usage(void) |
|
485 |
{ |
|
486 |
printf("dyngen (c) 2003 Fabrice Bellard\n" |
|
487 |
"usage: dyngen [-o outfile] objfile\n" |
|
488 |
"Generate a dynamic code generator from an object file\n"); |
|
489 |
exit(1); |
|
490 |
} |
|
491 |
|
|
492 |
int main(int argc, char **argv) |
|
493 |
{ |
|
494 |
int c; |
|
495 |
const char *filename, *outfilename; |
|
496 |
FILE *outfile; |
|
497 |
|
|
498 |
outfilename = "out.c"; |
|
499 |
for(;;) { |
|
500 |
c = getopt(argc, argv, "ho:"); |
|
501 |
if (c == -1) |
|
502 |
break; |
|
503 |
switch(c) { |
|
504 |
case 'h': |
|
505 |
usage(); |
|
506 |
break; |
|
507 |
case 'o': |
|
508 |
outfilename = optarg; |
|
509 |
break; |
|
510 |
} |
|
511 |
} |
|
512 |
if (optind >= argc) |
|
513 |
usage(); |
|
514 |
filename = argv[optind]; |
|
515 |
outfile = fopen(outfilename, "w"); |
|
516 |
if (!outfile) |
|
517 |
error("could not open '%s'", outfilename); |
|
518 |
load_elf(filename, outfile); |
|
519 |
fclose(outfile); |
|
520 |
return 0; |
|
521 |
} |
b/gen-i386.h | ||
---|---|---|
1 |
static inline void gen_start(void) |
|
2 |
{ |
|
3 |
} |
|
4 |
|
|
5 |
static inline void gen_end(void) |
|
6 |
{ |
|
7 |
*gen_code_ptr++ = 0xc3; /* ret */ |
|
8 |
} |
b/linux-user/main.c | ||
---|---|---|
191 | 191 |
} |
192 | 192 |
|
193 | 193 |
/***********************************************************/ |
194 |
/* new CPU core */ |
|
195 |
|
|
196 |
void port_outb(int addr, int val) |
|
197 |
{ |
|
198 |
fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val); |
|
199 |
} |
|
200 |
|
|
201 |
void port_outw(int addr, int val) |
|
202 |
{ |
|
203 |
fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val); |
|
204 |
} |
|
205 |
|
|
206 |
void port_outl(int addr, int val) |
|
207 |
{ |
|
208 |
fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val); |
|
209 |
} |
|
210 |
|
|
211 |
int port_inb(int addr) |
|
212 |
{ |
|
213 |
fprintf(stderr, "inb: port=0x%04x\n", addr); |
|
214 |
return 0; |
|
215 |
} |
|
216 |
|
|
217 |
int port_inw(int addr) |
|
218 |
{ |
|
219 |
fprintf(stderr, "inw: port=0x%04x\n", addr); |
|
220 |
return 0; |
|
221 |
} |
|
222 |
|
|
223 |
int port_inl(int addr) |
|
224 |
{ |
|
225 |
fprintf(stderr, "inl: port=0x%04x\n", addr); |
|
226 |
return 0; |
|
227 |
} |
|
228 |
|
|
194 | 229 |
|
195 | 230 |
/* XXX: currently we use LDT entries */ |
196 | 231 |
#define __USER_CS (0x23|4) |
... | ... | |
270 | 305 |
LDT[__USER_DS >> 3].dwSelLimit = 0xfffff; |
271 | 306 |
LDT[__USER_DS >> 3].lpSelBase = NULL; |
272 | 307 |
init_npu(); |
308 |
build_decode_tables(); |
|
273 | 309 |
|
274 | 310 |
for(;;) { |
275 | 311 |
int err; |
b/op-i386.c | ||
---|---|---|
8 | 8 |
typedef signed int int32_t; |
9 | 9 |
typedef signed long long int64_t; |
10 | 10 |
|
11 |
#define NULL 0 |
|
12 |
|
|
11 | 13 |
#ifdef __i386__ |
12 | 14 |
register int T0 asm("esi"); |
13 | 15 |
register int T1 asm("ebx"); |
... | ... | |
74 | 76 |
#include "cpu-i386.h" |
75 | 77 |
|
76 | 78 |
typedef struct CCTable { |
77 |
int (*compute_c)(void); /* return the C flag */ |
|
78 |
int (*compute_z)(void); /* return the Z flag */ |
|
79 |
int (*compute_s)(void); /* return the S flag */ |
|
80 |
int (*compute_o)(void); /* return the O flag */ |
|
81 | 79 |
int (*compute_all)(void); /* return all the flags */ |
80 |
int (*compute_c)(void); /* return the C flag */ |
|
82 | 81 |
} CCTable; |
83 | 82 |
|
83 |
extern CCTable cc_table[]; |
|
84 |
|
|
84 | 85 |
uint8_t parity_table[256] = { |
85 | 86 |
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, |
86 | 87 |
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, |
... | ... | |
116 | 117 |
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, |
117 | 118 |
}; |
118 | 119 |
|
119 |
static int compute_eflags_all(void) |
|
120 |
{ |
|
121 |
return CC_SRC; |
|
122 |
} |
|
123 |
|
|
124 |
static int compute_eflags_addb(void) |
|
125 |
{ |
|
126 |
int cf, pf, af, zf, sf, of; |
|
127 |
int src1, src2; |
|
128 |
src1 = CC_SRC; |
|
129 |
src2 = CC_DST - CC_SRC; |
|
130 |
cf = (uint8_t)CC_DST < (uint8_t)src1; |
|
131 |
pf = parity_table[(uint8_t)CC_DST]; |
|
132 |
af = (CC_DST ^ src1 ^ src2) & 0x10; |
|
133 |
zf = ((uint8_t)CC_DST != 0) << 6; |
|
134 |
sf = CC_DST & 0x80; |
|
135 |
of = ((src1 ^ src2 ^ -1) & (src1 ^ CC_DST) & 0x80) << 4; |
|
136 |
return cf | pf | af | zf | sf | of; |
|
137 |
} |
|
138 |
|
|
139 |
static int compute_eflags_subb(void) |
|
140 |
{ |
|
141 |
int cf, pf, af, zf, sf, of; |
|
142 |
int src1, src2; |
|
143 |
src1 = CC_SRC; |
|
144 |
src2 = CC_SRC - CC_DST; |
|
145 |
cf = (uint8_t)src1 < (uint8_t)src2; |
|
146 |
pf = parity_table[(uint8_t)CC_DST]; |
|
147 |
af = (CC_DST ^ src1 ^ src2) & 0x10; |
|
148 |
zf = ((uint8_t)CC_DST != 0) << 6; |
|
149 |
sf = CC_DST & 0x80; |
|
150 |
of = ((src1 ^ src2 ^ -1) & (src1 ^ CC_DST) & 0x80) << 4; |
|
151 |
return cf | pf | af | zf | sf | of; |
|
152 |
} |
|
153 |
|
|
154 |
static int compute_eflags_logicb(void) |
|
155 |
{ |
|
156 |
cf = 0; |
|
157 |
pf = parity_table[(uint8_t)CC_DST]; |
|
158 |
af = 0; |
|
159 |
zf = ((uint8_t)CC_DST != 0) << 6; |
|
160 |
sf = CC_DST & 0x80; |
|
161 |
of = 0; |
|
162 |
return cf | pf | af | zf | sf | of; |
|
163 |
} |
|
164 |
|
|
165 |
static int compute_eflags_incb(void) |
|
166 |
{ |
|
167 |
int cf, pf, af, zf, sf, of; |
|
168 |
int src2; |
|
169 |
src1 = CC_DST - 1; |
|
170 |
src2 = 1; |
|
171 |
cf = CC_SRC; |
|
172 |
pf = parity_table[(uint8_t)CC_DST]; |
|
173 |
af = (CC_DST ^ src1 ^ src2) & 0x10; |
|
174 |
zf = ((uint8_t)CC_DST != 0) << 6; |
|
175 |
sf = CC_DST & 0x80; |
|
176 |
of = ((src1 ^ src2 ^ -1) & (src1 ^ CC_DST) & 0x80) << 4; |
|
177 |
return cf | pf | af | zf | sf | of; |
|
178 |
} |
|
179 |
|
|
180 |
static int compute_eflags_decb(void) |
|
181 |
{ |
|
182 |
int cf, pf, af, zf, sf, of; |
|
183 |
int src1, src2; |
|
184 |
src1 = CC_DST + 1; |
|
185 |
src2 = 1; |
|
186 |
cf = (uint8_t)src1 < (uint8_t)src2; |
|
187 |
pf = parity_table[(uint8_t)CC_DST]; |
|
188 |
af = (CC_DST ^ src1 ^ src2) & 0x10; |
|
189 |
zf = ((uint8_t)CC_DST != 0) << 6; |
|
190 |
sf = CC_DST & 0x80; |
|
191 |
of = ((src1 ^ src2 ^ -1) & (src1 ^ CC_DST) & 0x80) << 4; |
|
192 |
return cf | pf | af | zf | sf | of; |
|
193 |
} |
|
194 |
|
|
195 |
static int compute_eflags_shlb(void) |
|
196 |
{ |
|
197 |
cf = CC_SRC; |
|
198 |
pf = parity_table[(uint8_t)CC_DST]; |
|
199 |
af = 0; /* undefined */ |
|
200 |
zf = ((uint8_t)CC_DST != 0) << 6; |
|
201 |
sf = CC_DST & 0x80; |
|
202 |
of = 0; /* undefined */ |
|
203 |
return cf | pf | af | zf | sf | of; |
|
204 |
} |
|
120 |
/* modulo 17 table */ |
|
121 |
const uint8_t rclw_table[32] = { |
|
122 |
0, 1, 2, 3, 4, 5, 6, 7, |
|
123 |
8, 9,10,11,12,13,14,15, |
|
124 |
16, 0, 1, 2, 3, 4, 5, 6, |
|
125 |
7, 8, 9,10,11,12,13,14, |
|
126 |
}; |
|
205 | 127 |
|
206 |
static int compute_eflags_shrb(void) |
|
207 |
{ |
|
208 |
cf = CC_SRC & 1; |
|
209 |
pf = parity_table[(uint8_t)CC_DST]; |
|
210 |
af = 0; /* undefined */ |
|
211 |
zf = ((uint8_t)CC_DST != 0) << 6; |
|
212 |
sf = CC_DST & 0x80; |
|
213 |
of = sf << 4; |
|
214 |
return cf | pf | af | zf | sf | of; |
|
215 |
} |
|
128 |
/* modulo 9 table */ |
|
129 |
const uint8_t rclb_table[32] = { |
|
130 |
0, 1, 2, 3, 4, 5, 6, 7, |
|
131 |
8, 0, 1, 2, 3, 4, 5, 6, |
|
132 |
7, 8, 0, 1, 2, 3, 4, 5, |
|
133 |
6, 7, 8, 0, 1, 2, 3, 4, |
|
134 |
}; |
|
216 | 135 |
|
217 |
static int compute_eflags_mul(void) |
|
136 |
/* n must be a constant to be efficient */ |
|
137 |
static inline int lshift(int x, int n) |
|
218 | 138 |
{ |
219 |
cf = (CC_SRC != 0); |
|
220 |
pf = 0; /* undefined */ |
|
221 |
af = 0; /* undefined */ |
|
222 |
zf = 0; /* undefined */ |
|
223 |
sf = 0; /* undefined */ |
|
224 |
of = cf << 11; |
|
225 |
return cf | pf | af | zf | sf | of; |
|
139 |
if (n >= 0) |
|
140 |
return x << n; |
|
141 |
else |
|
142 |
return x >> (-n); |
|
226 | 143 |
} |
227 |
|
|
228 |
CTable cc_table[CC_OP_NB] = { |
|
229 |
[CC_OP_DYNAMIC] = { NULL, NULL, NULL }, |
|
230 |
[CC_OP_EFLAGS] = { NULL, NULL, NULL }, |
|
231 |
|
|
232 |
}; |
|
233 | 144 |
|
234 | 145 |
/* we define the various pieces of code used by the JIT */ |
235 | 146 |
|
... | ... | |
365 | 276 |
CC_DST = T0 & T1; |
366 | 277 |
} |
367 | 278 |
|
368 |
/* shifts */ |
|
369 |
|
|
370 |
void OPPROTO op_roll_T0_T1_cc(void) |
|
371 |
{ |
|
372 |
int count; |
|
373 |
count = T1 & 0x1f; |
|
374 |
if (count) { |
|
375 |
CC_SRC = T0; |
|
376 |
T0 = (T0 << count) | (T0 >> (32 - count)); |
|
377 |
CC_DST = T0; |
|
378 |
CC_OP = CC_OP_ROLL; |
|
379 |
} |
|
380 |
} |
|
381 |
|
|
382 |
void OPPROTO op_rolw_T0_T1_cc(void) |
|
383 |
{ |
|
384 |
int count; |
|
385 |
count = T1 & 0xf; |
|
386 |
if (count) { |
|
387 |
T0 = T0 & 0xffff; |
|
388 |
CC_SRC = T0; |
|
389 |
T0 = (T0 << count) | (T0 >> (16 - count)); |
|
390 |
CC_DST = T0; |
|
391 |
CC_OP = CC_OP_ROLW; |
|
392 |
} |
|
393 |
} |
|
394 |
|
|
395 |
void OPPROTO op_rolb_T0_T1_cc(void) |
|
396 |
{ |
|
397 |
int count; |
|
398 |
count = T1 & 0x7; |
|
399 |
if (count) { |
|
400 |
T0 = T0 & 0xff; |
|
401 |
CC_SRC = T0; |
|
402 |
T0 = (T0 << count) | (T0 >> (8 - count)); |
|
403 |
CC_DST = T0; |
|
404 |
CC_OP = CC_OP_ROLB; |
|
405 |
} |
|
406 |
} |
|
407 |
|
|
408 |
void OPPROTO op_rorl_T0_T1_cc(void) |
|
409 |
{ |
|
410 |
int count; |
|
411 |
count = T1 & 0x1f; |
|
412 |
if (count) { |
|
413 |
CC_SRC = T0; |
|
414 |
T0 = (T0 >> count) | (T0 << (32 - count)); |
|
415 |
CC_DST = T0; |
|
416 |
CC_OP = CC_OP_RORB; |
|
417 |
} |
|
418 |
} |
|
419 |
|
|
420 |
void OPPROTO op_rorw_T0_T1_cc(void) |
|
421 |
{ |
|
422 |
int count; |
|
423 |
count = T1 & 0xf; |
|
424 |
if (count) { |
|
425 |
CC_SRC = T0; |
|
426 |
T0 = (T0 >> count) | (T0 << (16 - count)); |
|
427 |
CC_DST = T0; |
|
428 |
CC_OP = CC_OP_RORW; |
|
429 |
} |
|
430 |
} |
|
431 |
|
|
432 |
void OPPROTO op_rorb_T0_T1_cc(void) |
|
433 |
{ |
|
434 |
int count; |
|
435 |
count = T1 & 0x7; |
|
436 |
if (count) { |
|
437 |
CC_SRC = T0; |
|
438 |
T0 = (T0 >> count) | (T0 << (8 - count)); |
|
439 |
CC_DST = T0; |
|
440 |
CC_OP = CC_OP_RORL; |
|
441 |
} |
|
442 |
} |
|
443 |
|
|
444 |
/* modulo 17 table */ |
|
445 |
const uint8_t rclw_table[32] = { |
|
446 |
0, 1, 2, 3, 4, 5, 6, 7, |
|
447 |
8, 9,10,11,12,13,14,15, |
|
448 |
16, 0, 1, 2, 3, 4, 5, 6, |
|
449 |
7, 8, 9,10,11,12,13,14, |
|
450 |
}; |
|
451 |
|
|
452 |
/* modulo 9 table */ |
|
453 |
const uint8_t rclb_table[32] = { |
|
454 |
0, 1, 2, 3, 4, 5, 6, 7, |
|
455 |
8, 0, 1, 2, 3, 4, 5, 6, |
|
456 |
7, 8, 0, 1, 2, 3, 4, 5, |
|
457 |
6, 7, 8, 0, 1, 2, 3, 4, |
|
458 |
}; |
|
459 |
|
|
460 |
void helper_rcll_T0_T1_cc(void) |
|
461 |
{ |
|
462 |
int count, res; |
|
463 |
|
|
464 |
count = T1 & 0x1f; |
|
465 |
if (count) { |
|
466 |
CC_SRC = T0; |
|
467 |
res = (T0 << count) | (cc_table[CC_OP].compute_c() << (count - 1)); |
|
468 |
if (count > 1) |
|
469 |
res |= T0 >> (33 - count); |
|
470 |
T0 = res; |
|
471 |
CC_DST = T0 ^ CC_SRC; /* O is in bit 31 */ |
|
472 |
CC_SRC >>= (32 - count); /* CC is in bit 0 */ |
|
473 |
CC_OP = CC_OP_RCLL; |
|
474 |
} |
|
475 |
} |
|
476 |
|
|
477 |
void OPPROTO op_rcll_T0_T1_cc(void) |
|
478 |
{ |
|
479 |
helper_rcll_T0_T1_cc(); |
|
480 |
} |
|
481 |
|
|
482 |
void OPPROTO op_rclw_T0_T1_cc(void) |
|
483 |
{ |
|
484 |
int count; |
|
485 |
count = rclw_table[T1 & 0x1f]; |
|
486 |
if (count) { |
|
487 |
T0 = T0 & 0xffff; |
|
488 |
CC_SRC = T0; |
|
489 |
T0 = (T0 << count) | (cc_table[CC_OP].compute_c() << (count - 1)) | |
|
490 |
(T0 >> (17 - count)); |
|
491 |
CC_DST = T0 ^ CC_SRC; |
|
492 |
CC_SRC >>= (16 - count); |
|
493 |
CC_OP = CC_OP_RCLW; |
|
494 |
} |
|
495 |
} |
|
496 |
|
|
497 |
void OPPROTO op_rclb_T0_T1_cc(void) |
|
498 |
{ |
|
499 |
int count; |
|
500 |
count = rclb_table[T1 & 0x1f]; |
|
501 |
if (count) { |
|
502 |
T0 = T0 & 0xff; |
|
503 |
CC_SRC = T0; |
|
504 |
T0 = (T0 << count) | (cc_table[CC_OP].compute_c() << (count - 1)) | |
|
505 |
(T0 >> (9 - count)); |
|
506 |
CC_DST = T0 ^ CC_SRC; |
|
507 |
CC_SRC >>= (8 - count); |
|
508 |
CC_OP = CC_OP_RCLB; |
|
509 |
} |
|
510 |
} |
|
511 |
|
|
512 |
void OPPROTO op_rcrl_T0_T1_cc(void) |
|
513 |
{ |
|
514 |
int count, res; |
|
515 |
count = T1 & 0x1f; |
|
516 |
if (count) { |
|
517 |
CC_SRC = T0; |
|
518 |
res = (T0 >> count) | (cc_table[CC_OP].compute_c() << (32 - count)); |
|
519 |
if (count > 1) |
|
520 |
res |= T0 << (33 - count); |
|
521 |
T0 = res; |
|
522 |
CC_DST = T0 ^ CC_SRC; |
|
523 |
CC_SRC >>= (count - 1); |
|
524 |
CC_OP = CC_OP_RCLL; |
|
525 |
} |
|
526 |
} |
|
527 |
|
|
528 |
void OPPROTO op_rcrw_T0_T1_cc(void) |
|
529 |
{ |
|
530 |
int count; |
|
531 |
count = rclw_table[T1 & 0x1f]; |
|
532 |
if (count) { |
|
533 |
T0 = T0 & 0xffff; |
|
534 |
CC_SRC = T0; |
|
535 |
T0 = (T0 >> count) | (cc_table[CC_OP].compute_c() << (16 - count)) | |
|
536 |
(T0 << (17 - count)); |
|
537 |
CC_DST = T0 ^ CC_SRC; |
|
538 |
CC_SRC >>= (count - 1); |
|
539 |
CC_OP = CC_OP_RCLW; |
|
540 |
} |
|
541 |
} |
|
542 |
|
|
543 |
void OPPROTO op_rcrb_T0_T1_cc(void) |
|
544 |
{ |
|
545 |
int count; |
|
546 |
count = rclb_table[T1 & 0x1f]; |
|
547 |
if (count) { |
|
548 |
T0 = T0 & 0xff; |
|
549 |
CC_SRC = T0; |
|
550 |
T0 = (T0 >> count) | (cc_table[CC_OP].compute_c() << (8 - count)) | |
|
551 |
(T0 << (9 - count)); |
|
552 |
CC_DST = T0 ^ CC_SRC; |
|
553 |
CC_SRC >>= (count - 1); |
|
554 |
CC_OP = CC_OP_RCLB; |
|
555 |
} |
|
556 |
} |
|
557 |
|
|
558 |
void OPPROTO op_shll_T0_T1_cc(void) |
|
559 |
{ |
|
560 |
int count; |
|
561 |
count = T1 & 0x1f; |
|
562 |
if (count == 1) { |
|
563 |
CC_SRC = T0; |
|
564 |
T0 = T0 << 1; |
|
565 |
CC_DST = T0; |
|
566 |
CC_OP = CC_OP_ADDL; |
|
567 |
} else if (count) { |
|
568 |
CC_SRC = T0 >> (32 - count); |
|
569 |
T0 = T0 << count; |
|
570 |
CC_DST = T0; |
|
571 |
CC_OP = CC_OP_SHLL; |
|
572 |
} |
|
573 |
} |
|
574 |
|
|
575 |
void OPPROTO op_shlw_T0_T1_cc(void) |
|
576 |
{ |
|
577 |
int count; |
|
578 |
count = T1 & 0x1f; |
|
579 |
if (count == 1) { |
|
580 |
CC_SRC = T0; |
|
581 |
T0 = T0 << 1; |
|
582 |
CC_DST = T0; |
|
583 |
CC_OP = CC_OP_ADDW; |
|
584 |
} else if (count) { |
|
585 |
CC_SRC = T0 >> (16 - count); |
|
586 |
T0 = T0 << count; |
|
587 |
CC_DST = T0; |
|
588 |
CC_OP = CC_OP_SHLW; |
|
589 |
} |
|
590 |
} |
|
591 |
|
|
592 |
void OPPROTO op_shlb_T0_T1_cc(void) |
|
593 |
{ |
|
594 |
int count; |
|
595 |
count = T1 & 0x1f; |
|
596 |
if (count == 1) { |
|
597 |
CC_SRC = T0; |
|
598 |
T0 = T0 << 1; |
|
599 |
CC_DST = T0; |
|
600 |
CC_OP = CC_OP_ADDB; |
|
601 |
} else if (count) { |
|
602 |
CC_SRC = T0 >> (8 - count); |
|
603 |
T0 = T0 << count; |
|
604 |
CC_DST = T0; |
|
605 |
CC_OP = CC_OP_SHLB; |
|
606 |
} |
|
607 |
} |
|
608 |
|
|
609 |
void OPPROTO op_shrl_T0_T1_cc(void) |
|
610 |
{ |
|
611 |
int count; |
|
612 |
count = T1 & 0x1f; |
|
613 |
if (count == 1) { |
|
614 |
CC_SRC = T0; |
|
615 |
T0 = T0 >> 1; |
|
616 |
CC_DST = T0; |
|
617 |
CC_OP = CC_OP_SHRL; |
|
618 |
} else if (count) { |
|
619 |
CC_SRC = T0 >> (count - 1); |
|
620 |
T0 = T0 >> count; |
|
621 |
CC_DST = T0; |
|
622 |
CC_OP = CC_OP_SHLL; |
|
623 |
} |
|
624 |
} |
|
625 |
|
|
626 |
void OPPROTO op_shrw_T0_T1_cc(void) |
|
627 |
{ |
|
628 |
int count; |
|
629 |
count = T1 & 0x1f; |
|
630 |
if (count == 1) { |
|
631 |
T0 = T0 & 0xffff; |
|
632 |
CC_SRC = T0; |
|
633 |
T0 = T0 >> 1; |
|
634 |
CC_DST = T0; |
|
635 |
CC_OP = CC_OP_SHRW; |
|
636 |
} else if (count) { |
|
637 |
T0 = T0 & 0xffff; |
|
638 |
CC_SRC = T0 >> (count - 1); |
|
639 |
T0 = T0 >> count; |
|
640 |
CC_DST = T0; |
|
641 |
CC_OP = CC_OP_SHLW; |
|
642 |
} |
|
643 |
} |
|
644 |
|
|
645 |
void OPPROTO op_shrb_T0_T1_cc(void) |
|
646 |
{ |
|
647 |
int count; |
|
648 |
count = T1 & 0x1f; |
|
649 |
if (count == 1) { |
|
650 |
T0 = T0 & 0xff; |
|
651 |
CC_SRC = T0; |
|
652 |
T0 = T0 >> 1; |
|
653 |
CC_DST = T0; |
|
654 |
CC_OP = CC_OP_SHRB; |
|
655 |
} else if (count) { |
|
656 |
T0 = T0 & 0xff; |
|
657 |
CC_SRC = T0 >> (count - 1); |
|
658 |
T0 = T0 >> count; |
|
659 |
CC_DST = T0; |
|
660 |
CC_OP = CC_OP_SHLB; |
|
661 |
} |
|
662 |
} |
|
663 |
|
|
664 |
void OPPROTO op_sarl_T0_T1_cc(void) |
|
665 |
{ |
|
666 |
int count; |
|
667 |
count = T1 & 0x1f; |
|
668 |
if (count) { |
|
669 |
CC_SRC = (int32_t)T0 >> (count - 1); |
|
670 |
T0 = (int32_t)T0 >> count; |
|
671 |
CC_DST = T0; |
|
672 |
CC_OP = CC_OP_SHLL; |
|
673 |
} |
|
674 |
} |
|
675 |
|
|
676 |
void OPPROTO op_sarw_T0_T1_cc(void) |
|
677 |
{ |
|
678 |
int count; |
|
679 |
count = T1 & 0x1f; |
|
680 |
if (count) { |
|
681 |
CC_SRC = (int16_t)T0 >> (count - 1); |
|
682 |
T0 = (int16_t)T0 >> count; |
|
683 |
CC_DST = T0; |
|
684 |
CC_OP = CC_OP_SHLW; |
|
685 |
} |
|
686 |
} |
|
687 |
|
|
688 |
void OPPROTO op_sarb_T0_T1_cc(void) |
|
689 |
{ |
|
690 |
int count; |
|
691 |
count = T1 & 0x1f; |
|
692 |
if (count) { |
|
693 |
CC_SRC = (int8_t)T0 >> (count - 1); |
|
694 |
T0 = (int8_t)T0 >> count; |
|
695 |
CC_DST = T0; |
|
696 |
CC_OP = CC_OP_SHLB; |
|
697 |
} |
|
698 |
} |
|
699 |
|
|
700 | 279 |
/* multiply/divide */ |
701 | 280 |
void OPPROTO op_mulb_AL_T0(void) |
702 | 281 |
{ |
... | ... | |
924 | 503 |
stl((uint8_t *)A0, T0); |
925 | 504 |
} |
926 | 505 |
|
927 |
/* flags */ |
|
928 |
|
|
929 |
void OPPROTO op_set_cc_op(void) |
|
930 |
{ |
|
931 |
CC_OP = PARAM1; |
|
932 |
} |
|
933 |
|
|
934 |
void OPPROTO op_movl_eflags_T0(void) |
|
935 |
{ |
|
936 |
CC_SRC = T0; |
|
937 |
DF = (T0 & DIRECTION_FLAG) ? -1 : 1; |
|
938 |
} |
|
939 |
|
|
940 |
void OPPROTO op_movb_eflags_T0(void) |
|
941 |
{ |
|
942 |
int cc_o; |
|
943 |
cc_o = cc_table[CC_OP].compute_o(); |
|
944 |
CC_SRC = T0 | (cc_o << 11); |
|
945 |
} |
|
946 |
|
|
947 |
void OPPROTO op_movl_T0_eflags(void) |
|
948 |
{ |
|
949 |
cc_table[CC_OP].compute_eflags(); |
|
950 |
} |
|
951 |
|
|
952 |
void OPPROTO op_cld(void) |
|
953 |
{ |
|
954 |
DF = 1; |
|
955 |
} |
|
956 |
|
|
957 |
void OPPROTO op_std(void) |
|
958 |
{ |
|
959 |
DF = -1; |
|
960 |
} |
|
961 |
|
|
962 | 506 |
/* jumps */ |
963 | 507 |
|
964 | 508 |
/* indirect jump */ |
... | ... | |
972 | 516 |
PC = PARAM1; |
973 | 517 |
} |
974 | 518 |
|
975 |
void OPPROTO op_jne_b(void) |
|
976 |
{ |
|
977 |
if ((uint8_t)CC_DST != 0) |
|
978 |
PC += PARAM1; |
|
979 |
else |
|
980 |
PC += PARAM2; |
|
981 |
FORCE_RET(); |
|
982 |
} |
|
983 |
|
|
984 |
void OPPROTO op_jne_w(void) |
|
985 |
{ |
|
986 |
if ((uint16_t)CC_DST != 0) |
|
987 |
PC += PARAM1; |
|
988 |
else |
|
989 |
PC += PARAM2; |
|
990 |
FORCE_RET(); |
|
991 |
} |
|
992 |
|
|
993 |
void OPPROTO op_jne_l(void) |
|
994 |
{ |
|
995 |
if (CC_DST != 0) |
|
996 |
PC += PARAM1; |
|
997 |
else |
|
998 |
PC += PARAM2; |
|
999 |
FORCE_RET(); /* generate a return so that gcc does not generate an |
|
1000 |
early function return */ |
|
1001 |
} |
|
1002 |
|
|
1003 | 519 |
/* string ops */ |
1004 | 520 |
|
1005 | 521 |
#define ldul ldl |
1006 | 522 |
|
1007 |
#define SUFFIX b |
|
1008 | 523 |
#define SHIFT 0 |
1009 |
#include "opstring_template.h" |
|
1010 |
#undef SUFFIX |
|
524 |
#include "ops_template.h" |
|
1011 | 525 |
#undef SHIFT |
1012 | 526 |
|
1013 |
#define SUFFIX w |
|
1014 | 527 |
#define SHIFT 1 |
1015 |
#include "opstring_template.h" |
|
1016 |
#undef SUFFIX |
|
528 |
#include "ops_template.h" |
|
1017 | 529 |
#undef SHIFT |
1018 | 530 |
|
1019 |
#define SUFFIX l |
|
1020 | 531 |
#define SHIFT 2 |
1021 |
#include "opstring_template.h" |
|
1022 |
#undef SUFFIX |
|
532 |
#include "ops_template.h" |
|
1023 | 533 |
#undef SHIFT |
1024 | 534 |
|
1025 | 535 |
/* sign extend */ |
... | ... | |
1095 | 605 |
{ |
1096 | 606 |
ESP += PARAM1; |
1097 | 607 |
} |
608 |
|
|
609 |
/* flags handling */ |
|
610 |
|
|
611 |
/* slow jumps cases (compute x86 flags) */ |
|
612 |
void OPPROTO op_jo_cc(void) |
|
613 |
{ |
|
614 |
int eflags; |
|
615 |
eflags = cc_table[CC_OP].compute_all(); |
|
616 |
if (eflags & CC_O) |
|
617 |
PC += PARAM1; |
|
618 |
else |
|
619 |
PC += PARAM2; |
|
620 |
} |
|
621 |
|
|
622 |
void OPPROTO op_jb_cc(void) |
|
623 |
{ |
|
624 |
if (cc_table[CC_OP].compute_c()) |
|
625 |
PC += PARAM1; |
|
626 |
else |
|
627 |
PC += PARAM2; |
|
628 |
} |
|
629 |
|
|
630 |
void OPPROTO op_jz_cc(void) |
|
631 |
{ |
|
632 |
int eflags; |
|
633 |
eflags = cc_table[CC_OP].compute_all(); |
|
634 |
if (eflags & CC_Z) |
|
635 |
PC += PARAM1; |
|
636 |
else |
|
637 |
PC += PARAM2; |
|
638 |
} |
|
639 |
|
Also available in: Unified diff